From 03786c1fd224b341291b86ed5bd5572ba7e1518e Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 16 Sep 2024 11:13:02 +0200 Subject: [PATCH] Add forced logout flow when the proxy is no longer available (#3458) * Add `MatrixClient.isSlidingSyncProxySupported` function * Update localazy strings * Modify `ErrorDialog` to have an `onSubmit` call, which will be used for the submit action. Also make the title text optional and dismissing the dialog by tapping outside/going back configurable. * Check if a forced migration to SSS is needed because the proxy is no longer available. In that case, display the non-dismissable dialog and force the user to log out after enabling SSS. * Enable native/simplified sliding sync by default. * Refactor the login to make sure we: 1. Always try native/simplified sliding sync login first, if available. 2. Then, if it wasn't available or failed with an sliding sync not supported error, try with the proxy instead (either discovered proxy or forced custom one). * Move logic to `LoggedInPresenter` and the UI to `LoggedInView` * Update screenshots --------- Co-authored-by: ElementBot --- appnav/build.gradle.kts | 1 + .../android/appnav/loggedin/LoggedInEvents.kt | 2 + .../appnav/loggedin/LoggedInPresenter.kt | 17 +++ .../android/appnav/loggedin/LoggedInState.kt | 1 + .../appnav/loggedin/LoggedInStateProvider.kt | 3 + .../android/appnav/loggedin/LoggedInView.kt | 29 +++++ appnav/src/main/res/values/localazy.xml | 5 + .../appnav/loggedin/LoggedInPresenterTest.kt | 92 +++++++++++++- .../features/call/impl/ui/CallScreenView.kt | 2 +- .../features/leaveroom/api/LeaveRoomView.kt | 2 +- .../lockscreen/impl/setup/pin/SetupPinView.kt | 2 +- .../lockscreen/impl/unlock/PinUnlockView.kt | 4 +- .../impl/changeserver/ChangeServerView.kt | 2 +- .../ConfirmAccountProviderView.kt | 2 +- .../loginpassword/LoginPasswordView.kt | 2 +- .../src/main/res/values-be/translations.xml | 6 - .../src/main/res/values-bg/translations.xml | 1 - .../src/main/res/values-cs/translations.xml | 6 - .../src/main/res/values-de/translations.xml | 6 - .../src/main/res/values-el/translations.xml | 6 - .../src/main/res/values-es/translations.xml | 6 - .../src/main/res/values-et/translations.xml | 6 - .../src/main/res/values-fr/translations.xml | 6 - .../src/main/res/values-hu/translations.xml | 6 - .../src/main/res/values-in/translations.xml | 6 - .../src/main/res/values-it/translations.xml | 6 - .../src/main/res/values-ka/translations.xml | 6 - .../src/main/res/values-nl/translations.xml | 6 - .../src/main/res/values-pl/translations.xml | 6 - .../main/res/values-pt-rBR/translations.xml | 6 - .../src/main/res/values-pt/translations.xml | 6 - .../src/main/res/values-ro/translations.xml | 6 - .../src/main/res/values-ru/translations.xml | 6 - .../src/main/res/values-sk/translations.xml | 6 - .../src/main/res/values-sv/translations.xml | 6 - .../src/main/res/values-uk/translations.xml | 6 - .../src/main/res/values-uz/translations.xml | 6 - .../main/res/values-zh-rTW/translations.xml | 1 - .../src/main/res/values-zh/translations.xml | 6 - .../impl/src/main/res/values/localazy.xml | 6 - .../pinned/list/PinnedMessagesListView.kt | 2 +- .../timeline/focus/FocusRequestStateView.kt | 2 +- .../VoiceMessageSendingFailedDialog.kt | 2 +- .../notifications/NotificationSettingsView.kt | 2 +- .../RolesAndPermissionsView.kt | 2 +- .../changeroles/ChangeRolesView.kt | 2 +- .../impl/src/main/res/values/localazy.xml | 1 + .../src/main/res/values-be/translations.xml | 1 - .../src/main/res/values-cs/translations.xml | 1 - .../src/main/res/values-de/translations.xml | 4 - .../src/main/res/values-el/translations.xml | 1 - .../src/main/res/values-et/translations.xml | 1 - .../src/main/res/values-fr/translations.xml | 1 - .../src/main/res/values-hu/translations.xml | 1 - .../src/main/res/values-in/translations.xml | 1 - .../src/main/res/values-it/translations.xml | 1 - .../src/main/res/values-pl/translations.xml | 1 - .../src/main/res/values-pt/translations.xml | 1 - .../src/main/res/values-ro/translations.xml | 1 - .../src/main/res/values-ru/translations.xml | 4 - .../src/main/res/values-sk/translations.xml | 1 - .../src/main/res/values-sv/translations.xml | 1 - .../src/main/res/values-uk/translations.xml | 1 - .../src/main/res/values-zh/translations.xml | 1 - .../impl/src/main/res/values/localazy.xml | 1 - .../components/async/AsyncActionView.kt | 2 +- .../components/dialogs/ErrorDialog.kt | 19 ++- .../libraries/matrix/api/MatrixClient.kt | 5 +- .../libraries/matrix/impl/RustMatrixClient.kt | 4 + .../matrix/impl/RustMatrixClientFactory.kt | 20 +-- .../auth/RustMatrixAuthenticationService.kt | 120 ++++++++++++++---- .../libraries/matrix/test/FakeMatrixClient.kt | 5 + .../impl/store/DefaultAppPreferencesStore.kt | 2 +- .../src/main/res/values/localazy.xml | 9 ++ .../android/samples/minimal/MainActivity.kt | 2 +- .../services/apperror/impl/AppErrorView.kt | 2 +- .../appnav.loggedin_LoggedInView_Day_3_en.png | 3 + ...ppnav.loggedin_LoggedInView_Night_3_en.png | 3 + tools/localazy/config.json | 7 + 79 files changed, 315 insertions(+), 231 deletions(-) create mode 100644 appnav/src/main/res/values/localazy.xml create mode 100644 tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Day_3_en.png create mode 100644 tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Night_3_en.png diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index fae6fc9c15..fd389645a9 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -59,6 +59,7 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.oidc.impl) + testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.push.test) testImplementation(projects.libraries.pushproviders.test) testImplementation(projects.features.networkmonitor.test) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInEvents.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInEvents.kt index cd156bce02..4f60e543bb 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInEvents.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInEvents.kt @@ -9,4 +9,6 @@ package io.element.android.appnav.loggedin sealed interface LoggedInEvents { data class CloseErrorDialog(val doNotShowAgain: Boolean) : LoggedInEvents + data object CheckSlidingSyncProxyAvailability : LoggedInEvents + data object LogoutAndMigrateToNativeSlidingSync : LoggedInEvents } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt index e6779c2c99..c619629152 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import im.vector.app.features.analytics.plan.CryptoSessionStateChange import im.vector.app.features.analytics.plan.UserProperties import io.element.android.features.networkmonitor.api.NetworkMonitor @@ -29,6 +30,7 @@ import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus +import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase import io.element.android.libraries.push.api.PushService import io.element.android.libraries.pushproviders.api.RegistrationFailure import io.element.android.services.analytics.api.AnalyticsService @@ -48,6 +50,7 @@ class LoggedInPresenter @Inject constructor( private val sessionVerificationService: SessionVerificationService, private val analyticsService: AnalyticsService, private val encryptionService: EncryptionService, + private val enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase, ) : Presenter { @Composable override fun present(): LoggedInState { @@ -78,6 +81,7 @@ class LoggedInPresenter @Inject constructor( networkStatus == NetworkStatus.Online && syncIndicator == RoomListService.SyncIndicator.Show } } + var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) } LaunchedEffect(Unit) { combine( sessionVerificationService.sessionVerifiedStatus, @@ -97,6 +101,18 @@ class LoggedInPresenter @Inject constructor( } } } + LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch { + // Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is. + forceNativeSlidingSyncMigration = !matrixClient.isUsingNativeSlidingSync() && + matrixClient.isNativeSlidingSyncSupported() && + !matrixClient.isSlidingSyncProxySupported() + } + LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch { + // Enable native sliding sync if it wasn't already the case + enableNativeSlidingSyncUseCase() + // Then force the logout + matrixClient.logout(userInitiated = true, ignoreSdkError = true) + } } } @@ -104,6 +120,7 @@ class LoggedInPresenter @Inject constructor( showSyncSpinner = showSyncSpinner, pusherRegistrationState = pusherRegistrationState.value, ignoreRegistrationError = ignoreRegistrationError, + forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration, eventSink = ::handleEvent ) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInState.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInState.kt index 7ef0e6f549..2735b02706 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInState.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInState.kt @@ -13,5 +13,6 @@ data class LoggedInState( val showSyncSpinner: Boolean, val pusherRegistrationState: AsyncData, val ignoreRegistrationError: Boolean, + val forceNativeSlidingSyncMigration: Boolean, val eventSink: (LoggedInEvents) -> Unit, ) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInStateProvider.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInStateProvider.kt index bcc88b1c3a..13d100820b 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInStateProvider.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInStateProvider.kt @@ -16,15 +16,18 @@ open class LoggedInStateProvider : PreviewParameterProvider { aLoggedInState(), aLoggedInState(showSyncSpinner = true), aLoggedInState(pusherRegistrationState = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable())), + aLoggedInState(forceNativeSlidingSyncMigration = true), ) } fun aLoggedInState( showSyncSpinner: Boolean = false, pusherRegistrationState: AsyncData = AsyncData.Uninitialized, + forceNativeSlidingSyncMigration: Boolean = false, ) = LoggedInState( showSyncSpinner = showSyncSpinner, pusherRegistrationState = pusherRegistrationState, ignoreRegistrationError = false, + forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration, eventSink = {}, ) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInView.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInView.kt index 0af150e0b7..3134270965 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInView.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInView.kt @@ -15,10 +15,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.lifecycle.Lifecycle +import io.element.android.appnav.R import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.components.dialogs.ErrorDialogWithDoNotShowAgain import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.matrix.api.exception.isNetworkError import io.element.android.libraries.ui.strings.CommonStrings @@ -28,6 +32,11 @@ fun LoggedInView( navigateToNotificationTroubleshoot: () -> Unit, modifier: Modifier = Modifier ) { + OnLifecycleEvent { _, event -> + if (event == Lifecycle.Event.ON_RESUME) { + state.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability) + } + } Box( modifier = modifier .fillMaxSize() @@ -61,6 +70,13 @@ fun LoggedInView( } } } + + // Set the force migration dialog here so it's always displayed over every screen + if (state.forceNativeSlidingSyncMigration) { + ForceNativeSlidingSyncMigrationDialog(onSubmit = { + state.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync) + }) + } } private fun Throwable.getReason(): String? { @@ -80,6 +96,19 @@ private fun Throwable.getReason(): String? { } } +@Composable +private fun ForceNativeSlidingSyncMigrationDialog( + onSubmit: () -> Unit, +) { + ErrorDialog( + title = null, + content = stringResource(R.string.banner_migrate_to_native_sliding_sync_force_logout_title), + submitText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action), + onSubmit = onSubmit, + canDismiss = false, + ) +} + @PreviewsDayNight @Composable internal fun LoggedInViewPreview(@PreviewParameter(LoggedInStateProvider::class) state: LoggedInState) = ElementPreview { diff --git a/appnav/src/main/res/values/localazy.xml b/appnav/src/main/res/values/localazy.xml new file mode 100644 index 0000000000..bb6df44051 --- /dev/null +++ b/appnav/src/main/res/values/localazy.xml @@ -0,0 +1,5 @@ + + + "Log Out & Upgrade" + "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app." + diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index ee060f3444..519cceddfe 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -29,6 +29,8 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService +import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase +import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.test.FakePushService import io.element.android.libraries.pushproviders.api.Distributor @@ -42,6 +44,10 @@ import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -91,7 +97,8 @@ class LoggedInPresenterTest { pushService = FakePushService(), sessionVerificationService = verificationService, analyticsService = analyticsService, - encryptionService = encryptionService + encryptionService = encryptionService, + enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this), ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -487,26 +494,103 @@ class LoggedInPresenterTest { ) } + @Test + fun `present - CheckSlidingSyncProxyAvailability forces the sliding sync migration under the right circumstances`() = runTest { + // The migration will be forced if: + // - The user is not using the native sliding sync + // - The sliding sync proxy is no longer supported + // - The native sliding sync is supported + val matrixClient = FakeMatrixClient( + isUsingNativeSlidingSyncLambda = { false }, + isSlidingSyncProxySupportedLambda = { false }, + isNativeSlidingSyncSupportedLambda = { true }, + ) + val presenter = createLoggedInPresenter(matrixClient = matrixClient) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.forceNativeSlidingSyncMigration).isFalse() + + initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability) + + assertThat(awaitItem().forceNativeSlidingSyncMigration).isTrue() + } + } + + @Test + fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest { + val matrixClient = FakeMatrixClient( + isUsingNativeSlidingSyncLambda = { false }, + isSlidingSyncProxySupportedLambda = { false }, + isNativeSlidingSyncSupportedLambda = { false }, + ) + val presenter = createLoggedInPresenter(matrixClient = matrixClient) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + assertThat(initialState.forceNativeSlidingSyncMigration).isFalse() + + initialState.eventSink(LoggedInEvents.CheckSlidingSyncProxyAvailability) + + expectNoEvents() + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun `present - LogoutAndMigrateToNativeSlidingSync enables native sliding sync and logs out the user`() = runTest { + val logoutLambda = lambdaRecorder { userInitiated, ignoreSdkError -> + assertThat(userInitiated).isTrue() + assertThat(ignoreSdkError).isTrue() + null + } + val matrixClient = FakeMatrixClient().apply { + this.logoutLambda = logoutLambda + } + val appPreferencesStore = InMemoryAppPreferencesStore() + val enableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(appPreferencesStore, this) + val presenter = createLoggedInPresenter(matrixClient = matrixClient, enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + + assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isFalse() + + initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync) + + advanceUntilIdle() + + assertThat(appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first()).isTrue() + assertThat(logoutLambda.assertions().isCalledOnce()) + } + } + private suspend fun ReceiveTurbine.awaitFirstItem(): T { skipItems(1) return awaitItem() } - private fun createLoggedInPresenter( + private fun TestScope.createLoggedInPresenter( roomListService: RoomListService = FakeRoomListService(), networkStatus: NetworkStatus = NetworkStatus.Offline, analyticsService: AnalyticsService = FakeAnalyticsService(), sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(), encryptionService: EncryptionService = FakeEncryptionService(), pushService: PushService = FakePushService(), + enableNativeSlidingSyncUseCase: EnableNativeSlidingSyncUseCase = EnableNativeSlidingSyncUseCase(InMemoryAppPreferencesStore(), this), + matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService), ): LoggedInPresenter { return LoggedInPresenter( - matrixClient = FakeMatrixClient(roomListService = roomListService), + matrixClient = matrixClient, networkMonitor = FakeNetworkMonitor(networkStatus), pushService = pushService, sessionVerificationService = sessionVerificationService, analyticsService = analyticsService, - encryptionService = encryptionService + encryptionService = encryptionService, + enableNativeSlidingSyncUseCase = enableNativeSlidingSyncUseCase, ) } } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt index 7d0f1f6676..4641e4e7bc 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenView.kt @@ -111,7 +111,7 @@ internal fun CallScreenView( is AsyncData.Failure -> ErrorDialog( content = state.urlState.error.message.orEmpty(), - onDismiss = { state.eventSink(CallScreenEvents.Hangup) }, + onSubmit = { state.eventSink(CallScreenEvents.Hangup) }, ) is AsyncData.Success -> Unit } diff --git a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomView.kt b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomView.kt index 6ee2990c5b..a98bfbff2f 100644 --- a/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomView.kt +++ b/features/leaveroom/api/src/main/kotlin/io/element/android/features/leaveroom/api/LeaveRoomView.kt @@ -105,7 +105,7 @@ private fun LeaveRoomErrorDialog( is LeaveRoomState.Error.Hidden -> {} is LeaveRoomState.Error.Shown -> ErrorDialog( content = stringResource(CommonStrings.error_unknown), - onDismiss = { state.eventSink(LeaveRoomEvent.HideError) } + onSubmit = { state.eventSink(LeaveRoomEvent.HideError) } ) } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt index b794f2eed4..b3cd532487 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/pin/SetupPinView.kt @@ -116,7 +116,7 @@ private fun SetupPinContent( ErrorDialog( title = state.setupPinFailure.title(), content = state.setupPinFailure.content(), - onDismiss = { + onSubmit = { state.eventSink(SetupPinEvents.ClearFailure) } ) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt index 702e253f03..8667b3806a 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockView.kt @@ -104,7 +104,7 @@ fun PinUnlockView( if (state.showBiometricUnlockError) { ErrorDialog( content = state.biometricUnlockErrorMessage ?: "", - onDismiss = { state.eventSink(PinUnlockEvents.ClearBiometricError) } + onSubmit = { state.eventSink(PinUnlockEvents.ClearBiometricError) } ) } } @@ -206,7 +206,7 @@ private fun SignOutPrompt( ErrorDialog( title = stringResource(id = R.string.screen_app_lock_signout_alert_title), content = stringResource(id = R.string.screen_app_lock_signout_alert_message), - onDismiss = onSignOut, + onSubmit = onSignOut, ) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt index a2c3b48251..c6139ae492 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerView.kt @@ -36,7 +36,7 @@ fun ChangeServerView( ErrorDialog( modifier = modifier, content = error.message(), - onDismiss = { + onSubmit = { eventSink.invoke(ChangeServerEvents.ClearError) } ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderView.kt index a516c1b4a6..da1106d463 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderView.kt @@ -103,7 +103,7 @@ fun ConfirmAccountProviderView( is ChangeServerError.Error -> { ErrorDialog( content = error.message(), - onDismiss = { + onSubmit = { eventSink.invoke(ConfirmAccountProviderEvents.ClearError) } ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt index bd6437ddba..48fe71e0fc 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt @@ -283,7 +283,7 @@ private fun LoginErrorDialog(error: Throwable, onDismiss: () -> Unit) { ErrorDialog( title = stringResource(id = CommonStrings.dialog_title_error), content = stringResource(loginError(error)), - onDismiss = onDismiss + onSubmit = onDismiss ) } diff --git a/features/login/impl/src/main/res/values-be/translations.xml b/features/login/impl/src/main/res/values-be/translations.xml index f8e675854e..777acc423d 100644 --- a/features/login/impl/src/main/res/values-be/translations.xml +++ b/features/login/impl/src/main/res/values-be/translations.xml @@ -78,10 +78,4 @@ "Тут будуць захоўвацца вашыя размовы - сапраўды гэтак жа, як вы выкарыстоўваеце паштовага правайдара для захоўвання сваіх лістоў." "Вы збіраецеся ўвайсці ў %1$s" "Вы збіраецеся стварыць уліковы запіс на %1$s" - "Зараз існуе высокі попыт на %1$s на %2$s. Калі ласка, вярніцеся ў праграму праз некалькі дзён і паспрабуйце зноў. - -Дзякуй за цярпенне!" - "Вітаем у %1$s!" - "Амаль гатова." - "Вы зарэгістраваны." diff --git a/features/login/impl/src/main/res/values-bg/translations.xml b/features/login/impl/src/main/res/values-bg/translations.xml index cfc51c3f8c..eced3ef828 100644 --- a/features/login/impl/src/main/res/values-bg/translations.xml +++ b/features/login/impl/src/main/res/values-bg/translations.xml @@ -24,5 +24,4 @@ "Това е мястото, където ще живеят вашите разговори — точно както бихте използвали имейл доставчик, за да съхранявате вашите имейли." "На път сте да влезете в %1$s" "На път сте да създадете акаунт в %1$s" - "Добре дошли в %1$s!" diff --git a/features/login/impl/src/main/res/values-cs/translations.xml b/features/login/impl/src/main/res/values-cs/translations.xml index c0f00a87af..d65a5571e4 100644 --- a/features/login/impl/src/main/res/values-cs/translations.xml +++ b/features/login/impl/src/main/res/values-cs/translations.xml @@ -78,10 +78,4 @@ Zkuste se přihlásit ručně nebo naskenujte QR kód pomocí jiného zařízen "Zde budou uloženy vaše konverzace - podobně jako u poskytovatele e-mailových služeb uchováváte své e-maily." "Chystáte se přihlásit do služby %1$s" "Chystáte se vytvořit účet na %1$s" - "Na %2$s je momentálně vysoká poptávka po %1$s. Vraťte se do aplikace za pár dní a zkuste to znovu. - -Díky za trpělivost!" - "Vítá vás %1$s!" - "Jste v pořadníku!" - "Jdete do toho!" diff --git a/features/login/impl/src/main/res/values-de/translations.xml b/features/login/impl/src/main/res/values-de/translations.xml index 2399ec86ba..c2bdf37ca7 100644 --- a/features/login/impl/src/main/res/values-de/translations.xml +++ b/features/login/impl/src/main/res/values-de/translations.xml @@ -78,10 +78,4 @@ Versuche, dich manuell anzumelden, oder scanne den QR-Code mit einem anderen Ger "Hier werden deine Gespräche gespeichert - so wie du deine E-Mails bei einem E-Mail-Anbieter aufbewahren würden." "Du bist dabei, dich bei %1$s anzumelden" "Du bist dabei, ein Konto auf %1$s zu erstellen" - "Derzeit besteht eine hohe Nachfrage nach %1$s auf %2$s. Kehre in ein paar Tagen zur App zurück und versuche es erneut. - -Danke für deine Geduld!" - "Willkommen bei %1$s!" - "Du bist fast am Ziel." - "Du bist dabei." diff --git a/features/login/impl/src/main/res/values-el/translations.xml b/features/login/impl/src/main/res/values-el/translations.xml index 8ff0227168..24f26483fb 100644 --- a/features/login/impl/src/main/res/values-el/translations.xml +++ b/features/login/impl/src/main/res/values-el/translations.xml @@ -78,10 +78,4 @@ "Εδώ θα ζουν οι συνομιλίες σου - όπως θα χρησιμοποιούσες έναν πάροχο email για να διατηρήσεις τα email σου." "Πρόκειται να συνδεθείς στο %1$s" "Πρόκειται να δημιουργήσεις έναν λογαριασμό στο %1$s" - "Υπάρχει μεγάλη ζήτηση για το %1$s στον %2$s αυτή τη στιγμή. Επέστρεψε στην εφαρμογή σε λίγες μέρες και δοκίμασε ξανά. - -Ευχαριστώ για την υπομονή σου!" - "Καλώς ήρθες στο %1$s!" - "Σχεδόν τα κατάφερες." - "Είσαι μέσα." diff --git a/features/login/impl/src/main/res/values-es/translations.xml b/features/login/impl/src/main/res/values-es/translations.xml index c7537c9d7e..60324ae89d 100644 --- a/features/login/impl/src/main/res/values-es/translations.xml +++ b/features/login/impl/src/main/res/values-es/translations.xml @@ -37,10 +37,4 @@ "Aquí es donde se alojarán tus conversaciones — justo como utilizarías un proveedor de correo electrónico para guardar tus correos electrónicos." "Estás a punto de iniciar sesión en %1$s" "Estás a punto de crear una cuenta en %1$s" - "Hay una gran demanda para %1$s en %2$s en este momento. Vuelve a la aplicación en unos días e inténtalo de nuevo. - -¡Gracias por tu paciencia!" - "¡Bienvenido a %1$s!" - "Ya casi has terminado." - "Estás dentro." diff --git a/features/login/impl/src/main/res/values-et/translations.xml b/features/login/impl/src/main/res/values-et/translations.xml index 0558b349b4..f82ea50b91 100644 --- a/features/login/impl/src/main/res/values-et/translations.xml +++ b/features/login/impl/src/main/res/values-et/translations.xml @@ -78,10 +78,4 @@ Proovi käsitsi sisselogimist või skaneeri QR-koodi mõne muu seadmega.""See on koht, kus sinu vestlused elavad – just nagu kasutaksid oma e-kirjade säilitamiseks e-postitenuse pakkujat." "Sa oled sisselogimas koduserverisse %1$s" "Sa oled loomas kasutajakontot koduserveris %1$s" - "%1$s kasutamiseks %2$s koduserveris on hetkel palju huvilisi. Proovi seda samast rakendusest mõne päeva pärast. - -Täname kannatlikkuse eest!" - "Tere tulemast rakendusse %1$s!" - "Peaaegu olemas." - "Oled nüüd jututoas." diff --git a/features/login/impl/src/main/res/values-fr/translations.xml b/features/login/impl/src/main/res/values-fr/translations.xml index 49e513c2a8..a5928ffb3f 100644 --- a/features/login/impl/src/main/res/values-fr/translations.xml +++ b/features/login/impl/src/main/res/values-fr/translations.xml @@ -76,10 +76,4 @@ "C’est ici que vos conversations seront enregistrées, comme vous le feriez avec un fournisseur de messagerie pour conserver vos e-mails." "Vous êtes sur le point de vous connecter à %1$s" "Vous êtes sur le point de créer un compte sur %1$s" - "Il y a une forte demande pour %1$s sur %2$s à l’heure actuelle. Revenez sur l’application dans quelques jours et réessayez. - -Merci pour votre patience !" - "Bienvenue dans %1$s !" - "Vous y êtes presque." - "Vous y êtes." diff --git a/features/login/impl/src/main/res/values-hu/translations.xml b/features/login/impl/src/main/res/values-hu/translations.xml index 8d8bf40f3f..a37288fd6f 100644 --- a/features/login/impl/src/main/res/values-hu/translations.xml +++ b/features/login/impl/src/main/res/values-hu/translations.xml @@ -78,10 +78,4 @@ Próbáljon meg kézileg bejelentkezni, vagy olvassa be a QR-kódot egy másik e "Itt lesznek a beszélgetései – ahogyan egy e-mail-szolgáltatást is használna a levelei kezeléséhez." "Hamarosan bejelentkezik ebbe: %1$s" "Hamarosan létrehoz egy fiókot ezen: %1$s" - "Jelenleg nagy a kereslet a(z) %2$s oldalon futó %1$s iránt. Térjen vissza néhány nap múlva az alkalmazáshoz, és próbálja újra. - -Köszönjük a türelmét!" - "Üdvözli az %1$s!" - "Már majdnem kész van." - "Bent van." diff --git a/features/login/impl/src/main/res/values-in/translations.xml b/features/login/impl/src/main/res/values-in/translations.xml index 97d84ff1f4..749406da04 100644 --- a/features/login/impl/src/main/res/values-in/translations.xml +++ b/features/login/impl/src/main/res/values-in/translations.xml @@ -78,10 +78,4 @@ Coba masuk secara manual, atau pindai kode QR dengan perangkat lain." "Di sinilah percakapan Anda akan berlangsung — sama seperti Anda menggunakan penyedia surel untuk menyimpan surel Anda." "Anda akan masuk ke %1$s" "Anda akan membuat akun di %1$s" - "Ada permintaan tinggi untuk %1$s di %2$s saat ini. Kembalilah ke aplikasi dalam beberapa hari dan coba lagi. - -Terima kasih atas kesabaran Anda!" - "Selamat datang di %1$s!" - "Anda hampir selesai." - "Anda sudah masuk." diff --git a/features/login/impl/src/main/res/values-it/translations.xml b/features/login/impl/src/main/res/values-it/translations.xml index dcd9a7c2ae..eaa5313b03 100644 --- a/features/login/impl/src/main/res/values-it/translations.xml +++ b/features/login/impl/src/main/res/values-it/translations.xml @@ -78,10 +78,4 @@ Prova ad accedere manualmente o scansiona il codice QR con un altro dispositivo. "Qui è dove vivranno le tue conversazioni — proprio come useresti un fornitore di posta elettronica per conservare le tue email." "Stai per accedere a %1$s" "Stai per creare un account su %1$s" - "Al momento c\'è una grande richiesta per %1$s su %2$s. Torna a visitare l\'app tra qualche giorno e riprova. - -Grazie per la pazienza!" - "Benvenuti in %1$s!" - "Ci sei quasi." - "Sei dentro." diff --git a/features/login/impl/src/main/res/values-ka/translations.xml b/features/login/impl/src/main/res/values-ka/translations.xml index 84e97e0a34..6fc49e7b41 100644 --- a/features/login/impl/src/main/res/values-ka/translations.xml +++ b/features/login/impl/src/main/res/values-ka/translations.xml @@ -34,10 +34,4 @@ "აქ იქნება თქვენი საუბრები - ისევე, როგორც თქვენ ელ. ფოსტაში ინახება თქვენი ელ.წერილები." "თქვენ აპირებთ შესვლას %1$s-ში" "თქვენ აპირებთ ანგარიშის შექმნას %1$s-ში" - "ახლა დიდი მოთხოვნაა %1$s-ზე %2$s-ში. დაბრუნდით რამდენიმე დღეში და სცადეთ ერთხელაც. - -მადლობა მოთმენისათვის!" - "კეთილი იყოს თქვენი მობრძანება %1$s-ში!" - "თითქმის მზადაა." - "თქვენ შეხვედით." diff --git a/features/login/impl/src/main/res/values-nl/translations.xml b/features/login/impl/src/main/res/values-nl/translations.xml index 80fbe57afb..0e351f8498 100644 --- a/features/login/impl/src/main/res/values-nl/translations.xml +++ b/features/login/impl/src/main/res/values-nl/translations.xml @@ -35,10 +35,4 @@ "Dit is waar je gesprekken zullen worden bewaard — net zoals je een e-mailprovider zou gebruiken om je e-mails te bewaren." "Je staat op het punt je aan te melden bij %1$s" "Je staat op het punt een account aan te maken op %1$s" - "Er is momenteel veel vraag naar %1$s op %2$s. Kom over een paar dagen terug naar de app en probeer het opnieuw. - -Bedankt voor je geduld!" - "Welkom bij %1$s!" - "Je bent er bijna." - "Je bent binnen." diff --git a/features/login/impl/src/main/res/values-pl/translations.xml b/features/login/impl/src/main/res/values-pl/translations.xml index 4d23e15fe8..6990121a43 100644 --- a/features/login/impl/src/main/res/values-pl/translations.xml +++ b/features/login/impl/src/main/res/values-pl/translations.xml @@ -78,10 +78,4 @@ Spróbuj zalogować się ręcznie lub zeskanuj kod QR na innym urządzeniu.""Tutaj będą przechowywane Twoje konwersacje - w podobnej formie jak wiadomości widnieją na skrzynce e-mail." "Zamierzasz się zalogować do %1$s" "Zamierzasz utworzyć konto na %1$s" - "Obecnie istnieje duże zapotrzebowanie na %1$s na %2$s. Wróć do aplikacji za kilka dni i spróbuj ponownie. - -Dziękujemy za Twoją cierpliwość!" - "Witamy w %1$s!" - "Już prawie gotowe!" - "Witamy!" diff --git a/features/login/impl/src/main/res/values-pt-rBR/translations.xml b/features/login/impl/src/main/res/values-pt-rBR/translations.xml index 4cb9b4f7b0..7b753ffb9f 100644 --- a/features/login/impl/src/main/res/values-pt-rBR/translations.xml +++ b/features/login/impl/src/main/res/values-pt-rBR/translations.xml @@ -34,10 +34,4 @@ "Aqui é onde suas conversas vão ficar — assim como você usa um provedor de e-mails para manter seus e-mails." "Você está prestes a fazer login em %1$s" "Você está prestes a criar uma conta em %1$s" - "Há uma grande demanda por %1$s sobre %2$s no momento. Volte ao aplicativo em alguns dias e tente novamente. - -Obrigado pela sua paciência!" - "Bem-vindo ao %1$s!" - "Você está quase lá." - "Você está dentro." diff --git a/features/login/impl/src/main/res/values-pt/translations.xml b/features/login/impl/src/main/res/values-pt/translations.xml index f5feb0cbdd..f03b48c5dd 100644 --- a/features/login/impl/src/main/res/values-pt/translations.xml +++ b/features/login/impl/src/main/res/values-pt/translations.xml @@ -78,10 +78,4 @@ Tenta iniciar a sessão manualmente ou digitaliza o código QR com outro disposi "É aqui que as tuas conversas vão ficar — tal como num serviço de e-mail." "Irás iniciar sessão em %1$s" "Irás criar uma conta em %1$s" - "Há uma grande procura pela %1$s no %2$s, de momento. Volta à aplicação daqui a uns dias e tenta novamente. - -Obrigado!" - "Bem-vindo à %1$s!" - "Estás quase lá." - "Estás dentro." diff --git a/features/login/impl/src/main/res/values-ro/translations.xml b/features/login/impl/src/main/res/values-ro/translations.xml index 1ff3fe2436..261f16d9f6 100644 --- a/features/login/impl/src/main/res/values-ro/translations.xml +++ b/features/login/impl/src/main/res/values-ro/translations.xml @@ -78,10 +78,4 @@ "Aici vor trăi conversațiile dvs. - la fel cum ați folosi un furnizor de e-mail pentru a vă păstra e-mailurile." "Sunteți pe cale să vă conectați la %1$s" "Sunteți pe cale să creați un cont pe %1$s" - "Există o cerere mare pentru %1$s pentru %2$s în acest moment. Reveniți la aplicație în câteva zile și încercați din nou. - -Vă mulțumim pentru răbdare!" - "Bun venit la%1$s!" - "Sunteți pe lista de așteptare" - "Sunteți conectat!" diff --git a/features/login/impl/src/main/res/values-ru/translations.xml b/features/login/impl/src/main/res/values-ru/translations.xml index c64d683a12..71a2691b4c 100644 --- a/features/login/impl/src/main/res/values-ru/translations.xml +++ b/features/login/impl/src/main/res/values-ru/translations.xml @@ -78,10 +78,4 @@ "Здесь будут храниться ваши разговоры - точно так же, как вы используете почтового провайдера для хранения своих писем." "Вы собираетесь войти в %1$s" "Вы собираетесь создать учетную запись на %1$s" - "В настоящее время существует высокий спрос на %1$s на %2$s. Вернитесь в приложение через несколько дней и попробуйте снова. - -Спасибо за терпение!" - "Добро пожаловать в %1$s!" - "Почти готово." - "Вы зарегистрированы." diff --git a/features/login/impl/src/main/res/values-sk/translations.xml b/features/login/impl/src/main/res/values-sk/translations.xml index fea7879d01..8d862609b7 100644 --- a/features/login/impl/src/main/res/values-sk/translations.xml +++ b/features/login/impl/src/main/res/values-sk/translations.xml @@ -78,10 +78,4 @@ Skúste sa prihlásiť manuálne alebo naskenujte QR kód pomocou iného zariade "Tu budú žiť vaše konverzácie - podobne ako používate poskytovateľa e-mailových služieb na uchovávanie e-mailov." "Chystáte sa prihlásiť do %1$s" "Chystáte sa vytvoriť účet na %1$s" - "Momentálne je veľký dopyt po %1$s na %2$s. Vráťte sa do aplikácie za pár dní a skúste to znova. - -Ďakujeme za trpezlivosť!" - "Vitajte v %1$s!" - "Ste na čakanej listine!" - "Ste dnu!" diff --git a/features/login/impl/src/main/res/values-sv/translations.xml b/features/login/impl/src/main/res/values-sv/translations.xml index d50610adcc..de290469ca 100644 --- a/features/login/impl/src/main/res/values-sv/translations.xml +++ b/features/login/impl/src/main/res/values-sv/translations.xml @@ -78,10 +78,4 @@ Prova att logga in manuellt eller skanna QR-koden med en annan enhet." "Det är här dina konversationer kommer att sparas - precis som du skulle använda en e-postleverantör för att spara dina e-brev." "Du är på väg att logga in på %1$s" "Du är på väg att skapa ett konto på %1$s" - "Det finns en stor efterfrågan på %1$s på %2$s just nu. Kom tillbaka till appen om några dagar och försök igen. - -Tack för ditt tålamod!" - "Välkommen till %1$s!" - "Du är nästan framme." - "Du är inne." diff --git a/features/login/impl/src/main/res/values-uk/translations.xml b/features/login/impl/src/main/res/values-uk/translations.xml index 9cb6eb1f5f..df436a9a69 100644 --- a/features/login/impl/src/main/res/values-uk/translations.xml +++ b/features/login/impl/src/main/res/values-uk/translations.xml @@ -78,10 +78,4 @@ "Тут будуть зберігатися Ваші розмови - так само, як Ви використовуєте поштову скриньку для зберігання своїх електронних листів." "Ви збираєтесь увійти в %1$s" "Ви збираєтеся створити обліковий запис на %1$s" - "На цей момент існує високий попит на %1$s в %2$s. Поверніться до застосунку через кілька днів і спробуйте ще раз. - -Дякуємо за терпіння!" - "Ласкаво просимо до %1$s!" - "Майже готово." - "Готово." diff --git a/features/login/impl/src/main/res/values-uz/translations.xml b/features/login/impl/src/main/res/values-uz/translations.xml index 67dc5129d7..db16e17b09 100644 --- a/features/login/impl/src/main/res/values-uz/translations.xml +++ b/features/login/impl/src/main/res/values-uz/translations.xml @@ -33,10 +33,4 @@ "Bu sizning suhbatlaringiz yashaydigan joy - xuddi siz elektron pochta xabarlaringizni saqlash uchun elektron pochta provayderidan foydalanganingiz kabi." "Siz tizimga kirmoqchisiz%1$s" "Hisob yaratmoqchisiz%1$s" - "Hozirgi paytda %2$sga %1$sda talab yuqori. Bir necha kundan keyin ilovaga qayting va qaytadan urining. - -Sabr-toqatingiz uchun rahmat!" - "%1$sga Xush kelibsiz!" - "Siz deyarli keldingiz." - "Siz kirdingiz." diff --git a/features/login/impl/src/main/res/values-zh-rTW/translations.xml b/features/login/impl/src/main/res/values-zh-rTW/translations.xml index d345095c4b..b66cfca31f 100644 --- a/features/login/impl/src/main/res/values-zh-rTW/translations.xml +++ b/features/login/impl/src/main/res/values-zh-rTW/translations.xml @@ -29,5 +29,4 @@ "您的所有對話將保存於此,就如同您的電子郵件供應商會保存您的電子郵件一樣。" "您即將登入 %1$s" "您即將在 %1$s 建立帳號" - "歡迎使用 %1$s!" diff --git a/features/login/impl/src/main/res/values-zh/translations.xml b/features/login/impl/src/main/res/values-zh/translations.xml index 0afd6dad93..2f24aacf69 100644 --- a/features/login/impl/src/main/res/values-zh/translations.xml +++ b/features/login/impl/src/main/res/values-zh/translations.xml @@ -78,10 +78,4 @@ "这是您的对话将进行的地方,就像您使用电子邮件提供商来保存电子邮件一样。" "即将登录 %1$s" "即将在 %1$s 上创建一个账户" - "目前 %1$s 上 %2$s 的负载很大。过几天再回来试试吧。 - -感谢您的耐心!" - "欢迎使用 %1$s" - "马上就好。" - "您已加入。" diff --git a/features/login/impl/src/main/res/values/localazy.xml b/features/login/impl/src/main/res/values/localazy.xml index cade81c4f2..b0b6252d52 100644 --- a/features/login/impl/src/main/res/values/localazy.xml +++ b/features/login/impl/src/main/res/values/localazy.xml @@ -78,10 +78,4 @@ Try signing in manually, or scan the QR code with another device." "This is where your conversations will live — just like you would use an email provider to keep your emails." "You’re about to sign in to %1$s" "You’re about to create an account on %1$s" - "There\'s a high demand for %1$s on %2$s at the moment. Come back to the app in a few days and try again. - -Thanks for your patience!" - "Welcome to %1$s!" - "You’re almost there." - "You\'re in." diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt index 8a03ed857c..a9c12fe732 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListView.kt @@ -108,7 +108,7 @@ private fun PinnedMessagesListContent( ErrorDialog( title = stringResource(id = CommonStrings.error_unknown), content = stringResource(id = CommonStrings.error_failed_loading_messages), - onDismiss = onErrorDismiss + onSubmit = onErrorDismiss ) } PinnedMessagesListState.Empty -> PinnedMessagesListEmpty() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/focus/FocusRequestStateView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/focus/FocusRequestStateView.kt index 7bd5301208..75d4d5ebac 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/focus/FocusRequestStateView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/focus/FocusRequestStateView.kt @@ -36,7 +36,7 @@ fun FocusRequestStateView( } ErrorDialog( content = errorMessage, - onDismiss = onClearFocusRequestState, + onSubmit = onClearFocusRequestState, modifier = modifier, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageSendingFailedDialog.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageSendingFailedDialog.kt index f2cc385553..ffed5f31ac 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageSendingFailedDialog.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageSendingFailedDialog.kt @@ -19,7 +19,7 @@ internal fun VoiceMessageSendingFailedDialog( ErrorDialog( title = stringResource(CommonStrings.common_error), content = stringResource(CommonStrings.error_failed_uploading_voice_message), - onDismiss = onDismiss, + onSubmit = onDismiss, submitText = stringResource(CommonStrings.action_ok), ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt index 25cc166103..22884bc6ed 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsView.kt @@ -259,7 +259,7 @@ private fun InvalidNotificationSettingsView( ErrorDialog( title = stringResource(id = CommonStrings.dialog_title_error), content = stringResource(id = R.string.screen_notification_settings_failed_fixing_configuration), - onDismiss = onDismissError + onSubmit = onDismissError ) } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsView.kt index bfc19026a9..a3f39895df 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/RolesAndPermissionsView.kt @@ -124,7 +124,7 @@ fun RolesAndPermissionsView( is AsyncAction.Failure -> { ErrorDialog( content = stringResource(CommonStrings.error_unknown), - onDismiss = { state.eventSink(RolesAndPermissionsEvents.CancelPendingAction) } + onSubmit = { state.eventSink(RolesAndPermissionsEvents.CancelPendingAction) } ) } else -> Unit diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt index 2f7cfb16a0..ce362373f2 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/rolesandpermissions/changeroles/ChangeRolesView.kt @@ -210,7 +210,7 @@ fun ChangeRolesView( is AsyncAction.Failure -> { ErrorDialog( content = stringResource(CommonStrings.error_unknown), - onDismiss = { state.eventSink(ChangeRolesEvent.ClearError) } + onSubmit = { state.eventSink(ChangeRolesEvent.ClearError) } ) } is AsyncAction.Success -> { diff --git a/features/roomlist/impl/src/main/res/values/localazy.xml b/features/roomlist/impl/src/main/res/values/localazy.xml index ff6c626c63..36dc4b8d65 100644 --- a/features/roomlist/impl/src/main/res/values/localazy.xml +++ b/features/roomlist/impl/src/main/res/values/localazy.xml @@ -2,6 +2,7 @@ "Log Out & Upgrade" "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later." + "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app." "Upgrade available" "Generate a new recovery key that can be used to restore your encrypted message history in case you lose access to your devices." "Set up recovery" diff --git a/features/securebackup/impl/src/main/res/values-be/translations.xml b/features/securebackup/impl/src/main/res/values-be/translations.xml index 75e4c2ccb9..910350f41e 100644 --- a/features/securebackup/impl/src/main/res/values-be/translations.xml +++ b/features/securebackup/impl/src/main/res/values-be/translations.xml @@ -38,7 +38,6 @@ "Паўтарыце спробу, каб пацвердзіць доступ да рэзервовай копіі чата." "Няправільны ключ аднаўлення" "Калі ў вас ёсць ключ аднаўлення або парольная фраза, гэта таксама будзе працаваць." - "Ключ аднаўлення або код доступу" "Увесці…" "Страцілі ключ аднаўлення?" "Ключ аднаўлення пацверджаны" diff --git a/features/securebackup/impl/src/main/res/values-cs/translations.xml b/features/securebackup/impl/src/main/res/values-cs/translations.xml index 6425f52b66..ba113f9c89 100644 --- a/features/securebackup/impl/src/main/res/values-cs/translations.xml +++ b/features/securebackup/impl/src/main/res/values-cs/translations.xml @@ -39,7 +39,6 @@ "Zkuste prosím znovu potvrdit přístup k záloze chatu." "Nesprávný klíč pro obnovení" "Pokud máte bezpečnostní klíč nebo bezpečnostní frázi, bude to fungovat také." - "Klíč pro obnovení nebo přístupový kód" "Zadejte…" "Ztratili jste klíč pro obnovení?" "Klíč pro obnovení potvrzen" diff --git a/features/securebackup/impl/src/main/res/values-de/translations.xml b/features/securebackup/impl/src/main/res/values-de/translations.xml index c95e51db7e..413ae1ea81 100644 --- a/features/securebackup/impl/src/main/res/values-de/translations.xml +++ b/features/securebackup/impl/src/main/res/values-de/translations.xml @@ -51,10 +51,6 @@ Das bedeutet:" "Bitte versuche es noch einmal, um den Zugriff auf dein Chat-Backup zu bestätigen." "Falscher Wiederherstellungsschlüssel" "Dies funktioniert auch mit einem Sicherheitsschlüssel oder Sicherheitsphrase." - - "Wiederherstellungsschlüssel" - " oder Passcode" - "Eingeben…" "Hast du deinen Wiederherstellungschlüssel vergessen?" "Wiederherstellungsschlüssel bestätigt" diff --git a/features/securebackup/impl/src/main/res/values-el/translations.xml b/features/securebackup/impl/src/main/res/values-el/translations.xml index e62f465743..b3c6eb5a54 100644 --- a/features/securebackup/impl/src/main/res/values-el/translations.xml +++ b/features/securebackup/impl/src/main/res/values-el/translations.xml @@ -33,7 +33,6 @@ "Προσπάθησε ξανά για να επιβεβαιώσεις την πρόσβαση στο αντίγραφο ασφαλείας της συνομιλίας σου." "Λανθασμένο κλειδί ανάκτησης" "Εάν έχεις ένα κλειδί ασφαλείας ή μια φράση ασφαλείας, θα λειτουργήσει επίσης." - "Κλειδί ανάκτησης ή κωδικός πρόσβασης" "Εισαγωγή…" "Έχασες το κλειδί ανάκτησης;" "Επιβεβαιώθηκε το κλειδί ανάκτησης" diff --git a/features/securebackup/impl/src/main/res/values-et/translations.xml b/features/securebackup/impl/src/main/res/values-et/translations.xml index 2c3aa2d12b..b618432839 100644 --- a/features/securebackup/impl/src/main/res/values-et/translations.xml +++ b/features/securebackup/impl/src/main/res/values-et/translations.xml @@ -39,7 +39,6 @@ "Kinnitamaks ligipääsu sinu vestluse varukoopiale, palun proovi uuesti" "Vigane taastevõti" "Kui sul on turvavõti või turvafraas, siis need toimivad ka." - "Taastevõti või turvafraas" "Sisesta…" "Kas sa oled taastevõtme kaotanud?" "Taastevõti on kinnitatud" diff --git a/features/securebackup/impl/src/main/res/values-fr/translations.xml b/features/securebackup/impl/src/main/res/values-fr/translations.xml index 6656e0a8e3..1b36266924 100644 --- a/features/securebackup/impl/src/main/res/values-fr/translations.xml +++ b/features/securebackup/impl/src/main/res/values-fr/translations.xml @@ -37,7 +37,6 @@ "Veuillez réessayer afin de pouvoir accéder à vos anciens messages." "Clé de récupération incorrecte" "Si vous avez une clé de sécurité ou une phrase de sécurité, cela fonctionnera également." - "Clé de récupération" "Saisissez la clé ici…" "Clé de récupération perdue?" "Clé de récupération confirmée" diff --git a/features/securebackup/impl/src/main/res/values-hu/translations.xml b/features/securebackup/impl/src/main/res/values-hu/translations.xml index 20575540b7..48fe08a31b 100644 --- a/features/securebackup/impl/src/main/res/values-hu/translations.xml +++ b/features/securebackup/impl/src/main/res/values-hu/translations.xml @@ -39,7 +39,6 @@ "Próbálja meg újra megerősíteni a csevegés biztonsági mentéséhez való hozzáférését." "Helytelen helyreállítási kulcs" "Ha van biztonsági kulcsa vagy biztonsági jelmondata, akkor ez is fog működni." - "Helyreállítási kulcs vagy jelkód" "Megadás…" "Elvesztette a helyreállítási kulcsát?" "Helyreállítási kulcs megerősítve" diff --git a/features/securebackup/impl/src/main/res/values-in/translations.xml b/features/securebackup/impl/src/main/res/values-in/translations.xml index 83fa1f8092..62968d3471 100644 --- a/features/securebackup/impl/src/main/res/values-in/translations.xml +++ b/features/securebackup/impl/src/main/res/values-in/translations.xml @@ -33,7 +33,6 @@ "Silakan coba lagi untuk mengonfirmasi akses ke cadangan percakapan Anda." "Kunci pemulihan salah" "Jika Anda memiliki kunci keamanan atau frasa keamanan, ini juga bisa digunakan." - "Kunci pemulihan atau kode sandi" "Masukkan…" "Kehilangan kunci pemulihan Anda?" "Kunci pemulihan dikonfirmasi" diff --git a/features/securebackup/impl/src/main/res/values-it/translations.xml b/features/securebackup/impl/src/main/res/values-it/translations.xml index c1d67299ba..0e069b0ab2 100644 --- a/features/securebackup/impl/src/main/res/values-it/translations.xml +++ b/features/securebackup/impl/src/main/res/values-it/translations.xml @@ -38,7 +38,6 @@ "Riprova per confermare l\'accesso al backup della chat." "Chiave di recupero errata" "Se hai una chiave di sicurezza o una password, andrà bene anche questo." - "Chiave di recupero o codice di accesso" "Inserisci…" "Hai perso la chiave di recupero?" "Chiave di recupero confermata" diff --git a/features/securebackup/impl/src/main/res/values-pl/translations.xml b/features/securebackup/impl/src/main/res/values-pl/translations.xml index eea550627f..d708e18bab 100644 --- a/features/securebackup/impl/src/main/res/values-pl/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pl/translations.xml @@ -38,7 +38,6 @@ "Spróbuj ponownie, aby potwierdzić dostęp do backupu czatu." "Nieprawidłowy klucz przywracania" "To też zadziała, jeśli posiadasz klucz lub frazę bezpieczeństwa." - "Klucz przywracania lub hasło" "Wprowadź…" "Zgubiłeś swój kod przywracania?" "Potwierdzono klucz przywracania" diff --git a/features/securebackup/impl/src/main/res/values-pt/translations.xml b/features/securebackup/impl/src/main/res/values-pt/translations.xml index f93e5dedf4..0e409ea22c 100644 --- a/features/securebackup/impl/src/main/res/values-pt/translations.xml +++ b/features/securebackup/impl/src/main/res/values-pt/translations.xml @@ -38,7 +38,6 @@ "Por favor, tenta novamente para confirmar o acesso à tua cópia de segurança das conversas." "Chave de recuperação incorreta" "Também funciona se tiveres uma chave ou frase de segurança." - "Chave ou código de recuperação" "Inserir…" "Perdeste a tua chave?" "Chave de recuperação confirmada" diff --git a/features/securebackup/impl/src/main/res/values-ro/translations.xml b/features/securebackup/impl/src/main/res/values-ro/translations.xml index 6b2f2e31dc..7266533d78 100644 --- a/features/securebackup/impl/src/main/res/values-ro/translations.xml +++ b/features/securebackup/impl/src/main/res/values-ro/translations.xml @@ -33,7 +33,6 @@ "Vă rugăm să încercați din nou să confirmați accesul la backup." "Cheie de recuperare incorectă" "Dacă aveți o cheie de securitate sau o frază de securitate, aceasta va funcționa și ea." - "Cheie de recuperare sau cod de acces" "Introduceți…" "Ați pierdut cheia de recuperare?" "Cheia de recuperare confirmată" diff --git a/features/securebackup/impl/src/main/res/values-ru/translations.xml b/features/securebackup/impl/src/main/res/values-ru/translations.xml index 8866dc9613..ae45ab45eb 100644 --- a/features/securebackup/impl/src/main/res/values-ru/translations.xml +++ b/features/securebackup/impl/src/main/res/values-ru/translations.xml @@ -60,10 +60,6 @@ "ключ восстановления" "Если у вас есть пароль для восстановления или секретный пароль/ключ, это тоже сработает." - - "Ключ восстановления" - " или пароль" - "Вход…" "Потеряли ключ восстановления?" diff --git a/features/securebackup/impl/src/main/res/values-sk/translations.xml b/features/securebackup/impl/src/main/res/values-sk/translations.xml index 8a088f4245..24d80c6b00 100644 --- a/features/securebackup/impl/src/main/res/values-sk/translations.xml +++ b/features/securebackup/impl/src/main/res/values-sk/translations.xml @@ -39,7 +39,6 @@ "Skúste prosím znova potvrdiť prístup k vašej zálohe konverzácie." "Nesprávny kľúč na obnovenie" "Ak máte bezpečnostný kľúč alebo bezpečnostnú frázu, bude to fungovať tiež." - "Kľúč na obnovenie alebo prístupový kód" "Zadať…" "Stratili ste kľúč na obnovenie?" "Kľúč na obnovu potvrdený" diff --git a/features/securebackup/impl/src/main/res/values-sv/translations.xml b/features/securebackup/impl/src/main/res/values-sv/translations.xml index 3599320cd8..7b2364f450 100644 --- a/features/securebackup/impl/src/main/res/values-sv/translations.xml +++ b/features/securebackup/impl/src/main/res/values-sv/translations.xml @@ -39,7 +39,6 @@ "Vänligen pröva igen för att bekräfta åtkomsten till din chattsäkerhetskopia." "Felaktig återställningsnyckel" "Om du har en säkerhetsnyckel eller säkerhetsfras så funkar den också." - "Återställningsnyckel eller lösenkod" "Ange …" "Blivit av med din återställningsnyckel?" "Återställningsnyckel bekräftad" diff --git a/features/securebackup/impl/src/main/res/values-uk/translations.xml b/features/securebackup/impl/src/main/res/values-uk/translations.xml index 14e47f8bad..7d88980f8b 100644 --- a/features/securebackup/impl/src/main/res/values-uk/translations.xml +++ b/features/securebackup/impl/src/main/res/values-uk/translations.xml @@ -38,7 +38,6 @@ "Будь ласка, спробуйте ще раз, щоб підтвердити доступ до резервної копії чату." "Неправильний ключ відновлення" "Якщо у вас є ключ безпеки або фраза безпеки, це теж спрацює." - "Ключ відновлення або код допуску" "Ввести…" "Загубили ключ відновлення?" "Ключ відновлення підтверджено" diff --git a/features/securebackup/impl/src/main/res/values-zh/translations.xml b/features/securebackup/impl/src/main/res/values-zh/translations.xml index 0b4f12b17a..c8f2b7d9ed 100644 --- a/features/securebackup/impl/src/main/res/values-zh/translations.xml +++ b/features/securebackup/impl/src/main/res/values-zh/translations.xml @@ -38,7 +38,6 @@ "请重试以访问您的聊天备份。" "恢复密钥不正确" "如果您有安全密钥或安全短语,也可以用。" - "恢复密钥或密码" "输入……" "丢失了恢复密钥?" "恢复密钥已确认" diff --git a/features/securebackup/impl/src/main/res/values/localazy.xml b/features/securebackup/impl/src/main/res/values/localazy.xml index f4795c23da..55c6c547f5 100644 --- a/features/securebackup/impl/src/main/res/values/localazy.xml +++ b/features/securebackup/impl/src/main/res/values/localazy.xml @@ -39,7 +39,6 @@ "Please try again to confirm access to your chat backup." "Incorrect recovery key" "If you have a security key or security phrase, this will work too." - "Recovery key or passcode" "Enter…" "Lost your recovery key?" "Recovery key confirmed" diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt index 08c2f352e6..6e42909f0b 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/async/AsyncActionView.kt @@ -48,7 +48,7 @@ fun AsyncActionView( ErrorDialog( title = errorTitle(async.error), content = errorMessage(async.error), - onDismiss = onErrorDismiss + onSubmit = onErrorDismiss ) } else { RetryDialog( diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt index acef5bf9f9..add7bf2904 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/dialogs/ErrorDialog.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.window.DialogProperties import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementThemedPreview import io.element.android.libraries.designsystem.preview.PreviewGroup @@ -25,17 +26,23 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun ErrorDialog( content: String, - onDismiss: () -> Unit, + onSubmit: () -> Unit, modifier: Modifier = Modifier, - title: String = ErrorDialogDefaults.title, + title: String? = ErrorDialogDefaults.title, submitText: String = ErrorDialogDefaults.submitText, + onDismiss: () -> Unit = onSubmit, + canDismiss: Boolean = true, ) { - BasicAlertDialog(modifier = modifier, onDismissRequest = onDismiss) { + BasicAlertDialog( + modifier = modifier, + onDismissRequest = onDismiss, + properties = DialogProperties(dismissOnClickOutside = canDismiss, dismissOnBackPress = canDismiss) + ) { ErrorDialogContent( title = title, content = content, submitText = submitText, - onSubmitClick = onDismiss, + onSubmitClick = onSubmit, ) } } @@ -44,7 +51,7 @@ fun ErrorDialog( private fun ErrorDialogContent( content: String, onSubmitClick: () -> Unit, - title: String = ErrorDialogDefaults.title, + title: String? = ErrorDialogDefaults.title, submitText: String = ErrorDialogDefaults.submitText, ) { SimpleAlertDialogContent( @@ -78,6 +85,6 @@ internal fun ErrorDialogContentPreview() { internal fun ErrorDialogPreview() = ElementPreview { ErrorDialog( content = "Content", - onDismiss = {}, + onSubmit = {}, ) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index e45686b1a2..3b7441395a 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -131,6 +131,9 @@ interface MatrixClient : Closeable { /** Returns `true` if the home server supports native sliding sync. */ suspend fun isNativeSlidingSyncSupported(): Boolean - /** Returns `true` if the current session is using native sliding sync. */ + /** Returns `true` if the home server supports sliding sync using a proxy. */ + suspend fun isSlidingSyncProxySupported(): Boolean + + /** Returns `true` if the current session is using native sliding sync, `false` if it's using a proxy. */ fun isUsingNativeSlidingSync(): Boolean } 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 0fc9f6695b..c9989796e5 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 @@ -534,6 +534,10 @@ class RustMatrixClient( return client.availableSlidingSyncVersions().contains(SlidingSyncVersion.Native) } + override suspend fun isSlidingSyncProxySupported(): Boolean { + return client.availableSlidingSyncVersions().any { it is SlidingSyncVersion.Proxy } + } + override fun isUsingNativeSlidingSync(): Boolean { return client.session().slidingSyncVersion == SlidingSyncVersion.Native } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index 7681dda6f0..ad4c2d1549 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -7,7 +7,6 @@ package io.element.android.libraries.matrix.impl -import io.element.android.appconfig.AuthenticationConfig import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.featureflag.api.FeatureFlagService @@ -19,12 +18,10 @@ import io.element.android.libraries.matrix.impl.paths.getSessionPaths import io.element.android.libraries.matrix.impl.proxy.ProxyProvider import io.element.android.libraries.matrix.impl.util.anonymizedTokens import io.element.android.libraries.network.useragent.UserAgentProvider -import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.sessionstorage.api.SessionData import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.services.toolbox.api.systemclock.SystemClock import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.Session @@ -47,7 +44,6 @@ class RustMatrixClientFactory @Inject constructor( private val proxyProvider: ProxyProvider, private val clock: SystemClock, private val utdTracker: UtdTracker, - private val appPreferencesStore: AppPreferencesStore, private val featureFlagService: FeatureFlagService, ) { suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) { @@ -55,7 +51,7 @@ class RustMatrixClientFactory @Inject constructor( val client = getBaseClientBuilder( sessionPaths = sessionData.getSessionPaths(), passphrase = sessionData.passphrase, - restore = true, + slidingSyncType = ClientBuilderSlidingSync.Restored, ) .homeserverUrl(sessionData.homeserverUrl) .username(sessionData.userId) @@ -88,16 +84,8 @@ class RustMatrixClientFactory @Inject constructor( internal suspend fun getBaseClientBuilder( sessionPaths: SessionPaths, passphrase: String?, - restore: Boolean, + slidingSyncType: ClientBuilderSlidingSync, ): ClientBuilder { - val slidingSync = when { - // Always check restore first, since otherwise other values could accidentally override the already persisted config - restore -> ClientBuilderSlidingSync.Restored - AuthenticationConfig.SLIDING_SYNC_PROXY_URL != null -> ClientBuilderSlidingSync.CustomProxy(AuthenticationConfig.SLIDING_SYNC_PROXY_URL!!) - appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first() -> ClientBuilderSlidingSync.Simplified - else -> ClientBuilderSlidingSync.Discovered - } - return ClientBuilder() .sessionPaths( dataPath = sessionPaths.fileDirectory.absolutePath, @@ -117,9 +105,9 @@ class RustMatrixClientFactory @Inject constructor( ) .run { // Apply sliding sync version settings - when (slidingSync) { + when (slidingSyncType) { ClientBuilderSlidingSync.Restored -> this - is ClientBuilderSlidingSync.CustomProxy -> slidingSyncVersionBuilder(SlidingSyncVersionBuilder.Proxy(slidingSync.url)) + is ClientBuilderSlidingSync.CustomProxy -> slidingSyncVersionBuilder(SlidingSyncVersionBuilder.Proxy(slidingSyncType.url)) ClientBuilderSlidingSync.Discovered -> slidingSyncVersionBuilder(SlidingSyncVersionBuilder.DiscoverProxy) ClientBuilderSlidingSync.Simplified -> slidingSyncVersionBuilder(SlidingSyncVersionBuilder.DiscoverNative) ClientBuilderSlidingSync.ForcedSimplified -> slidingSyncVersionBuilder(SlidingSyncVersionBuilder.Native) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt index 344ae588a1..47a010cf2d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationService.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.impl.auth import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.appconfig.AuthenticationConfig import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.extensions.mapFailure import io.element.android.libraries.di.AppScope @@ -19,6 +20,7 @@ import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.impl.ClientBuilderSlidingSync import io.element.android.libraries.matrix.impl.RustMatrixClientFactory import io.element.android.libraries.matrix.impl.auth.qrlogin.QrErrorMapper import io.element.android.libraries.matrix.impl.auth.qrlogin.SdkQrCodeLoginData @@ -28,6 +30,7 @@ import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator import io.element.android.libraries.matrix.impl.mapper.toSessionData import io.element.android.libraries.matrix.impl.paths.SessionPaths import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory +import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.sessionstorage.api.LoggedInState import io.element.android.libraries.sessionstorage.api.LoginType import io.element.android.libraries.sessionstorage.api.SessionStore @@ -35,9 +38,13 @@ import kotlinx.coroutines.CancellationException import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Client +import org.matrix.rustcomponents.sdk.ClientBuilder import org.matrix.rustcomponents.sdk.HumanQrLoginException +import org.matrix.rustcomponents.sdk.OidcConfiguration +import org.matrix.rustcomponents.sdk.QrCodeData import org.matrix.rustcomponents.sdk.QrCodeDecodeException import org.matrix.rustcomponents.sdk.QrLoginProgress import org.matrix.rustcomponents.sdk.QrLoginProgressListener @@ -55,6 +62,7 @@ class RustMatrixAuthenticationService @Inject constructor( private val rustMatrixClientFactory: RustMatrixClientFactory, private val passphraseGenerator: PassphraseGenerator, private val oidcConfigurationProvider: OidcConfigurationProvider, + private val appPreferencesStore: AppPreferencesStore, ) : MatrixAuthenticationService { // Passphrase which will be used for new sessions. Existing sessions will use the passphrase // stored in the SessionData. @@ -117,9 +125,10 @@ class RustMatrixAuthenticationService @Inject constructor( withContext(coroutineDispatchers.io) { val emptySessionPath = rotateSessionPath() runCatching { - val client = getBaseClientBuilder(emptySessionPath) - .serverNameOrHomeserverUrl(homeserver) - .build() + val client = makeClient(sessionPaths = emptySessionPath) { + serverNameOrHomeserverUrl(homeserver) + } + currentClient = client val homeServerDetails = client.homeserverLoginDetails().map() currentHomeserver.value = homeServerDetails.copy(url = homeserver) @@ -207,23 +216,24 @@ class RustMatrixAuthenticationService @Inject constructor( override suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit) = withContext(coroutineDispatchers.io) { + val sdkQrCodeLoginData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData val emptySessionPaths = rotateSessionPath() + val oidcConfiguration = oidcConfigurationProvider.get() + val progressListener = object : QrLoginProgressListener { + override fun onUpdate(state: QrLoginProgress) { + Timber.d("QR Code login progress: $state") + progress(state.toStep()) + } + } runCatching { - val client = rustMatrixClientFactory.getBaseClientBuilder( + val client = makeQrCodeLoginClient( sessionPaths = emptySessionPaths, passphrase = pendingPassphrase, - restore = false, + qrCodeData = sdkQrCodeLoginData, + oidcConfiguration = oidcConfiguration, + progressListener = progressListener, ) - .buildWithQrCode( - qrCodeData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData, - oidcConfiguration = oidcConfigurationProvider.get(), - progressListener = object : QrLoginProgressListener { - override fun onUpdate(state: QrLoginProgress) { - Timber.d("QR Code login progress: $state") - progress(state.toStep()) - } - } - ) + client.use { rustClient -> val sessionData = rustClient.session() .toSessionData( @@ -249,14 +259,80 @@ class RustMatrixAuthenticationService @Inject constructor( } } - private suspend fun getBaseClientBuilder( + private suspend fun makeClient( sessionPaths: SessionPaths, - ) = rustMatrixClientFactory - .getBaseClientBuilder( - sessionPaths = sessionPaths, - passphrase = pendingPassphrase, - restore = false, - ) + config: suspend ClientBuilder.() -> ClientBuilder, + ): Client { + val slidingSyncType = getSlidingSyncType() + if (slidingSyncType is ClientBuilderSlidingSync.Simplified) { + Timber.d("Creating client with simplified sliding sync") + try { + return rustMatrixClientFactory + .getBaseClientBuilder( + sessionPaths = sessionPaths, + passphrase = pendingPassphrase, + slidingSyncType = slidingSyncType, + ) + .run { config() } + .build() + } catch (e: HumanQrLoginException.SlidingSyncNotAvailable) { + Timber.e(e, "Failed to create client with simplified sliding sync, trying with Proxy now") + } + } + Timber.d("Creating client with Proxy sliding sync") + return rustMatrixClientFactory + .getBaseClientBuilder( + sessionPaths = sessionPaths, + passphrase = pendingPassphrase, + slidingSyncType = getSlidingSyncProxy(), + ) + .run { config() } + .build() + } + + private suspend fun makeQrCodeLoginClient( + sessionPaths: SessionPaths, + passphrase: String?, + qrCodeData: QrCodeData, + oidcConfiguration: OidcConfiguration, + progressListener: QrLoginProgressListener, + ): Client { + val slidingSyncType = getSlidingSyncType() + if (slidingSyncType is ClientBuilderSlidingSync.Simplified) { + Timber.d("Creating client for QR Code login with simplified sliding sync") + try { + return rustMatrixClientFactory + .getBaseClientBuilder( + sessionPaths = sessionPaths, + passphrase = pendingPassphrase, + slidingSyncType = slidingSyncType, + ) + .passphrase(passphrase) + .buildWithQrCode(qrCodeData, oidcConfiguration, progressListener) + } catch (e: HumanQrLoginException.SlidingSyncNotAvailable) { + Timber.e(e, "Failed to create client with simplified sliding sync, trying with Proxy now") + } + } + Timber.d("Creating client for QR Code login with Proxy sliding sync") + return rustMatrixClientFactory + .getBaseClientBuilder( + sessionPaths = sessionPaths, + passphrase = pendingPassphrase, + slidingSyncType = getSlidingSyncProxy(), + ) + .passphrase(passphrase) + .buildWithQrCode(qrCodeData, oidcConfiguration, progressListener) + } + + private suspend fun getSlidingSyncType(nativeSlidingSyncFailed: Boolean = false) = when { + appPreferencesStore.isSimplifiedSlidingSyncEnabledFlow().first() && !nativeSlidingSyncFailed -> ClientBuilderSlidingSync.Simplified + else -> getSlidingSyncProxy() + } + + private fun getSlidingSyncProxy() = when { + AuthenticationConfig.SLIDING_SYNC_PROXY_URL != null -> ClientBuilderSlidingSync.CustomProxy(AuthenticationConfig.SLIDING_SYNC_PROXY_URL!!) + else -> ClientBuilderSlidingSync.Discovered + } private fun clear() { currentClient?.close() diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index ed484f4426..5db394f77d 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -79,6 +79,7 @@ class FakeMatrixClient( private val userIdServerNameLambda: () -> String = { lambdaError() }, private val getUrlLambda: (String) -> Result = { lambdaError() }, var isNativeSlidingSyncSupportedLambda: suspend () -> Boolean = { true }, + var isSlidingSyncProxySupportedLambda: suspend () -> Boolean = { true }, var isUsingNativeSlidingSyncLambda: () -> Boolean = { true }, ) : MatrixClient { var setDisplayNameCalled: Boolean = false @@ -324,6 +325,10 @@ class FakeMatrixClient( return isNativeSlidingSyncSupportedLambda() } + override suspend fun isSlidingSyncProxySupported(): Boolean { + return isSlidingSyncProxySupportedLambda() + } + override fun isUsingNativeSlidingSync(): Boolean { return isUsingNativeSlidingSyncLambda() } diff --git a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt index 8e09547fb4..ab985e798d 100644 --- a/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt +++ b/libraries/preferences/impl/src/main/kotlin/io/element/android/libraries/preferences/impl/store/DefaultAppPreferencesStore.kt @@ -87,7 +87,7 @@ class DefaultAppPreferencesStore @Inject constructor( override fun isSimplifiedSlidingSyncEnabledFlow(): Flow { return store.data.map { prefs -> - prefs[simplifiedSlidingSyncKey] ?: false + prefs[simplifiedSlidingSyncKey] ?: true } } diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index f7c3213ba4..b4fec91a0c 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -36,6 +36,7 @@ "Back" "Call" "Cancel" + "Cancel for now" "Choose photo" "Clear" "Close" @@ -283,6 +284,12 @@ Reason: %1$s." "Pinned messages" "You\'re about to go to your %1$s account to reset your identity. Afterwards you\'ll be taken back to the app." "Can\'t confirm? Go to your account to reset your identity." + "Withdraw verification and send" + "You can withdraw your verification and send this message anyway, or you can cancel for now and try again later after reverifying %1$s." + "Your message was not sent because %1$s’s verified identity has changed" + "Send message anyway" + "%1$s is using one or more unverified devices. You can send the message anyway, or you can cancel for now and try again later after %2$s has verified all their devices." + "Your message was not sent because %1$s has not verified one or more devices" "Pinned messages" "Failed processing media to upload, please try again." "Could not retrieve user details" @@ -304,6 +311,8 @@ Reason: %1$s." "Open in Google Maps" "Open in OpenStreetMap" "Share this location" + "Message not sent because %1$s’s verified identity has changed." + "Message not sent because %1$s has not verified one or more devices." "Location" "Version: %1$s (%2$s)" "en" diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt index 5319baf10e..19e1390f47 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/MainActivity.kt @@ -55,11 +55,11 @@ class MainActivity : ComponentActivity() { proxyProvider = proxyProvider, clock = DefaultSystemClock(), utdTracker = UtdTracker(NoopAnalyticsService()), - appPreferencesStore = InMemoryAppPreferencesStore(), featureFlagService = AlwaysEnabledFeatureFlagService(), ), passphraseGenerator = NullPassphraseGenerator(), oidcConfigurationProvider = OidcConfigurationProvider(baseDirectory), + appPreferencesStore = InMemoryAppPreferencesStore(), ) } diff --git a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/AppErrorView.kt b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/AppErrorView.kt index 80d3de2dfe..2bd46eeb00 100644 --- a/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/AppErrorView.kt +++ b/services/apperror/impl/src/main/kotlin/io/element/android/services/apperror/impl/AppErrorView.kt @@ -36,7 +36,7 @@ private fun AppErrorViewContent( ErrorDialog( title = title, content = body, - onDismiss = onDismiss, + onSubmit = onDismiss, ) } diff --git a/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Day_3_en.png new file mode 100644 index 0000000000..e625c84b24 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98f68bcb22f867add02028ec43cc9b609d8cd76ace450eec1f010899b3f29445 +size 24728 diff --git a/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Night_3_en.png new file mode 100644 index 0000000000..6d9414c34a --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/appnav.loggedin_LoggedInView_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:48e881658f3627275743a5f5cf172f312d26ea0633fa84243da4b277b664f66b +size 22753 diff --git a/tools/localazy/config.json b/tools/localazy/config.json index f736825725..6f41be8693 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -1,5 +1,12 @@ { "modules" : [ + { + "name" : ":appnav", + "includeRegex" : [ + "banner\\.migrate_to_native_sliding_sync\\.force_logout.title", + "banner\\.migrate_to_native_sliding_sync\\.action" + ] + }, { "name" : ":features:rageshake:impl", "includeRegex" : [