Fix title of sign out screen regarding the different states
This commit is contained in:
parent
3ab7876dbd
commit
6ab07e0cba
5 changed files with 60 additions and 3 deletions
|
|
@ -28,9 +28,11 @@ import androidx.compose.runtime.setValue
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
|
import io.element.android.libraries.core.bool.orTrue
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -70,6 +72,19 @@ class LogoutPresenter @Inject constructor(
|
||||||
isLastSession = encryptionService.isLastDevice().getOrNull() ?: false
|
isLastSession = encryptionService.isLastDevice().getOrNull() ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val backupState by encryptionService.backupStateStateFlow.collectAsState()
|
||||||
|
val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState()
|
||||||
|
|
||||||
|
val doesBackupExistOnServerAction: MutableState<Async<Boolean>> = remember {
|
||||||
|
mutableStateOf(Async.Uninitialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(backupState) {
|
||||||
|
if (backupState == BackupState.UNKNOWN) {
|
||||||
|
getKeyBackupStatus(doesBackupExistOnServerAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleEvents(event: LogoutEvents) {
|
fun handleEvents(event: LogoutEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is LogoutEvents.Logout -> {
|
is LogoutEvents.Logout -> {
|
||||||
|
|
@ -89,6 +104,9 @@ class LogoutPresenter @Inject constructor(
|
||||||
|
|
||||||
return LogoutState(
|
return LogoutState(
|
||||||
isLastSession = isLastSession,
|
isLastSession = isLastSession,
|
||||||
|
backupState = backupState,
|
||||||
|
doesBackupExistOnServer = doesBackupExistOnServerAction.value.dataOrNull().orTrue(),
|
||||||
|
recoveryState = recoveryState,
|
||||||
backupUploadState = backupUploadState,
|
backupUploadState = backupUploadState,
|
||||||
showConfirmationDialog = showLogoutDialog,
|
showConfirmationDialog = showLogoutDialog,
|
||||||
logoutAction = logoutAction.value,
|
logoutAction = logoutAction.value,
|
||||||
|
|
@ -96,6 +114,12 @@ class LogoutPresenter @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun CoroutineScope.getKeyBackupStatus(action: MutableState<Async<Boolean>>) = launch {
|
||||||
|
suspend {
|
||||||
|
encryptionService.doesBackupExistOnServer().getOrThrow()
|
||||||
|
}.runCatchingUpdatingState(action)
|
||||||
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.logout(
|
private fun CoroutineScope.logout(
|
||||||
logoutAction: MutableState<Async<String?>>,
|
logoutAction: MutableState<Async<String?>>,
|
||||||
ignoreSdkError: Boolean,
|
ignoreSdkError: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,15 @@
|
||||||
package io.element.android.features.logout.impl
|
package io.element.android.features.logout.impl
|
||||||
|
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
|
|
||||||
data class LogoutState(
|
data class LogoutState(
|
||||||
val isLastSession: Boolean,
|
val isLastSession: Boolean,
|
||||||
|
val backupState: BackupState,
|
||||||
|
val doesBackupExistOnServer: Boolean,
|
||||||
|
val recoveryState: RecoveryState,
|
||||||
val backupUploadState: BackupUploadState,
|
val backupUploadState: BackupUploadState,
|
||||||
val showConfirmationDialog: Boolean,
|
val showConfirmationDialog: Boolean,
|
||||||
val logoutAction: Async<String?>,
|
val logoutAction: Async<String?>,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ package io.element.android.features.logout.impl
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.encryption.SteadyStateException
|
import io.element.android.libraries.matrix.api.encryption.SteadyStateException
|
||||||
|
|
||||||
open class LogoutStateProvider : PreviewParameterProvider<LogoutState> {
|
open class LogoutStateProvider : PreviewParameterProvider<LogoutState> {
|
||||||
|
|
@ -32,16 +34,26 @@ open class LogoutStateProvider : PreviewParameterProvider<LogoutState> {
|
||||||
aLogoutState(logoutAction = Async.Loading()),
|
aLogoutState(logoutAction = Async.Loading()),
|
||||||
aLogoutState(logoutAction = Async.Failure(Exception("Failed to logout"))),
|
aLogoutState(logoutAction = Async.Failure(Exception("Failed to logout"))),
|
||||||
aLogoutState(backupUploadState = BackupUploadState.SteadyException(SteadyStateException.Connection("No network"))),
|
aLogoutState(backupUploadState = BackupUploadState.SteadyException(SteadyStateException.Connection("No network"))),
|
||||||
|
// Last session no recovery
|
||||||
|
aLogoutState(isLastSession = true, recoveryState = RecoveryState.DISABLED),
|
||||||
|
// Last session no backup
|
||||||
|
aLogoutState(isLastSession = true, backupState = BackupState.UNKNOWN, doesBackupExistOnServer = false),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun aLogoutState(
|
fun aLogoutState(
|
||||||
isLastSession: Boolean = false,
|
isLastSession: Boolean = false,
|
||||||
|
backupState: BackupState = BackupState.ENABLED,
|
||||||
|
doesBackupExistOnServer: Boolean = true,
|
||||||
|
recoveryState: RecoveryState = RecoveryState.ENABLED,
|
||||||
backupUploadState: BackupUploadState = BackupUploadState.Unknown,
|
backupUploadState: BackupUploadState = BackupUploadState.Unknown,
|
||||||
showConfirmationDialog: Boolean = false,
|
showConfirmationDialog: Boolean = false,
|
||||||
logoutAction: Async<String?> = Async.Uninitialized,
|
logoutAction: Async<String?> = Async.Uninitialized,
|
||||||
) = LogoutState(
|
) = LogoutState(
|
||||||
isLastSession = isLastSession,
|
isLastSession = isLastSession,
|
||||||
|
backupState = backupState,
|
||||||
|
doesBackupExistOnServer = doesBackupExistOnServer,
|
||||||
|
recoveryState = recoveryState,
|
||||||
backupUploadState = backupUploadState,
|
backupUploadState = backupUploadState,
|
||||||
showConfirmationDialog = showConfirmationDialog,
|
showConfirmationDialog = showConfirmationDialog,
|
||||||
logoutAction = logoutAction,
|
logoutAction = logoutAction,
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor
|
import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor
|
||||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.encryption.SteadyStateException
|
import io.element.android.libraries.matrix.api.encryption.SteadyStateException
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
|
|
@ -120,7 +122,15 @@ fun LogoutView(
|
||||||
private fun title(state: LogoutState): String {
|
private fun title(state: LogoutState): String {
|
||||||
return when {
|
return when {
|
||||||
state.backupUploadState.isBackingUp() -> stringResource(id = R.string.screen_signout_key_backup_ongoing_title)
|
state.backupUploadState.isBackingUp() -> stringResource(id = R.string.screen_signout_key_backup_ongoing_title)
|
||||||
state.isLastSession -> stringResource(id = R.string.screen_signout_key_backup_disabled_title)
|
state.isLastSession -> {
|
||||||
|
if (state.recoveryState != RecoveryState.ENABLED) {
|
||||||
|
stringResource(id = R.string.screen_signout_recovery_disabled_title)
|
||||||
|
} else if (state.backupState == BackupState.UNKNOWN && state.doesBackupExistOnServer.not()) {
|
||||||
|
stringResource(id = R.string.screen_signout_key_backup_disabled_title)
|
||||||
|
} else {
|
||||||
|
stringResource(id = R.string.screen_signout_save_recovery_key_title)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> stringResource(CommonStrings.action_signout)
|
else -> stringResource(CommonStrings.action_signout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,10 +148,10 @@ private fun subtitle(state: LogoutState): String? {
|
||||||
|
|
||||||
private fun BackupUploadState.isBackingUp(): Boolean {
|
private fun BackupUploadState.isBackingUp(): Boolean {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
BackupUploadState.Unknown,
|
|
||||||
BackupUploadState.Waiting,
|
BackupUploadState.Waiting,
|
||||||
is BackupUploadState.Uploading -> true
|
is BackupUploadState.Uploading -> true
|
||||||
is BackupUploadState.SteadyException -> exception is SteadyStateException.Connection
|
is BackupUploadState.SteadyException -> exception is SteadyStateException.Connection
|
||||||
|
BackupUploadState.Unknown,
|
||||||
BackupUploadState.Done,
|
BackupUploadState.Done,
|
||||||
BackupUploadState.Error -> false
|
BackupUploadState.Error -> false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupState
|
||||||
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
||||||
|
|
@ -50,6 +52,9 @@ class LogoutPresenterTest {
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
val initialState = awaitLastSequentialItem()
|
||||||
assertThat(initialState.isLastSession).isFalse()
|
assertThat(initialState.isLastSession).isFalse()
|
||||||
|
assertThat(initialState.backupState).isEqualTo(BackupState.UNKNOWN)
|
||||||
|
assertThat(initialState.doesBackupExistOnServer).isTrue()
|
||||||
|
assertThat(initialState.recoveryState).isEqualTo(RecoveryState.UNKNOWN)
|
||||||
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
|
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
|
||||||
assertThat(initialState.showConfirmationDialog).isFalse()
|
assertThat(initialState.showConfirmationDialog).isFalse()
|
||||||
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
||||||
|
|
@ -93,14 +98,15 @@ class LogoutPresenterTest {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
skipItems(1)
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.isLastSession).isFalse()
|
assertThat(initialState.isLastSession).isFalse()
|
||||||
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
|
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
|
||||||
assertThat(initialState.showConfirmationDialog).isFalse()
|
assertThat(initialState.showConfirmationDialog).isFalse()
|
||||||
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
||||||
|
skipItems(1)
|
||||||
val waitingState = awaitItem()
|
val waitingState = awaitItem()
|
||||||
assertThat(waitingState.backupUploadState).isEqualTo(BackupUploadState.Waiting)
|
assertThat(waitingState.backupUploadState).isEqualTo(BackupUploadState.Waiting)
|
||||||
|
skipItems(1)
|
||||||
val uploadingState = awaitItem()
|
val uploadingState = awaitItem()
|
||||||
assertThat(uploadingState.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
assertThat(uploadingState.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
||||||
val doneState = awaitItem()
|
val doneState = awaitItem()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue