diff --git a/.github/workflows/maestro.yml b/.github/workflows/maestro.yml index 54889c58b7b..23b5fc12a01 100644 --- a/.github/workflows/maestro.yml +++ b/.github/workflows/maestro.yml @@ -55,9 +55,10 @@ jobs: # app-file should point to an x86 compatible APK file, so upload the x86_64 one (much smaller than the universal APK). app-file: app/build/outputs/apk/gplay/debug/app-gplay-x86_64-debug.apk env: | - USERNAME=maestroelement - PASSWORD=${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }} - ROOM_NAME=MyRoom - INVITEE1_MXID=@maestroelement2:matrix.org - INVITEE2_MXID=@maestroelement3:matrix.org - APP_ID=io.element.android.x.debug + MAESTRO_USERNAME=maestroelement + MAESTRO_PASSWORD=${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }} + MAESTRO_RECOVERY_KEY=${{ secrets.MATRIX_MAESTRO_ACCOUNT_RECOVERY_KEY }} + MAESTRO_ROOM_NAME=MyRoom + MAESTRO_INVITEE1_MXID=@maestroelement2:matrix.org + MAESTRO_INVITEE2_MXID=@maestroelement3:matrix.org + MAESTRO_APP_ID=io.element.android.x.debug diff --git a/.maestro/README.md b/.maestro/README.md index 9d9090744cb..c0ee525ac7b 100644 --- a/.maestro/README.md +++ b/.maestro/README.md @@ -22,12 +22,13 @@ From root dir of the project ```shell maestro test \ - -e APP_ID=io.element.android.x.debug \ - -e USERNAME=user1 \ - -e PASSWORD=123 \ - -e ROOM_NAME="MyRoom" \ - -e INVITEE1_MXID=user2 \ - -e INVITEE2_MXID=user3 \ + -e MAESTRO_APP_ID=io.element.android.x.debug \ + -e MAESTRO_USERNAME=user1 \ + -e MAESTRO_PASSWORD=123 \ + -e MAESTRO_RECOVERY_KEY=ABC \ + -e MAESTRO_ROOM_NAME="MyRoom" \ + -e MAESTRO_INVITEE1_MXID=user2 \ + -e MAESTRO_INVITEE2_MXID=user3 \ .maestro/allTests.yaml ``` diff --git a/.maestro/allTests.yaml b/.maestro/allTests.yaml index cd3ca342e2e..927a1cb0e54 100644 --- a/.maestro/allTests.yaml +++ b/.maestro/allTests.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- ## Check that all env variables required in the whole test suite are declared (to fail faster) - runScript: ./scripts/checkEnv.js diff --git a/.maestro/scripts/checkEnv.js b/.maestro/scripts/checkEnv.js index 74b4b569562..fa61d3c7637 100644 --- a/.maestro/scripts/checkEnv.js +++ b/.maestro/scripts/checkEnv.js @@ -1,9 +1,10 @@ // This array contains all the required environment variable. When adding a variable, add it here also. // If a variable is missing, an error will occur. -if (APP_ID == null) throw "Fatal: missing env variable APP_ID" -if (USERNAME == null) throw "Fatal: missing env variable USERNAME" -if (PASSWORD == null) throw "Fatal: missing env variable PASSWORD" -if (ROOM_NAME == null) throw "Fatal: missing env variable ROOM_NAME" -if (INVITEE1_MXID == null) throw "Fatal: missing env variable INVITEE1_MXID" -if (INVITEE2_MXID == null) throw "Fatal: missing env variable INVITEE2_MXID" +if (MAESTRO_APP_ID == null) throw "Fatal: missing env variable MAESTRO_APP_ID" +if (MAESTRO_USERNAME == null) throw "Fatal: missing env variable MAESTRO_USERNAME" +if (MAESTRO_PASSWORD == null) throw "Fatal: missing env variable MAESTRO_PASSWORD" +if (MAESTRO_RECOVERY_KEY == null) throw "Fatal: missing env variable MAESTRO_RECOVERY_KEY" +if (MAESTRO_ROOM_NAME == null) throw "Fatal: missing env variable MAESTRO_ROOM_NAME" +if (MAESTRO_INVITEE1_MXID == null) throw "Fatal: missing env variable MAESTRO_INVITEE1_MXID" +if (MAESTRO_INVITEE2_MXID == null) throw "Fatal: missing env variable MAESTRO_INVITEE2_MXID" diff --git a/.maestro/tests/account/changeServer.yaml b/.maestro/tests/account/changeServer.yaml index 1971e5a71b9..7ae4c3450f5 100644 --- a/.maestro/tests/account/changeServer.yaml +++ b/.maestro/tests/account/changeServer.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - tapOn: id: "login-change_server" diff --git a/.maestro/tests/account/login.yaml b/.maestro/tests/account/login.yaml index 6126e34459a..397cc61f5c8 100644 --- a/.maestro/tests/account/login.yaml +++ b/.maestro/tests/account/login.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - tapOn: "Continue" - runFlow: ../assertions/assertLoginDisplayed.yaml @@ -9,7 +9,7 @@ appId: ${APP_ID} id: "login-continue" - tapOn: id: "login-email_username" -- inputText: ${USERNAME} +- inputText: ${MAESTRO_USERNAME} - pressKey: Enter - tapOn: id: "login-password" @@ -20,7 +20,7 @@ appId: ${APP_ID} - tapOn: id: "login-password" - eraseText: 20 -- inputText: ${PASSWORD} +- inputText: ${MAESTRO_PASSWORD} - pressKey: Enter - tapOn: "Continue" - runFlow: ../assertions/assertWelcomeScreenDisplayed.yaml @@ -28,3 +28,4 @@ appId: ${APP_ID} - runFlow: ../assertions/assertAnalyticsDisplayed.yaml - tapOn: "Not now" - runFlow: ../assertions/assertHomeDisplayed.yaml +- runFlow: ./verifySession.yaml diff --git a/.maestro/tests/account/logout.yaml b/.maestro/tests/account/logout.yaml index 3019f1d2c3b..f27f5dada3c 100644 --- a/.maestro/tests/account/logout.yaml +++ b/.maestro/tests/account/logout.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - tapOn: id: "home_screen-settings" diff --git a/.maestro/tests/account/verifySession.yaml b/.maestro/tests/account/verifySession.yaml new file mode 100644 index 00000000000..eeb0489e3eb --- /dev/null +++ b/.maestro/tests/account/verifySession.yaml @@ -0,0 +1,11 @@ +appId: ${MAESTRO_APP_ID} +--- +- tapOn: "Continue" +- takeScreenshot: build/maestro/150-Verify +- tapOn: "Enter recovery key" +- tapOn: + id: "verification-recovery_key" +- inputText: ${MAESTRO_RECOVERY_KEY} +- hideKeyboard +- tapOn: "Confirm" +- runFlow: ../assertions/assertHomeDisplayed.yaml diff --git a/.maestro/tests/assertions/assertAnalyticsDisplayed.yaml b/.maestro/tests/assertions/assertAnalyticsDisplayed.yaml index 9c63c99ffc2..516dcc86eaa 100644 --- a/.maestro/tests/assertions/assertAnalyticsDisplayed.yaml +++ b/.maestro/tests/assertions/assertAnalyticsDisplayed.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: visible: "Help improve Element X dbg" diff --git a/.maestro/tests/assertions/assertHomeDisplayed.yaml b/.maestro/tests/assertions/assertHomeDisplayed.yaml index ca409705e18..40b6dc3e678 100644 --- a/.maestro/tests/assertions/assertHomeDisplayed.yaml +++ b/.maestro/tests/assertions/assertHomeDisplayed.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: visible: "All Chats" diff --git a/.maestro/tests/assertions/assertInitDisplayed.yaml b/.maestro/tests/assertions/assertInitDisplayed.yaml index 9424f382c19..6e895d9bbfe 100644 --- a/.maestro/tests/assertions/assertInitDisplayed.yaml +++ b/.maestro/tests/assertions/assertInitDisplayed.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: visible: "Be in your element" diff --git a/.maestro/tests/assertions/assertLoginDisplayed.yaml b/.maestro/tests/assertions/assertLoginDisplayed.yaml index b18078f9168..6d8558c38e3 100644 --- a/.maestro/tests/assertions/assertLoginDisplayed.yaml +++ b/.maestro/tests/assertions/assertLoginDisplayed.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: visible: "Change account provider" diff --git a/.maestro/tests/assertions/assertRoomListSynced.yaml b/.maestro/tests/assertions/assertRoomListSynced.yaml index 5fcd6e093ed..0eb1c52ac2e 100644 --- a/.maestro/tests/assertions/assertRoomListSynced.yaml +++ b/.maestro/tests/assertions/assertRoomListSynced.yaml @@ -1,5 +1,5 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: - visible: ${ROOM_NAME} + visible: ${MAESTRO_ROOM_NAME} timeout: 10000 diff --git a/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml b/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml index 3fbd9d25138..340d21ff2e0 100644 --- a/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml +++ b/.maestro/tests/assertions/assertWelcomeScreenDisplayed.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - extendedWaitUntil: visible: diff --git a/.maestro/tests/init.yaml b/.maestro/tests/init.yaml index acd5f86dfde..6cb056d96d5 100644 --- a/.maestro/tests/init.yaml +++ b/.maestro/tests/init.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - clearState - launchApp: diff --git a/.maestro/tests/roomList/createAndDeleteDM.yaml b/.maestro/tests/roomList/createAndDeleteDM.yaml index 6c2ebed11e2..6e0d55ab26e 100644 --- a/.maestro/tests/roomList/createAndDeleteDM.yaml +++ b/.maestro/tests/roomList/createAndDeleteDM.yaml @@ -1,13 +1,14 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- # Purpose: Test the creation and deletion of a DM room. - tapOn: "Create a new conversation or room" - tapOn: "Search for someone" -- inputText: ${INVITEE1_MXID} +- inputText: ${MAESTRO_INVITEE1_MXID} - tapOn: - text: ${INVITEE1_MXID} + text: ${MAESTRO_INVITEE1_MXID} index: 1 - takeScreenshot: build/maestro/330-createAndDeleteDM - tapOn: "maestroelement2" +- scroll - tapOn: "Leave conversation" - tapOn: "Leave" diff --git a/.maestro/tests/roomList/createAndDeleteRoom.yaml b/.maestro/tests/roomList/createAndDeleteRoom.yaml index 9fed7707ddf..60619154935 100644 --- a/.maestro/tests/roomList/createAndDeleteRoom.yaml +++ b/.maestro/tests/roomList/createAndDeleteRoom.yaml @@ -1,12 +1,12 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- # Purpose: Test the creation and deletion of a room - tapOn: "Create a new conversation or room" - tapOn: "New room" - tapOn: "Search for someone" -- inputText: ${INVITEE1_MXID} +- inputText: ${MAESTRO_INVITEE1_MXID} - tapOn: - text: ${INVITEE1_MXID} + text: ${MAESTRO_INVITEE1_MXID} index: 1 - tapOn: "Next" - tapOn: "e.g. your project name" @@ -19,9 +19,9 @@ appId: ${APP_ID} - tapOn: "Invite people" # assert there's 1 member and 1 invitee - tapOn: "Search for someone" -- inputText: ${INVITEE2_MXID} +- inputText: ${MAESTRO_INVITEE2_MXID} - tapOn: - text: ${INVITEE2_MXID} + text: ${MAESTRO_INVITEE2_MXID} index: 1 - tapOn: "Invite" - tapOn: "Back" diff --git a/.maestro/tests/roomList/roomContextMenu.yaml b/.maestro/tests/roomList/roomContextMenu.yaml index c2a87645589..160f8a31f70 100644 --- a/.maestro/tests/roomList/roomContextMenu.yaml +++ b/.maestro/tests/roomList/roomContextMenu.yaml @@ -1,13 +1,13 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- # Purpose: Test the context menu of a room in the room list -- longPressOn: ${ROOM_NAME} +- longPressOn: ${MAESTRO_ROOM_NAME} - takeScreenshot: build/maestro/310-RoomList-ContextMenu - tapOn: text: "Settings" index: 0 - tapOn: "Back" -- longPressOn: ${ROOM_NAME} +- longPressOn: ${MAESTRO_ROOM_NAME} - tapOn: text: "Leave room" index: 0 diff --git a/.maestro/tests/roomList/roomList.yaml b/.maestro/tests/roomList/roomList.yaml index 6365759e722..5cc9e269c50 100644 --- a/.maestro/tests/roomList/roomList.yaml +++ b/.maestro/tests/roomList/roomList.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - runFlow: searchRoomList.yaml - takeScreenshot: build/maestro/300-RoomList diff --git a/.maestro/tests/roomList/searchRoomList.yaml b/.maestro/tests/roomList/searchRoomList.yaml index 5939c0bc5e7..8b41c4d259f 100644 --- a/.maestro/tests/roomList/searchRoomList.yaml +++ b/.maestro/tests/roomList/searchRoomList.yaml @@ -1,10 +1,10 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - runFlow: ../assertions/assertRoomListSynced.yaml - tapOn: "search" -- inputText: ${ROOM_NAME.substring(0, 3)} +- inputText: ${MAESTRO_ROOM_NAME.substring(0, 3)} - takeScreenshot: build/maestro/400-SearchRoom -- tapOn: ${ROOM_NAME} +- tapOn: ${MAESTRO_ROOM_NAME} # Back from timeline - back - assertVisible: "MyR" diff --git a/.maestro/tests/roomList/timeline/messages/location.yaml b/.maestro/tests/roomList/timeline/messages/location.yaml index 73dca6eeb47..c9382bd30c2 100644 --- a/.maestro/tests/roomList/timeline/messages/location.yaml +++ b/.maestro/tests/roomList/timeline/messages/location.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - takeScreenshot: build/maestro/520-Timeline - tapOn: "Add attachment" diff --git a/.maestro/tests/roomList/timeline/messages/poll.yaml b/.maestro/tests/roomList/timeline/messages/poll.yaml index 65495dda607..c6fffebd7d6 100644 --- a/.maestro/tests/roomList/timeline/messages/poll.yaml +++ b/.maestro/tests/roomList/timeline/messages/poll.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - takeScreenshot: build/maestro/530-Timeline - tapOn: "Add attachment" diff --git a/.maestro/tests/roomList/timeline/messages/text.yaml b/.maestro/tests/roomList/timeline/messages/text.yaml index 963b2cf9e9a..6767886d8df 100644 --- a/.maestro/tests/roomList/timeline/messages/text.yaml +++ b/.maestro/tests/roomList/timeline/messages/text.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - takeScreenshot: build/maestro/510-Timeline - tapOn: diff --git a/.maestro/tests/roomList/timeline/timeline.yaml b/.maestro/tests/roomList/timeline/timeline.yaml index 1acb10a9aa4..5f85366e9ec 100644 --- a/.maestro/tests/roomList/timeline/timeline.yaml +++ b/.maestro/tests/roomList/timeline/timeline.yaml @@ -1,7 +1,7 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- # This is the name of one room -- tapOn: ${ROOM_NAME} +- tapOn: ${MAESTRO_ROOM_NAME} - takeScreenshot: build/maestro/500-Timeline - runFlow: messages/text.yaml - runFlow: messages/location.yaml diff --git a/.maestro/tests/settings/settings.yaml b/.maestro/tests/settings/settings.yaml index d5f1e110e54..c77d118a3b1 100644 --- a/.maestro/tests/settings/settings.yaml +++ b/.maestro/tests/settings/settings.yaml @@ -1,4 +1,4 @@ -appId: ${APP_ID} +appId: ${MAESTRO_APP_ID} --- - tapOn: id: "home_screen-settings" diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index db75acff64f..e4290d5bdf4 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -338,6 +338,10 @@ class LoggedInFlowNode @AssistedInject constructor( ) ) } + + override fun onDone() { + backstack.pop() + } } verifySessionEntryPoint .nodeBuilder(this, buildContext) diff --git a/features/securebackup/impl/build.gradle.kts b/features/securebackup/impl/build.gradle.kts index a3509b65dd6..1d7a97b344f 100644 --- a/features/securebackup/impl/build.gradle.kts +++ b/features/securebackup/impl/build.gradle.kts @@ -42,6 +42,7 @@ dependencies { implementation(projects.libraries.matrixui) implementation(projects.libraries.designsystem) implementation(projects.libraries.uiStrings) + implementation(projects.libraries.testtags) api(libs.statemachine) api(projects.features.securebackup.api) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt index 208248a8d53..7a4d92fcd32 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/setup/views/RecoveryKeyView.kt @@ -53,6 +53,8 @@ import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.OutlinedTextField import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.autofill +import io.element.android.libraries.testtags.TestTags +import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings @Composable @@ -169,6 +171,7 @@ private fun RecoveryKeyFormContent( OutlinedTextField( modifier = Modifier .fillMaxWidth() + .testTag(TestTags.recoveryKey) .autofill( autofillTypes = listOf(AutofillType.Password), onFill = { onChange(it) }, diff --git a/features/verifysession/api/src/main/kotlin/io/element/android/features/verifysession/api/VerifySessionEntryPoint.kt b/features/verifysession/api/src/main/kotlin/io/element/android/features/verifysession/api/VerifySessionEntryPoint.kt index 5eb1bc8daae..8d19ca56989 100644 --- a/features/verifysession/api/src/main/kotlin/io/element/android/features/verifysession/api/VerifySessionEntryPoint.kt +++ b/features/verifysession/api/src/main/kotlin/io/element/android/features/verifysession/api/VerifySessionEntryPoint.kt @@ -31,5 +31,6 @@ interface VerifySessionEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onEnterRecoveryKey() + fun onDone() } } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt index 3aa75f0c268..cc97faa6e35 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt @@ -40,14 +40,20 @@ class VerifySelfSessionNode @AssistedInject constructor( } } + private fun onDone() { + plugins().forEach { + it.onDone() + } + } + @Composable override fun View(modifier: Modifier) { val state = presenter.present() VerifySelfSessionView( state = state, modifier = modifier, - onEnterRecoveryKey = { onEnterRecoveryKey() }, - goBack = { navigateUp() } + onEnterRecoveryKey = ::onEnterRecoveryKey, + goBack = ::onDone, ) } } 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 e642813e3b6..521d26f062a 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 @@ -138,7 +138,7 @@ class RustMatrixClient( syncService = rustSyncService, sessionCoroutineScope = sessionCoroutineScope, dispatchers = dispatchers, - ).apply { start() } + ) private val sessionDirectoryNameProvider = SessionDirectoryNameProvider() private val isLoggingOut = AtomicBoolean(false) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/EncryptionExtension.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/EncryptionExtension.kt new file mode 100644 index 00000000000..976ed4c2dee --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/EncryptionExtension.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 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.BackupState +import io.element.android.libraries.matrix.api.encryption.RecoveryState +import io.element.android.libraries.matrix.impl.util.mxCallbackFlow +import kotlinx.coroutines.flow.Flow +import org.matrix.rustcomponents.sdk.BackupStateListener +import org.matrix.rustcomponents.sdk.EncryptionInterface +import org.matrix.rustcomponents.sdk.RecoveryStateListener +import org.matrix.rustcomponents.sdk.BackupState as RustBackupState +import org.matrix.rustcomponents.sdk.RecoveryState as RustRecoveryState + +internal fun EncryptionInterface.backupStateFlow(): Flow = mxCallbackFlow { + val backupStateMapper = BackupStateMapper() + trySend(backupStateMapper.map(backupState())) + val listener = object : BackupStateListener { + override fun onUpdate(status: RustBackupState) { + trySend(backupStateMapper.map(status)) + } + } + backupStateListener(listener) +} + +internal fun EncryptionInterface.recoveryStateFlow(): Flow = mxCallbackFlow { + val recoveryStateMapper = RecoveryStateMapper() + trySend(recoveryStateMapper.map(recoveryState())) + val listener = object : RecoveryStateListener { + override fun onUpdate(status: RustRecoveryState) { + trySend(recoveryStateMapper.map(status)) + } + } + recoveryStateListener(listener) +} 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 84e9fb2f140..f5a63909893 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 @@ -25,7 +25,6 @@ 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 io.element.android.libraries.matrix.impl.util.cancelAndDestroy import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.currentCoroutineContext @@ -40,17 +39,12 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.BackupStateListener import org.matrix.rustcomponents.sdk.BackupSteadyStateListener import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.EnableRecoveryProgressListener import org.matrix.rustcomponents.sdk.Encryption -import org.matrix.rustcomponents.sdk.RecoveryStateListener -import org.matrix.rustcomponents.sdk.TaskHandle -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( @@ -61,18 +55,12 @@ internal class RustEncryptionService( ) : EncryptionService { private val service: Encryption = client.encryption() - private val backupStateMapper = BackupStateMapper() - private val recoveryStateMapper = RecoveryStateMapper() private val enableRecoveryProgressMapper = EnableRecoveryProgressMapper() private val backupUploadStateMapper = BackupUploadStateMapper() private val steadyStateExceptionMapper = SteadyStateExceptionMapper() - private var backupStateListenerTaskHandle: TaskHandle? = null - private var recoveryStateListenerTaskHandle: TaskHandle? = null - - private val backupStateFlow = MutableStateFlow(service.backupState().let(backupStateMapper::map)) override val backupStateStateFlow = combine( - backupStateFlow, + service.backupStateFlow(), syncService.syncState, ) { backupState, syncState -> if (syncState == SyncState.Running) { @@ -82,10 +70,8 @@ internal class RustEncryptionService( } }.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, BackupState.WAITING_FOR_SYNC) - private val recoveryStateFlow: MutableStateFlow = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map)) - override val recoveryStateStateFlow = combine( - recoveryStateFlow, + service.recoveryStateFlow(), syncService.syncState, ) { recoveryState, syncState -> if (syncState == SyncState.Running) { @@ -111,23 +97,7 @@ internal class RustEncryptionService( } .stateIn(sessionCoroutineScope, SharingStarted.Eagerly, false) - fun start() { - backupStateListenerTaskHandle = service.backupStateListener(object : BackupStateListener { - override fun onUpdate(status: RustBackupState) { - backupStateFlow.value = backupStateMapper.map(status) - } - }) - - recoveryStateListenerTaskHandle = service.recoveryStateListener(object : RecoveryStateListener { - override fun onUpdate(status: RustRecoveryState) { - recoveryStateFlow.value = recoveryStateMapper.map(status) - } - }) - } - fun destroy() { - backupStateListenerTaskHandle?.cancelAndDestroy() - recoveryStateListenerTaskHandle?.cancelAndDestroy() service.destroy() } diff --git a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt index 7992ddee179..5eb7780e1ff 100644 --- a/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt +++ b/libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt @@ -33,6 +33,11 @@ object TestTags { val loginPassword = TestTag("login-password") val loginContinue = TestTag("login-continue") + /** + * Verification screen. + */ + val recoveryKey = TestTag("verification-recovery_key") + /** * Sign out screen. */