From c160d18ea505969674ae7b9b8bfa31b6c949fdd9 Mon Sep 17 00:00:00 2001 From: Noah Statton Date: Fri, 15 May 2026 14:55:17 -0400 Subject: [PATCH] fix: render error UI for TopicUiState.Error instead of crashing --- .../topic/api/src/main/res/values/strings.xml | 1 + .../feature/topic/impl/TopicScreenTest.kt | 22 +++++++++++++++++++ .../feature/topic/impl/TopicScreen.kt | 22 +++++++++++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/feature/topic/api/src/main/res/values/strings.xml b/feature/topic/api/src/main/res/values/strings.xml index 1e3f376cf8..a629d0aade 100644 --- a/feature/topic/api/src/main/res/values/strings.xml +++ b/feature/topic/api/src/main/res/values/strings.xml @@ -16,4 +16,5 @@ --> Loading topic + Couldn\'t load topic diff --git a/feature/topic/impl/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreenTest.kt b/feature/topic/impl/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreenTest.kt index 5f6782160a..57c5682f7b 100644 --- a/feature/topic/impl/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreenTest.kt +++ b/feature/topic/impl/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreenTest.kt @@ -42,11 +42,13 @@ class TopicScreenTest { val composeTestRule = createAndroidComposeRule() private lateinit var topicLoading: String + private lateinit var topicErrorHeader: String @Before fun setup() { composeTestRule.activity.apply { topicLoading = getString(R.string.feature_topic_api_loading) + topicErrorHeader = getString(R.string.feature_topic_api_error_header) } } @@ -97,6 +99,26 @@ class TopicScreenTest { .assertExists() } + @Test + fun errorMessage_whenTopicIsError_isShown() { + composeTestRule.setContent { + TopicScreen( + topicUiState = TopicUiState.Error, + newsUiState = NewsUiState.Loading, + showBackButton = true, + onBackClick = {}, + onFollowClick = {}, + onTopicClick = {}, + onBookmarkChanged = { _, _ -> }, + onNewsResourceViewed = {}, + ) + } + + composeTestRule + .onNodeWithText(topicErrorHeader) + .assertExists() + } + @Test fun news_whenTopicIsLoading_isNotShown() { composeTestRule.setContent { diff --git a/feature/topic/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreen.kt b/feature/topic/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreen.kt index 5c802f225b..7a78c625ef 100644 --- a/feature/topic/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreen.kt +++ b/feature/topic/impl/src/main/kotlin/com/google/samples/apps/nowinandroid/feature/topic/impl/TopicScreen.kt @@ -129,7 +129,9 @@ internal fun TopicScreen( ) } - TopicUiState.Error -> TODO() + TopicUiState.Error -> item { + TopicErrorBody() + } is TopicUiState.Success -> { item { TopicToolbar( @@ -177,7 +179,7 @@ private fun topicItemsSize( topicUiState: TopicUiState, newsUiState: NewsUiState, ) = when (topicUiState) { - TopicUiState.Error -> 0 // Nothing + TopicUiState.Error -> 1 // Error message TopicUiState.Loading -> 1 // Loading bar is TopicUiState.Success -> when (newsUiState) { NewsUiState.Error -> 0 // Nothing @@ -203,6 +205,22 @@ private fun LazyListScope.topicBody( userNewsResourceCards(news, onBookmarkChanged, onNewsResourceViewed, onTopicClick) } +@Composable +private fun TopicErrorBody() { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 48.dp), + ) { + Text( + text = stringResource(id = TopicR.string.feature_topic_api_error_header), + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(vertical = 24.dp), + ) + } +} + @Composable private fun TopicHeader(name: String, description: String, imageUrl: String) { Column(