Sort authors stream by news count

Fixes #393
pull/447/head
Simon Marquis 3 years ago
parent 9fa3dadcfd
commit 00fc9c29d2

@ -17,34 +17,49 @@
package com.google.samples.apps.nowinandroid.core.domain
import com.google.samples.apps.nowinandroid.core.data.repository.AuthorsRepository
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.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.Author
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
/**
* A use case which obtains a list of authors sorted alphabetically by name with their followed
* state.
* A use case which obtains a list of authors sorted by descending news count and then alphabetically by name with their followed state.
*/
class GetSortedFollowableAuthorsStreamUseCase @Inject constructor(
private val authorsRepository: AuthorsRepository,
private val userDataRepository: UserDataRepository
private val newsRepository: NewsRepository,
private val userDataRepository: UserDataRepository,
) {
/**
* Returns a list of authors with their associated followed state sorted alphabetically by name.
* Returns a list of authors with their associated followed state sorted by descending news count and then alphabetically by name.
*/
operator fun invoke(): Flow<List<FollowableAuthor>> =
combine(
authorsRepository.getAuthorsStream(),
userDataRepository.userDataStream
) { authors, userData ->
newsRepository.getNewsResourcesStream(),
userDataRepository.userDataStream,
) { authors, news, userData ->
val newsCountByAuthor: Map<Author, Long> = buildMap {
news.forEach { news ->
news.authors.forEach { author ->
compute(author) { _, count -> count?.inc() ?: 1 }
}
}
}
authors.map { author ->
FollowableAuthor(
author = author,
isFollowed = author.id in userData.followedAuthors
)
}
.sortedBy { it.author.name }
}.sortedWith(
compareByDescending<FollowableAuthor> {
newsCountByAuthor[it.author]
}.thenBy {
it.author.name
}
)
}
}

@ -18,12 +18,16 @@ package com.google.samples.apps.nowinandroid.core.domain
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.model.data.Author
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.testing.repository.TestAuthorsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import kotlin.test.assertEquals
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
import org.junit.Rule
import org.junit.Test
@ -33,15 +37,18 @@ class GetSortedFollowableAuthorsStreamUseCaseTest {
val mainDispatcherRule = MainDispatcherRule()
private val authorsRepository = TestAuthorsRepository()
private val newsRepository = TestNewsRepository()
private val userDataRepository = TestUserDataRepository()
val useCase = GetSortedFollowableAuthorsStreamUseCase(
authorsRepository = authorsRepository,
userDataRepository = userDataRepository
newsRepository = newsRepository,
userDataRepository = userDataRepository,
)
@Test
fun whenFollowedAuthorsSupplied_sortedFollowableAuthorsAreReturned() = runTest {
newsRepository.sendNewsResources(listOf(sampleNews1))
// Specify some authors which the user is following.
userDataRepository.setFollowedAuthorIds(setOf(sampleAuthor1.id))
@ -95,3 +102,16 @@ private val sampleAuthor3 =
)
private val sampleAuthors = listOf(sampleAuthor1, sampleAuthor2, sampleAuthor3)
private val sampleNews1 =
NewsResource(
id = "1",
title = "",
content = "",
url = "",
headerImageUrl = null,
publishDate = Instant.parse("2021-11-09T00:00:00.000Z"),
type = Video,
authors = listOf(sampleAuthor2),
topics = emptyList()
)

@ -65,6 +65,7 @@ class ForYouViewModelTest {
)
private val getSortedFollowableAuthorsStream = GetSortedFollowableAuthorsStreamUseCase(
authorsRepository = authorsRepository,
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
private val getFollowableTopicsStreamUseCase = GetFollowableTopicsStreamUseCase(
@ -190,6 +191,7 @@ class ForYouViewModelTest {
userDataRepository.setFollowedTopicIds(emptySet())
authorsRepository.sendAuthors(sampleAuthors)
userDataRepository.setFollowedAuthorIds(emptySet())
newsRepository.sendNewsResources(emptyList())
assertEquals(
OnboardingUiState.Shown(
@ -329,8 +331,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -340,8 +342,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -386,6 +388,7 @@ class ForYouViewModelTest {
userDataRepository.setFollowedAuthorIds(emptySet())
topicsRepository.sendTopics(sampleTopics)
userDataRepository.setFollowedTopicIds(setOf("0", "1"))
newsRepository.sendNewsResources(emptyList())
viewModel.dismissOnboarding()
assertEquals(
@ -469,8 +472,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -480,8 +483,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -553,8 +556,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -564,8 +567,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -660,8 +663,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -671,8 +674,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -744,25 +747,25 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
bio = "",
),
isFollowed = false
isFollowed = true
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
bio = "",
),
isFollowed = true
isFollowed = false
),
FollowableAuthor(
author = Author(
@ -854,8 +857,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -865,8 +868,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -955,8 +958,8 @@ class ForYouViewModelTest {
authors = listOf(
FollowableAuthor(
author = Author(
id = "0",
name = "Android Dev",
id = "1",
name = "Android Dev 2",
imageUrl = "",
twitter = "",
mediumPage = "",
@ -966,8 +969,8 @@ class ForYouViewModelTest {
),
FollowableAuthor(
author = Author(
id = "1",
name = "Android Dev 2",
id = "0",
name = "Android Dev",
imageUrl = "",
twitter = "",
mediumPage = "",

@ -23,6 +23,7 @@ import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.Author
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.testing.repository.TestAuthorsRepository
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.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
@ -48,6 +49,7 @@ class InterestsViewModelTest {
private val userDataRepository = TestUserDataRepository()
private val authorsRepository = TestAuthorsRepository()
private val newsRepository = TestNewsRepository()
private val topicsRepository = TestTopicsRepository()
private val getFollowableTopicsStreamUseCase = GetFollowableTopicsStreamUseCase(
topicsRepository = topicsRepository,
@ -56,6 +58,7 @@ class InterestsViewModelTest {
private val getSortedFollowableAuthorsStream =
GetSortedFollowableAuthorsStreamUseCase(
authorsRepository = authorsRepository,
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
private lateinit var viewModel: InterestsViewModel
@ -67,6 +70,7 @@ class InterestsViewModelTest {
getFollowableTopicsStream = getFollowableTopicsStreamUseCase,
getSortedFollowableAuthorsStream = getSortedFollowableAuthorsStream
)
newsRepository.sendNewsResources(emptyList())
}
@Test

@ -68,6 +68,7 @@ class TopicViewModelTest {
topicsRepository = topicsRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStreamUseCase
)
newsRepository.sendNewsResources(emptyList())
}
@Test

Loading…
Cancel
Save