diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt index c3253e338c3..7e2f78a811f 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeScreen.kt @@ -54,6 +54,7 @@ import androidx.compose.ui.unit.min import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.repeatOnLifecycle import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations @@ -122,8 +123,18 @@ fun HomeScreen( creationCallback = { it.create(ConversationFoldersStateArgs(null)) } ) ) { - homeViewModel.checkRequirements { it.navigate(navigator::navigate) } val context = LocalContext.current + val lifecycle = androidx.lifecycle.compose.LocalLifecycleOwner.current + + homeViewModel.checkRequirements() + + LaunchedEffect(Unit) { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + homeViewModel.actions.collect { + it.navigate(navigator::navigate) + } + } + } val homeScreenState = rememberHomeScreenState(navigator) val notificationsPermissionDeniedDialogState = rememberVisibilityState() diff --git a/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt index 26b367afd43..f733f931647 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/HomeViewModel.kt @@ -38,10 +38,13 @@ import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForSelfUserU import com.wire.kalium.logic.feature.personaltoteamaccount.CanMigrateFromPersonalToTeamUseCase import com.wire.kalium.logic.feature.user.ObserveSelfUserUseCase import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import javax.inject.Inject @@ -64,6 +67,12 @@ class HomeViewModel @Inject constructor( private val selfUserFlow = MutableSharedFlow(replay = 1) + private val _actions = Channel( + capacity = Channel.BUFFERED, + onBufferOverflow = BufferOverflow.DROP_OLDEST + ) + internal val actions = _actions.receiveAsFlow() + init { observeSelfUser() observeLegalHoldStatus() @@ -114,21 +123,21 @@ class HomeViewModel @Inject constructor( } } - fun checkRequirements(onRequirement: (HomeRequirement) -> Unit) { + fun checkRequirements() { viewModelScope.launch { val selfUser = selfUserFlow.firstOrNull() ?: return@launch when { shouldTriggerMigrationForUser(selfUser.id) -> // check if the user needs to be migrated from scala app - onRequirement(HomeRequirement.Migration(selfUser.id)) + _actions.send(HomeRequirement.Migration(selfUser.id)) needsToRegisterClient() -> // check if the client needs to be registered - onRequirement(HomeRequirement.RegisterDevice) + _actions.send(HomeRequirement.RegisterDevice) !dataStore.initialSyncCompleted.first() -> // check if the initial sync needs to be completed - onRequirement(HomeRequirement.InitialSync) + _actions.send(HomeRequirement.InitialSync) selfUser.handle.isNullOrEmpty() -> // check if the user handle needs to be set - onRequirement(HomeRequirement.CreateAccountUsername) + _actions.send(HomeRequirement.CreateAccountUsername) // check if the "welcome to the new app" screen needs to be displayed shouldDisplayWelcomeToARScreen() -> diff --git a/app/src/test/kotlin/com/wire/android/ui/home/HomeViewModelTest.kt b/app/src/test/kotlin/com/wire/android/ui/home/HomeViewModelTest.kt index 7e157ff12d9..3ff24c6e0ff 100644 --- a/app/src/test/kotlin/com/wire/android/ui/home/HomeViewModelTest.kt +++ b/app/src/test/kotlin/com/wire/android/ui/home/HomeViewModelTest.kt @@ -18,6 +18,7 @@ package com.wire.android.ui.home import androidx.lifecycle.SavedStateHandle +import app.cash.turbine.test import com.wire.android.config.CoroutineTestExtension import com.wire.android.datastore.GlobalDataStore import com.wire.android.datastore.UserDataStore @@ -33,8 +34,6 @@ import com.wire.kalium.logic.feature.user.ObserveSelfUserUseCase import io.mockk.MockKAnnotations import io.mockk.coEvery import io.mockk.impl.annotations.MockK -import io.mockk.impl.annotations.RelaxedMockK -import io.mockk.verify import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -102,11 +101,13 @@ class HomeViewModelTest { val (arrangement, viewModel) = Arrangement() .withShouldTriggerMigrationForUserReturning(true) .arrange() - // when - viewModel.checkRequirements(arrangement.onRequirement) - advanceUntilIdle() - // then - verify { arrangement.onRequirement(HomeRequirement.Migration(TestUser.SELF_USER.id)) } + viewModel.actions.test { + // when + viewModel.checkRequirements() + advanceUntilIdle() + // then + assertEquals(HomeRequirement.Migration(TestUser.SELF_USER.id), expectMostRecentItem()) + } } @Test @@ -116,10 +117,12 @@ class HomeViewModelTest { .withShouldTriggerMigrationForUserReturning(false) .withNeedsToRegisterClientReturning(true) .arrange() - // when - viewModel.checkRequirements(arrangement.onRequirement) - // then - verify { arrangement.onRequirement(HomeRequirement.RegisterDevice) } + viewModel.actions.test { + // when + viewModel.checkRequirements() + // then + assertEquals(HomeRequirement.RegisterDevice, expectMostRecentItem()) + } } @Test @@ -130,10 +133,12 @@ class HomeViewModelTest { .withNeedsToRegisterClientReturning(false) .withInitialSyncCompletedReturning(flowOf(false)) .arrange() - // when - viewModel.checkRequirements(arrangement.onRequirement) - // then - verify { arrangement.onRequirement(HomeRequirement.InitialSync) } + viewModel.actions.test { + // when + viewModel.checkRequirements() + // then + assertEquals(HomeRequirement.InitialSync, expectMostRecentItem()) + } } @Test @@ -145,10 +150,12 @@ class HomeViewModelTest { .withInitialSyncCompletedReturning(flowOf(true)) .withSelfUser(flowOf(TestUser.SELF_USER.copy(handle = null))) .arrange() - // when - viewModel.checkRequirements(arrangement.onRequirement) - // then - verify { arrangement.onRequirement(HomeRequirement.CreateAccountUsername) } + viewModel.actions.test { + // when + viewModel.checkRequirements() + // then + assertEquals(HomeRequirement.CreateAccountUsername, expectMostRecentItem()) + } } @Test @@ -163,7 +170,7 @@ class HomeViewModelTest { .withWelcomeScreenPresentedReturning(false) .arrange() // when - viewModel.checkRequirements(arrangement.onRequirement) + viewModel.checkRequirements() // then assertEquals(true, viewModel.homeState.shouldDisplayWelcomeMessage) } @@ -180,7 +187,7 @@ class HomeViewModelTest { .withWelcomeScreenPresentedReturning(true) .arrange() // when - viewModel.checkRequirements(arrangement.onRequirement) + viewModel.checkRequirements() // then assertEquals(false, viewModel.homeState.shouldDisplayWelcomeMessage) } @@ -211,9 +218,6 @@ class HomeViewModelTest { @MockK lateinit var canMigrateFromPersonalToTeam: CanMigrateFromPersonalToTeamUseCase - @RelaxedMockK - lateinit var onRequirement: (HomeRequirement) -> Unit - private val viewModel by lazy { HomeViewModel( savedStateHandle = savedStateHandle,