diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/ABoxManagerApp.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/ABoxManagerApp.kt index 0a1b959..5ced03b 100644 --- a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/ABoxManagerApp.kt +++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/ABoxManagerApp.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.hilt.navigation.compose.hiltViewModel @@ -26,11 +27,14 @@ fun ABoxManagerApp( sessionActionsViewModel: SessionActionsViewModel = hiltViewModel(), ) { val actionState = sessionActionsViewModel.uiState.collectAsStateWithLifecycle().value + val sessionState = appSessionViewModel.uiState.collectAsStateWithLifecycle().value + val screenKey = sessionState.screenKey() + LaunchedEffect(screenKey) { + sessionActionsViewModel.dismissError() + } ABoxTheme { ABoxSurface(modifier = Modifier.fillMaxSize()) { - when ( - val state = appSessionViewModel.uiState.collectAsStateWithLifecycle().value - ) { + when (val state = sessionState) { AppSessionUiState.Loading -> Box( modifier = Modifier .fillMaxSize() @@ -58,3 +62,10 @@ fun ABoxManagerApp( } } } + +private fun AppSessionUiState.screenKey(): String = when (this) { + AppSessionUiState.Loading -> "loading" + AppSessionUiState.ProviderSelection -> "providers" + is AppSessionUiState.Login -> "login:${profile.id.value}" + is AppSessionUiState.Authenticated -> "authenticated:${profile.id.value}" +} diff --git a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/session/AppSessionViewModel.kt b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/session/AppSessionViewModel.kt index 39d43f0..7525220 100644 --- a/android/app/src/main/kotlin/com/flagship/abox/manager/ui/session/AppSessionViewModel.kt +++ b/android/app/src/main/kotlin/com/flagship/abox/manager/ui/session/AppSessionViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.flagship.abox.manager.domain.DomainResult import com.flagship.abox.manager.domain.ProviderProfile +import com.flagship.abox.manager.domain.ProviderProfileId import com.flagship.abox.manager.domain.ProviderProfileStore import com.flagship.abox.manager.domain.Session import com.flagship.abox.manager.domain.SessionCoordinator @@ -24,15 +25,19 @@ class AppSessionViewModel @Inject constructor( private val profileStore: ProviderProfileStore, private val availability: ProviderAvailability, ) : ViewModel() { - private val bootstrapResult = MutableStateFlow?>(null) + private val bootstrapResult = MutableStateFlow(null) val uiState: StateFlow = combine( bootstrapResult, profileStore.observeActiveProfile(), coordinator.observeActiveSession(), - ) { result, profile, session -> - if (result == null) AppSessionUiState.Loading - else stateFor(profile, session, (result as? DomainResult.Failure)?.error?.detail) + ) { bootstrap, profile, session -> + if (bootstrap == null) AppSessionUiState.Loading + else stateFor( + profile = profile, + session = session, + bootstrapError = bootstrap.errorFor(profile?.id), + ) }.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), @@ -44,9 +49,15 @@ class AppSessionViewModel @Inject constructor( val activeProfile = profileStore.activeProfile() if (activeProfile != null && availability.forType(activeProfile.type) is Availability.Disabled) { coordinator.switchProvider() - bootstrapResult.value = DomainResult.Success(null) + bootstrapResult.value = ProviderBootstrapResult( + profileId = null, + result = DomainResult.Success(null), + ) } else { - bootstrapResult.value = coordinator.bootstrap() + bootstrapResult.value = ProviderBootstrapResult( + profileId = activeProfile?.id, + result = coordinator.bootstrap(), + ) } } } @@ -63,6 +74,18 @@ class AppSessionViewModel @Inject constructor( } } +private data class ProviderBootstrapResult( + val profileId: ProviderProfileId?, + val result: DomainResult, +) { + fun errorFor(currentProfileId: ProviderProfileId?): String? = + if (profileId == currentProfileId) { + (result as? DomainResult.Failure)?.error?.detail + } else { + null + } +} + sealed interface AppSessionUiState { data object Loading : AppSessionUiState data object ProviderSelection : AppSessionUiState