diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 9b05f6a57..b8a38f033 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -12,4 +12,5 @@ android { dependencies { implementation(projects.core.designsystem) implementation(projects.core.domain.domainSessionApi) + implementation(projects.core.router.routerApi) } diff --git a/core/ui/src/main/java/com/droidknights/app/core/ui/BaseViewModel.kt b/core/ui/src/main/java/com/droidknights/app/core/ui/BaseViewModel.kt new file mode 100644 index 000000000..a224ecea0 --- /dev/null +++ b/core/ui/src/main/java/com/droidknights/app/core/ui/BaseViewModel.kt @@ -0,0 +1,42 @@ +package com.droidknights.app.core.ui + +import androidx.annotation.VisibleForTesting +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.droidknights.app.core.router.api.Navigator +import com.droidknights.app.core.router.api.model.Route +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +open class BaseViewModel @Inject constructor() : ViewModel() { + protected val internalErrorFlow = MutableSharedFlow() + val errorFlow = internalErrorFlow.asSharedFlow() + + @Inject + lateinit var navigator: Navigator + + @VisibleForTesting + fun injectNavigator(navigator: Navigator) { + this.navigator = navigator + } + + fun navigateBack() = viewModelScope.launch { + navigator.navigateBack() + } + + fun navigateWeb(url: String) = viewModelScope.launch { + navigator.navigateWeb(url) + } + + fun navigateTo( + route: Route, + saveState: Boolean = false, + launchSingleTop: Boolean = false + ) = viewModelScope.launch { + navigator.navigate(route, saveState, launchSingleTop) + } +} diff --git a/feature/bookmark/src/main/java/com/droidknights/app/feature/bookmark/BookmarkViewModel.kt b/feature/bookmark/src/main/java/com/droidknights/app/feature/bookmark/BookmarkViewModel.kt index 8c408cd08..b14d65a0a 100644 --- a/feature/bookmark/src/main/java/com/droidknights/app/feature/bookmark/BookmarkViewModel.kt +++ b/feature/bookmark/src/main/java/com/droidknights/app/feature/bookmark/BookmarkViewModel.kt @@ -1,11 +1,10 @@ package com.droidknights.app.feature.bookmark -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.droidknights.app.core.domain.session.usecase.api.DeleteBookmarkedSessionUseCase import com.droidknights.app.core.domain.session.usecase.api.GetBookmarkedSessionsUseCase import com.droidknights.app.core.model.session.Session -import com.droidknights.app.core.router.api.Navigator +import com.droidknights.app.core.ui.BaseViewModel import com.droidknights.app.feature.bookmark.model.BookmarkItemUiState import com.droidknights.app.feature.bookmark.model.BookmarkUiState import com.droidknights.app.feature.session.api.RouteSession @@ -13,9 +12,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentSet -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine @@ -29,12 +26,8 @@ import javax.inject.Inject @HiltViewModel class BookmarkViewModel @Inject constructor( private val getBookmarkedSessionsUseCase: GetBookmarkedSessionsUseCase, - private val deleteBookmarkedSessionUseCase: DeleteBookmarkedSessionUseCase, - private val navigator: Navigator, -) : ViewModel() { - - private val _errorFlow = MutableSharedFlow() - val errorFlow = _errorFlow.asSharedFlow() + private val deleteBookmarkedSessionUseCase: DeleteBookmarkedSessionUseCase +) : BaseViewModel() { private val _bookmarkUiState = MutableStateFlow(BookmarkUiState.Loading) val bookmarkUiState = _bookmarkUiState.asStateFlow() @@ -74,7 +67,7 @@ class BookmarkViewModel @Inject constructor( } } }.catch { throwable -> - _errorFlow.emit(throwable) + internalErrorFlow.emit(throwable) }.collect { _bookmarkUiState.value = it } } } @@ -123,7 +116,7 @@ class BookmarkViewModel @Inject constructor( state.copy(selectedSessionIds = persistentSetOf()) } }.catch { throwable -> - _errorFlow.emit(throwable) + internalErrorFlow.emit(throwable) }.launchIn(viewModelScope) } @@ -132,10 +125,8 @@ class BookmarkViewModel @Inject constructor( if (state !is BookmarkUiState.Success || state.isEditMode) { return } - viewModelScope.launch { - navigator.navigate( - route = RouteSession(sessionId = session.id), - ) - } + navigateTo( + route = RouteSession(sessionId = session.id) + ) } } diff --git a/feature/bookmark/src/test/java/com/droidknights/app/feature/bookmark/BookmarkViewModelTest.kt b/feature/bookmark/src/test/java/com/droidknights/app/feature/bookmark/BookmarkViewModelTest.kt index 43716c00a..b49fe1679 100644 --- a/feature/bookmark/src/test/java/com/droidknights/app/feature/bookmark/BookmarkViewModelTest.kt +++ b/feature/bookmark/src/test/java/com/droidknights/app/feature/bookmark/BookmarkViewModelTest.kt @@ -48,9 +48,8 @@ class BookmarkViewModelTest { // given & when viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } // then viewModel.bookmarkUiState.test { @@ -76,9 +75,8 @@ class BookmarkViewModelTest { // given viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } viewModel.bookmarkUiState.test { val initialIsEditMode = (awaitItem() as BookmarkUiState.Success).isEditMode @@ -98,9 +96,8 @@ class BookmarkViewModelTest { // given viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } // when viewModel.selectSession(mockSession1) @@ -120,9 +117,9 @@ class BookmarkViewModelTest { // given viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } + viewModel.selectSession(mockSession1) // when @@ -144,9 +141,9 @@ class BookmarkViewModelTest { coEvery { deleteBookmarkedSessionUseCase(persistentSetOf("1")) } just Runs viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } + viewModel.selectSession(mockSession1) // when @@ -167,9 +164,8 @@ class BookmarkViewModelTest { coEvery { navigator.navigate(RouteSession(sessionId = mockSession2.id)) } just Runs viewModel = BookmarkViewModel( getBookmarkedSessionsUseCase, - deleteBookmarkedSessionUseCase, - navigator - ) + deleteBookmarkedSessionUseCase + ).also { it.injectNavigator(navigator) } // when viewModel.redirectToSessionScreen(mockSession2) diff --git a/feature/contributor/src/main/java/com/droidknights/app/feature/contributor/ContributorViewModel.kt b/feature/contributor/src/main/java/com/droidknights/app/feature/contributor/ContributorViewModel.kt index b909a9849..e61bb41d7 100644 --- a/feature/contributor/src/main/java/com/droidknights/app/feature/contributor/ContributorViewModel.kt +++ b/feature/contributor/src/main/java/com/droidknights/app/feature/contributor/ContributorViewModel.kt @@ -1,30 +1,22 @@ package com.droidknights.app.feature.contributor -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.droidknights.app.core.domain.contributor.usecase.api.GetContributorsUseCase -import com.droidknights.app.core.router.api.Navigator +import com.droidknights.app.core.ui.BaseViewModel import com.droidknights.app.feature.contributor.model.ContributorsUiState import com.droidknights.app.feature.contributor.model.convert.toContributorsUiState import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class ContributorViewModel @Inject constructor( - getContributorsUseCase: GetContributorsUseCase, - private val navigator: Navigator, -) : ViewModel() { - - private val _errorFlow = MutableSharedFlow() - val errorFlow = _errorFlow.asSharedFlow() + getContributorsUseCase: GetContributorsUseCase +) : BaseViewModel() { val uiState: StateFlow by lazy { getContributorsUseCase() @@ -32,7 +24,7 @@ class ContributorViewModel @Inject constructor( it.toContributorsUiState() } .catch { throwable -> - _errorFlow.emit(throwable) + internalErrorFlow.emit(throwable) } .stateIn( scope = viewModelScope, @@ -40,8 +32,4 @@ class ContributorViewModel @Inject constructor( initialValue = ContributorsUiState.Loading ) } - - fun navigateBack() = viewModelScope.launch { - navigator.navigateBack() - } } diff --git a/feature/contributor/src/test/java/com/droidknights/app/feature/contributor/ContributorViewModelTest.kt b/feature/contributor/src/test/java/com/droidknights/app/feature/contributor/ContributorViewModelTest.kt index 57da87843..3eb48f623 100644 --- a/feature/contributor/src/test/java/com/droidknights/app/feature/contributor/ContributorViewModelTest.kt +++ b/feature/contributor/src/test/java/com/droidknights/app/feature/contributor/ContributorViewModelTest.kt @@ -31,7 +31,9 @@ internal class ContributorViewModelTest { fun `컨트리뷰터 데이터를 확인할 수 있다`() = runTest { // given coEvery { getContributorsUseCase() } returns flowOf(fakeContributors) - viewModel = ContributorViewModel(getContributorsUseCase, navigator) + viewModel = ContributorViewModel(getContributorsUseCase).also { + it.injectNavigator(navigator) + } // when & then viewModel.uiState.test { @@ -44,7 +46,9 @@ internal class ContributorViewModelTest { fun `navigateBack이 호출될 때 navigator에게 위임한다`() = runTest { // suspend 함수 호출에 대한 stub coEvery { navigator.navigateBack() } just Runs - viewModel = ContributorViewModel(getContributorsUseCase, navigator) + viewModel = ContributorViewModel(getContributorsUseCase).also { + it.injectNavigator(navigator) + } // when viewModel.navigateBack() diff --git a/feature/home/src/main/java/com/droidknights/app/feature/home/HomeScreen.kt b/feature/home/src/main/java/com/droidknights/app/feature/home/HomeScreen.kt index 09565ef51..efa708cfc 100644 --- a/feature/home/src/main/java/com/droidknights/app/feature/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/droidknights/app/feature/home/HomeScreen.kt @@ -15,10 +15,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.droidknights.app.feature.contributor.api.RouteContributor import com.droidknights.app.feature.home.component.ContributorCard import com.droidknights.app.feature.home.component.SessionCard import com.droidknights.app.feature.home.component.SponsorCard import com.droidknights.app.feature.home.model.SponsorsUiState +import com.droidknights.app.feature.session.api.RouteSession import kotlinx.coroutines.flow.collectLatest @Composable @@ -35,9 +37,9 @@ internal fun HomeRoute( HomeScreen( padding = padding, sponsorsUiState = sponsorsUiState, - onSessionClick = viewModel::navigateSession, - onContributorClick = viewModel::navigateContributor, - onOrganizationSponsorClick = viewModel::navigateOrganizationSponsor, + onSessionClick = { viewModel.navigateTo(RouteSession()) }, + onContributorClick = { viewModel.navigateTo(RouteContributor) }, + onOrganizationSponsorClick = viewModel::navigateWeb, ) } diff --git a/feature/home/src/main/java/com/droidknights/app/feature/home/HomeViewModel.kt b/feature/home/src/main/java/com/droidknights/app/feature/home/HomeViewModel.kt index c049b7ece..49a0528e6 100644 --- a/feature/home/src/main/java/com/droidknights/app/feature/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/droidknights/app/feature/home/HomeViewModel.kt @@ -1,33 +1,23 @@ package com.droidknights.app.feature.home -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.droidknights.app.core.domain.sponsor.usecase.api.GetSponsorsUseCase -import com.droidknights.app.core.router.api.Navigator -import com.droidknights.app.feature.contributor.api.RouteContributor +import com.droidknights.app.core.ui.BaseViewModel import com.droidknights.app.feature.home.model.SponsorsUiState -import com.droidknights.app.feature.session.api.RouteSession import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( - getSponsorsUseCase: GetSponsorsUseCase, - private val navigator: Navigator, -) : ViewModel() { - - private val _errorFlow = MutableSharedFlow() - val errorFlow get() = _errorFlow.asSharedFlow() + getSponsorsUseCase: GetSponsorsUseCase +) : BaseViewModel() { val sponsorsUiState: StateFlow = flow { emit(getSponsorsUseCase()) } @@ -39,23 +29,11 @@ class HomeViewModel @Inject constructor( } } .catch { throwable -> - _errorFlow.emit(throwable) + internalErrorFlow.emit(throwable) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = SponsorsUiState.Loading, ) - - fun navigateSession() = viewModelScope.launch { - navigator.navigate(RouteSession()) - } - - fun navigateContributor() = viewModelScope.launch { - navigator.navigate(RouteContributor) - } - - fun navigateOrganizationSponsor(url: String) = viewModelScope.launch { - navigator.navigateWeb(url) - } } diff --git a/feature/home/src/test/java/com/droidknights/app/feature/home/HomeViewModelTest.kt b/feature/home/src/test/java/com/droidknights/app/feature/home/HomeViewModelTest.kt index 78c2afcf2..7d8009742 100644 --- a/feature/home/src/test/java/com/droidknights/app/feature/home/HomeViewModelTest.kt +++ b/feature/home/src/test/java/com/droidknights/app/feature/home/HomeViewModelTest.kt @@ -30,7 +30,9 @@ internal class HomeViewModelTest { fun `후원사 리스트가 비어있다면 후원사 데이터를 확인할 수 없다`() = runTest { // given coEvery { getSponsorsUseCase() } returns emptyList() - viewModel = HomeViewModel(getSponsorsUseCase, navigator) + viewModel = HomeViewModel(getSponsorsUseCase).also { + it.injectNavigator(navigator) + } // when & then viewModel.sponsorsUiState.test { @@ -43,7 +45,9 @@ internal class HomeViewModelTest { fun `후원사 리스트가 존재한다면 후원사 데이터를 확인할 수 있다`() = runTest { // given coEvery { getSponsorsUseCase() } returns fakeSponsors - viewModel = HomeViewModel(getSponsorsUseCase, navigator) + viewModel = HomeViewModel(getSponsorsUseCase).also { + it.injectNavigator(navigator) + } // when & then viewModel.sponsorsUiState.test { @@ -56,10 +60,12 @@ internal class HomeViewModelTest { fun `navigate(RouteSession)가 호출될 때 navigator에게 위임한다`() = runTest { // given coEvery { navigator.navigate(RouteSession()) } just Runs - viewModel = HomeViewModel(getSponsorsUseCase, navigator) + viewModel = HomeViewModel(getSponsorsUseCase).also { + it.injectNavigator(navigator) + } // when - viewModel.navigateSession() + viewModel.navigateTo(RouteSession()) // then coVerify(exactly = 1) { navigator.navigate(RouteSession()) } @@ -69,10 +75,12 @@ internal class HomeViewModelTest { fun `navigate(RouteContributor)가 호출될 때 navigator에게 위임한다`() = runTest { // given coEvery { navigator.navigate(RouteContributor) } just Runs - viewModel = HomeViewModel(getSponsorsUseCase, navigator) + viewModel = HomeViewModel(getSponsorsUseCase).also { + it.injectNavigator(navigator) + } // when - viewModel.navigateContributor() + viewModel.navigateTo(RouteContributor) // then coVerify(exactly = 1) { navigator.navigate(RouteContributor) } diff --git a/feature/main/src/main/java/com/droidknights/app/feature/main/MainActivity.kt b/feature/main/src/main/java/com/droidknights/app/feature/main/MainActivity.kt index 898361672..70a9fa97f 100644 --- a/feature/main/src/main/java/com/droidknights/app/feature/main/MainActivity.kt +++ b/feature/main/src/main/java/com/droidknights/app/feature/main/MainActivity.kt @@ -12,6 +12,7 @@ import com.droidknights.app.core.designsystem.theme.KnightsTheme import com.droidknights.app.core.router.LaunchedRouter import com.droidknights.app.feature.bookmark.api.RouteBookmark import com.droidknights.app.feature.home.api.RouteHome +import com.droidknights.app.feature.session.api.RouteSessionDetail import com.droidknights.app.feature.setting.api.RouteSetting import com.droidknights.app.widget.DroidKnightsWidget.Companion.KEY_SESSION_ID import com.droidknights.app.widget.sendWidgetUpdateCommand @@ -47,7 +48,7 @@ class MainActivity : ComponentActivity() { LaunchedEffect(sessionId) { sessionId?.let { - viewModel.navigateSessionDetail(it) + viewModel.navigateTo(RouteSessionDetail(it)) } } @@ -56,9 +57,21 @@ class MainActivity : ComponentActivity() { navigator = navigator, onTabSelected = { when (it.route) { - is RouteSetting -> viewModel.navigateSetting() - is RouteBookmark -> viewModel.navigateBookmark() - is RouteHome -> viewModel.navigateHome() + is RouteSetting -> viewModel.navigateTo( + route = RouteSetting, + saveState = true, + launchSingleTop = true + ) + is RouteBookmark -> viewModel.navigateTo( + route = RouteBookmark, + saveState = true, + launchSingleTop = true + ) + is RouteHome -> viewModel.navigateTo( + route = RouteHome, + saveState = true, + launchSingleTop = true + ) } }, ) diff --git a/feature/main/src/main/java/com/droidknights/app/feature/main/MainViewModel.kt b/feature/main/src/main/java/com/droidknights/app/feature/main/MainViewModel.kt index fba836056..4ea6c9cb8 100644 --- a/feature/main/src/main/java/com/droidknights/app/feature/main/MainViewModel.kt +++ b/feature/main/src/main/java/com/droidknights/app/feature/main/MainViewModel.kt @@ -1,50 +1,14 @@ package com.droidknights.app.feature.main -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope import com.droidknights.app.core.data.settings.api.SettingsRepository -import com.droidknights.app.core.router.api.Navigator -import com.droidknights.app.feature.bookmark.api.RouteBookmark -import com.droidknights.app.feature.home.api.RouteHome -import com.droidknights.app.feature.session.api.RouteSessionDetail -import com.droidknights.app.feature.setting.api.RouteSetting +import com.droidknights.app.core.ui.BaseViewModel import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel internal class MainViewModel @Inject constructor( - settingsRepository: SettingsRepository, - private val navigator: Navigator, -) : ViewModel() { + settingsRepository: SettingsRepository +) : BaseViewModel() { val isDarkTheme = settingsRepository.flowIsDarkTheme() - - fun navigateSessionDetail(sessionId: String) = viewModelScope.launch { - navigator.navigate(RouteSessionDetail(sessionId)) - } - - fun navigateSetting() = viewModelScope.launch { - navigator.navigate( - route = RouteSetting, - saveState = true, - launchSingleTop = true, - ) - } - - fun navigateBookmark() = viewModelScope.launch { - navigator.navigate( - route = RouteBookmark, - saveState = true, - launchSingleTop = true, - ) - } - - fun navigateHome() = viewModelScope.launch { - navigator.navigate( - route = RouteHome, - saveState = true, - launchSingleTop = true, - ) - } } diff --git a/feature/main/src/test/java/com/droidknights/app/feature/main/MainViewModelTest.kt b/feature/main/src/test/java/com/droidknights/app/feature/main/MainViewModelTest.kt index 06fe23ae5..8aaa0be28 100644 --- a/feature/main/src/test/java/com/droidknights/app/feature/main/MainViewModelTest.kt +++ b/feature/main/src/test/java/com/droidknights/app/feature/main/MainViewModelTest.kt @@ -35,7 +35,8 @@ class MainViewModelTest { fun setup() { // given every { settingsRepository.flowIsDarkTheme() } returns flowOf(false) - viewModel = MainViewModel(settingsRepository, navigator) + viewModel = MainViewModel(settingsRepository) + viewModel.injectNavigator(navigator) } @Test @@ -52,7 +53,7 @@ class MainViewModelTest { coEvery { navigator.navigate(RouteSessionDetail(fakeSessionId)) } just Runs // when - viewModel.navigateSessionDetail(fakeSessionId) + viewModel.navigateTo(RouteSessionDetail(fakeSessionId)) // then coVerify(exactly = 1) { navigator.navigate(RouteSessionDetail(fakeSessionId)) } @@ -70,7 +71,11 @@ class MainViewModelTest { } just Runs // when - viewModel.navigateSetting() + viewModel.navigateTo( + route = RouteSetting, + saveState = true, + launchSingleTop = true + ) // then coVerify(exactly = 1) { @@ -94,14 +99,18 @@ class MainViewModelTest { } just Runs // when - viewModel.navigateBookmark() + viewModel.navigateTo( + route = RouteBookmark, + saveState = true, + launchSingleTop = true + ) // then coVerify(exactly = 1) { navigator.navigate( route = RouteBookmark, saveState = true, - launchSingleTop = true, + launchSingleTop = true ) } } @@ -118,7 +127,11 @@ class MainViewModelTest { } just Runs // when - viewModel.navigateHome() + viewModel.navigateTo( + route = RouteHome, + saveState = true, + launchSingleTop = true + ) // then coVerify(exactly = 1) { diff --git a/feature/session/src/main/java/com/droidknights/app/feature/session/detail/SessionDetailViewModel.kt b/feature/session/src/main/java/com/droidknights/app/feature/session/detail/SessionDetailViewModel.kt index e9f244fe4..2db9023b2 100644 --- a/feature/session/src/main/java/com/droidknights/app/feature/session/detail/SessionDetailViewModel.kt +++ b/feature/session/src/main/java/com/droidknights/app/feature/session/detail/SessionDetailViewModel.kt @@ -1,11 +1,10 @@ package com.droidknights.app.feature.session.detail -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.droidknights.app.core.domain.session.usecase.api.BookmarkSessionUseCase import com.droidknights.app.core.domain.session.usecase.api.GetBookmarkedSessionIdsUseCase import com.droidknights.app.core.domain.session.usecase.api.GetSessionUseCase -import com.droidknights.app.core.router.api.Navigator +import com.droidknights.app.core.ui.BaseViewModel import com.droidknights.app.feature.session.detail.model.SessionDetailEffect import com.droidknights.app.feature.session.detail.model.SessionDetailUiState import dagger.hilt.android.lifecycle.HiltViewModel @@ -21,9 +20,8 @@ import javax.inject.Inject class SessionDetailViewModel @Inject constructor( private val getSessionUseCase: GetSessionUseCase, getBookmarkedSessionIdsUseCase: GetBookmarkedSessionIdsUseCase, - private val bookmarkSessionUseCase: BookmarkSessionUseCase, - private val navigator: Navigator, -) : ViewModel() { + private val bookmarkSessionUseCase: BookmarkSessionUseCase +) : BaseViewModel() { private val _sessionUiState = MutableStateFlow(SessionDetailUiState.Loading) @@ -72,8 +70,4 @@ class SessionDetailViewModel @Inject constructor( _sessionUiEffect.value = SessionDetailEffect.Idle } } - - fun navigateBack() = viewModelScope.launch { - navigator.navigateBack() - } } diff --git a/feature/session/src/main/java/com/droidknights/app/feature/session/list/SessionListViewModel.kt b/feature/session/src/main/java/com/droidknights/app/feature/session/list/SessionListViewModel.kt index 0dafff14f..b7d20829a 100644 --- a/feature/session/src/main/java/com/droidknights/app/feature/session/list/SessionListViewModel.kt +++ b/feature/session/src/main/java/com/droidknights/app/feature/session/list/SessionListViewModel.kt @@ -1,17 +1,14 @@ package com.droidknights.app.feature.session.list -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.droidknights.app.core.domain.session.usecase.api.GetBookmarkedSessionIdsUseCase import com.droidknights.app.core.domain.session.usecase.api.GetSessionsUseCase -import com.droidknights.app.core.router.api.Navigator +import com.droidknights.app.core.ui.BaseViewModel import com.droidknights.app.feature.session.api.RouteSessionDetail import com.droidknights.app.feature.session.list.model.SessionUiState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.toPersistentList -import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine @@ -23,12 +20,8 @@ import javax.inject.Inject @HiltViewModel class SessionListViewModel @Inject constructor( getSessionsUseCase: GetSessionsUseCase, - getBookmarkedSessionIdsUseCase: GetBookmarkedSessionIdsUseCase, - private val navigator: Navigator, -) : ViewModel() { - - private val _errorFlow = MutableSharedFlow() - val errorFlow = _errorFlow.asSharedFlow() + getBookmarkedSessionIdsUseCase: GetBookmarkedSessionIdsUseCase +) : BaseViewModel() { private val _uiState = MutableStateFlow(SessionUiState.Loading) val uiState = _uiState.asStateFlow() @@ -47,7 +40,7 @@ class SessionListViewModel @Inject constructor( ) } .catch { throwable -> - _errorFlow.emit(throwable) + internalErrorFlow.emit(throwable) } .onEach { combinedUiState -> _uiState.value = combinedUiState @@ -58,8 +51,4 @@ class SessionListViewModel @Inject constructor( fun navigateSessionDetail(sessionId: String) = viewModelScope.launch { navigator.navigate(RouteSessionDetail(sessionId)) } - - fun navigateBack() = viewModelScope.launch { - navigator.navigateBack() - } } diff --git a/feature/session/src/test/java/com/droidknights/app/feature/session/detail/SessionDetailViewModelTest.kt b/feature/session/src/test/java/com/droidknights/app/feature/session/detail/SessionDetailViewModelTest.kt index 53976e91e..df42dd6a8 100644 --- a/feature/session/src/test/java/com/droidknights/app/feature/session/detail/SessionDetailViewModelTest.kt +++ b/feature/session/src/test/java/com/droidknights/app/feature/session/detail/SessionDetailViewModelTest.kt @@ -60,9 +60,8 @@ class SessionDetailViewModelTest { viewModel = SessionDetailViewModel( getSessionUseCase, getBookmarkedSessionIdsUseCase, - bookmarkSessionUseCase, - navigator, - ) + bookmarkSessionUseCase + ).also { it.injectNavigator(navigator) } // when viewModel.fetchSession(sessionId) @@ -83,9 +82,8 @@ class SessionDetailViewModelTest { viewModel = SessionDetailViewModel( getSessionUseCase, getBookmarkedSessionIdsUseCase, - bookmarkSessionUseCase, - navigator, - ) + bookmarkSessionUseCase + ).also { it.injectNavigator(navigator) } // when viewModel.fetchSession(sessionId) @@ -112,9 +110,9 @@ class SessionDetailViewModelTest { viewModel = SessionDetailViewModel( getSessionUseCase, getBookmarkedSessionIdsUseCase, - bookmarkSessionUseCase, - navigator, - ) + bookmarkSessionUseCase + ).also { it.injectNavigator(navigator) } + viewModel.fetchSession(sessionId) // when @@ -134,9 +132,8 @@ class SessionDetailViewModelTest { viewModel = SessionDetailViewModel( getSessionUseCase, getBookmarkedSessionIdsUseCase, - bookmarkSessionUseCase, - navigator, - ) + bookmarkSessionUseCase + ).also { it.injectNavigator(navigator) } // when viewModel.navigateBack() diff --git a/feature/session/src/test/java/com/droidknights/app/feature/session/list/SessionListViewModelTest.kt b/feature/session/src/test/java/com/droidknights/app/feature/session/list/SessionListViewModelTest.kt index 636845bd7..6831e3edb 100644 --- a/feature/session/src/test/java/com/droidknights/app/feature/session/list/SessionListViewModelTest.kt +++ b/feature/session/src/test/java/com/droidknights/app/feature/session/list/SessionListViewModelTest.kt @@ -53,9 +53,8 @@ internal class SessionListViewModelTest { // given viewModel = SessionListViewModel( getSessionsUseCase, - getBookmarkedSessionIdsUseCase, - navigator, - ) + getBookmarkedSessionIdsUseCase + ).also { it.injectNavigator(navigator) } } @Test