From f5ac01de093b1143a5fd44d2c2d5178c667f31e8 Mon Sep 17 00:00:00 2001 From: Wally Hackenslacker Date: Mon, 16 Mar 2026 01:33:48 -0400 Subject: [PATCH] feat: route board and card taps to detail screens --- .../kanbn4droid/app/BoardDetailFlowTest.kt | 47 +++++++++++++++++++ .../kanbn4droid/app/BoardsFlowTest.kt | 12 ++--- app/src/main/AndroidManifest.xml | 2 +- .../app/BoardDetailPlaceholderActivity.kt | 24 ---------- .../kanbn4droid/app/BoardsActivity.kt | 7 +-- .../app/CardDetailPlaceholderActivity.kt | 24 ++++++++++ .../app/boarddetail/BoardDetailActivity.kt | 18 ++++++- .../activity_card_detail_placeholder.xml | 30 ++++++++++++ 8 files changed, 129 insertions(+), 35 deletions(-) delete mode 100644 app/src/main/java/space/hackenslacker/kanbn4droid/app/BoardDetailPlaceholderActivity.kt create mode 100644 app/src/main/java/space/hackenslacker/kanbn4droid/app/CardDetailPlaceholderActivity.kt create mode 100644 app/src/main/res/layout/activity_card_detail_placeholder.xml diff --git a/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardDetailFlowTest.kt b/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardDetailFlowTest.kt index ef032bb..f73ad9b 100644 --- a/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardDetailFlowTest.kt +++ b/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardDetailFlowTest.kt @@ -11,6 +11,9 @@ import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.longClick import androidx.test.espresso.action.ViewActions.replaceText import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent +import androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.isDisplayed @@ -53,12 +56,14 @@ class BoardDetailFlowTest { @Before fun setUp() { originalLocale = Locale.getDefault() + Intents.init() defaultDataSource = FakeBoardDetailDataSource(initialDetail = detailOneList()) BoardDetailActivity.testDataSourceFactory = { defaultDataSource } } @After fun tearDown() { + Intents.release() BoardDetailActivity.testDataSourceFactory = null originalLocale?.let { Locale.setDefault(it) } } @@ -245,6 +250,29 @@ class BoardDetailFlowTest { } } + @Test + fun cardTapNavigatesToCardPlaceholderWithExtras() { + launchBoardDetail() + + onView(withText("Card 1")).perform(click()) + + Intents.intended(hasComponent(CardDetailPlaceholderActivity::class.java.name)) + Intents.intended(hasExtra(CardDetailPlaceholderActivity.EXTRA_CARD_ID, "card-1")) + Intents.intended(hasExtra(CardDetailPlaceholderActivity.EXTRA_CARD_TITLE, "Card 1")) + } + + @Test + fun cardTapBlankTitle_usesCardFallbackInPlaceholderExtra() { + defaultDataSource.currentDetail = detailWithCardTitle(" ") + launchBoardDetail() + + onView(withId(R.id.cardItemRoot)).perform(click()) + + Intents.intended(hasComponent(CardDetailPlaceholderActivity::class.java.name)) + Intents.intended(hasExtra(CardDetailPlaceholderActivity.EXTRA_CARD_ID, "card-1")) + Intents.intended(hasExtra(CardDetailPlaceholderActivity.EXTRA_CARD_TITLE, "Card")) + } + private fun launchBoardDetail(): ActivityScenario { val intent = Intent( androidx.test.core.app.ApplicationProvider.getApplicationContext(), @@ -353,5 +381,24 @@ class BoardDetailFlowTest { ), ) } + + fun detailWithCardTitle(title: String): BoardDetail { + return detailOneList().copy( + lists = listOf( + BoardListDetail( + id = "list-1", + title = "To Do", + cards = listOf( + BoardCardSummary( + id = "card-1", + title = title, + tags = emptyList(), + dueAtEpochMillis = null, + ), + ), + ), + ), + ) + } } } diff --git a/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardsFlowTest.kt b/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardsFlowTest.kt index fbd6c8e..603ee70 100644 --- a/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardsFlowTest.kt +++ b/app/src/androidTest/java/space/hackenslacker/kanbn4droid/app/BoardsFlowTest.kt @@ -46,7 +46,7 @@ class BoardsFlowTest { } @Test - fun boardTapNavigatesToDetailPlaceholderWithExtras() { + fun boardTapNavigatesToBoardDetailActivity() { MainActivity.dependencies.apiClientFactory = { FakeBoardsApiClient( boards = mutableListOf(BoardSummary("1", "Alpha")), @@ -58,9 +58,9 @@ class BoardsFlowTest { onView(withText("Alpha")).perform(click()) - Intents.intended(hasComponent(BoardDetailPlaceholderActivity::class.java.name)) - Intents.intended(hasExtra(BoardDetailPlaceholderActivity.EXTRA_BOARD_ID, "1")) - Intents.intended(hasExtra(BoardDetailPlaceholderActivity.EXTRA_BOARD_TITLE, "Alpha")) + Intents.intended(hasComponent(space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity::class.java.name)) + Intents.intended(hasExtra(space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity.EXTRA_BOARD_ID, "1")) + Intents.intended(hasExtra(space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity.EXTRA_BOARD_TITLE, "Alpha")) } @Test @@ -79,8 +79,8 @@ class BoardsFlowTest { onView(withId(R.id.useTemplateChip)).perform(click()) onView(withId(android.R.id.button1)).inRoot(isDialog()).perform(click()) - Intents.intended(hasComponent(BoardDetailPlaceholderActivity::class.java.name)) - Intents.intended(hasExtra(BoardDetailPlaceholderActivity.EXTRA_BOARD_TITLE, "Roadmap")) + Intents.intended(hasComponent(space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity::class.java.name)) + Intents.intended(hasExtra(space.hackenslacker.kanbn4droid.app.boarddetail.BoardDetailActivity.EXTRA_BOARD_TITLE, "Roadmap")) } @Test diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 14acd5f..69dfb94 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:usesCleartextTraffic="true" android:theme="@style/Theme.Kanbn4Droid"> when (event) { is BoardDetailUiEvent.NavigateToCardPlaceholder -> { - Snackbar.make(pager, getString(R.string.board_detail_card_detail_coming_soon), Snackbar.LENGTH_SHORT).show() + val cardTitle = viewModel.uiState.value.boardDetail + ?.lists + .orEmpty() + .asSequence() + .flatMap { list -> list.cards.asSequence() } + .firstOrNull { card -> card.id == event.cardId } + ?.title + .orEmpty() + .trim() + .ifBlank { "Card" } + startActivity( + Intent(this@BoardDetailActivity, CardDetailPlaceholderActivity::class.java) + .putExtra(CardDetailPlaceholderActivity.EXTRA_CARD_ID, event.cardId) + .putExtra(CardDetailPlaceholderActivity.EXTRA_CARD_TITLE, cardTitle), + ) } is BoardDetailUiEvent.ShowServerError -> { diff --git a/app/src/main/res/layout/activity_card_detail_placeholder.xml b/app/src/main/res/layout/activity_card_detail_placeholder.xml new file mode 100644 index 0000000..7189ea4 --- /dev/null +++ b/app/src/main/res/layout/activity_card_detail_placeholder.xml @@ -0,0 +1,30 @@ + + + + + + + +