diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootView.kt index dd352ca99e..9c87216b3d 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/root/SecureBackupRootView.kt @@ -70,6 +70,7 @@ fun SecureBackupRootView( // Disable / Enable backup when (state.backupState) { + BackupState.WAITING_FOR_SYNC, BackupState.UNKNOWN -> Unit BackupState.DISABLED -> { PreferenceText( @@ -97,6 +98,7 @@ fun SecureBackupRootView( // Setup recovery when (state.recoveryState) { + RecoveryState.WAITING_FOR_SYNC -> Unit RecoveryState.UNKNOWN, RecoveryState.DISABLED -> { PreferenceText( diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupState.kt index 41506417aa..98c45a1c9e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/BackupState.kt @@ -17,6 +17,14 @@ package io.element.android.libraries.matrix.api.encryption enum class BackupState { + /** + * Special value, when the SDK is waiting for the first sync to be done. + */ + WAITING_FOR_SYNC, + + /** + * Values mapped from the SDK. + */ UNKNOWN, CREATING, ENABLING, diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/RecoveryState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/RecoveryState.kt index c033332d8f..3d857b6d41 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/RecoveryState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/RecoveryState.kt @@ -17,6 +17,14 @@ package io.element.android.libraries.matrix.api.encryption enum class RecoveryState { + /** + * Special value, when the SDK is waiting for the first sync to be done. + */ + WAITING_FOR_SYNC, + + /** + * Values mapped from the SDK. + */ UNKNOWN, ENABLED, DISABLED, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 035add9ab2..8429968af3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -122,7 +122,12 @@ class RustMatrixClient constructor( private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock) private val notificationSettingsService = RustNotificationSettingsService(notificationSettings, dispatchers) private val roomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers) - private val encryptionService = RustEncryptionService(client, dispatchers).apply { start() } + private val encryptionService = RustEncryptionService( + client = client, + syncService = rustSyncService, + sessionCoroutineScope = sessionCoroutineScope, + dispatchers = dispatchers, + ).apply { start() } private val isLoggingOut = AtomicBoolean(false) 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 2b3c757642..11f9842d62 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 @@ -22,10 +22,16 @@ import io.element.android.libraries.matrix.api.encryption.BackupUploadState import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState +import io.element.android.libraries.matrix.api.sync.SyncState +import io.element.android.libraries.matrix.impl.sync.RustSyncService +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.BackupStateListener import org.matrix.rustcomponents.sdk.BackupSteadyStateListener @@ -41,6 +47,8 @@ import org.matrix.rustcomponents.sdk.SteadyStateException as RustSteadyStateExce internal class RustEncryptionService( client: Client, + syncService: RustSyncService, + sessionCoroutineScope: CoroutineScope, private val dispatchers: CoroutineDispatchers, ) : EncryptionService { @@ -52,20 +60,44 @@ internal class RustEncryptionService( 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)) + private val backupStateFlow = MutableStateFlow(service.backupState().let(backupStateMapper::map)) + + override val backupStateStateFlow = combine( + backupStateFlow, + syncService.syncState, + ) { backupState, syncState -> + if (syncState == SyncState.Running) { + backupState + } else { + BackupState.WAITING_FOR_SYNC + } + }.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, BackupState.WAITING_FOR_SYNC) + + private val recoveryStateFlow: MutableStateFlow = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map)) + + override val recoveryStateStateFlow = combine( + recoveryStateFlow, + syncService.syncState, + ) { recoveryState, syncState -> + if (syncState == SyncState.Running) { + recoveryState + } else { + RecoveryState.WAITING_FOR_SYNC + } + }.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, RecoveryState.WAITING_FOR_SYNC) + override val enableRecoveryProgressStateFlow: MutableStateFlow = MutableStateFlow(EnableRecoveryProgress.Unknown) fun start() { service.backupStateListener(object : BackupStateListener { override fun onUpdate(status: RustBackupState) { - backupStateStateFlow.value = backupStateMapper.map(status) + backupStateFlow.value = backupStateMapper.map(status) } }) service.recoveryStateListener(object : RecoveryStateListener { override fun onUpdate(status: RustRecoveryState) { - recoveryStateStateFlow.value = recoveryStateMapper.map(status) + recoveryStateFlow.value = recoveryStateMapper.map(status) } }) }