Skip to content

Commit 4a1fb58

Browse files
authored
Merge pull request #301 from android/caren/topics_bookmarks
Enable bookmarks on topics page
2 parents 23ad5e8 + cf9cf1d commit 4a1fb58

File tree

4 files changed

+209
-102
lines changed

4 files changed

+209
-102
lines changed

feature/topic/src/androidTest/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreenTest.kt

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import androidx.compose.ui.test.performScrollToNode
2727
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
2828
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
2929
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video
30+
import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource
3031
import com.google.samples.apps.nowinandroid.core.model.data.Topic
3132
import kotlinx.datetime.Instant
3233
import org.junit.Before
@@ -56,10 +57,11 @@ class TopicScreenTest {
5657
fun niaLoadingWheel_whenScreenIsLoading_showLoading() {
5758
composeTestRule.setContent {
5859
TopicScreen(
59-
topicState = TopicUiState.Loading,
60-
newsState = NewsUiState.Loading,
60+
topicUiState = TopicUiState.Loading,
61+
newsUiState = NewsUiState.Loading,
6162
onBackClick = { },
62-
onFollowClick = { }
63+
onFollowClick = { },
64+
onBookmarkChanged = { _, _ -> },
6365
)
6466
}
6567

@@ -73,10 +75,11 @@ class TopicScreenTest {
7375
val testTopic = testTopics.first()
7476
composeTestRule.setContent {
7577
TopicScreen(
76-
topicState = TopicUiState.Success(testTopic),
77-
newsState = NewsUiState.Loading,
78+
topicUiState = TopicUiState.Success(testTopic),
79+
newsUiState = NewsUiState.Loading,
7880
onBackClick = { },
79-
onFollowClick = { }
81+
onFollowClick = { },
82+
onBookmarkChanged = { _, _ -> },
8083
)
8184
}
8285

@@ -95,10 +98,18 @@ class TopicScreenTest {
9598
fun news_whenTopicIsLoading_isNotShown() {
9699
composeTestRule.setContent {
97100
TopicScreen(
98-
topicState = TopicUiState.Loading,
99-
newsState = NewsUiState.Success(sampleNewsResources),
101+
topicUiState = TopicUiState.Loading,
102+
newsUiState = NewsUiState.Success(
103+
sampleNewsResources.mapIndexed { index, newsResource ->
104+
SaveableNewsResource(
105+
newsResource = newsResource,
106+
isSaved = index % 2 == 0,
107+
)
108+
}
109+
),
100110
onBackClick = { },
101-
onFollowClick = { }
111+
onFollowClick = { },
112+
onBookmarkChanged = { _, _ -> },
102113
)
103114
}
104115

@@ -107,15 +118,24 @@ class TopicScreenTest {
107118
.onNodeWithContentDescription(topicLoading)
108119
.assertExists()
109120
}
121+
110122
@Test
111123
fun news_whenSuccessAndTopicIsSuccess_isShown() {
112124
val testTopic = testTopics.first()
113125
composeTestRule.setContent {
114126
TopicScreen(
115-
topicState = TopicUiState.Success(testTopic),
116-
newsState = NewsUiState.Success(sampleNewsResources),
127+
topicUiState = TopicUiState.Success(testTopic),
128+
newsUiState = NewsUiState.Success(
129+
sampleNewsResources.mapIndexed { index, newsResource ->
130+
SaveableNewsResource(
131+
newsResource = newsResource,
132+
isSaved = index % 2 == 0,
133+
)
134+
}
135+
),
117136
onBackClick = { },
118-
onFollowClick = { }
137+
onFollowClick = { },
138+
onBookmarkChanged = { _, _ -> },
119139
)
120140
}
121141

feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilte
5252
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel
5353
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
5454
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
55+
import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource
5556
import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources
5657
import com.google.samples.apps.nowinandroid.core.model.data.previewTopics
5758
import com.google.samples.apps.nowinandroid.core.ui.DevicePreviews
@@ -66,24 +67,27 @@ fun TopicRoute(
6667
modifier: Modifier = Modifier,
6768
viewModel: TopicViewModel = hiltViewModel(),
6869
) {
69-
val uiState: TopicScreenUiState by viewModel.uiState.collectAsStateWithLifecycle()
70+
val topicUiState: TopicUiState by viewModel.topicUiState.collectAsStateWithLifecycle()
71+
val newsUiState: NewsUiState by viewModel.newUiState.collectAsStateWithLifecycle()
7072

7173
TopicScreen(
72-
topicState = uiState.topicState,
73-
newsState = uiState.newsState,
74+
topicUiState = topicUiState,
75+
newsUiState = newsUiState,
7476
modifier = modifier,
7577
onBackClick = onBackClick,
7678
onFollowClick = viewModel::followTopicToggle,
79+
onBookmarkChanged = viewModel::bookmarkNews,
7780
)
7881
}
7982

8083
@VisibleForTesting
8184
@Composable
8285
internal fun TopicScreen(
83-
topicState: TopicUiState,
84-
newsState: NewsUiState,
86+
topicUiState: TopicUiState,
87+
newsUiState: NewsUiState,
8588
onBackClick: () -> Unit,
8689
onFollowClick: (Boolean) -> Unit,
90+
onBookmarkChanged: (String, Boolean) -> Unit,
8791
modifier: Modifier = Modifier,
8892
) {
8993
LazyColumn(
@@ -93,7 +97,7 @@ internal fun TopicScreen(
9397
item {
9498
Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing))
9599
}
96-
when (topicState) {
100+
when (topicUiState) {
97101
Loading -> item {
98102
NiaLoadingWheel(
99103
modifier = modifier,
@@ -106,14 +110,15 @@ internal fun TopicScreen(
106110
TopicToolbar(
107111
onBackClick = onBackClick,
108112
onFollowClick = onFollowClick,
109-
uiState = topicState.followableTopic,
113+
uiState = topicUiState.followableTopic,
110114
)
111115
}
112116
TopicBody(
113-
name = topicState.followableTopic.topic.name,
114-
description = topicState.followableTopic.topic.longDescription,
115-
news = newsState,
116-
imageUrl = topicState.followableTopic.topic.imageUrl
117+
name = topicUiState.followableTopic.topic.name,
118+
description = topicUiState.followableTopic.topic.longDescription,
119+
news = newsUiState,
120+
imageUrl = topicUiState.followableTopic.topic.imageUrl,
121+
onBookmarkChanged = onBookmarkChanged
117122
)
118123
}
119124
}
@@ -127,14 +132,15 @@ private fun LazyListScope.TopicBody(
127132
name: String,
128133
description: String,
129134
news: NewsUiState,
130-
imageUrl: String
135+
imageUrl: String,
136+
onBookmarkChanged: (String, Boolean) -> Unit
131137
) {
132138
// TODO: Show icon if available
133139
item {
134140
TopicHeader(name, description, imageUrl)
135141
}
136142

137-
TopicCards(news)
143+
TopicCards(news, onBookmarkChanged)
138144
}
139145

140146
@Composable
@@ -161,14 +167,17 @@ private fun TopicHeader(name: String, description: String, imageUrl: String) {
161167
}
162168
}
163169

164-
private fun LazyListScope.TopicCards(news: NewsUiState) {
170+
private fun LazyListScope.TopicCards(
171+
news: NewsUiState,
172+
onBookmarkChanged: (String, Boolean) -> Unit
173+
) {
165174
when (news) {
166175
is NewsUiState.Success -> {
167176
newsResourceCardItems(
168177
items = news.news,
169-
newsResourceMapper = { it },
170-
isBookmarkedMapper = { /* TODO */ false },
171-
onToggleBookmark = { /* TODO */ },
178+
newsResourceMapper = { it.newsResource },
179+
isBookmarkedMapper = { it.isSaved },
180+
onToggleBookmark = { onBookmarkChanged(it.newsResource.id, !it.isSaved) },
172181
itemModifier = Modifier.padding(24.dp)
173182
)
174183
}
@@ -188,7 +197,7 @@ private fun TopicBodyPreview() {
188197
LazyColumn {
189198
TopicBody(
190199
"Jetpack Compose", "Lorem ipsum maximum",
191-
NewsUiState.Success(emptyList()), ""
200+
NewsUiState.Success(emptyList()), "", { _, _ -> }
192201
)
193202
}
194203
}
@@ -237,10 +246,18 @@ fun TopicScreenPopulated() {
237246
NiaTheme {
238247
NiaBackground {
239248
TopicScreen(
240-
topicState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)),
241-
newsState = NewsUiState.Success(previewNewsResources),
249+
topicUiState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)),
250+
newsUiState = NewsUiState.Success(
251+
previewNewsResources.mapIndexed { index, newsResource ->
252+
SaveableNewsResource(
253+
newsResource = newsResource,
254+
isSaved = index % 2 == 0,
255+
)
256+
}
257+
),
242258
onBackClick = {},
243-
onFollowClick = {}
259+
onFollowClick = {},
260+
onBookmarkChanged = { _, _ -> },
244261
)
245262
}
246263
}
@@ -252,10 +269,11 @@ fun TopicScreenLoading() {
252269
NiaTheme {
253270
NiaBackground {
254271
TopicScreen(
255-
topicState = TopicUiState.Loading,
256-
newsState = NewsUiState.Loading,
272+
topicUiState = TopicUiState.Loading,
273+
newsUiState = NewsUiState.Loading,
257274
onBackClick = {},
258-
onFollowClick = {}
275+
onFollowClick = {},
276+
onBookmarkChanged = { _, _ -> },
259277
)
260278
}
261279
}

0 commit comments

Comments
 (0)