Move mapping logic into secondary constructor

Change-Id: I032326f502d27f2d3bd9fb8273ae44df878d172c
pull/521/head
Don Turner 2 years ago
parent 355b0540aa
commit 24df51349d

@ -56,6 +56,6 @@ private fun Flow<List<NewsResource>>.mapToUserNewsResources(
filterNot { it.isEmpty() } filterNot { it.isEmpty() }
.combine(userDataStream) { newsResources, userData -> .combine(userDataStream) { newsResources, userData ->
newsResources.map { newsResource -> newsResources.map { newsResource ->
UserNewsResource.from(newsResource, userData) UserNewsResource(newsResource, userData)
} }
} }

@ -30,9 +30,10 @@ import kotlinx.datetime.toInstant
/* ktlint-disable max-line-length */ /* ktlint-disable max-line-length */
/** /**
* A [NewsResource] with the additional user information. * A [NewsResource] with additional user information such as whether the user is following the
* news resource's topics and whether they have saved (bookmarked) this news resource.
*/ */
data class UserNewsResource( data class UserNewsResource internal constructor(
val id: String, val id: String,
val title: String, val title: String,
val content: String, val content: String,
@ -43,9 +44,7 @@ data class UserNewsResource(
val followableTopics: List<FollowableTopic>, val followableTopics: List<FollowableTopic>,
val isSaved: Boolean val isSaved: Boolean
) { ) {
companion object { constructor(newsResource: NewsResource, userData: UserData) : this(
fun from(newsResource: NewsResource, userData: UserData): UserNewsResource {
return UserNewsResource(
id = newsResource.id, id = newsResource.id,
title = newsResource.title, title = newsResource.title,
content = newsResource.content, content = newsResource.content,
@ -61,8 +60,10 @@ data class UserNewsResource(
}, },
isSaved = userData.bookmarkedNewsResources.contains(newsResource.id) isSaved = userData.bookmarkedNewsResources.contains(newsResource.id)
) )
} }
}
fun List<NewsResource>.mapToUserNewsResources(userData: UserData): List<UserNewsResource> {
return map { UserNewsResource(it, userData) }
} }
val previewUserNewsResources = listOf( val previewUserNewsResources = listOf(

@ -66,9 +66,9 @@ class GetUserNewsResourcesUseCaseTest {
// Check that the correct news resources are returned with their bookmarked state. // Check that the correct news resources are returned with their bookmarked state.
assertEquals( assertEquals(
listOf( listOf(
UserNewsResource.from(sampleNewsResources[0], userData), UserNewsResource(sampleNewsResources[0], userData),
UserNewsResource.from(sampleNewsResources[1], userData), UserNewsResource(sampleNewsResources[1], userData),
UserNewsResource.from(sampleNewsResources[2], userData), UserNewsResource(sampleNewsResources[2], userData),
), ),
userNewsResources.first() userNewsResources.first()
) )
@ -96,7 +96,7 @@ class GetUserNewsResourcesUseCaseTest {
sampleNewsResources sampleNewsResources
.filter { it.topics.contains(sampleTopic1) } .filter { it.topics.contains(sampleTopic1) }
.map { .map {
UserNewsResource.from(it, userData) UserNewsResource(it, userData)
}, },
userNewsResources.first() userNewsResources.first()
) )

@ -75,7 +75,7 @@ class UserNewsResourceTest {
shouldHideOnboarding = true shouldHideOnboarding = true
) )
val userNewsResource = UserNewsResource.from(newsResource1, userData) val userNewsResource = UserNewsResource(newsResource1, userData)
// Check that the simple field mappings have been done correctly. // Check that the simple field mappings have been done correctly.
assertEquals(newsResource1.id, userNewsResource.id) assertEquals(newsResource1.id, userNewsResource.id)

@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
private val emptyUserData = UserData( val emptyUserData = UserData(
bookmarkedNewsResources = emptySet(), bookmarkedNewsResources = emptySet(),
followedTopics = emptySet(), followedTopics = emptySet(),
themeBrand = ThemeBrand.DEFAULT, themeBrand = ThemeBrand.DEFAULT,

@ -20,12 +20,14 @@ import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCa
import com.google.samples.apps.nowinandroid.core.domain.GetUserNewsResourcesUseCase 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.FollowableTopic
import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource import com.google.samples.apps.nowinandroid.core.domain.model.UserNewsResource
import com.google.samples.apps.nowinandroid.core.domain.model.mapToUserNewsResources
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video
import com.google.samples.apps.nowinandroid.core.model.data.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserData
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestNetworkMonitor
import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncStatusMonitor import com.google.samples.apps.nowinandroid.core.testing.util.TestSyncStatusMonitor
@ -265,7 +267,8 @@ class ForYouViewModelTest {
topicsRepository.sendTopics(sampleTopics) topicsRepository.sendTopics(sampleTopics)
val followedTopicIds = setOf("0", "1") val followedTopicIds = setOf("0", "1")
userDataRepository.setFollowedTopicIds(followedTopicIds) val userData = emptyUserData.copy(followedTopics = followedTopicIds)
userDataRepository.setUserData(userData)
viewModel.dismissOnboarding() viewModel.dismissOnboarding()
assertEquals( assertEquals(
@ -282,25 +285,7 @@ class ForYouViewModelTest {
) )
assertEquals( assertEquals(
NewsFeedUiState.Success( NewsFeedUiState.Success(
feed = feed = sampleNewsResources.mapToUserNewsResources(userData)
sampleNewsResources.map {
UserNewsResource(
id = it.id,
title = it.title,
content = it.content,
url = it.url,
headerImageUrl = it.headerImageUrl,
publishDate = it.publishDate,
type = it.type,
followableTopics = it.topics.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = followedTopicIds.contains(topic.id)
)
},
isSaved = false
)
}
), ),
viewModel.feedState.value viewModel.feedState.value
) )
@ -345,41 +330,14 @@ class ForYouViewModelTest {
), ),
viewModel.onboardingUiState.value viewModel.onboardingUiState.value
) )
val userData = emptyUserData.copy(followedTopics = setOf(followedTopicId))
assertEquals( assertEquals(
NewsFeedUiState.Success( NewsFeedUiState.Success(
feed = listOf( feed = listOf(
UserNewsResource( UserNewsResource(sampleNewsResources[1], userData),
id = sampleNewsResources[1].id, UserNewsResource(sampleNewsResources[2], userData),
title = sampleNewsResources[1].title,
content = sampleNewsResources[1].content,
url = sampleNewsResources[1].url,
headerImageUrl = sampleNewsResources[1].headerImageUrl,
publishDate = sampleNewsResources[1].publishDate,
type = sampleNewsResources[1].type,
followableTopics = sampleNewsResources[1].topics.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = topic.id == followedTopicId
)
},
isSaved = false
),
UserNewsResource(
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,
followableTopics = sampleNewsResources[2].topics.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = topic.id == followedTopicId
)
},
isSaved = false
)
) )
), ),
viewModel.feedState.value viewModel.feedState.value
@ -460,12 +418,24 @@ class ForYouViewModelTest {
val collectJob2 = launch(UnconfinedTestDispatcher()) { viewModel.feedState.collect() } val collectJob2 = launch(UnconfinedTestDispatcher()) { viewModel.feedState.collect() }
val followedTopicIds = setOf("1") val followedTopicIds = setOf("1")
val userData = emptyUserData.copy(
followedTopics = followedTopicIds,
shouldHideOnboarding = true
)
topicsRepository.sendTopics(sampleTopics) topicsRepository.sendTopics(sampleTopics)
userDataRepository.setFollowedTopicIds(followedTopicIds) userDataRepository.setUserData(userData)
userDataRepository.setShouldHideOnboarding(true)
newsRepository.sendNewsResources(sampleNewsResources) newsRepository.sendNewsResources(sampleNewsResources)
viewModel.updateNewsResourceSaved("2", true)
val bookmarkedNewsResourceId = "2"
viewModel.updateNewsResourceSaved(
newsResourceId = bookmarkedNewsResourceId,
isChecked = true
)
val userDataExpected = userData.copy(
bookmarkedNewsResources = setOf(bookmarkedNewsResourceId)
)
assertEquals( assertEquals(
OnboardingUiState.NotShown, OnboardingUiState.NotShown,
@ -474,38 +444,8 @@ class ForYouViewModelTest {
assertEquals( assertEquals(
NewsFeedUiState.Success( NewsFeedUiState.Success(
feed = listOf( feed = listOf(
UserNewsResource( UserNewsResource(newsResource = sampleNewsResources[1], userDataExpected),
id = sampleNewsResources[1].id, UserNewsResource(newsResource = sampleNewsResources[2], userDataExpected)
title = sampleNewsResources[1].title,
content = sampleNewsResources[1].content,
url = sampleNewsResources[1].url,
headerImageUrl = sampleNewsResources[1].headerImageUrl,
publishDate = sampleNewsResources[1].publishDate,
type = sampleNewsResources[1].type,
followableTopics = sampleNewsResources[1].topics.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = followedTopicIds.contains(topic.id)
)
},
isSaved = true
),
UserNewsResource(
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,
followableTopics = sampleNewsResources[2].topics.map { topic ->
FollowableTopic(
topic = topic,
isFollowed = followedTopicIds.contains(topic.id)
)
},
isSaved = false
),
) )
), ),
viewModel.feedState.value viewModel.feedState.value

Loading…
Cancel
Save