From 01351f1ef07c26df44d419b72880437eca37f4cf Mon Sep 17 00:00:00 2001 From: Mohsen Rzna Date: Sun, 20 Nov 2022 16:34:46 +0100 Subject: [PATCH] Refactor - using `StateInViewModelScope()` extension function inside ViewModels This commit also includes refactoring for functions, making functions more clear by extracting them inside ViewModels. --- .../nowinandroid/MainActivityViewModel.kt | 9 +- .../feature/author/AuthorViewModel.kt | 130 +++++++++--------- .../feature/bookmarks/BookmarksViewModel.kt | 15 +- .../feature/foryou/ForYouViewModel.kt | 43 ++---- .../feature/interests/InterestsViewModel.kt | 21 +-- .../feature/settings/SettingsViewModel.kt | 36 ++--- .../feature/topic/TopicViewModel.kt | 84 +++++------ 7 files changed, 135 insertions(+), 203 deletions(-) diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivityViewModel.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivityViewModel.kt index 885fb6c3d..ba343f228 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivityViewModel.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivityViewModel.kt @@ -22,12 +22,11 @@ import com.google.samples.apps.nowinandroid.MainActivityUiState.Loading import com.google.samples.apps.nowinandroid.MainActivityUiState.Success import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.model.data.UserData +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn @HiltViewModel class MainActivityViewModel @Inject constructor( @@ -35,11 +34,7 @@ class MainActivityViewModel @Inject constructor( ) : ViewModel() { val uiState: StateFlow = userDataRepository.userDataStream.map { Success(it) - }.stateIn( - scope = viewModelScope, - initialValue = Loading, - started = SharingStarted.WhileSubscribed(5_000) - ) + }.stateInViewModelScope(viewModelScope, initialValue = Loading) } sealed interface MainActivityUiState { diff --git a/feature/author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModel.kt b/feature/author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModel.kt index 2f63dbc11..c9b465224 100644 --- a/feature/author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModel.kt +++ b/feature/author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModel.kt @@ -27,17 +27,19 @@ 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 import com.google.samples.apps.nowinandroid.core.result.Result +import com.google.samples.apps.nowinandroid.core.result.Result.Error +import com.google.samples.apps.nowinandroid.core.result.Result.Loading +import com.google.samples.apps.nowinandroid.core.result.Result.Success import com.google.samples.apps.nowinandroid.core.result.asResult +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import com.google.samples.apps.nowinandroid.feature.author.navigation.AuthorArgs import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +import javax.inject.Inject @HiltViewModel class AuthorViewModel @Inject constructor( @@ -54,75 +56,67 @@ class AuthorViewModel @Inject constructor( authorId = authorArgs.authorId, userDataRepository = userDataRepository, authorsRepository = authorsRepository - ) - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = AuthorUiState.Loading - ) + ).stateInViewModelScope(viewModelScope, initialValue = AuthorUiState.Loading) - val newsUiState: StateFlow = - getSaveableNewsResourcesStream.newsUiStateStream(authorId = authorArgs.authorId) - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = NewsUiState.Loading - ) + val newsUiState: StateFlow = getSaveableNewsResourcesStream + .newsUiStateStream(authorId = authorArgs.authorId) + .stateInViewModelScope(viewModelScope, initialValue = NewsUiState.Loading) - fun followAuthorToggle(followed: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedAuthorId(authorArgs.authorId, followed) - } + fun followAuthorToggle(followed: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedAuthorId(authorArgs.authorId, followed) } - fun bookmarkNews(newsResourceId: String, bookmarked: Boolean) { - viewModelScope.launch { - userDataRepository.updateNewsResourceBookmark(newsResourceId, bookmarked) - } + fun bookmarkNews(newsResourceId: String, bookmarked: Boolean) = viewModelScope.launch { + userDataRepository.updateNewsResourceBookmark(newsResourceId, bookmarked) } -} -private fun authorUiStateStream( - authorId: String, - userDataRepository: UserDataRepository, - authorsRepository: AuthorsRepository, -): Flow { - // Observe the followed authors, as they could change over time. - val followedAuthorIdsStream: Flow> = - userDataRepository.userDataStream - .map { it.followedAuthors } - - // Observe author information - val authorStream: Flow = authorsRepository.getAuthorStream( - id = authorId - ) - - return combine( - followedAuthorIdsStream, - authorStream, - ::Pair - ) - .asResult() - .map { followedAuthorToAuthorResult -> - when (followedAuthorToAuthorResult) { - is Result.Success -> { - val (followedAuthors, author) = followedAuthorToAuthorResult.data - val followed = followedAuthors.contains(authorId) - AuthorUiState.Success( - followableAuthor = FollowableAuthor( - author = author, - isFollowed = followed - ) - ) - } - is Result.Loading -> { - AuthorUiState.Loading - } - is Result.Error -> { - AuthorUiState.Error - } + private fun authorUiStateStream( + authorId: String, + userDataRepository: UserDataRepository, + authorsRepository: AuthorsRepository, + ): Flow { + // Observe the followed authors, as they could change over time. + val followedAuthorIdsStream: Flow> = + userDataRepository.userDataStream.map { it.followedAuthors } + + // Observe author information + val authorStream: Flow = authorsRepository.getAuthorStream( + id = authorId + ) + + return combine( + followedAuthorIdsStream, + authorStream, + ::Pair + ) + .asResult() + .map { followedAuthorToAuthorResult -> + handleToAuthorResult(followedAuthorToAuthorResult, authorId) } - } + } + + private fun handleToAuthorResult( + followedAuthorToAuthorResult: Result, Author>>, + authorId: String + ) = when (followedAuthorToAuthorResult) { + is Success -> onSuccessResult(followedAuthorToAuthorResult, authorId) + is Loading -> AuthorUiState.Loading + is Error -> AuthorUiState.Error + } + + private fun onSuccessResult( + followedAuthorToAuthorResult: Success, Author>>, + authorId: String + ): AuthorUiState.Success { + val (followedAuthors, author) = followedAuthorToAuthorResult.data + val followed = followedAuthors.contains(authorId) + return AuthorUiState.Success( + followableAuthor = FollowableAuthor( + author = author, + isFollowed = followed + ) + ) + } } private fun GetSaveableNewsResourcesStreamUseCase.newsUiStateStream( @@ -134,9 +128,9 @@ private fun GetSaveableNewsResourcesStreamUseCase.newsUiStateStream( ).asResult() .map { newsResult -> when (newsResult) { - is Result.Success -> NewsUiState.Success(newsResult.data) - is Result.Loading -> NewsUiState.Loading - is Result.Error -> NewsUiState.Error + is Success -> NewsUiState.Success(newsResult.data) + is Loading -> NewsUiState.Loading + is Error -> NewsUiState.Error } } } 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 1b9efc6aa..bd41e05ee 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 @@ -23,14 +23,13 @@ import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResources 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 +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @HiltViewModel @@ -44,15 +43,9 @@ class BookmarksViewModel @Inject constructor( .map { newsResources -> newsResources.filter(SaveableNewsResource::isSaved) } // Only show bookmarked news resources. .map, NewsFeedUiState>(NewsFeedUiState::Success) .onStart { emit(Loading) } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = Loading - ) + .stateInViewModelScope(viewModelScope, initialValue = Loading) - fun removeFromSavedResources(newsResourceId: String) { - viewModelScope.launch { - userDataRepository.updateNewsResourceBookmark(newsResourceId, false) - } + fun removeFromSavedResources(newsResourceId: String) = viewModelScope.launch { + userDataRepository.updateNewsResourceBookmark(newsResourceId, false) } } 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 599bfd868..ac99ed5f9 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 @@ -25,17 +25,16 @@ import com.google.samples.apps.nowinandroid.core.domain.GetSaveableNewsResources import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAuthorsStreamUseCase 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.stateInViewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @HiltViewModel @@ -50,12 +49,9 @@ class ForYouViewModel @Inject constructor( private val shouldShowOnboarding: Flow = userDataRepository.userDataStream.map { !it.shouldHideOnboarding } - val isSyncing = syncStatusMonitor.isSyncing - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = false - ) + val isSyncing = syncStatusMonitor + .isSyncing + .stateInViewModelScope(viewModelScope, initialValue = false) val feedState: StateFlow = userDataRepository.userDataStream @@ -79,11 +75,7 @@ class ForYouViewModel @Inject constructor( // As the selected topics and topic state changes, this will cancel the old feed // monitoring and start the new one. .flatMapLatest { it } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = NewsFeedUiState.Loading - ) + .stateInViewModelScope(viewModelScope, initialValue = NewsFeedUiState.Loading) val onboardingUiState: StateFlow = combine( @@ -99,23 +91,14 @@ class ForYouViewModel @Inject constructor( } else { OnboardingUiState.NotShown } - } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = OnboardingUiState.Loading - ) + }.stateInViewModelScope(viewModelScope, initialValue = OnboardingUiState.Loading) - fun updateTopicSelection(topicId: String, isChecked: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedTopicId(topicId, isChecked) - } + fun updateTopicSelection(topicId: String, isChecked: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedTopicId(topicId, isChecked) } - fun updateAuthorSelection(authorId: String, isChecked: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedAuthorId(authorId, isChecked) - } + fun updateAuthorSelection(authorId: String, isChecked: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedAuthorId(authorId, isChecked) } fun updateNewsResourceSaved(newsResourceId: String, isChecked: Boolean) { @@ -124,10 +107,8 @@ class ForYouViewModel @Inject constructor( } } - fun dismissOnboarding() { - viewModelScope.launch { - userDataRepository.setShouldHideOnboarding(true) - } + fun dismissOnboarding() = viewModelScope.launch { + userDataRepository.setShouldHideOnboarding(true) } } diff --git a/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsViewModel.kt b/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsViewModel.kt index 01d8b0d6e..59aff907b 100644 --- a/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsViewModel.kt +++ b/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsViewModel.kt @@ -24,14 +24,13 @@ import com.google.samples.apps.nowinandroid.core.domain.GetSortedFollowableAutho 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 +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch @@ -54,22 +53,14 @@ class InterestsViewModel @Inject constructor( getSortedFollowableAuthorsStream(), getFollowableTopicsStream(sortBy = TopicSortField.NAME), InterestsUiState::Interests - ).stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = InterestsUiState.Loading - ) + ).stateInViewModelScope(viewModelScope, initialValue = InterestsUiState.Loading) - fun followTopic(followedTopicId: String, followed: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedTopicId(followedTopicId, followed) - } + fun followTopic(followedTopicId: String, followed: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedTopicId(followedTopicId, followed) } - fun followAuthor(followedAuthorId: String, followed: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedAuthorId(followedAuthorId, followed) - } + fun followAuthor(followedAuthorId: String, followed: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedAuthorId(followedAuthorId, followed) } fun switchTab(newIndex: Int) { diff --git a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt index fa159b555..0338d6630 100644 --- a/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/java/com/google/samples/apps/nowinandroid/feature/settings/SettingsViewModel.kt @@ -21,6 +21,7 @@ import androidx.lifecycle.viewModelScope import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success import dagger.hilt.android.lifecycle.HiltViewModel @@ -28,7 +29,6 @@ import javax.inject.Inject import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @HiltViewModel @@ -44,29 +44,23 @@ class SettingsViewModel @Inject constructor( darkThemeConfig = userData.darkThemeConfig ) ) - } - .stateIn( - scope = viewModelScope, - // Starting eagerly means the user data is ready when the SettingsDialog is laid out - // for the first time. Without this, due to b/221643630 the layout is done using the - // "Loading" text, then replaced with the user editable fields once loaded, however, - // the layout height doesn't change meaning all the fields are squashed into a small - // scrollable column. - // TODO: Change to SharingStarted.WhileSubscribed(5_000) when b/221643630 is fixed - started = SharingStarted.Eagerly, - initialValue = Loading - ) + }.stateInViewModelScope(viewModelScope, SharingStarted.Eagerly, Loading) - fun updateThemeBrand(themeBrand: ThemeBrand) { - viewModelScope.launch { - userDataRepository.setThemeBrand(themeBrand) - } + /** + * Starting eagerly means the user data is ready when the SettingsDialog is laid out + * for the first time. Without this, due to b/221643630 the layout is done using the + * "Loading" text, then replaced with the user editable fields once loaded, however, + * the layout height doesn't change meaning all the fields are squashed into a small + * scrollable column. + * TODO: Change to SharingStarted.WhileSubscribed(5_000) when b/221643630 is fixed + */ + + fun updateThemeBrand(themeBrand: ThemeBrand) = viewModelScope.launch { + userDataRepository.setThemeBrand(themeBrand) } - fun updateDarkThemeConfig(darkThemeConfig: DarkThemeConfig) { - viewModelScope.launch { - userDataRepository.setDarkThemeConfig(darkThemeConfig) - } + fun updateDarkThemeConfig(darkThemeConfig: DarkThemeConfig) = viewModelScope.launch { + userDataRepository.setDarkThemeConfig(darkThemeConfig) } } 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 160bcfb3b..f1344234f 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 @@ -27,16 +27,18 @@ 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 import com.google.samples.apps.nowinandroid.core.result.Result +import com.google.samples.apps.nowinandroid.core.result.Result.Error +import com.google.samples.apps.nowinandroid.core.result.Result.Loading +import com.google.samples.apps.nowinandroid.core.result.Result.Success import com.google.samples.apps.nowinandroid.core.result.asResult +import com.google.samples.apps.nowinandroid.core.ui.stateInViewModelScope import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicArgs import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @HiltViewModel @@ -45,7 +47,6 @@ class TopicViewModel @Inject constructor( stringDecoder: StringDecoder, private val userDataRepository: UserDataRepository, topicsRepository: TopicsRepository, - // newsRepository: NewsRepository, getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase ) : ViewModel() { @@ -55,34 +56,20 @@ class TopicViewModel @Inject constructor( topicId = topicArgs.topicId, userDataRepository = userDataRepository, topicsRepository = topicsRepository - ) - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = TopicUiState.Loading - ) + ).stateInViewModelScope(viewModelScope, initialValue = TopicUiState.Loading) val newUiState: StateFlow = newsUiStateStream( topicId = topicArgs.topicId, userDataRepository = userDataRepository, getSaveableNewsResourcesStream = getSaveableNewsResourcesStream - ) - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = NewsUiState.Loading - ) + ).stateInViewModelScope(viewModelScope, initialValue = NewsUiState.Loading) - fun followTopicToggle(followed: Boolean) { - viewModelScope.launch { - userDataRepository.toggleFollowedTopicId(topicArgs.topicId, followed) - } + fun followTopicToggle(followed: Boolean) = viewModelScope.launch { + userDataRepository.toggleFollowedTopicId(topicArgs.topicId, followed) } - fun bookmarkNews(newsResourceId: String, bookmarked: Boolean) { - viewModelScope.launch { - userDataRepository.updateNewsResourceBookmark(newsResourceId, bookmarked) - } + fun bookmarkNews(newsResourceId: String, bookmarked: Boolean) = viewModelScope.launch { + userDataRepository.updateNewsResourceBookmark(newsResourceId, bookmarked) } } @@ -92,9 +79,9 @@ private fun topicUiStateStream( topicsRepository: TopicsRepository, ): Flow { // Observe the followed topics, as they could change over time. - val followedTopicIdsStream: Flow> = - userDataRepository.userDataStream - .map { it.followedTopics } + val followedTopicIdsStream: Flow> = userDataRepository + .userDataStream + .map { it.followedTopics } // Observe topic information val topicStream: Flow = topicsRepository.getTopic( @@ -108,27 +95,28 @@ private fun topicUiStateStream( ) .asResult() .map { followedTopicToTopicResult -> - when (followedTopicToTopicResult) { - is Result.Success -> { - val (followedTopics, topic) = followedTopicToTopicResult.data - val followed = followedTopics.contains(topicId) - TopicUiState.Success( - followableTopic = FollowableTopic( - topic = topic, - isFollowed = followed - ) - ) - } - is Result.Loading -> { - TopicUiState.Loading - } - is Result.Error -> { - TopicUiState.Error - } - } + handleTopicResult(followedTopicToTopicResult, topicId) } } +private fun handleTopicResult( + followedTopicToTopicResult: Result, Topic>>, + topicId: String +) = when (followedTopicToTopicResult) { + is Success -> { + val (followedTopics, topic) = followedTopicToTopicResult.data + val followed = followedTopics.contains(topicId) + TopicUiState.Success( + followableTopic = FollowableTopic( + topic = topic, + isFollowed = followed + ) + ) + } + is Loading -> TopicUiState.Loading + is Error -> TopicUiState.Error +} + private fun newsUiStateStream( topicId: String, getSaveableNewsResourcesStream: GetSaveableNewsResourcesStreamUseCase, @@ -156,12 +144,8 @@ private fun newsUiStateStream( val (news, bookmarks) = newsToBookmarksResult.data NewsUiState.Success(news) } - is Result.Loading -> { - NewsUiState.Loading - } - is Result.Error -> { - NewsUiState.Error - } + is Result.Loading -> NewsUiState.Loading + is Result.Error -> NewsUiState.Error } } }