From 464f28a07fac87d088bac975c8c29400aa211ae7 Mon Sep 17 00:00:00 2001 From: magicalmeghan Date: Mon, 19 Dec 2022 11:39:05 -0800 Subject: [PATCH] Renamed SaveableNewsResource to UserNewsResource --- ...Case.kt => GetUserNewsResourcesUseCase.kt} | 36 ++++---- .../core/domain/model/FollowableTopic.kt | 18 +++- .../core/domain/model/UserNewsResource.kt | 84 ++++++++++++++++++- .../domain/GetUserNewsResourcesUseCaseTest.kt | 67 +++++++++++++-- .../core/ui/NewsResourceCardTest.kt | 4 +- .../apps/nowinandroid/core/ui/NewsFeed.kt | 21 ++--- .../nowinandroid/core/ui/NewsResourceCard.kt | 30 +++---- .../core/ui/NewsResourceCardList.kt | 5 +- .../feature/bookmarks/BookmarksScreen.kt | 5 +- .../feature/bookmarks/BookmarksViewModel.kt | 4 +- .../bookmarks/BookmarksViewModelTest.kt | 6 +- .../feature/foryou/ForYouScreen.kt | 17 ++-- .../feature/foryou/ForYouViewModel.kt | 4 +- .../feature/foryou/ForYouViewModelTest.kt | 78 +++++++++++++++-- .../nowinandroid/feature/topic/TopicScreen.kt | 12 +-- .../feature/topic/TopicViewModel.kt | 6 +- .../feature/topic/TopicViewModelTest.kt | 6 +- 17 files changed, 304 insertions(+), 99 deletions(-) rename core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/{GetSaveableNewsResourcesUseCase.kt => GetUserNewsResourcesUseCase.kt} (62%) diff --git a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetSaveableNewsResourcesUseCase.kt b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt similarity index 62% rename from core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetSaveableNewsResourcesUseCase.kt rename to core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt index df63a4487..19d65581f 100644 --- a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetSaveableNewsResourcesUseCase.kt +++ b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCase.kt @@ -18,29 +18,25 @@ package com.google.samples.apps.nowinandroid.core.domain import com.google.samples.apps.nowinandroid.core.data.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository +import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource +import com.google.samples.apps.nowinandroid.core.model.data.UserData import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNot -import kotlinx.coroutines.flow.map /** * A use case responsible for obtaining news resources with their associated bookmarked (also known * as "saved") state. */ -class GetSaveableNewsResourcesUseCase @Inject constructor( +class GetUserNewsResourcesUseCase @Inject constructor( private val newsRepository: NewsRepository, - userDataRepository: UserDataRepository + private val userDataRepository: UserDataRepository ) { - - private val bookmarkedNewsResources = userDataRepository.userData.map { - it.bookmarkedNewsResources - } - /** - * Returns a list of SaveableNewsResources which match the supplied set of topic ids. + * Returns a list of UserNewsResources which match the supplied set of topic ids. * * @param filterTopicIds - A set of topic ids used to filter the list of news resources. If * this is empty the list of news resources will not be filtered. @@ -52,18 +48,30 @@ class GetSaveableNewsResourcesUseCase @Inject constructor( newsRepository.getNewsResources() } else { newsRepository.getNewsResources(filterTopicIds = filterTopicIds) - }.mapToSaveableNewsResources(bookmarkedNewsResources) + }.mapToSaveableNewsResources(userDataRepository.userData) } private fun Flow>.mapToSaveableNewsResources( - savedNewsResourceIds: Flow> + userData: Flow ): Flow> = filterNot { it.isEmpty() } - .combine(savedNewsResourceIds) { newsResources, savedNewsResourceIds -> + .combine(userData) { newsResources, userData -> newsResources.map { newsResource -> UserNewsResource( - newsResource = newsResource, - isSaved = savedNewsResourceIds.contains(newsResource.id) + id = newsResource.id, + title = newsResource.title, + content = newsResource.content, + url = newsResource.url, + headerImageUrl = newsResource.headerImageUrl, + publishDate = newsResource.publishDate, + type = newsResource.type, + topics = newsResource.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = userData.followedTopics.contains(topic.id) + ) + }, + isSaved = userData.bookmarkedNewsResources.contains(newsResource.id) ) } } diff --git a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/FollowableTopic.kt b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/FollowableTopic.kt index 87a77daa4..c081abf1f 100644 --- a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/FollowableTopic.kt +++ b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/FollowableTopic.kt @@ -17,11 +17,27 @@ package com.google.samples.apps.nowinandroid.core.domain.model import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.core.model.data.previewTopics /** * A [topic] with the additional information for whether or not it is followed. */ -data class FollowableTopic( +data class FollowableTopic( //TODO consider changing to UserTopic and flattening val topic: Topic, val isFollowed: Boolean ) + +val previewFollowableTopics = listOf( + FollowableTopic( + previewTopics[0], + isFollowed = false + ), + FollowableTopic( + previewTopics[1], + isFollowed = true + ), + FollowableTopic( + previewTopics[2], + isFollowed = false + ) +) diff --git a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt index ddd8a27f6..c70f549b2 100644 --- a/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt +++ b/core/domain/src/main/java/com/google/samples/apps/nowinandroid/core/domain/model/UserNewsResource.kt @@ -17,11 +17,89 @@ package com.google.samples.apps.nowinandroid.core.domain.model import com.google.samples.apps.nowinandroid.core.model.data.NewsResource +import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType +import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Codelab +import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Unknown +import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video +import com.google.samples.apps.nowinandroid.core.model.data.previewTopics +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toInstant /** - * A [NewsResource] with the additional information for whether it is saved. + * A [NewsResource] with the additional user information. */ data class UserNewsResource( - val newsResource: NewsResource, - val isSaved: Boolean, + val id: String, + val title: String, + val content: String, + val url: String, + val headerImageUrl: String?, + val publishDate: Instant, + val type: NewsResourceType, + val topics: List, + val isSaved: Boolean +) + +val previewUserNewsResources = listOf( + UserNewsResource( + id = "1", + title = "Android Basics with Compose", + content = "We released the first two units of Android Basics with Compose, our first free course that teaches Android Development with Jetpack Compose to anyone; you do not need any prior programming experience other than basic computer literacy to get started. You’ll learn the fundamentals of programming in Kotlin while building Android apps using Jetpack Compose, Android’s modern toolkit that simplifies and accelerates native UI development. These two units are just the beginning; more will be coming soon. Check out Android Basics with Compose to get started on your Android development journey", + url = "https://android-developers.googleblog.com/2022/05/new-android-basics-with-compose-course.html", + headerImageUrl = "https://developer.android.com/images/hero-assets/android-basics-compose.svg", + publishDate = LocalDateTime( + year = 2022, + monthNumber = 5, + dayOfMonth = 4, + hour = 23, + minute = 0, + second = 0, + nanosecond = 0 + ).toInstant(TimeZone.UTC), + type = Codelab, + topics = listOf(previewFollowableTopics[1]), + isSaved = true + ), + UserNewsResource( + id = "2", + title = "Thanks for helping us reach 1M YouTube Subscribers", + content = "Thank you everyone for following the Now in Android series and everything the " + + "Android Developers YouTube channel has to offer. During the Android Developer " + + "Summit, our YouTube channel reached 1 million subscribers! Here’s a small video to " + + "thank you all.", + url = "https://youtu.be/-fJ6poHQrjM", + headerImageUrl = "https://i.ytimg.com/vi/-fJ6poHQrjM/maxresdefault.jpg", + publishDate = Instant.parse("2021-11-09T00:00:00.000Z"), + type = Video, + topics = listOf(previewFollowableTopics[0], previewFollowableTopics[1]), + isSaved = false + ), + UserNewsResource( + id = "3", + title = "Transformations and customisations in the Paging Library", + content = "A demonstration of different operations that can be performed " + + "with Paging. Transformations like inserting separators, when to " + + "create a new pager, and customisation options for consuming " + + "PagingData.", + url = "https://youtu.be/ZARz0pjm5YM", + headerImageUrl = "https://i.ytimg.com/vi/ZARz0pjm5YM/maxresdefault.jpg", + publishDate = Instant.parse("2021-11-01T00:00:00.000Z"), + type = Video, + topics = listOf(previewFollowableTopics[2]), + isSaved = false + ), + UserNewsResource( + id = "4", + title = "New Jetpack Release", + content = "New Jetpack release includes updates to libraries such as CameraX, Benchmark, and" + + "more!", + url = "https://developer.android.com/jetpack/androidx/versions/all-channel", + headerImageUrl = "", + publishDate = Instant.parse("2022-10-01T00:00:00.000Z"), + type = Unknown, + topics = listOf(previewFollowableTopics[2]), + isSaved = true + ) ) diff --git a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt index 6bdbd9f34..ce730d6f2 100644 --- a/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt +++ b/core/domain/src/test/java/com/google/samples/apps/nowinandroid/core/domain/GetUserNewsResourcesUseCaseTest.kt @@ -16,6 +16,7 @@ package com.google.samples.apps.nowinandroid.core.domain +import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video @@ -38,7 +39,7 @@ class GetUserNewsResourcesUseCaseTest { private val newsRepository = TestNewsRepository() private val userDataRepository = TestUserDataRepository() - val useCase = GetSaveableNewsResourcesUseCase(newsRepository, userDataRepository) + val useCase = GetUserNewsResourcesUseCase(newsRepository, userDataRepository) @Test fun whenNoFilters_allNewsResourcesAreReturned() = runTest { @@ -55,9 +56,51 @@ class GetUserNewsResourcesUseCaseTest { // Check that the correct news resources are returned with their bookmarked state. assertEquals( listOf( - UserNewsResource(sampleNewsResources[0], true), - UserNewsResource(sampleNewsResources[1], false), - UserNewsResource(sampleNewsResources[2], true) + UserNewsResource( + sampleNewsResources[0].id, + sampleNewsResources[0].title, + sampleNewsResources[0].content, + sampleNewsResources[0].url, + sampleNewsResources[0].headerImageUrl, + sampleNewsResources[0].publishDate, + sampleNewsResources[0].type, + sampleNewsResources[0].topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, + true), + UserNewsResource( + sampleNewsResources[1].id, + sampleNewsResources[1].title, + sampleNewsResources[1].content, + sampleNewsResources[1].url, + sampleNewsResources[1].headerImageUrl, + sampleNewsResources[1].publishDate, + sampleNewsResources[1].type, + sampleNewsResources[1].topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, + false), + UserNewsResource( + sampleNewsResources[2].id, + sampleNewsResources[2].title, + sampleNewsResources[2].content, + sampleNewsResources[2].url, + sampleNewsResources[2].headerImageUrl, + sampleNewsResources[2].publishDate, + sampleNewsResources[2].type, + sampleNewsResources[2].topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = true + ) + }, + true), ), saveableNewsResources.first() ) @@ -77,7 +120,21 @@ class GetUserNewsResourcesUseCaseTest { assertEquals( sampleNewsResources .filter { it.topics.contains(sampleTopic1) } - .map { UserNewsResource(it, false) }, + .map { UserNewsResource( + id = it.id, + title = it.title, + content = it.content, + url = it.url, + headerImageUrl = it.headerImageUrl, + publishDate = it.publishDate, + type = it.type, + topics = it.topics.map { topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, + isSaved = false) }, saveableNewsResources.first() ) } diff --git a/core/ui/src/androidTest/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardTest.kt b/core/ui/src/androidTest/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardTest.kt index 69f919a62..c334f1bab 100644 --- a/core/ui/src/androidTest/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardTest.kt +++ b/core/ui/src/androidTest/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardTest.kt @@ -35,7 +35,7 @@ class NewsResourceCardTest { composeTestRule.setContent { NewsResourceCardExpanded( - newsResource = newsWithKnownResourceType, + userNewsResource = newsWithKnownResourceType, isBookmarked = false, onToggleBookmark = {}, onClick = {} @@ -62,7 +62,7 @@ class NewsResourceCardTest { composeTestRule.setContent { NewsResourceCardExpanded( - newsResource = newsWithUnknownResourceType, + userNewsResource = newsWithUnknownResourceType, isBookmarked = false, onToggleBookmark = {}, onClick = {} diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt index cf2714db7..a4ccdaca5 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsFeed.kt @@ -38,7 +38,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource -import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources +import com.google.samples.apps.nowinandroid.core.domain.model.previewUserNewsResources /** * An extension on [LazyListScope] defining a feed with news resources. @@ -51,21 +51,21 @@ fun LazyGridScope.newsFeed( when (feedState) { NewsFeedUiState.Loading -> Unit is NewsFeedUiState.Success -> { - items(feedState.feed, key = { it.newsResource.id }) { saveableNewsResource -> + items(feedState.feed, key = { it.id }) { userNewsResource -> val resourceUrl by remember { - mutableStateOf(Uri.parse(saveableNewsResource.newsResource.url)) + mutableStateOf(Uri.parse(userNewsResource.url)) } val context = LocalContext.current val backgroundColor = MaterialTheme.colorScheme.background.toArgb() NewsResourceCardExpanded( - newsResource = saveableNewsResource.newsResource, - isBookmarked = saveableNewsResource.isSaved, + userNewsResource = userNewsResource, + isBookmarked = userNewsResource.isSaved, onClick = { launchCustomChromeTab(context, resourceUrl, backgroundColor) }, onToggleBookmark = { onNewsResourcesCheckedChanged( - saveableNewsResource.newsResource.id, - !saveableNewsResource.isSaved + userNewsResource.id, + !userNewsResource.isSaved ) } ) @@ -125,12 +125,7 @@ fun NewsFeedContentPreview() { LazyVerticalGrid(columns = GridCells.Adaptive(300.dp)) { newsFeed( feedState = NewsFeedUiState.Success( - previewNewsResources.map { - UserNewsResource( - it, - false - ) - } + previewUserNewsResources ), onNewsResourcesCheckedChanged = { _, _ -> } ) diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index 21ee1a7a8..6eb6e7859 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -56,9 +56,11 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconT import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme +import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic +import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource +import com.google.samples.apps.nowinandroid.core.domain.model.previewUserNewsResources import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType -import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import java.time.ZoneId import java.time.format.DateTimeFormatter @@ -73,7 +75,7 @@ import kotlinx.datetime.toJavaInstant @OptIn(ExperimentalMaterial3Api::class) @Composable fun NewsResourceCardExpanded( - newsResource: NewsResource, + userNewsResource: UserNewsResource, isBookmarked: Boolean, onToggleBookmark: () -> Unit, onClick: () -> Unit, @@ -91,9 +93,9 @@ fun NewsResourceCardExpanded( } ) { Column { - if (!newsResource.headerImageUrl.isNullOrEmpty()) { + if (!userNewsResource.headerImageUrl.isNullOrEmpty()) { Row { - NewsResourceHeaderImage(newsResource.headerImageUrl) + NewsResourceHeaderImage(userNewsResource.headerImageUrl) } } Box( @@ -103,18 +105,18 @@ fun NewsResourceCardExpanded( Spacer(modifier = Modifier.height(12.dp)) Row { NewsResourceTitle( - newsResource.title, + userNewsResource.title, modifier = Modifier.fillMaxWidth((.8f)) ) Spacer(modifier = Modifier.weight(1f)) BookmarkButton(isBookmarked, onToggleBookmark) } Spacer(modifier = Modifier.height(12.dp)) - NewsResourceMetaData(newsResource.publishDate, newsResource.type) + NewsResourceMetaData(userNewsResource.publishDate, userNewsResource.type) Spacer(modifier = Modifier.height(12.dp)) - NewsResourceShortDescription(newsResource.content) + NewsResourceShortDescription(userNewsResource.content) Spacer(modifier = Modifier.height(12.dp)) - NewsResourceTopics(newsResource.topics) + NewsResourceTopics(userNewsResource.topics) } } } @@ -227,7 +229,7 @@ fun NewsResourceShortDescription( @Composable fun NewsResourceTopics( - topics: List, + topics: List, modifier: Modifier = Modifier ) { // Store the ID of the Topic which has its "following" menu expanded, if any. @@ -238,17 +240,17 @@ fun NewsResourceTopics( modifier = modifier.horizontalScroll(rememberScrollState()), // causes narrow chips horizontalArrangement = Arrangement.spacedBy(4.dp), ) { - for (topic in topics) { + for (followableTopic in topics) { NiaTopicTag( - expanded = expandedTopicId == topic.id, + expanded = expandedTopicId == followableTopic.topic.id, followed = true, // ToDo: Check if topic is followed onDropdownMenuToggle = { show -> - expandedTopicId = if (show) topic.id else null + expandedTopicId = if (show) followableTopic.topic.id else null }, onFollowClick = { }, // ToDo onUnfollowClick = { }, // ToDo onBrowseClick = { }, // ToDo - text = { Text(text = topic.name.uppercase(Locale.getDefault())) } + text = { Text(text = followableTopic.topic.name.uppercase(Locale.getDefault())) } ) } } @@ -280,7 +282,7 @@ fun ExpandedNewsResourcePreview() { NiaTheme { Surface { NewsResourceCardExpanded( - newsResource = previewNewsResources[0], + userNewsResource = previewUserNewsResources[0], isBookmarked = true, onToggleBookmark = {}, onClick = {} diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardList.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardList.kt index c76a8124d..c2bdb6580 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardList.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCardList.kt @@ -23,6 +23,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext +import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource /** @@ -37,7 +38,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResource */ fun LazyListScope.newsResourceCardItems( items: List, - newsResourceMapper: (item: T) -> NewsResource, + newsResourceMapper: (item: T) -> UserNewsResource, //TODO remove this? isBookmarkedMapper: (item: T) -> Boolean, onToggleBookmark: (item: T) -> Unit, onItemClick: ((item: T) -> Unit)? = null, @@ -52,7 +53,7 @@ fun LazyListScope.newsResourceCardItems( val context = LocalContext.current NewsResourceCardExpanded( - newsResource = newsResource, + userNewsResource = newsResource, isBookmarked = isBookmarkedMapper(item), onToggleBookmark = { onToggleBookmark(item) }, onClick = { diff --git a/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt b/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt index 0bab4e449..9dbad373b 100644 --- a/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt +++ b/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksScreen.kt @@ -53,6 +53,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource +import com.google.samples.apps.nowinandroid.core.domain.model.previewUserNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading @@ -184,9 +185,7 @@ private fun BookmarksGridPreview() { NiaTheme { BookmarksGrid( feedState = Success( - previewNewsResources.map { - UserNewsResource(it, false) - } + previewUserNewsResources ), removeFromBookmarks = {} ) diff --git a/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModel.kt b/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModel.kt index 8ea565bfd..db94839be 100644 --- a/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModel.kt +++ b/feature/bookmarks/src/main/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModel.kt @@ -19,7 +19,7 @@ package com.google.samples.apps.nowinandroid.feature.bookmarks import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading @@ -36,7 +36,7 @@ import kotlinx.coroutines.launch @HiltViewModel class BookmarksViewModel @Inject constructor( private val userDataRepository: UserDataRepository, - getSaveableNewsResources: GetSaveableNewsResourcesUseCase + getSaveableNewsResources: GetUserNewsResourcesUseCase ) : ViewModel() { val feedUiState: StateFlow = getSaveableNewsResources() diff --git a/feature/bookmarks/src/test/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt b/feature/bookmarks/src/test/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt index 56f30eff5..a8da1a4ff 100644 --- a/feature/bookmarks/src/test/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt +++ b/feature/bookmarks/src/test/java/com/google/samples/apps/nowinandroid/feature/bookmarks/BookmarksViewModelTest.kt @@ -16,7 +16,7 @@ package com.google.samples.apps.nowinandroid.feature.bookmarks -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository @@ -43,7 +43,7 @@ class BookmarksViewModelTest { private val userDataRepository = TestUserDataRepository() private val newsRepository = TestNewsRepository() - private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase( + private val getUserNewsResourcesUseCase = GetUserNewsResourcesUseCase( newsRepository = newsRepository, userDataRepository = userDataRepository ) @@ -53,7 +53,7 @@ class BookmarksViewModelTest { fun setup() { viewModel = BookmarksViewModel( userDataRepository = userDataRepository, - getSaveableNewsResources = getSaveableNewsResourcesUseCase + getSaveableNewsResources = getUserNewsResourcesUseCase ) } diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index e1a5b5e9e..fb4d83c7e 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -84,6 +84,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource +import com.google.samples.apps.nowinandroid.core.domain.model.previewUserNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.DevicePreviews @@ -396,9 +397,7 @@ fun ForYouScreenPopulatedFeed() { isSyncing = false, onboardingUiState = OnboardingUiState.NotShown, feedState = NewsFeedUiState.Success( - feed = previewNewsResources.map { - UserNewsResource(it, false) - } + feed = previewUserNewsResources ), onTopicCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, @@ -417,9 +416,7 @@ fun ForYouScreenOfflinePopulatedFeed() { isSyncing = false, onboardingUiState = OnboardingUiState.NotShown, feedState = NewsFeedUiState.Success( - feed = previewNewsResources.map { - UserNewsResource(it, false) - } + feed = previewUserNewsResources ), onTopicCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, @@ -440,9 +437,7 @@ fun ForYouScreenTopicSelection() { topics = previewTopics.map { FollowableTopic(it, false) }, ), feedState = NewsFeedUiState.Success( - feed = previewNewsResources.map { - UserNewsResource(it, false) - } + feed = previewUserNewsResources ), onTopicCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, @@ -478,9 +473,7 @@ fun ForYouScreenPopulatedAndLoading() { isSyncing = true, onboardingUiState = OnboardingUiState.Loading, feedState = NewsFeedUiState.Success( - feed = previewNewsResources.map { - UserNewsResource(it, false) - } + feed = previewUserNewsResources ), onTopicCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt index 645566056..6c9218a75 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModel.kt @@ -21,7 +21,7 @@ import androidx.lifecycle.viewModelScope import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.data.util.SyncStatusMonitor import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import dagger.hilt.android.lifecycle.HiltViewModel @@ -41,7 +41,7 @@ import kotlinx.coroutines.launch class ForYouViewModel @Inject constructor( syncStatusMonitor: SyncStatusMonitor, private val userDataRepository: UserDataRepository, - private val getSaveableNewsResources: GetSaveableNewsResourcesUseCase, + private val getSaveableNewsResources: GetUserNewsResourcesUseCase, getFollowableTopics: GetFollowableTopicsUseCase ) : ViewModel() { diff --git a/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index 06b7ebe7a..35b8a2f5a 100644 --- a/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature/foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -17,7 +17,7 @@ package com.google.samples.apps.nowinandroid.feature.foryou import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource @@ -54,7 +54,7 @@ class ForYouViewModelTest { private val userDataRepository = TestUserDataRepository() private val topicsRepository = TestTopicsRepository() private val newsRepository = TestNewsRepository() - private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase( + private val getUserNewsResourcesUseCase = GetUserNewsResourcesUseCase( newsRepository = newsRepository, userDataRepository = userDataRepository ) @@ -69,7 +69,7 @@ class ForYouViewModelTest { viewModel = ForYouViewModel( syncStatusMonitor = syncStatusMonitor, userDataRepository = userDataRepository, - getSaveableNewsResources = getSaveableNewsResourcesUseCase, + getSaveableNewsResources = getUserNewsResourcesUseCase, getFollowableTopics = getFollowableTopicsUseCase ) } @@ -283,7 +283,19 @@ class ForYouViewModelTest { feed = sampleNewsResources.map { UserNewsResource( - newsResource = it, + id = it.id, + title = it.title, + content = it.content, + url = it.url, + headerImageUrl = it.headerImageUrl, + publishDate = it.publishDate, + type = it.type, + topics = it.topics.map{ topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, isSaved = false ) } @@ -398,11 +410,35 @@ class ForYouViewModelTest { NewsFeedUiState.Success( feed = listOf( UserNewsResource( - newsResource = sampleNewsResources[1], + id = sampleNewsResources[1].id, + title = sampleNewsResources[1].title, + content = sampleNewsResources[1].content, + url = sampleNewsResources[1].url, + headerImageUrl = sampleNewsResources[1].headerImageUrl, + publishDate = sampleNewsResources[1].publishDate, + type = sampleNewsResources[1].type, + topics = sampleNewsResources[1].topics.map{ topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, isSaved = false ), UserNewsResource( - newsResource = sampleNewsResources[2], + id = sampleNewsResources[2].id, + title = sampleNewsResources[2].title, + content = sampleNewsResources[2].content, + url = sampleNewsResources[2].url, + headerImageUrl = sampleNewsResources[2].headerImageUrl, + publishDate = sampleNewsResources[2].publishDate, + type = sampleNewsResources[2].type, + topics = sampleNewsResources[2].topics.map{ topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, isSaved = false ) ) @@ -498,13 +534,37 @@ class ForYouViewModelTest { NewsFeedUiState.Success( feed = listOf( UserNewsResource( - newsResource = sampleNewsResources[1], + id = sampleNewsResources[1].id, + title = sampleNewsResources[1].title, + content = sampleNewsResources[1].content, + url = sampleNewsResources[1].url, + headerImageUrl = sampleNewsResources[1].headerImageUrl, + publishDate = sampleNewsResources[1].publishDate, + type = sampleNewsResources[1].type, + topics = sampleNewsResources[1].topics.map{ topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, isSaved = true ), UserNewsResource( - newsResource = sampleNewsResources[2], + id = sampleNewsResources[2].id, + title = sampleNewsResources[2].title, + content = sampleNewsResources[2].content, + url = sampleNewsResources[2].url, + headerImageUrl = sampleNewsResources[2].headerImageUrl, + publishDate = sampleNewsResources[2].publishDate, + type = sampleNewsResources[2].type, + topics = sampleNewsResources[2].topics.map{ topic -> + FollowableTopic( + topic = topic, + isFollowed = false + ) + }, isSaved = false - ) + ), ) ), viewModel.feedState.value diff --git a/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt b/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt index b57c96954..3e79318eb 100644 --- a/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt +++ b/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt @@ -54,6 +54,7 @@ import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource +import com.google.samples.apps.nowinandroid.core.domain.model.previewUserNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.DevicePreviews @@ -182,9 +183,9 @@ private fun LazyListScope.TopicCards( is NewsUiState.Success -> { newsResourceCardItems( items = news.news, - newsResourceMapper = { it.newsResource }, + newsResourceMapper = { it }, isBookmarkedMapper = { it.isSaved }, - onToggleBookmark = { onBookmarkChanged(it.newsResource.id, !it.isSaved) }, + onToggleBookmark = { onBookmarkChanged(it.id, !it.isSaved) }, itemModifier = Modifier.padding(24.dp) ) } @@ -257,12 +258,7 @@ fun TopicScreenPopulated() { TopicScreen( topicUiState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)), newsUiState = NewsUiState.Success( - previewNewsResources.mapIndexed { index, newsResource -> - UserNewsResource( - newsResource = newsResource, - isSaved = index % 2 == 0, - ) - } + previewUserNewsResources ), onBackClick = {}, onFollowClick = {}, diff --git a/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt b/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt index e65bc1dee..1f08d233a 100644 --- a/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt +++ b/feature/topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModel.kt @@ -22,7 +22,7 @@ import androidx.lifecycle.viewModelScope import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.Topic @@ -46,7 +46,7 @@ class TopicViewModel @Inject constructor( private val userDataRepository: UserDataRepository, topicsRepository: TopicsRepository, // newsRepository: NewsRepository, - getSaveableNewsResources: GetSaveableNewsResourcesUseCase + getSaveableNewsResources: GetUserNewsResourcesUseCase ) : ViewModel() { private val topicArgs: TopicArgs = TopicArgs(savedStateHandle, stringDecoder) @@ -131,7 +131,7 @@ private fun topicUiState( private fun newsUiState( topicId: String, - getSaveableNewsResources: GetSaveableNewsResourcesUseCase, + getSaveableNewsResources: GetUserNewsResourcesUseCase, userDataRepository: UserDataRepository, ): Flow { // Observe news diff --git a/feature/topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt b/feature/topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt index 32768c4d7..6c61e59d5 100644 --- a/feature/topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt +++ b/feature/topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt @@ -17,7 +17,7 @@ package com.google.samples.apps.nowinandroid.feature.topic import androidx.lifecycle.SavedStateHandle -import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase +import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video @@ -53,7 +53,7 @@ class TopicViewModelTest { private val userDataRepository = TestUserDataRepository() private val topicsRepository = TestTopicsRepository() private val newsRepository = TestNewsRepository() - private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase( + private val getUserNewsResourcesUseCase = GetUserNewsResourcesUseCase( newsRepository = newsRepository, userDataRepository = userDataRepository ) @@ -66,7 +66,7 @@ class TopicViewModelTest { stringDecoder = FakeStringDecoder(), userDataRepository = userDataRepository, topicsRepository = topicsRepository, - getSaveableNewsResources = getSaveableNewsResourcesUseCase + getSaveableNewsResources = getUserNewsResourcesUseCase ) }