diff --git a/feature/topic/api/src/main/res/values/strings.xml b/feature/topic/api/src/main/res/values/strings.xml
index 1e3f376cf..a5f3c0d58 100644
--- a/feature/topic/api/src/main/res/values/strings.xml
+++ b/feature/topic/api/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
-->
Loading topic
+ Unable to load topic
+ Unable to load news
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 5f6782160..98582c44a 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 topicError: String
@Before
fun setup() {
composeTestRule.activity.apply {
topicLoading = getString(R.string.feature_topic_api_loading)
+ topicError = getString(R.string.feature_topic_api_error)
}
}
@@ -70,6 +72,26 @@ class TopicScreenTest {
.assertExists()
}
+ @Test
+ fun topicError_whenTopicIsError_isShown() {
+ composeTestRule.setContent {
+ TopicScreen(
+ topicUiState = TopicUiState.Error,
+ newsUiState = NewsUiState.Loading,
+ showBackButton = true,
+ onBackClick = {},
+ onFollowClick = {},
+ onTopicClick = {},
+ onBookmarkChanged = { _, _ -> },
+ onNewsResourceViewed = {},
+ )
+ }
+
+ composeTestRule
+ .onNodeWithText(topicError)
+ .assertExists()
+ }
+
@Test
fun topicTitle_whenTopicIsSuccess_isShown() {
val testTopic = followableTopicTestData.first()
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 5c802f225..7469c3a42 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,17 @@ internal fun TopicScreen(
)
}
- TopicUiState.Error -> TODO()
+ TopicUiState.Error -> {
+ item {
+ TopicErrorToolbar(
+ showBackButton = showBackButton,
+ onBackClick = onBackClick,
+ )
+ }
+ item {
+ TopicErrorState()
+ }
+ }
is TopicUiState.Success -> {
item {
TopicToolbar(
@@ -177,12 +187,12 @@ private fun topicItemsSize(
topicUiState: TopicUiState,
newsUiState: NewsUiState,
) = when (topicUiState) {
- TopicUiState.Error -> 0 // Nothing
+ TopicUiState.Error -> 2 // Toolbar and error message
TopicUiState.Loading -> 1 // Loading bar
is TopicUiState.Success -> when (newsUiState) {
- NewsUiState.Error -> 0 // Nothing
- NewsUiState.Loading -> 1 // Loading bar
- is NewsUiState.Success -> 2 + newsUiState.news.size // Toolbar, header
+ NewsUiState.Error -> 3 // Toolbar, header, and error message
+ NewsUiState.Loading -> 3 // Toolbar, header, and loading indicator
+ is NewsUiState.Success -> 2 + newsUiState.news.size // Toolbar, header, and news items
}
}
@@ -250,7 +260,11 @@ private fun LazyListScope.userNewsResourceCards(
}
else -> item {
- Text("Error") // TODO
+ Text(
+ text = stringResource(id = TopicR.string.feature_topic_api_news_error),
+ modifier = Modifier.padding(24.dp),
+ style = MaterialTheme.typography.bodyLarge,
+ )
}
}
}
@@ -273,6 +287,44 @@ private fun TopicBodyPreview() {
}
}
+@Composable
+private fun TopicErrorState(modifier: Modifier = Modifier) {
+ Text(
+ text = stringResource(id = TopicR.string.feature_topic_api_error),
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(24.dp)
+ .testTag("topic:error"),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+}
+
+@Composable
+private fun TopicErrorToolbar(
+ showBackButton: Boolean,
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(bottom = 32.dp),
+ ) {
+ if (showBackButton) {
+ IconButton(onClick = onBackClick) {
+ Icon(
+ imageVector = NiaIcons.ArrowBack,
+ contentDescription = stringResource(
+ id = UiR.string.core_ui_back,
+ ),
+ )
+ }
+ }
+ }
+}
+
@Composable
private fun TopicToolbar(
uiState: FollowableTopic,