diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStateProvider.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStateProvider.kt index c0ceb5302b..ddf0f30340 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStateProvider.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStateProvider.kt @@ -19,6 +19,7 @@ package io.element.android.features.logout.impl import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.encryption.BackupUploadState +import io.element.android.libraries.matrix.api.encryption.SteadyStateException open class LogoutStateProvider : PreviewParameterProvider { override val values: Sequence @@ -30,6 +31,7 @@ open class LogoutStateProvider : PreviewParameterProvider { aLogoutState(showConfirmationDialog = true), aLogoutState(logoutAction = Async.Loading()), aLogoutState(logoutAction = Async.Failure(Exception("Failed to logout"))), + aLogoutState(backupUploadState = BackupUploadState.SteadyException(SteadyStateException.Connection("No network"))), ) } diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt index 7a8b4599bb..c663fb60bd 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt @@ -45,6 +45,7 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.matrix.api.encryption.BackupUploadState +import io.element.android.libraries.matrix.api.encryption.SteadyStateException import io.element.android.libraries.theme.ElementTheme import io.element.android.libraries.ui.strings.CommonStrings @@ -128,7 +129,6 @@ fun LogoutView( } } -// TODO i18n @Composable private fun HeaderContent( state: LogoutState, @@ -137,9 +137,11 @@ private fun HeaderContent( val title = when { 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) - else -> "Sign out of Element" // TODO + else -> stringResource(CommonStrings.action_signout) } val subtitle = when { + (state.backupUploadState as? BackupUploadState.SteadyException)?.exception is SteadyStateException.Connection -> + stringResource(id = R.string.screen_signout_key_backup_offline_subtitle) state.backupUploadState.isBackingUp() -> stringResource(id = R.string.screen_signout_key_backup_ongoing_subtitle) state.isLastSession -> stringResource(id = R.string.screen_signout_key_backup_disabled_subtitle) else -> null @@ -151,7 +153,6 @@ private fun HeaderContent( iconResourceId = CommonDrawables.ic_key, title = title, subTitle = subtitle, - // iconComposable = iconComposable, ) } @@ -160,7 +161,8 @@ private fun BackupUploadState.isBackingUp(): Boolean { BackupUploadState.Unknown, BackupUploadState.Waiting, is BackupUploadState.Uploading, - is BackupUploadState.CheckingIfUploadNeeded -> true + is BackupUploadState.CheckingIfUploadNeeded, + is BackupUploadState.SteadyException -> true BackupUploadState.Done, BackupUploadState.Error -> false } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt index 2035dc71a1..8b5d721b28 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupUploadState.kt @@ -34,4 +34,6 @@ sealed interface BackupUploadState { data object Done : BackupUploadState data object Error : BackupUploadState + + data class SteadyException(val exception: SteadyStateException) : BackupUploadState } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt new file mode 100644 index 0000000000..1e83344a02 --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/SteadyStateException.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.api.encryption + +sealed interface SteadyStateException { + /** + * The backup can be deleted. + */ + data class BackupDisabled(val message: String) : SteadyStateException + + /** + * The task waiting for notifications coming from the upload task can fall behind so much that it lost some notifications. + */ + data class Lagged(val message: String) : SteadyStateException + + /** + * The request(s) to upload the room keys failed. + */ + data class Connection(val message: String) : SteadyStateException +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt index b1089a215d..794419cfaa 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustEncryptionService.kt @@ -37,6 +37,7 @@ import org.matrix.rustcomponents.sdk.BackupState as RustBackupState import org.matrix.rustcomponents.sdk.BackupUploadState as RustBackupUploadState import org.matrix.rustcomponents.sdk.EnableRecoveryProgress as RustEnableRecoveryProgress import org.matrix.rustcomponents.sdk.RecoveryState as RustRecoveryState +import org.matrix.rustcomponents.sdk.SteadyStateException as RustSteadyStateException internal class RustEncryptionService( client: Client, @@ -49,6 +50,7 @@ internal class RustEncryptionService( private val recoveryStateMapper = RecoveryStateMapper() private val enableRecoveryProgressMapper = EnableRecoveryProgressMapper() private val backupUploadStateMapper = BackupUploadStateMapper() + private val steadyStateExceptionMapper = SteadyStateExceptionMapper() override val backupStateStateFlow: MutableStateFlow = MutableStateFlow(service.backupState().let(backupStateMapper::map)) override val recoveryStateStateFlow: MutableStateFlow = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map)) @@ -98,16 +100,25 @@ internal class RustEncryptionService( override fun waitForBackupUploadSteadyState(): Flow { return callbackFlow { - service.waitForBackupUploadSteadyState( - progressListener = object : BackupSteadyStateListener { - override fun onUpdate(status: RustBackupUploadState) { - trySend(backupUploadStateMapper.map(status)) - if (status == RustBackupUploadState.Done) { - close() + runCatching { + service.waitForBackupUploadSteadyState( + progressListener = object : BackupSteadyStateListener { + override fun onUpdate(status: RustBackupUploadState) { + trySend(backupUploadStateMapper.map(status)) + if (status == RustBackupUploadState.Done) { + close() + } } } + ) + }.onFailure { + if (it is RustSteadyStateException) { + trySend(BackupUploadState.SteadyException(steadyStateExceptionMapper.map(it))) + } else { + trySend(BackupUploadState.Error) } - ) + close(it) + } awaitClose {} } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/SteadyStateExceptionMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/SteadyStateExceptionMapper.kt new file mode 100644 index 0000000000..331d3f8473 --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/SteadyStateExceptionMapper.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.matrix.impl.encryption + +import io.element.android.libraries.matrix.api.encryption.SteadyStateException +import org.matrix.rustcomponents.sdk.SteadyStateException as RustSteadyStateException + +class SteadyStateExceptionMapper { + fun map(data: RustSteadyStateException): SteadyStateException { + return when (data) { + is RustSteadyStateException.BackupDisabled -> SteadyStateException.BackupDisabled( + message = data.message + ) + is RustSteadyStateException.Connection -> SteadyStateException.Connection( + message = data.message + ) + is RustSteadyStateException.Laged -> SteadyStateException.Lagged( + message = data.message + ) + } + } +}