Merge pull request #468 from android/remove-stream-suffixes

Remove `Stream` suffixes
pull/473/head
Márton Braun 2 years ago committed by GitHub
commit 56b3c1d0b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

File diff suppressed because it is too large Load Diff

@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.stateIn
class MainActivityViewModel @Inject constructor(
userDataRepository: UserDataRepository
) : ViewModel() {
val uiState: StateFlow<MainActivityUiState> = userDataRepository.userDataStream.map {
val uiState: StateFlow<MainActivityUiState> = userDataRepository.userData.map {
Success(it)
}.stateIn(
scope = viewModelScope,

@ -24,10 +24,10 @@ interface AuthorsRepository : Syncable {
/**
* Gets the available Authors as a stream
*/
fun getAuthorsStream(): Flow<List<Author>>
fun getAuthors(): Flow<List<Author>>
/**
* Gets data for a specific author
*/
fun getAuthorStream(id: String): Flow<Author>
fun getAuthor(id: String): Flow<Author>
}

@ -27,12 +27,12 @@ interface NewsRepository : Syncable {
/**
* Returns available news resources as a stream.
*/
fun getNewsResourcesStream(): Flow<List<NewsResource>>
fun getNewsResources(): Flow<List<NewsResource>>
/**
* Returns available news resources as a stream filtered by authors or topics.
*/
fun getNewsResourcesStream(
fun getNewsResources(
filterAuthorIds: Set<String> = emptySet(),
filterTopicIds: Set<String> = emptySet(),
): Flow<List<NewsResource>>

@ -39,13 +39,13 @@ class OfflineFirstAuthorsRepository @Inject constructor(
private val network: NiaNetworkDataSource,
) : AuthorsRepository {
override fun getAuthorStream(id: String): Flow<Author> =
authorDao.getAuthorEntityStream(id).map {
override fun getAuthor(id: String): Flow<Author> =
authorDao.getAuthorEntity(id).map {
it.asExternalModel()
}
override fun getAuthorsStream(): Flow<List<Author>> =
authorDao.getAuthorEntitiesStream()
override fun getAuthors(): Flow<List<Author>> =
authorDao.getAuthorEntities()
.map { it.map(AuthorEntity::asExternalModel) }
override suspend fun syncWith(synchronizer: Synchronizer): Boolean =

@ -49,14 +49,14 @@ class OfflineFirstNewsRepository @Inject constructor(
private val network: NiaNetworkDataSource,
) : NewsRepository {
override fun getNewsResourcesStream(): Flow<List<NewsResource>> =
newsResourceDao.getNewsResourcesStream()
override fun getNewsResources(): Flow<List<NewsResource>> =
newsResourceDao.getNewsResources()
.map { it.map(PopulatedNewsResource::asExternalModel) }
override fun getNewsResourcesStream(
override fun getNewsResources(
filterAuthorIds: Set<String>,
filterTopicIds: Set<String>
): Flow<List<NewsResource>> = newsResourceDao.getNewsResourcesStream(
): Flow<List<NewsResource>> = newsResourceDao.getNewsResources(
filterAuthorIds = filterAuthorIds,
filterTopicIds = filterTopicIds
)

@ -39,8 +39,8 @@ class OfflineFirstTopicsRepository @Inject constructor(
private val network: NiaNetworkDataSource,
) : TopicsRepository {
override fun getTopicsStream(): Flow<List<Topic>> =
topicDao.getTopicEntitiesStream()
override fun getTopics(): Flow<List<Topic>> =
topicDao.getTopicEntities()
.map { it.map(TopicEntity::asExternalModel) }
override fun getTopic(id: String): Flow<Topic> =

@ -27,8 +27,8 @@ class OfflineFirstUserDataRepository @Inject constructor(
private val niaPreferencesDataSource: NiaPreferencesDataSource
) : UserDataRepository {
override val userDataStream: Flow<UserData> =
niaPreferencesDataSource.userDataStream
override val userData: Flow<UserData> =
niaPreferencesDataSource.userData
override suspend fun setFollowedTopicIds(followedTopicIds: Set<String>) =
niaPreferencesDataSource.setFollowedTopicIds(followedTopicIds)

@ -24,7 +24,7 @@ interface TopicsRepository : Syncable {
/**
* Gets the available topics as a stream
*/
fun getTopicsStream(): Flow<List<Topic>>
fun getTopics(): Flow<List<Topic>>
/**
* Gets data for a specific topic

@ -26,7 +26,7 @@ interface UserDataRepository {
/**
* Stream of [UserData]
*/
val userDataStream: Flow<UserData>
val userData: Flow<UserData>
/**
* Sets the user's currently followed topics

@ -40,7 +40,7 @@ class FakeAuthorsRepository @Inject constructor(
private val datasource: FakeNiaNetworkDataSource
) : AuthorsRepository {
override fun getAuthorsStream(): Flow<List<Author>> = flow {
override fun getAuthors(): Flow<List<Author>> = flow {
emit(
datasource.getAuthors().map {
Author(
@ -55,8 +55,8 @@ class FakeAuthorsRepository @Inject constructor(
)
}.flowOn(ioDispatcher)
override fun getAuthorStream(id: String): Flow<Author> {
return getAuthorsStream().map { it.first { author -> author.id == id } }
override fun getAuthor(id: String): Flow<Author> {
return getAuthors().map { it.first { author -> author.id == id } }
}
override suspend fun syncWith(synchronizer: Synchronizer) = true

@ -43,7 +43,7 @@ class FakeNewsRepository @Inject constructor(
private val datasource: FakeNiaNetworkDataSource
) : NewsRepository {
override fun getNewsResourcesStream(): Flow<List<NewsResource>> =
override fun getNewsResources(): Flow<List<NewsResource>> =
flow {
emit(
datasource.getNewsResources()
@ -52,7 +52,7 @@ class FakeNewsRepository @Inject constructor(
)
}.flowOn(ioDispatcher)
override fun getNewsResourcesStream(
override fun getNewsResources(
filterAuthorIds: Set<String>,
filterTopicIds: Set<String>,
): Flow<List<NewsResource>> =

@ -40,7 +40,7 @@ class FakeTopicsRepository @Inject constructor(
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
private val datasource: FakeNiaNetworkDataSource
) : TopicsRepository {
override fun getTopicsStream(): Flow<List<Topic>> = flow {
override fun getTopics(): Flow<List<Topic>> = flow {
emit(
datasource.getTopics().map {
Topic(
@ -56,7 +56,7 @@ class FakeTopicsRepository @Inject constructor(
}.flowOn(ioDispatcher)
override fun getTopic(id: String): Flow<Topic> {
return getTopicsStream().map { it.first { topic -> topic.id == id } }
return getTopics().map { it.first { topic -> topic.id == id } }
}
override suspend fun syncWith(synchronizer: Synchronizer) = true

@ -35,8 +35,8 @@ class FakeUserDataRepository @Inject constructor(
private val niaPreferencesDataSource: NiaPreferencesDataSource,
) : UserDataRepository {
override val userDataStream: Flow<UserData> =
niaPreferencesDataSource.userDataStream
override val userData: Flow<UserData> =
niaPreferencesDataSource.userData
override suspend fun setFollowedTopicIds(followedTopicIds: Set<String>) =
niaPreferencesDataSource.setFollowedTopicIds(followedTopicIds)

@ -69,10 +69,10 @@ class OfflineFirstAuthorsRepositoryTest {
fun offlineFirstAuthorsRepository_Authors_stream_is_backed_by_Authors_dao() =
runTest {
assertEquals(
authorDao.getAuthorEntitiesStream()
authorDao.getAuthorEntities()
.first()
.map(AuthorEntity::asExternalModel),
subject.getAuthorsStream()
subject.getAuthors()
.first()
)
}
@ -85,7 +85,7 @@ class OfflineFirstAuthorsRepositoryTest {
val networkAuthors = network.getAuthors()
.map(NetworkAuthor::asEntity)
val dbAuthors = authorDao.getAuthorEntitiesStream()
val dbAuthors = authorDao.getAuthorEntities()
.first()
assertEquals(
@ -122,7 +122,7 @@ class OfflineFirstAuthorsRepositoryTest {
.map(NetworkAuthor::asEntity)
.filter { it.id in changeListIds }
val db = authorDao.getAuthorEntitiesStream()
val db = authorDao.getAuthorEntities()
.first()
assertEquals(
@ -161,7 +161,7 @@ class OfflineFirstAuthorsRepositoryTest {
subject.syncWith(synchronizer)
val dbAuthors = authorDao.getAuthorEntitiesStream()
val dbAuthors = authorDao.getAuthorEntities()
.first()
.map(AuthorEntity::asExternalModel)

@ -88,10 +88,10 @@ class OfflineFirstNewsRepositoryTest {
fun offlineFirstNewsRepository_news_resources_stream_is_backed_by_news_resource_dao() =
runTest {
assertEquals(
newsResourceDao.getNewsResourcesStream()
newsResourceDao.getNewsResources()
.first()
.map(PopulatedNewsResource::asExternalModel),
subject.getNewsResourcesStream()
subject.getNewsResources()
.first()
)
}
@ -100,12 +100,12 @@ class OfflineFirstNewsRepositoryTest {
fun offlineFirstNewsRepository_news_resources_for_topic_is_backed_by_news_resource_dao() =
runTest {
assertEquals(
newsResourceDao.getNewsResourcesStream(
newsResourceDao.getNewsResources(
filterTopicIds = filteredInterestsIds,
)
.first()
.map(PopulatedNewsResource::asExternalModel),
subject.getNewsResourcesStream(
subject.getNewsResources(
filterTopicIds = filteredInterestsIds,
)
.first()
@ -113,7 +113,7 @@ class OfflineFirstNewsRepositoryTest {
assertEquals(
emptyList(),
subject.getNewsResourcesStream(
subject.getNewsResources(
filterTopicIds = nonPresentInterestsIds,
)
.first()
@ -124,12 +124,12 @@ class OfflineFirstNewsRepositoryTest {
fun offlineFirstNewsRepository_news_resources_for_author_is_backed_by_news_resource_dao() =
runTest {
assertEquals(
newsResourceDao.getNewsResourcesStream(
newsResourceDao.getNewsResources(
filterAuthorIds = filteredInterestsIds
)
.first()
.map(PopulatedNewsResource::asExternalModel),
subject.getNewsResourcesStream(
subject.getNewsResources(
filterAuthorIds = filteredInterestsIds
)
.first()
@ -137,7 +137,7 @@ class OfflineFirstNewsRepositoryTest {
assertEquals(
emptyList(),
subject.getNewsResourcesStream(
subject.getNewsResources(
filterAuthorIds = nonPresentInterestsIds
)
.first()
@ -153,7 +153,7 @@ class OfflineFirstNewsRepositoryTest {
.map(NetworkNewsResource::asEntity)
.map(NewsResourceEntity::asExternalModel)
val newsResourcesFromDb = newsResourceDao.getNewsResourcesStream()
val newsResourcesFromDb = newsResourceDao.getNewsResources()
.first()
.map(PopulatedNewsResource::asExternalModel)
@ -193,7 +193,7 @@ class OfflineFirstNewsRepositoryTest {
subject.syncWith(synchronizer)
val newsResourcesFromDb = newsResourceDao.getNewsResourcesStream()
val newsResourcesFromDb = newsResourceDao.getNewsResources()
.first()
.map(PopulatedNewsResource::asExternalModel)
@ -233,7 +233,7 @@ class OfflineFirstNewsRepositoryTest {
.map(NewsResourceEntity::asExternalModel)
.filter { it.id in changeListIds }
val newsResourcesFromDb = newsResourceDao.getNewsResourcesStream()
val newsResourcesFromDb = newsResourceDao.getNewsResources()
.first()
.map(PopulatedNewsResource::asExternalModel)
@ -259,7 +259,7 @@ class OfflineFirstNewsRepositoryTest {
.map(NetworkNewsResource::topicEntityShells)
.flatten()
.distinctBy(TopicEntity::id),
topicDao.getTopicEntitiesStream()
topicDao.getTopicEntities()
.first()
)
}
@ -274,7 +274,7 @@ class OfflineFirstNewsRepositoryTest {
.map(NetworkNewsResource::authorEntityShells)
.flatten()
.distinctBy(AuthorEntity::id),
authorDao.getAuthorEntitiesStream()
authorDao.getAuthorEntities()
.first()
)
}

@ -70,10 +70,10 @@ class OfflineFirstTopicsRepositoryTest {
fun offlineFirstTopicsRepository_topics_stream_is_backed_by_topics_dao() =
runTest {
assertEquals(
topicDao.getTopicEntitiesStream()
topicDao.getTopicEntities()
.first()
.map(TopicEntity::asExternalModel),
subject.getTopicsStream()
subject.getTopics()
.first()
)
}
@ -86,7 +86,7 @@ class OfflineFirstTopicsRepositoryTest {
val networkTopics = network.getTopics()
.map(NetworkTopic::asEntity)
val dbTopics = topicDao.getTopicEntitiesStream()
val dbTopics = topicDao.getTopicEntities()
.first()
assertEquals(
@ -116,7 +116,7 @@ class OfflineFirstTopicsRepositoryTest {
// Drop 10 to simulate the first 10 items being unchanged
.drop(10)
val dbTopics = topicDao.getTopicEntitiesStream()
val dbTopics = topicDao.getTopicEntities()
.first()
assertEquals(
@ -155,7 +155,7 @@ class OfflineFirstTopicsRepositoryTest {
subject.syncWith(synchronizer)
val dbTopics = topicDao.getTopicEntitiesStream()
val dbTopics = topicDao.getTopicEntities()
.first()
.map(TopicEntity::asExternalModel)

@ -63,7 +63,7 @@ class OfflineFirstUserDataRepositoryTest {
darkThemeConfig = DarkThemeConfig.FOLLOW_SYSTEM,
shouldHideOnboarding = false
),
subject.userDataStream.first()
subject.userData.first()
)
}
@ -74,7 +74,7 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
setOf("0"),
subject.userDataStream
subject.userData
.map { it.followedTopics }
.first()
)
@ -83,16 +83,16 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
setOf("0", "1"),
subject.userDataStream
subject.userData
.map { it.followedTopics }
.first()
)
assertEquals(
niaPreferencesDataSource.userDataStream
niaPreferencesDataSource.userData
.map { it.followedTopics }
.first(),
subject.userDataStream
subject.userData
.map { it.followedTopics }
.first()
)
@ -105,16 +105,16 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
setOf("1", "2"),
subject.userDataStream
subject.userData
.map { it.followedTopics }
.first()
)
assertEquals(
niaPreferencesDataSource.userDataStream
niaPreferencesDataSource.userData
.map { it.followedTopics }
.first(),
subject.userDataStream
subject.userData
.map { it.followedTopics }
.first()
)
@ -127,7 +127,7 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
setOf("0"),
subject.userDataStream
subject.userData
.map { it.bookmarkedNewsResources }
.first()
)
@ -136,16 +136,16 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
setOf("0", "1"),
subject.userDataStream
subject.userData
.map { it.bookmarkedNewsResources }
.first()
)
assertEquals(
niaPreferencesDataSource.userDataStream
niaPreferencesDataSource.userData
.map { it.bookmarkedNewsResources }
.first(),
subject.userDataStream
subject.userData
.map { it.bookmarkedNewsResources }
.first()
)
@ -158,14 +158,14 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
ThemeBrand.ANDROID,
subject.userDataStream
subject.userData
.map { it.themeBrand }
.first()
)
assertEquals(
ThemeBrand.ANDROID,
niaPreferencesDataSource
.userDataStream
.userData
.map { it.themeBrand }
.first()
)
@ -178,14 +178,14 @@ class OfflineFirstUserDataRepositoryTest {
assertEquals(
DarkThemeConfig.DARK,
subject.userDataStream
subject.userData
.map { it.darkThemeConfig }
.first()
)
assertEquals(
DarkThemeConfig.DARK,
niaPreferencesDataSource
.userDataStream
.userData
.map { it.darkThemeConfig }
.first()
)
@ -196,9 +196,9 @@ class OfflineFirstUserDataRepositoryTest {
runTest {
subject.setFollowedTopicIds(setOf("1"))
subject.setShouldHideOnboarding(true)
assertTrue(subject.userDataStream.first().shouldHideOnboarding)
assertTrue(subject.userData.first().shouldHideOnboarding)
subject.setFollowedTopicIds(emptySet())
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
}

@ -40,10 +40,10 @@ class TestAuthorDao : AuthorDao {
)
)
override fun getAuthorEntitiesStream(): Flow<List<AuthorEntity>> =
override fun getAuthorEntities(): Flow<List<AuthorEntity>> =
entitiesStateFlow
override fun getAuthorEntityStream(authorId: String): Flow<AuthorEntity> {
override fun getAuthorEntity(authorId: String): Flow<AuthorEntity> {
throw NotImplementedError("Unused in tests")
}

@ -56,16 +56,16 @@ class TestNewsResourceDao : NewsResourceDao {
internal var authorCrossReferences: List<NewsResourceAuthorCrossRef> = listOf()
override fun getNewsResourcesStream(): Flow<List<PopulatedNewsResource>> =
override fun getNewsResources(): Flow<List<PopulatedNewsResource>> =
entitiesStateFlow.map {
it.map(NewsResourceEntity::asPopulatedNewsResource)
}
override fun getNewsResourcesStream(
override fun getNewsResources(
filterAuthorIds: Set<String>,
filterTopicIds: Set<String>
): Flow<List<PopulatedNewsResource>> =
getNewsResourcesStream()
getNewsResources()
.map { resources ->
resources.filter { resource ->
resource.topics.any { it.id in filterTopicIds } ||

@ -45,11 +45,11 @@ class TestTopicDao : TopicDao {
throw NotImplementedError("Unused in tests")
}
override fun getTopicEntitiesStream(): Flow<List<TopicEntity>> =
override fun getTopicEntities(): Flow<List<TopicEntity>> =
entitiesStateFlow
override fun getTopicEntitiesStream(ids: Set<String>): Flow<List<TopicEntity>> =
getTopicEntitiesStream()
override fun getTopicEntities(ids: Set<String>): Flow<List<TopicEntity>> =
getTopicEntities()
.map { topics -> topics.filter { it.id in ids } }
override suspend fun insertOrIgnoreTopics(topicEntities: List<TopicEntity>): List<Long> {

@ -77,7 +77,7 @@ class NewsResourceDaoTest {
newsResourceEntities
)
val savedNewsResourceEntities = newsResourceDao.getNewsResourcesStream()
val savedNewsResourceEntities = newsResourceDao.getNewsResources()
.first()
assertEquals(
@ -135,7 +135,7 @@ class NewsResourceDaoTest {
newsResourceTopicCrossRefEntities
)
val filteredNewsResources = newsResourceDao.getNewsResourcesStream(
val filteredNewsResources = newsResourceDao.getNewsResources(
filterTopicIds = topicEntities
.map(TopicEntity::id)
.toSet(),
@ -188,7 +188,7 @@ class NewsResourceDaoTest {
newsResourceDao.upsertNewsResources(newsResourceEntities)
newsResourceDao.insertOrIgnoreAuthorCrossRefEntities(newsResourceAuthorCrossRefEntities)
val filteredNewsResources = newsResourceDao.getNewsResourcesStream(
val filteredNewsResources = newsResourceDao.getNewsResources(
filterAuthorIds = authorEntities
.map(AuthorEntity::id)
.toSet()
@ -268,7 +268,7 @@ class NewsResourceDaoTest {
newsResourceDao.insertOrIgnoreTopicCrossRefEntities(newsResourceTopicCrossRefEntities)
newsResourceDao.insertOrIgnoreAuthorCrossRefEntities(newsResourceAuthorCrossRefEntities)
val filteredNewsResources = newsResourceDao.getNewsResourcesStream(
val filteredNewsResources = newsResourceDao.getNewsResources(
filterTopicIds = topicEntities
.map(TopicEntity::id)
.toSet(),
@ -315,7 +315,7 @@ class NewsResourceDaoTest {
assertEquals(
toKeep.map(NewsResourceEntity::id)
.toSet(),
newsResourceDao.getNewsResourcesStream().first()
newsResourceDao.getNewsResources().first()
.map { it.entity.id }
.toSet()
)

@ -36,10 +36,10 @@ interface AuthorDao {
WHERE id = :authorId
"""
)
fun getAuthorEntityStream(authorId: String): Flow<AuthorEntity>
fun getAuthorEntity(authorId: String): Flow<AuthorEntity>
@Query(value = "SELECT * FROM authors")
fun getAuthorEntitiesStream(): Flow<List<AuthorEntity>>
fun getAuthorEntities(): Flow<List<AuthorEntity>>
/**
* Inserts [authorEntities] into the db if they don't exist, and ignores those that do

@ -42,7 +42,7 @@ interface NewsResourceDao {
ORDER BY publish_date DESC
"""
)
fun getNewsResourcesStream(): Flow<List<PopulatedNewsResource>>
fun getNewsResources(): Flow<List<PopulatedNewsResource>>
@Transaction
@Query(
@ -61,7 +61,7 @@ interface NewsResourceDao {
ORDER BY publish_date DESC
"""
)
fun getNewsResourcesStream(
fun getNewsResources(
filterAuthorIds: Set<String> = emptySet(),
filterTopicIds: Set<String> = emptySet(),
): Flow<List<PopulatedNewsResource>>

@ -39,7 +39,7 @@ interface TopicDao {
fun getTopicEntity(topicId: String): Flow<TopicEntity>
@Query(value = "SELECT * FROM topics")
fun getTopicEntitiesStream(): Flow<List<TopicEntity>>
fun getTopicEntities(): Flow<List<TopicEntity>>
@Query(
value = """
@ -47,7 +47,7 @@ interface TopicDao {
WHERE id IN (:ids)
"""
)
fun getTopicEntitiesStream(ids: Set<String>): Flow<List<TopicEntity>>
fun getTopicEntities(ids: Set<String>): Flow<List<TopicEntity>>
/**
* Inserts [topicEntities] into the db if they don't exist, and ignores those that do

@ -30,7 +30,7 @@ class NiaPreferencesDataSource @Inject constructor(
private val userPreferences: DataStore<UserPreferences>
) {
val userDataStream = userPreferences.data
val userData = userPreferences.data
.map {
UserData(
bookmarkedNewsResources = it.bookmarkedNewsResourceIdsMap.keys,

@ -41,13 +41,13 @@ class NiaPreferencesDataSourceTest {
@Test
fun shouldHideOnboardingIsFalseByDefault() = runTest {
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
@Test
fun userShouldHideOnboardingIsTrueWhenSet() = runTest {
subject.setShouldHideOnboarding(true)
assertTrue(subject.userDataStream.first().shouldHideOnboarding)
assertTrue(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -61,7 +61,7 @@ class NiaPreferencesDataSourceTest {
subject.toggleFollowedAuthorId("1", false)
// Then: onboarding should be shown again
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -75,7 +75,7 @@ class NiaPreferencesDataSourceTest {
subject.toggleFollowedTopicId("1", false)
// Then: onboarding should be shown again
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -89,7 +89,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedAuthorIds(emptySet())
// Then: onboarding should be shown again
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -103,7 +103,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedTopicIds(emptySet())
// Then: onboarding should be shown again
assertFalse(subject.userDataStream.first().shouldHideOnboarding)
assertFalse(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -118,7 +118,7 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedTopicIds(emptySet())
// Then: onboarding should still be dismissed
assertTrue(subject.userDataStream.first().shouldHideOnboarding)
assertTrue(subject.userData.first().shouldHideOnboarding)
}
@Test
@ -133,6 +133,6 @@ class NiaPreferencesDataSourceTest {
subject.setFollowedAuthorIds(emptySet())
// Then: onboarding should still be dismissed
assertTrue(subject.userDataStream.first().shouldHideOnboarding)
assertTrue(subject.userData.first().shouldHideOnboarding)
}
}

@ -24,12 +24,11 @@ import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
/**
* A use case which obtains a list of topics with their followed state.
*/
class GetFollowableTopicsStreamUseCase @Inject constructor(
class GetFollowableTopicsUseCase @Inject constructor(
private val topicsRepository: TopicsRepository,
private val userDataRepository: UserDataRepository
) {
@ -40,8 +39,8 @@ class GetFollowableTopicsStreamUseCase @Inject constructor(
*/
operator fun invoke(sortBy: TopicSortField = NONE): Flow<List<FollowableTopic>> {
return combine(
userDataRepository.userDataStream,
topicsRepository.getTopicsStream()
userDataRepository.userData,
topicsRepository.getTopics()
) { userData, topics ->
val followedTopics = topics
.map { topic ->

@ -30,12 +30,12 @@ import kotlinx.coroutines.flow.map
* A use case responsible for obtaining news resources with their associated bookmarked (also known
* as "saved") state.
*/
class GetSaveableNewsResourcesStreamUseCase @Inject constructor(
class GetSaveableNewsResourcesUseCase @Inject constructor(
private val newsRepository: NewsRepository,
userDataRepository: UserDataRepository
) {
private val bookmarkedNewsResourcesStream = userDataRepository.userDataStream.map {
private val bookmarkedNewsResources = userDataRepository.userData.map {
it.bookmarkedNewsResources
}
@ -54,20 +54,20 @@ class GetSaveableNewsResourcesStreamUseCase @Inject constructor(
filterAuthorIds: Set<String> = emptySet()
): Flow<List<SaveableNewsResource>> =
if (filterTopicIds.isEmpty() && filterAuthorIds.isEmpty()) {
newsRepository.getNewsResourcesStream()
newsRepository.getNewsResources()
} else {
newsRepository.getNewsResourcesStream(
newsRepository.getNewsResources(
filterTopicIds = filterTopicIds,
filterAuthorIds = filterAuthorIds
)
}.mapToSaveableNewsResources(bookmarkedNewsResourcesStream)
}.mapToSaveableNewsResources(bookmarkedNewsResources)
}
private fun Flow<List<NewsResource>>.mapToSaveableNewsResources(
savedNewsResourceIdsStream: Flow<Set<String>>
savedNewsResourceIds: Flow<Set<String>>
): Flow<List<SaveableNewsResource>> =
filterNot { it.isEmpty() }
.combine(savedNewsResourceIdsStream) { newsResources, savedNewsResourceIds ->
.combine(savedNewsResourceIds) { newsResources, savedNewsResourceIds ->
newsResources.map { newsResource ->
SaveableNewsResource(
newsResource = newsResource,

@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.combine
* A use case which obtains a list of authors sorted alphabetically by name with their followed
* state.
*/
class GetSortedFollowableAuthorsStreamUseCase @Inject constructor(
class GetSortedFollowableAuthorsUseCase @Inject constructor(
private val authorsRepository: AuthorsRepository,
private val userDataRepository: UserDataRepository
) {
@ -36,8 +36,8 @@ class GetSortedFollowableAuthorsStreamUseCase @Inject constructor(
*/
operator fun invoke(): Flow<List<FollowableAuthor>> =
combine(
authorsRepository.getAuthorsStream(),
userDataRepository.userDataStream
authorsRepository.getAuthors(),
userDataRepository.userData
) { authors, userData ->
authors.map { author ->
FollowableAuthor(

@ -28,7 +28,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class GetFollowableTopicsStreamUseCaseTest {
class GetFollowableTopicsUseCaseTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
@ -36,7 +36,7 @@ class GetFollowableTopicsStreamUseCaseTest {
private val topicsRepository = TestTopicsRepository()
private val userDataRepository = TestUserDataRepository()
val useCase = GetFollowableTopicsStreamUseCase(
val useCase = GetFollowableTopicsUseCase(
topicsRepository,
userDataRepository
)

@ -31,7 +31,7 @@ import kotlinx.datetime.Instant
import org.junit.Rule
import org.junit.Test
class GetSaveableNewsResourcesStreamUseCaseTest {
class GetSaveableNewsResourcesUseCaseTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
@ -39,7 +39,7 @@ class GetSaveableNewsResourcesStreamUseCaseTest {
private val newsRepository = TestNewsRepository()
private val userDataRepository = TestUserDataRepository()
val useCase = GetSaveableNewsResourcesStreamUseCase(newsRepository, userDataRepository)
val useCase = GetSaveableNewsResourcesUseCase(newsRepository, userDataRepository)
@Test
fun whenNoFilters_allNewsResourcesAreReturned() = runTest {

@ -27,7 +27,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class GetSortedFollowableAuthorsStreamUseCaseTest {
class GetSortedFollowableAuthorsUseCaseTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
@ -35,7 +35,7 @@ class GetSortedFollowableAuthorsStreamUseCaseTest {
private val authorsRepository = TestAuthorsRepository()
private val userDataRepository = TestUserDataRepository()
val useCase = GetSortedFollowableAuthorsStreamUseCase(
val useCase = GetSortedFollowableAuthorsUseCase(
authorsRepository = authorsRepository,
userDataRepository = userDataRepository
)
@ -47,14 +47,14 @@ class GetSortedFollowableAuthorsStreamUseCaseTest {
userDataRepository.setFollowedAuthorIds(setOf(sampleAuthor1.id))
// Obtain the stream of authors, specifying their followed state.
val followableAuthorsStream = useCase()
val followableAuthors = useCase()
// Supply some authors.
authorsRepository.sendAuthors(sampleAuthors)
// Check that the authors have been sorted, and that the followed state is correct.
assertEquals(
followableAuthorsStream.first(),
followableAuthors.first(),
listOf(
FollowableAuthor(sampleAuthor2, false),
FollowableAuthor(sampleAuthor1, true),

@ -31,9 +31,9 @@ class TestAuthorsRepository : AuthorsRepository {
private val authorsFlow: MutableSharedFlow<List<Author>> =
MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override fun getAuthorsStream(): Flow<List<Author>> = authorsFlow
override fun getAuthors(): Flow<List<Author>> = authorsFlow
override fun getAuthorStream(id: String): Flow<Author> {
override fun getAuthor(id: String): Flow<Author> {
return authorsFlow.map { authors -> authors.find { it.id == id }!! }
}

@ -34,13 +34,13 @@ class TestNewsRepository : NewsRepository {
private val newsResourcesFlow: MutableSharedFlow<List<NewsResource>> =
MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override fun getNewsResourcesStream(): Flow<List<NewsResource>> = newsResourcesFlow
override fun getNewsResources(): Flow<List<NewsResource>> = newsResourcesFlow
override fun getNewsResourcesStream(
override fun getNewsResources(
filterAuthorIds: Set<String>,
filterTopicIds: Set<String>
): Flow<List<NewsResource>> =
getNewsResourcesStream().map { newsResources ->
getNewsResources().map { newsResources ->
newsResources
.filter {
it.authors.map(Author::id).intersect(filterAuthorIds).isNotEmpty() ||

@ -31,7 +31,7 @@ class TestTopicsRepository : TopicsRepository {
private val topicsFlow: MutableSharedFlow<List<Topic>> =
MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override fun getTopicsStream(): Flow<List<Topic>> = topicsFlow
override fun getTopics(): Flow<List<Topic>> = topicsFlow
override fun getTopic(id: String): Flow<Topic> {
return topicsFlow.map { topics -> topics.find { it.id == id }!! }

@ -42,7 +42,7 @@ class TestUserDataRepository : UserDataRepository {
private val currentUserData get() = _userData.replayCache.firstOrNull() ?: emptyUserData
override val userDataStream: Flow<UserData> = _userData.filterNotNull()
override val userData: Flow<UserData> = _userData.filterNotNull()
override suspend fun setFollowedTopicIds(followedTopicIds: Set<String>) {
_userData.tryEmit(currentUserData.copy(followedTopics = followedTopicIds))

@ -120,7 +120,7 @@ Here's what's happening in each step. The easiest way to find the associated cod
</td>
<td>When data changes in <code>NewsResourceDao</code> it is emitted into the news resources data stream (which is a <a href="https://developer.android.com/kotlin/flow">Flow</a>).
</td>
<td><code>NewsResourceDao.getNewsResourcesStream</code>
<td><code>NewsResourceDao.getNewsResources</code>
</td>
</tr>
<tr>
@ -128,7 +128,7 @@ Here's what's happening in each step. The easiest way to find the associated cod
</td>
<td><code>OfflineFirstNewsRepository</code> acts as an <a href="https://developer.android.com/kotlin/flow#modify">intermediate operator</a> on this stream, transforming the incoming <code>PopulatedNewsResource</code> (a database model, internal to the data layer) to the public <code>NewsResource</code> model which is consumed by other layers.
</td>
<td><code>OfflineFirstNewsRepository.getNewsResourcesStream</code>
<td><code>OfflineFirstNewsRepository.getNewsResources</code>
</td>
</tr>
<tr>
@ -167,7 +167,7 @@ Reads are performed from local storage as the source of truth, therefore errors
_Example: Read a list of authors_
A list of Authors can be obtained by subscribing to `AuthorsRepository::getAuthorsStream` flow which emits `List<Authors>`.
A list of Authors can be obtained by subscribing to `AuthorsRepository::getAuthors` flow which emits `List<Authors>`.
Whenever the list of authors changes (for example, when a new author is added), the updated `List<Author>` is emitted into the stream.
@ -280,7 +280,7 @@ The `InterestsViewModel` exposes `uiState` as a `StateFlow<InterestsUiState>`. T
* List of authors (`getAuthorsStream`)
* List of authors (`getAuthors`)
* List of author IDs which the current user is following
* List of topics
* List of topic IDs which the current user is following

@ -22,7 +22,7 @@ import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.repository.AuthorsRepository
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.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.model.data.Author
@ -45,12 +45,12 @@ class AuthorViewModel @Inject constructor(
stringDecoder: StringDecoder,
private val userDataRepository: UserDataRepository,
authorsRepository: AuthorsRepository,
getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase
getSaveableNewsResources: GetSaveableNewsResourcesUseCase
) : ViewModel() {
private val authorArgs: AuthorArgs = AuthorArgs(savedStateHandle, stringDecoder)
val authorUiState: StateFlow<AuthorUiState> = authorUiStateStream(
val authorUiState: StateFlow<AuthorUiState> = authorUiState(
authorId = authorArgs.authorId,
userDataRepository = userDataRepository,
authorsRepository = authorsRepository
@ -62,7 +62,7 @@ class AuthorViewModel @Inject constructor(
)
val newsUiState: StateFlow<NewsUiState> =
getSaveableNewsResourcesStream.newsUiStateStream(authorId = authorArgs.authorId)
getSaveableNewsResources.newsUiState(authorId = authorArgs.authorId)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
@ -82,24 +82,24 @@ class AuthorViewModel @Inject constructor(
}
}
private fun authorUiStateStream(
private fun authorUiState(
authorId: String,
userDataRepository: UserDataRepository,
authorsRepository: AuthorsRepository,
): Flow<AuthorUiState> {
// Observe the followed authors, as they could change over time.
val followedAuthorIdsStream: Flow<Set<String>> =
userDataRepository.userDataStream
val followedAuthorIds: Flow<Set<String>> =
userDataRepository.userData
.map { it.followedAuthors }
// Observe author information
val authorStream: Flow<Author> = authorsRepository.getAuthorStream(
val author: Flow<Author> = authorsRepository.getAuthor(
id = authorId
)
return combine(
followedAuthorIdsStream,
authorStream,
followedAuthorIds,
author,
::Pair
)
.asResult()
@ -125,7 +125,7 @@ private fun authorUiStateStream(
}
}
private fun GetSaveableNewsResourcesStreamUseCase.newsUiStateStream(
private fun GetSaveableNewsResourcesUseCase.newsUiState(
authorId: String
): Flow<NewsUiState> {
// Observe news

@ -17,7 +17,7 @@
package com.google.samples.apps.nowinandroid.feature.author
import androidx.lifecycle.SavedStateHandle
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
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
@ -54,7 +54,7 @@ class AuthorViewModelTest {
private val userDataRepository = TestUserDataRepository()
private val authorsRepository = TestAuthorsRepository()
private val newsRepository = TestNewsRepository()
private val getSaveableNewsResourcesStreamUseCase = GetSaveableNewsResourcesStreamUseCase(
private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase(
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
@ -71,7 +71,7 @@ class AuthorViewModelTest {
stringDecoder = FakeStringDecoder(),
userDataRepository = userDataRepository,
authorsRepository = authorsRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStreamUseCase
getSaveableNewsResources = getSaveableNewsResourcesUseCase
)
}
@ -86,7 +86,7 @@ class AuthorViewModelTest {
val item = viewModel.authorUiState.value
assertIs<AuthorUiState.Success>(item)
val authorFromRepository = authorsRepository.getAuthorStream(
val authorFromRepository = authorsRepository.getAuthor(
id = testInputAuthors[0].author.id
).first()

@ -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.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading
@ -36,10 +36,10 @@ import kotlinx.coroutines.launch
@HiltViewModel
class BookmarksViewModel @Inject constructor(
private val userDataRepository: UserDataRepository,
getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase
getSaveableNewsResources: GetSaveableNewsResourcesUseCase
) : ViewModel() {
val feedUiState: StateFlow<NewsFeedUiState> = getSaveableNewsResourcesStream()
val feedUiState: StateFlow<NewsFeedUiState> = getSaveableNewsResources()
.filterNot { it.isEmpty() }
.map { newsResources -> newsResources.filter(SaveableNewsResource::isSaved) } // Only show bookmarked news resources.
.map<List<SaveableNewsResource>, NewsFeedUiState>(NewsFeedUiState::Success)

@ -16,7 +16,7 @@
package com.google.samples.apps.nowinandroid.feature.bookmarks
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
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 getSaveableNewsResourcesStreamUseCase = GetSaveableNewsResourcesStreamUseCase(
private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase(
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
@ -53,7 +53,7 @@ class BookmarksViewModelTest {
fun setup() {
viewModel = BookmarksViewModel(
userDataRepository = userDataRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStreamUseCase
getSaveableNewsResources = getSaveableNewsResourcesUseCase
)
}

@ -20,9 +20,9 @@ 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.data.util.SyncStatusMonitor
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsStreamUseCase
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.GetSortedFollowableAuthorsUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import dagger.hilt.android.lifecycle.HiltViewModel
@ -42,13 +42,13 @@ import kotlinx.coroutines.launch
class ForYouViewModel @Inject constructor(
syncStatusMonitor: SyncStatusMonitor,
private val userDataRepository: UserDataRepository,
private val getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase,
getSortedFollowableAuthorsStream: GetSortedFollowableAuthorsStreamUseCase,
getFollowableTopicsStream: GetFollowableTopicsStreamUseCase
private val getSaveableNewsResources: GetSaveableNewsResourcesUseCase,
getSortedFollowableAuthors: GetSortedFollowableAuthorsUseCase,
getFollowableTopics: GetFollowableTopicsUseCase
) : ViewModel() {
private val shouldShowOnboarding: Flow<Boolean> =
userDataRepository.userDataStream.map { !it.shouldHideOnboarding }
userDataRepository.userData.map { !it.shouldHideOnboarding }
val isSyncing = syncStatusMonitor.isSyncing
.stateIn(
@ -58,7 +58,7 @@ class ForYouViewModel @Inject constructor(
)
val feedState: StateFlow<NewsFeedUiState> =
userDataRepository.userDataStream
userDataRepository.userData
.map { userData ->
// If the user hasn't completed the onboarding and hasn't selected any interests
// show an empty news list to clearly demonstrate that their selections affect the
@ -69,7 +69,7 @@ class ForYouViewModel @Inject constructor(
) {
flowOf(NewsFeedUiState.Success(emptyList()))
} else {
getSaveableNewsResourcesStream(
getSaveableNewsResources(
filterTopicIds = userData.followedTopics,
filterAuthorIds = userData.followedAuthors
).mapToFeedState()
@ -88,8 +88,8 @@ class ForYouViewModel @Inject constructor(
val onboardingUiState: StateFlow<OnboardingUiState> =
combine(
shouldShowOnboarding,
getFollowableTopicsStream(),
getSortedFollowableAuthorsStream()
getFollowableTopics(),
getSortedFollowableAuthors()
) { shouldShowOnboarding, topics, authors ->
if (shouldShowOnboarding) {
OnboardingUiState.Shown(

@ -16,9 +16,9 @@
package com.google.samples.apps.nowinandroid.feature.foryou
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsStreamUseCase
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.GetSortedFollowableAuthorsUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
@ -59,15 +59,15 @@ class ForYouViewModelTest {
private val authorsRepository = TestAuthorsRepository()
private val topicsRepository = TestTopicsRepository()
private val newsRepository = TestNewsRepository()
private val getSaveableNewsResourcesStreamUseCase = GetSaveableNewsResourcesStreamUseCase(
private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase(
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
private val getSortedFollowableAuthorsStream = GetSortedFollowableAuthorsStreamUseCase(
private val getSortedFollowableAuthors = GetSortedFollowableAuthorsUseCase(
authorsRepository = authorsRepository,
userDataRepository = userDataRepository
)
private val getFollowableTopicsStreamUseCase = GetFollowableTopicsStreamUseCase(
private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase(
topicsRepository = topicsRepository,
userDataRepository = userDataRepository
)
@ -78,9 +78,9 @@ class ForYouViewModelTest {
viewModel = ForYouViewModel(
syncStatusMonitor = syncStatusMonitor,
userDataRepository = userDataRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStreamUseCase,
getSortedFollowableAuthorsStream = getSortedFollowableAuthorsStream,
getFollowableTopicsStream = getFollowableTopicsStreamUseCase
getSaveableNewsResources = getSaveableNewsResourcesUseCase,
getSortedFollowableAuthors = getSortedFollowableAuthors,
getFollowableTopics = getFollowableTopicsUseCase
)
}

@ -19,8 +19,8 @@ package com.google.samples.apps.nowinandroid.feature.interests
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.GetFollowableTopicsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsUseCase
import com.google.samples.apps.nowinandroid.core.domain.TopicSortField
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
@ -38,8 +38,8 @@ import kotlinx.coroutines.launch
@HiltViewModel
class InterestsViewModel @Inject constructor(
val userDataRepository: UserDataRepository,
getFollowableTopicsStream: GetFollowableTopicsStreamUseCase,
getSortedFollowableAuthorsStream: GetSortedFollowableAuthorsStreamUseCase
getFollowableTopics: GetFollowableTopicsUseCase,
getSortedFollowableAuthors: GetSortedFollowableAuthorsUseCase
) : ViewModel() {
private val _tabState = MutableStateFlow(
@ -51,8 +51,8 @@ class InterestsViewModel @Inject constructor(
val tabState: StateFlow<InterestsTabState> = _tabState.asStateFlow()
val uiState: StateFlow<InterestsUiState> = combine(
getSortedFollowableAuthorsStream(),
getFollowableTopicsStream(sortBy = TopicSortField.NAME),
getSortedFollowableAuthors(),
getFollowableTopics(sortBy = TopicSortField.NAME),
InterestsUiState::Interests
).stateIn(
scope = viewModelScope,

@ -16,8 +16,8 @@
package com.google.samples.apps.nowinandroid.interests
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableAuthor
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.Author
@ -49,12 +49,12 @@ class InterestsViewModelTest {
private val userDataRepository = TestUserDataRepository()
private val authorsRepository = TestAuthorsRepository()
private val topicsRepository = TestTopicsRepository()
private val getFollowableTopicsStreamUseCase = GetFollowableTopicsStreamUseCase(
private val getFollowableTopicsUseCase = GetFollowableTopicsUseCase(
topicsRepository = topicsRepository,
userDataRepository = userDataRepository
)
private val getSortedFollowableAuthorsStream =
GetSortedFollowableAuthorsStreamUseCase(
private val getSortedFollowableAuthors =
GetSortedFollowableAuthorsUseCase(
authorsRepository = authorsRepository,
userDataRepository = userDataRepository
)
@ -64,8 +64,8 @@ class InterestsViewModelTest {
fun setup() {
viewModel = InterestsViewModel(
userDataRepository = userDataRepository,
getFollowableTopicsStream = getFollowableTopicsStreamUseCase,
getSortedFollowableAuthorsStream = getSortedFollowableAuthorsStream
getFollowableTopics = getFollowableTopicsUseCase,
getSortedFollowableAuthors = getSortedFollowableAuthors
)
}

@ -36,7 +36,7 @@ class SettingsViewModel @Inject constructor(
private val userDataRepository: UserDataRepository,
) : ViewModel() {
val settingsUiState: StateFlow<SettingsUiState> =
userDataRepository.userDataStream
userDataRepository.userData
.map { userData ->
Success(
settings = UserEditableSettings(

@ -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.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic
import com.google.samples.apps.nowinandroid.core.domain.model.SaveableNewsResource
import com.google.samples.apps.nowinandroid.core.model.data.Topic
@ -46,12 +46,12 @@ class TopicViewModel @Inject constructor(
private val userDataRepository: UserDataRepository,
topicsRepository: TopicsRepository,
// newsRepository: NewsRepository,
getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase
getSaveableNewsResources: GetSaveableNewsResourcesUseCase
) : ViewModel() {
private val topicArgs: TopicArgs = TopicArgs(savedStateHandle, stringDecoder)
val topicUiState: StateFlow<TopicUiState> = topicUiStateStream(
val topicUiState: StateFlow<TopicUiState> = topicUiState(
topicId = topicArgs.topicId,
userDataRepository = userDataRepository,
topicsRepository = topicsRepository
@ -62,10 +62,10 @@ class TopicViewModel @Inject constructor(
initialValue = TopicUiState.Loading
)
val newUiState: StateFlow<NewsUiState> = newsUiStateStream(
val newUiState: StateFlow<NewsUiState> = newsUiState(
topicId = topicArgs.topicId,
userDataRepository = userDataRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStream
getSaveableNewsResources = getSaveableNewsResources
)
.stateIn(
scope = viewModelScope,
@ -86,24 +86,24 @@ class TopicViewModel @Inject constructor(
}
}
private fun topicUiStateStream(
private fun topicUiState(
topicId: String,
userDataRepository: UserDataRepository,
topicsRepository: TopicsRepository,
): Flow<TopicUiState> {
// Observe the followed topics, as they could change over time.
val followedTopicIdsStream: Flow<Set<String>> =
userDataRepository.userDataStream
val followedTopicIds: Flow<Set<String>> =
userDataRepository.userData
.map { it.followedTopics }
// Observe topic information
val topicStream: Flow<Topic> = topicsRepository.getTopic(
val topic: Flow<Topic> = topicsRepository.getTopic(
id = topicId
)
return combine(
followedTopicIdsStream,
topicStream,
followedTopicIds,
topic,
::Pair
)
.asResult()
@ -129,24 +129,24 @@ private fun topicUiStateStream(
}
}
private fun newsUiStateStream(
private fun newsUiState(
topicId: String,
getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase,
getSaveableNewsResources: GetSaveableNewsResourcesUseCase,
userDataRepository: UserDataRepository,
): Flow<NewsUiState> {
// Observe news
val newsStream: Flow<List<SaveableNewsResource>> = getSaveableNewsResourcesStream(
val news: Flow<List<SaveableNewsResource>> = getSaveableNewsResources(
filterAuthorIds = emptySet(),
filterTopicIds = setOf(element = topicId),
)
// Observe bookmarks
val bookmarkStream: Flow<Set<String>> = userDataRepository.userDataStream
val bookmark: Flow<Set<String>> = userDataRepository.userData
.map { it.bookmarkedNewsResources }
return combine(
newsStream,
bookmarkStream,
news,
bookmark,
::Pair
)
.asResult()

@ -17,7 +17,7 @@
package com.google.samples.apps.nowinandroid.feature.topic
import androidx.lifecycle.SavedStateHandle
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesStreamUseCase
import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResourcesUseCase
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 getSaveableNewsResourcesStreamUseCase = GetSaveableNewsResourcesStreamUseCase(
private val getSaveableNewsResourcesUseCase = GetSaveableNewsResourcesUseCase(
newsRepository = newsRepository,
userDataRepository = userDataRepository
)
@ -66,7 +66,7 @@ class TopicViewModelTest {
stringDecoder = FakeStringDecoder(),
userDataRepository = userDataRepository,
topicsRepository = topicsRepository,
getSaveableNewsResourcesStream = getSaveableNewsResourcesStreamUseCase
getSaveableNewsResources = getSaveableNewsResourcesUseCase
)
}

Loading…
Cancel
Save