diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 0f4c8ee581..4b70cffe61 100644 --- a/.github/workflows/recordScreenshots.yml +++ b/.github/workflows/recordScreenshots.yml @@ -17,6 +17,7 @@ jobs: permissions: # Need write permissions on PRs to remove the label "Record-Screenshots" pull-requests: write + contents: write name: Record screenshots on branch ${{ github.event.pull_request.head.ref || github.ref_name }} runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' || github.event.label.name == 'Record-Screenshots' diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a4ee1c8459..da90ec82e4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -103,13 +103,13 @@ android { logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]") buildTypes { - val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android" + val oAuthRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android" getByName("debug") { resValue("string", "app_name", "$baseAppName dbg") resValue( "string", "login_redirect_scheme", - "$oidcRedirectSchemeBase.debug", + "$oAuthRedirectSchemeBase.debug", ) applicationIdSuffix = ".debug" signingConfig = signingConfigs.getByName("debug") @@ -120,7 +120,7 @@ android { resValue( "string", "login_redirect_scheme", - oidcRedirectSchemeBase, + oAuthRedirectSchemeBase, ) signingConfig = signingConfigs.getByName("debug") @@ -157,7 +157,7 @@ android { resValue( "string", "login_redirect_scheme", - "$oidcRedirectSchemeBase.nightly", + "$oAuthRedirectSchemeBase.nightly", ) matchingFallbacks += listOf("release") signingConfig = signingConfigs.getByName("nightly") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6041fbb118..d63e18ec1a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -75,7 +75,7 @@ android:scheme="elementx" /> diff --git a/app/src/main/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProvider.kt b/app/src/main/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProvider.kt similarity index 82% rename from app/src/main/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProvider.kt rename to app/src/main/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProvider.kt index ad4f9a47b2..16db564aaf 100644 --- a/app/src/main/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProvider.kt +++ b/app/src/main/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProvider.kt @@ -10,14 +10,14 @@ package io.element.android.x.oidc import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider +import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider import io.element.android.services.toolbox.api.strings.StringProvider import io.element.android.x.R @ContributesBinding(AppScope::class) -class DefaultOidcRedirectUrlProvider( +class DefaultOAuthRedirectUrlProvider( private val stringProvider: StringProvider, -) : OidcRedirectUrlProvider { +) : OAuthRedirectUrlProvider { override fun provide() = buildString { append(stringProvider.getString(R.string.login_redirect_scheme)) append(":/") diff --git a/app/src/test/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProviderTest.kt b/app/src/test/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProviderTest.kt similarity index 89% rename from app/src/test/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProviderTest.kt rename to app/src/test/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProviderTest.kt index 18567355d2..c26e3dc692 100644 --- a/app/src/test/kotlin/io/element/android/x/oidc/DefaultOidcRedirectUrlProviderTest.kt +++ b/app/src/test/kotlin/io/element/android/x/oidc/DefaultOAuthRedirectUrlProviderTest.kt @@ -13,13 +13,13 @@ import io.element.android.services.toolbox.test.strings.FakeStringProvider import io.element.android.x.R import org.junit.Test -class DefaultOidcRedirectUrlProviderTest { +class DefaultOAuthRedirectUrlProviderTest { @Test fun `test provide`() { val stringProvider = FakeStringProvider( defaultResult = "str" ) - val sut = DefaultOidcRedirectUrlProvider( + val sut = DefaultOAuthRedirectUrlProvider( stringProvider = stringProvider, ) val result = sut.provide() diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/ProtectionConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/ProtectionConfig.kt new file mode 100644 index 0000000000..f6ad71eeb1 --- /dev/null +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/ProtectionConfig.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.appconfig + +object ProtectionConfig { + /** + * The maximum length of a room name, to limit attack vectors in room invite. + */ + const val MAX_ROOM_NAME_LENGTH = 128 +} diff --git a/appnav/build.gradle.kts b/appnav/build.gradle.kts index 24a0355b3f..6be468b0d1 100644 --- a/appnav/build.gradle.kts +++ b/appnav/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation(projects.libraries.deeplink.api) implementation(projects.libraries.featureflag.api) implementation(projects.libraries.matrix.api) - implementation(projects.libraries.oidc.api) + implementation(projects.libraries.oauth.api) implementation(projects.libraries.preferences.api) implementation(projects.libraries.push.api) implementation(projects.libraries.pushproviders.api) @@ -59,7 +59,7 @@ dependencies { testImplementation(projects.features.login.test) testImplementation(projects.features.share.test) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.libraries.oidc.test) + testImplementation(projects.libraries.oauth.test) testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.push.test) testImplementation(projects.libraries.pushproviders.test) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index 0e458d3b9c..acf7b66db9 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -63,8 +63,8 @@ import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.asEventId import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias import io.element.android.libraries.matrix.api.permalink.PermalinkData -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow import io.element.android.libraries.sessionstorage.api.LoggedInState import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.ui.common.nodes.emptyNode @@ -95,7 +95,7 @@ class RootFlowNode( private val signedOutEntryPoint: SignedOutEntryPoint, private val accountSelectEntryPoint: AccountSelectEntryPoint, private val intentResolver: IntentResolver, - private val oidcActionFlow: OidcActionFlow, + private val oAuthActionFlow: OAuthActionFlow, private val featureFlagService: FeatureFlagService, private val announcementService: AnnouncementService, private val analyticsService: AnalyticsService, @@ -392,7 +392,7 @@ class RootFlowNode( navigateTo(resolvedIntent.deeplinkData) } is ResolvedIntent.Login -> onLoginLink(resolvedIntent.params) - is ResolvedIntent.Oidc -> onOidcAction(resolvedIntent.oidcAction) + is ResolvedIntent.OAuth -> onOAuthAction(resolvedIntent.oAuthAction) is ResolvedIntent.Permalink -> navigateTo(resolvedIntent.permalinkData) is ResolvedIntent.IncomingShare -> onIncomingShare(resolvedIntent.shareIntentData) } @@ -529,8 +529,8 @@ class RootFlowNode( } } - private fun onOidcAction(oidcAction: OidcAction) { - oidcActionFlow.post(oidcAction) + private fun onOAuthAction(oAuthAction: OAuthAction) { + oAuthActionFlow.post(oAuthAction) } private suspend fun attachSession(sessionId: SessionId): LoggedInFlowNode { diff --git a/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt b/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt index 6844db3ed6..ee316f00aa 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/intent/IntentResolver.kt @@ -18,13 +18,13 @@ import io.element.android.libraries.deeplink.api.DeeplinkData import io.element.android.libraries.deeplink.api.DeeplinkParser import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.permalink.PermalinkParser -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcIntentResolver +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthIntentResolver import timber.log.Timber sealed interface ResolvedIntent { data class Navigation(val deeplinkData: DeeplinkData) : ResolvedIntent - data class Oidc(val oidcAction: OidcAction) : ResolvedIntent + data class OAuth(val oAuthAction: OAuthAction) : ResolvedIntent data class Permalink(val permalinkData: PermalinkData) : ResolvedIntent data class Login(val params: LoginParams) : ResolvedIntent data class IncomingShare(val shareIntentData: ShareIntentData) : ResolvedIntent @@ -34,7 +34,7 @@ sealed interface ResolvedIntent { class IntentResolver( private val deeplinkParser: DeeplinkParser, private val loginIntentResolver: LoginIntentResolver, - private val oidcIntentResolver: OidcIntentResolver, + private val oAuthIntentResolver: OAuthIntentResolver, private val permalinkParser: PermalinkParser, private val shareIntentHandler: ShareIntentHandler, ) { @@ -45,9 +45,9 @@ class IntentResolver( val deepLinkData = deeplinkParser.getFromIntent(intent) if (deepLinkData != null) return ResolvedIntent.Navigation(deepLinkData) - // Coming during login using Oidc? - val oidcAction = oidcIntentResolver.resolve(intent) - if (oidcAction != null) return ResolvedIntent.Oidc(oidcAction) + // Coming during login using OAuth? + val oAuthAction = oAuthIntentResolver.resolve(intent) + if (oAuthAction != null) return ResolvedIntent.OAuth(oAuthAction) val actionViewData = intent .takeIf { it.action == Intent.ACTION_VIEW } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt index 576e1aaea6..451ca279f8 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/intent/IntentResolverTest.kt @@ -26,8 +26,8 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_THREAD_ID import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.test.FakeOidcIntentResolver +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.test.FakeOAuthIntentResolver import io.element.android.tests.testutils.lambda.lambdaError import org.junit.Test import org.junit.runner.RunWith @@ -170,9 +170,9 @@ class IntentResolverTest { } @Test - fun `test resolve oidc`() { + fun `test resolve OAuth`() { val sut = createIntentResolver( - oidcIntentResolverResult = { OidcAction.GoBack() }, + oAuthIntentResolverResult = { OAuthAction.GoBack() }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW @@ -180,8 +180,8 @@ class IntentResolverTest { } val result = sut.resolve(intent) assertThat(result).isEqualTo( - ResolvedIntent.Oidc( - oidcAction = OidcAction.GoBack() + ResolvedIntent.OAuth( + oAuthAction = OAuthAction.GoBack() ) ) } @@ -194,7 +194,7 @@ class IntentResolverTest { val sut = createIntentResolver( loginIntentResolverResult = { null }, permalinkParserResult = { permalinkData }, - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW @@ -213,7 +213,7 @@ class IntentResolverTest { val sut = createIntentResolver( permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) }, loginIntentResolverResult = { null }, - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW @@ -230,7 +230,7 @@ class IntentResolverTest { ) val sut = createIntentResolver( permalinkParserResult = { permalinkData }, - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_BATTERY_LOW @@ -244,7 +244,7 @@ class IntentResolverTest { fun `test incoming share simple`() { val shareIntentData = ShareIntentData.PlainText("Hello") val sut = createIntentResolver( - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, onIncomingShareIntent = { shareIntentData }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { @@ -260,7 +260,7 @@ class IntentResolverTest { val fileUri = "content://com.example.app/file1.jpg".toUri() val shareIntentData = ShareIntentData.Uris(text = "Hello", uris = listOf(UriToShare(fileUri, "image/jpg"))) val sut = createIntentResolver( - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, onIncomingShareIntent = { shareIntentData }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { @@ -277,7 +277,7 @@ class IntentResolverTest { val sut = createIntentResolver( permalinkParserResult = { PermalinkData.FallbackLink(Uri.parse("https://matrix.org")) }, loginIntentResolverResult = { null }, - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW @@ -292,7 +292,7 @@ class IntentResolverTest { val aLoginParams = LoginParams("accountProvider", null) val sut = createIntentResolver( loginIntentResolverResult = { aLoginParams }, - oidcIntentResolverResult = { null }, + oAuthIntentResolverResult = { null }, ) val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW @@ -306,7 +306,7 @@ class IntentResolverTest { deeplinkParserResult: DeeplinkData? = null, permalinkParserResult: (String) -> PermalinkData = { lambdaError() }, loginIntentResolverResult: (String) -> LoginParams? = { lambdaError() }, - oidcIntentResolverResult: (Intent) -> OidcAction? = { lambdaError() }, + oAuthIntentResolverResult: (Intent) -> OAuthAction? = { lambdaError() }, onIncomingShareIntent: (Intent) -> ShareIntentData? = { null }, ): IntentResolver { return IntentResolver( @@ -314,8 +314,8 @@ class IntentResolverTest { loginIntentResolver = FakeLoginIntentResolver( parseResult = loginIntentResolverResult, ), - oidcIntentResolver = FakeOidcIntentResolver( - resolveResult = oidcIntentResolverResult, + oAuthIntentResolver = FakeOAuthIntentResolver( + resolveResult = oAuthIntentResolverResult, ), permalinkParser = FakePermalinkParser( result = permalinkParserResult 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 902f446a6f..18c8cfd7b9 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 @@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.SessionId 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.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion import io.element.android.libraries.matrix.api.sync.SyncState diff --git a/docs/oidc.md b/docs/oauth.md similarity index 81% rename from docs/oidc.md rename to docs/oauth.md index 23709b608c..1080c64b0e 100644 --- a/docs/oidc.md +++ b/docs/oauth.md @@ -1,4 +1,4 @@ -This file contains some rough notes about Oidc implementation, with some examples of actual data. +This file contains some rough notes about OAuth implementation, with some examples of actual data. [ios implementation](https://github.com/element-hq/element-x-ios/compare/develop...doug/oidc-temp) @@ -25,7 +25,7 @@ tosUri = "https://element.io/user-terms-of-service", policyUri = "https://element.io/privacy" -Example of OidcData (from presentUrl callback): +Example of OAuthData (from presentUrl callback): url: https://auth-oidc.lab.element.dev/authorize?response_type=code&client_id=01GYCAGG3PA70CJ97ZVP0WFJY3&redirect_uri=io.element%3A%2Fcallback&scope=openid+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Aapi%3A*+urn%3Amatrix%3Aorg.matrix.msc2967.client%3Adevice%3AYAgcPW4mcG&state=ex6mNJVFZ5jn9wL8&nonce=NZ93DOyIGQd9exPQ&code_challenge_method=S256&code_challenge=FFRcPALNSPCh-ZgpyTRFu_h8NZJVncfvihbfT9CyX8U&prompt=consent Formatted url: @@ -43,8 +43,8 @@ https://auth-oidc.lab.element.dev/authorize? state: ex6mNJVFZ5jn9wL8 -Oidc client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs -Oidc sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs +OAuth client example: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/examples/oidc_cli/src/main.rs +OAuth sdk doc: https://github.com/matrix-org/matrix-rust-sdk/blob/39ad8a46801fb4317a777ebf895822b3675b709c/crates/matrix-sdk/src/oidc.rs Test server: diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenBackPressPolicy.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenBackPressPolicy.kt new file mode 100644 index 0000000000..cd47cd8bb1 --- /dev/null +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenBackPressPolicy.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.call.impl.ui +internal sealed interface CallScreenBackPressAction { + data object DispatchEscapeToWebView : CallScreenBackPressAction + data object EnterPictureInPicture : CallScreenBackPressAction +} + +internal object CallScreenBackPressPolicy { + fun resolve( + supportPip: Boolean, + hasWebView: Boolean, + fromNative: Boolean, + ): CallScreenBackPressAction? { + return when { + hasWebView && fromNative -> CallScreenBackPressAction.DispatchEscapeToWebView + hasWebView && supportPip -> CallScreenBackPressAction.EnterPictureInPicture + else -> null + } + } +} 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 1c68a62f55..ea3668316b 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 @@ -64,11 +64,15 @@ internal fun CallScreenView( requestPermissions: (Array, RequestPermissionCallback) -> Unit, modifier: Modifier = Modifier, ) { - fun handleBack() { - if (pipState.supportPip) { - pipState.eventSink.invoke(PictureInPictureEvent.EnterPictureInPicture) - } else { - state.eventSink(CallScreenEvent.Hangup) + var callWebView by remember { mutableStateOf(null) } + + fun handleBack(fromNative: Boolean = false) { + when (CallScreenBackPressPolicy.resolve(supportPip = pipState.supportPip, hasWebView = callWebView != null, fromNative)) { + CallScreenBackPressAction.EnterPictureInPicture -> + pipState.eventSink(PictureInPictureEvent.EnterPictureInPicture) + CallScreenBackPressAction.DispatchEscapeToWebView -> + callWebView?.dispatchEscKeyEvent() + null -> Timber.d("Back press with unsupported pip is a no-op") } } @@ -76,7 +80,7 @@ internal fun CallScreenView( modifier = modifier, ) { padding -> BackHandler { - handleBack() + handleBack(fromNative = true) } if (state.webViewError != null) { ErrorDialog( @@ -111,6 +115,7 @@ internal fun CallScreenView( }, onConsoleMessage = onConsoleMessage, onCreateWebView = { webView -> + callWebView = webView webView.addBackHandler(onBackPressed = ::handleBack) val interceptor = WebViewWidgetMessageInterceptor( webView = webView, @@ -135,6 +140,7 @@ internal fun CallScreenView( pipState.eventSink(PictureInPictureEvent.SetPipController(pipController)) }, onDestroyWebView = { + callWebView = null // Reset audio mode webViewAudioManager?.onCallStopped() } @@ -143,6 +149,7 @@ internal fun CallScreenView( AsyncData.Uninitialized, is AsyncData.Loading -> ProgressDialog(text = stringResource(id = CommonStrings.common_please_wait)) + is AsyncData.Failure -> { Timber.e(state.urlState.error, "WebView failed to load URL: ${state.urlState.error.message}") ErrorDialog( @@ -150,6 +157,7 @@ internal fun CallScreenView( onSubmit = { state.eventSink(CallScreenEvent.Hangup) }, ) } + is AsyncData.Success -> Unit } } @@ -248,15 +256,18 @@ private fun WebView.setup( private fun WebView.addBackHandler(onBackPressed: () -> Unit) { addJavascriptInterface( - object { - @Suppress("unused") - @JavascriptInterface - fun onBackPressed() = onBackPressed() + JavascriptBackHandler { + onBackPressed() }, "backHandler" ) } +private fun WebView.dispatchEscKeyEvent() { + dispatchKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_DOWN, android.view.KeyEvent.KEYCODE_ESCAPE)) + dispatchKeyEvent(android.view.KeyEvent(android.view.KeyEvent.ACTION_UP, android.view.KeyEvent.KEYCODE_ESCAPE)) +} + @PreviewsDayNight @Composable internal fun CallScreenViewPreview( @@ -275,3 +286,8 @@ internal fun CallScreenViewPreview( internal fun InvalidAudioDeviceDialogPreview() = ElementPreview { InvalidAudioDeviceDialog(invalidAudioDeviceReason = InvalidAudioDeviceReason.BT_AUDIO_DEVICE_DISABLED) {} } + +internal fun interface JavascriptBackHandler { + @JavascriptInterface + fun onBackPressed() +} diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenBackPressPolicyTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenBackPressPolicyTest.kt new file mode 100644 index 0000000000..f07f7039d3 --- /dev/null +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenBackPressPolicyTest.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.call.ui + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.call.impl.ui.CallScreenBackPressAction +import io.element.android.features.call.impl.ui.CallScreenBackPressPolicy +import org.junit.Test + +class CallScreenBackPressPolicyTest { + @Test + fun `resolve returns dispatch escape when a web view is available and native button is pressed`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = false, + hasWebView = true, + fromNative = true, + ) + + assertThat(result).isEqualTo(CallScreenBackPressAction.DispatchEscapeToWebView) + } + + @Test + fun `resolve dispatch escape when there is a web view and pip is supported on native button press`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = true, + hasWebView = true, + fromNative = true, + ) + + assertThat(result).isEqualTo(CallScreenBackPressAction.DispatchEscapeToWebView) + } + + @Test + fun `resolve returns hangup when there is no web view and pip is not supported from native button`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = false, + hasWebView = false, + fromNative = true, + ) + + assertThat(result).isNull() + } + + @Test + fun `resolve returns hangup when there is no web view even though pip is supported from native button`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = true, + hasWebView = false, + fromNative = true, + ) + + assertThat(result).isNull() + } + + @Test + fun `resolve goes to pip if its not from native but from the webview`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = true, + hasWebView = true, + fromNative = false, + ) + + assertThat(result).isEqualTo(CallScreenBackPressAction.EnterPictureInPicture) + } + @Test + fun `resolve hangs up if its not from native but from the webview and pip is not supported`() { + val result = CallScreenBackPressPolicy.resolve( + supportPip = false, + hasWebView = true, + fromNative = false, + ) + + assertThat(result).isNull() + } + + @Test + fun `invalid cases (event comes from webview but there is now webview) all result in hangup`() { + val withPipSupport = CallScreenBackPressPolicy.resolve( + supportPip = true, + hasWebView = false, + fromNative = false, + ) + assertThat(withPipSupport).isNull() + val withOutPipSupport = CallScreenBackPressPolicy.resolve( + supportPip = false, + hasWebView = false, + fromNative = false, + ) + assertThat(withOutPipSupport).isNull() + } +} diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt new file mode 100644 index 0000000000..35b90a6716 --- /dev/null +++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenViewTest.kt @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.call.ui + +import android.view.KeyEvent +import android.webkit.WebView +import androidx.activity.ComponentActivity +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.features.call.impl.pip.PictureInPictureEvents +import io.element.android.features.call.impl.pip.aPictureInPictureState +import io.element.android.features.call.impl.ui.CallScreenEvents +import io.element.android.features.call.impl.ui.CallScreenView +import io.element.android.features.call.impl.ui.JavascriptBackHandler +import io.element.android.features.call.impl.ui.aCallScreenState +import io.element.android.tests.testutils.EventsRecorder +import io.element.android.tests.testutils.pressBackKey +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith +import org.robolectric.annotation.Config +import org.robolectric.annotation.Implementation +import org.robolectric.annotation.Implements +import org.robolectric.annotation.Resetter +import org.robolectric.shadows.ShadowWebView + +@RunWith(AndroidJUnit4::class) +class CallScreenViewTest { + @get:Rule + val rule = createAndroidComposeRule() + + @Test + fun `pressing back key triggers hangup when no web view is available and pip is unsupported`() { + val callEvents = EventsRecorder() + + rule.setCallScreenView( + state = aCallScreenState(eventSink = callEvents), + useInspectionMode = true, + ) + + rule.pressBackKey() + + callEvents.assertEmpty() + } + + @Config(shadows = [RecordingShadowWebView::class]) + @Test + fun `pressing back key dispatches escape key events to web view when pip is unsupported`() { + rule.setCallScreenView( + state = aCallScreenState(), + useInspectionMode = false, + ) + + rule.pressBackKey() + + val dispatchedEvents = RecordingShadowWebView.dispatchedEvents + assertEquals(2, dispatchedEvents.size) + assertEquals(KeyEvent.ACTION_DOWN, dispatchedEvents[0].action) + assertEquals(KeyEvent.KEYCODE_ESCAPE, dispatchedEvents[0].keyCode) + assertEquals(KeyEvent.ACTION_UP, dispatchedEvents[1].action) + assertEquals(KeyEvent.KEYCODE_ESCAPE, dispatchedEvents[1].keyCode) + } + + @Config(shadows = [RecordingShadowWebView::class]) + @Test + fun `web view javascript back handler emits pip event when pip is supported`() { + val pipEvents = EventsRecorder() + + rule.setCallScreenView( + state = aCallScreenState(), + useInspectionMode = false, + pipState = aPictureInPictureState( + supportPip = true, + eventSink = pipEvents, + ), + ) + + rule.runOnIdle { + RecordingShadowWebView.invokeJavascriptBackHandler() + } + + pipEvents.assertSize(2) + pipEvents.assertTrue(0) { it is PictureInPictureEvents.SetPipController } + pipEvents.assertTrue(1) { it is PictureInPictureEvents.EnterPictureInPicture } + } +} + +private fun AndroidComposeTestRule.setCallScreenView( + state: io.element.android.features.call.impl.ui.CallScreenState, + useInspectionMode: Boolean, + pipState: io.element.android.features.call.impl.pip.PictureInPictureState = aPictureInPictureState(supportPip = false), +) { + setContent { + // Inspection mode disables AndroidView creation; keep it configurable per test. + CompositionLocalProvider(LocalInspectionMode provides useInspectionMode) { + CallScreenView( + state = state, + pipState = pipState, + onConsoleMessage = {}, + requestPermissions = { _, _ -> }, + ) + } + } +} + +@Implements(WebView::class) +internal class RecordingShadowWebView : ShadowWebView() { + companion object { + val dispatchedEvents = mutableListOf() + private var backHandlerJavascriptInterface: JavascriptBackHandler? = null + + @Resetter + @JvmStatic + @Suppress("unused") + fun resetRecordedEvents() { + dispatchedEvents.clear() + backHandlerJavascriptInterface = null + } + + fun invokeJavascriptBackHandler() { + val backHandler = checkNotNull(backHandlerJavascriptInterface) { "Expected backHandler JavaScript interface to be registered" } + backHandler.onBackPressed() + } + } + + @Implementation + protected override fun addJavascriptInterface(`object`: Any, name: String) { + super.addJavascriptInterface(`object`, name) + if (name == "backHandler") { + backHandlerJavascriptInterface = `object` as? JavascriptBackHandler + } + } + + @Implementation + @Suppress("unused") + fun dispatchKeyEvent(event: KeyEvent): Boolean { + dispatchedEvents += KeyEvent(event) + return false + } +} diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt index 6b7b66b897..1480e57334 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/SelectParentSpaceOptions.kt @@ -95,7 +95,8 @@ internal fun SelectParentSpaceOptions( sheetState.hide(coroutineScope) { displaySelectSpaceBottomSheet = false } - } + }, + scrollable = false, ) { SelectParentSpaceBottomSheet( spaces = spaces, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt index 30e3aaf0b7..66982961fd 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListContextMenu.kt @@ -11,6 +11,8 @@ package io.element.android.features.home.impl.roomlist import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -43,6 +45,7 @@ fun RoomListContextMenu( ) { ModalBottomSheet( onDismissRequest = { eventSink(RoomListEvent.HideContextMenu) }, + scrollable = false, ) { RoomListModalBottomSheetContent( contextMenu = contextMenu, @@ -91,7 +94,9 @@ private fun RoomListModalBottomSheetContent( onReportRoomClick: () -> Unit, ) { Column( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() + .verticalScroll(rememberScrollState()) ) { ListItem( headlineContent = { @@ -212,23 +217,16 @@ private fun RoomListModalBottomSheetContent( } } -// TODO This component should be seen in [RoomListView] @Preview but it doesn't show up. -// see: https://issuetracker.google.com/issues/283843380 -// Remove this preview when the issue is fixed. @PreviewsDayNight @Composable -internal fun RoomListModalBottomSheetContentPreview( +internal fun RoomListContextMenuPreview( @PreviewParameter(RoomListStateContextMenuShownProvider::class) contextMenu: RoomListState.ContextMenu.Shown ) = ElementPreview { - RoomListModalBottomSheetContent( + RoomListContextMenu( contextMenu = contextMenu, canReportRoom = true, - onRoomMarkReadClick = {}, - onRoomMarkUnreadClick = {}, onRoomSettingsClick = {}, - onLeaveRoomClick = {}, - onFavoriteChange = {}, - onClearCacheRoomClick = {}, onReportRoomClick = {}, + eventSink = {}, ) } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenu.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenu.kt index 523e677a57..0a7a29ebc2 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenu.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListDeclineInviteMenu.kt @@ -13,16 +13,21 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import io.element.android.appconfig.ProtectionConfig import io.element.android.compound.theme.ElementTheme import io.element.android.features.home.impl.R import io.element.android.features.home.impl.model.RoomListRoomSummary +import io.element.android.libraries.core.extensions.toSafeLength import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -42,9 +47,14 @@ fun RoomListDeclineInviteMenu( ) { ModalBottomSheet( onDismissRequest = { eventSink(RoomListEvent.HideDeclineInviteMenu) }, + scrollable = false, ) { RoomListDeclineInviteMenuContent( - roomName = menu.roomSummary.name ?: menu.roomSummary.roomId.value, + roomName = menu.roomSummary.name?.toSafeLength( + maxLength = ProtectionConfig.MAX_ROOM_NAME_LENGTH, + ellipsize = true, + ) + ?: menu.roomSummary.roomId.value, onDeclineClick = { eventSink(RoomListEvent.HideDeclineInviteMenu) eventSink(RoomListEvent.DeclineInvite(menu.roomSummary, false)) @@ -74,7 +84,8 @@ private fun RoomListDeclineInviteMenuContent( Column( modifier = Modifier .fillMaxWidth() - .padding(all = 16.dp), + .padding(all = 16.dp) + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, ) { Text( @@ -112,16 +123,15 @@ private fun RoomListDeclineInviteMenuContent( } } -// TODO This component should be seen in [RoomListView] @Preview but it doesn't show up. -// see: https://issuetracker.google.com/issues/283843380 -// Remove this preview when the issue is fixed. @PreviewsDayNight @Composable -internal fun RoomListDeclineInviteMenuContentPreview() = ElementPreview { - RoomListDeclineInviteMenuContent( - roomName = "Room name", - onCancelClick = {}, - onDeclineClick = {}, +internal fun RoomListDeclineInviteMenuPreview( + @PreviewParameter(RoomListStateDeclineInviteMenuShownProvider::class) menu: RoomListState.DeclineInviteMenu.Shown, +) = ElementPreview { + RoomListDeclineInviteMenu( + menu = menu, + canReportRoom = false, onDeclineAndBlockClick = {}, + eventSink = {}, ) } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateDeclineInviteMenuShownProvider.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateDeclineInviteMenuShownProvider.kt new file mode 100644 index 0000000000..73d4785e96 --- /dev/null +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListStateDeclineInviteMenuShownProvider.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.home.impl.roomlist + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.tooling.preview.datasource.LoremIpsum +import io.element.android.features.home.impl.model.RoomListRoomSummary +import io.element.android.features.home.impl.model.aRoomListRoomSummary + +open class RoomListStateDeclineInviteMenuShownProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + aDeclineInviteMenuShown(), + aDeclineInviteMenuShown( + aRoomListRoomSummary( + name = LoremIpsum(500).values.first(), + ) + ), + aDeclineInviteMenuShown( + aRoomListRoomSummary( + name = null, + ) + ), + ) +} + +internal fun aDeclineInviteMenuShown( + roomSummary: RoomListRoomSummary = aRoomListRoomSummary(), +) = RoomListState.DeclineInviteMenu.Shown( + roomSummary = roomSummary, +) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt index fb77c74203..1f0d6ff7d9 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersView.kt @@ -81,7 +81,8 @@ fun SpaceFiltersView( if (state is SpaceFiltersState.Selecting) { state.eventSink(SpaceFiltersEvent.Selecting.Cancel) } - } + }, + scrollable = false, ) { Box( modifier = Modifier diff --git a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt index 289ac193d4..b1f139f43c 100644 --- a/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt +++ b/features/invitepeople/impl/src/main/kotlin/io/element/android/features/invitepeople/impl/InvitePeopleView.kt @@ -262,6 +262,7 @@ private fun InvitePeopleConfirmModal( ModalBottomSheet( onDismissRequest = onDismiss, dragHandle = null, + scrollable = false, ) { IconTitleSubtitleMolecule( title = simplePluralStringResource( diff --git a/features/linknewdevice/impl/build.gradle.kts b/features/linknewdevice/impl/build.gradle.kts index 9c1aa9e990..adbec91e6a 100644 --- a/features/linknewdevice/impl/build.gradle.kts +++ b/features/linknewdevice/impl/build.gradle.kts @@ -43,7 +43,7 @@ dependencies { implementation(projects.libraries.permissions.api) implementation(projects.libraries.sessionStorage.api) implementation(projects.libraries.qrcode) - implementation(projects.libraries.oidc.api) + implementation(projects.libraries.oauth.api) implementation(projects.libraries.uiUtils) implementation(projects.libraries.wellknown.api) implementation(libs.androidx.browser) @@ -56,7 +56,7 @@ dependencies { testImplementation(projects.features.enterprise.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.libraries.oidc.test) + testImplementation(projects.libraries.oauth.test) testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.sessionStorage.test) testImplementation(projects.libraries.wellknown.test) diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt index 54baee6663..30f456240f 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/LinkNewDeviceFlowNode.kt @@ -27,6 +27,7 @@ import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.compound.theme.ElementTheme import io.element.android.features.linknewdevice.api.LinkNewDeviceEntryPoint +import io.element.android.features.linknewdevice.impl.screens.confirmation.CodeConfirmationNode import io.element.android.features.linknewdevice.impl.screens.desktop.DesktopNoticeNode import io.element.android.features.linknewdevice.impl.screens.error.ErrorNode import io.element.android.features.linknewdevice.impl.screens.error.ErrorScreenType @@ -107,6 +108,11 @@ class LinkNewDeviceFlowNode( val data: String, ) : NavTarget + @Parcelize + data class CodeConfirmation( + val code: String, + ) : NavTarget + @Parcelize data object MobileEnterNumber : NavTarget @@ -145,10 +151,7 @@ class LinkNewDeviceFlowNode( LinkMobileStep.Starting -> { // This step is not received at the moment, so do nothing } - LinkMobileStep.SyncingSecrets -> { - // LinkMobileStep.Done is not received at the moment, so consider that the flow is done here - callback.onDone() - } + LinkMobileStep.SyncingSecrets -> Unit is LinkMobileStep.WaitingForAuth -> { navigateToBrowser(linkMobileStep.verificationUri) } @@ -166,7 +169,9 @@ class LinkNewDeviceFlowNode( is LinkDesktopStep.Error -> { navigateToError(linkDesktopStep.errorType) } - is LinkDesktopStep.EstablishingSecureChannel -> Unit + is LinkDesktopStep.EstablishingSecureChannel -> { + backstack.push(NavTarget.CodeConfirmation(linkDesktopStep.checkCodeString)) + } is LinkDesktopStep.InvalidQrCode -> { // This error will be handled by the ScanQrCodeNode } @@ -183,20 +188,20 @@ class LinkNewDeviceFlowNode( private fun navigateToError(errorType: ErrorType) { // Map the error to an error screen - // TODO Update this mapping val error = when (errorType) { - is ErrorType.DeviceIdAlreadyInUse -> ErrorScreenType.UnknownError - is ErrorType.InvalidCheckCode -> ErrorScreenType.InsecureChannelDetected - is ErrorType.MissingSecretsBackup -> ErrorScreenType.UnknownError - is ErrorType.NotFound -> ErrorScreenType.Expired - is ErrorType.DeviceNotFound -> ErrorScreenType.UnknownError - is ErrorType.Unknown -> ErrorScreenType.UnknownError - is ErrorType.UnsupportedProtocol -> ErrorScreenType.UnknownError - is ErrorType.Cancelled -> ErrorScreenType.UnknownError + is ErrorType.InvalidCheckCode -> ErrorScreenType.Mismatch2Digits + is ErrorType.UnsupportedProtocol -> ErrorScreenType.ProtocolNotSupported + is ErrorType.Cancelled -> ErrorScreenType.Cancelled is ErrorType.ConnectionInsecure -> ErrorScreenType.InsecureChannelDetected - is ErrorType.Expired -> ErrorScreenType.Expired - is ErrorType.OtherDeviceAlreadySignedIn -> ErrorScreenType.UnknownError + is ErrorType.Expired, + is ErrorType.NotFound, + is ErrorType.DeviceNotFound -> ErrorScreenType.Expired + is ErrorType.OtherDeviceAlreadySignedIn -> ErrorScreenType.OtherDeviceAlreadySignedIn + // TODO check if we expect to hit this here or if it should be caught earlier on is ErrorType.UnsupportedQrCodeType -> ErrorScreenType.UnknownError + is ErrorType.MissingSecretsBackup, + is ErrorType.DeviceIdAlreadyInUse, + is ErrorType.Unknown -> ErrorScreenType.UnknownError } // It is OK to push on backstack, since when user leaves the error screen, a new root will be set, // or the whole flow will be popped. @@ -250,6 +255,18 @@ class LinkNewDeviceFlowNode( } createNode(buildContext, listOf(callback)) } + is NavTarget.CodeConfirmation -> { + val callback = object : CodeConfirmationNode.Callback { + override fun onCancel() { + // Push error + backstack.push(NavTarget.Error(ErrorScreenType.Cancelled)) + } + } + val inputs = CodeConfirmationNode.Inputs( + code = navTarget.code, + ) + createNode(buildContext, listOf(inputs, callback)) + } is NavTarget.MobileShowQrCode -> { val callback = object : ShowQrCodeNode.Callback { override fun navigateBack() { diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationNode.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationNode.kt new file mode 100644 index 0000000000..a8db4d2d75 --- /dev/null +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationNode.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.linknewdevice.impl.screens.confirmation + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedInject +import io.element.android.annotations.ContributesNode +import io.element.android.libraries.architecture.NodeInputs +import io.element.android.libraries.architecture.callback +import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.di.SessionScope + +@ContributesNode(SessionScope::class) +@AssistedInject +class CodeConfirmationNode( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : Node(buildContext = buildContext, plugins = plugins) { + interface Callback : Plugin { + fun onCancel() + } + + data class Inputs( + val code: String, + ) : NodeInputs + + private val callback: Callback = callback() + private val input = inputs() + + @Composable + override fun View(modifier: Modifier) { + CodeConfirmationView( + code = input.code, + onCancel = callback::onCancel, + ) + } +} diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationView.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationView.kt new file mode 100644 index 0000000000..d981574f86 --- /dev/null +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/confirmation/CodeConfirmationView.kt @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.linknewdevice.impl.screens.confirmation + +import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.compound.tokens.generated.CompoundIcons +import io.element.android.features.linknewdevice.impl.R +import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage +import io.element.android.libraries.designsystem.components.BigIcon +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.OutlinedButton +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.ui.strings.CommonStrings + +@Composable +fun CodeConfirmationView( + code: String, + onCancel: () -> Unit, + modifier: Modifier = Modifier, +) { + BackHandler(onBack = onCancel) + FlowStepPage( + modifier = modifier, + iconStyle = BigIcon.Style.Default(CompoundIcons.Computer()), + title = stringResource(R.string.screen_qr_code_login_device_code_title), + subTitle = stringResource(R.string.screen_qr_code_login_device_code_subtitle), + content = { Content(code = code) }, + buttons = { Buttons(onCancel = onCancel) } + ) +} + +@Composable +private fun Content(code: String) { + Column( + modifier = Modifier.padding(top = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Digits(code = code) + Spacer(modifier = Modifier.height(32.dp)) + WaitingForOtherDevice() + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun Digits(code: String) { + FlowRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + code.forEach { + Text( + modifier = Modifier + .padding(horizontal = 6.dp, vertical = 4.dp) + .clip(RoundedCornerShape(4.dp)) + .background(ElementTheme.colors.bgActionSecondaryPressed) + .padding(horizontal = 16.dp, vertical = 17.dp), + text = it.toString() + ) + } + } +} + +@Composable +private fun WaitingForOtherDevice() { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + CircularProgressIndicator( + modifier = Modifier + .size(20.dp) + .padding(2.dp), + strokeWidth = 2.dp, + ) + Text( + text = stringResource(R.string.screen_qr_code_login_verify_code_loading), + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + textAlign = TextAlign.Center, + ) + } +} + +@Composable +private fun Buttons( + onCancel: () -> Unit, +) { + Column(modifier = Modifier.fillMaxWidth()) { + OutlinedButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(CommonStrings.action_cancel), + onClick = onCancel, + ) + } +} + +@PreviewsDayNight +@Composable +internal fun CodeConfirmationViewPreview() { + ElementPreview { + CodeConfirmationView( + code = "67", + onCancel = {}, + ) + } +} diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenType.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenType.kt index b92a19ef8a..ad8cc276c5 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenType.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenType.kt @@ -20,6 +20,9 @@ sealed interface ErrorScreenType : NodeInputs, Parcelable { @Parcelize data object Expired : ErrorScreenType + @Parcelize + data object OtherDeviceAlreadySignedIn : ErrorScreenType + @Parcelize data object Mismatch2Digits : ErrorScreenType diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenTypeProvider.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenTypeProvider.kt index 7fd699101b..5946eb9ab2 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenTypeProvider.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorScreenTypeProvider.kt @@ -19,5 +19,6 @@ class ErrorScreenTypeProvider : PreviewParameterProvider { ErrorScreenType.InsecureChannelDetected, ErrorScreenType.SlidingSyncNotAvailable, ErrorScreenType.UnknownError, + ErrorScreenType.OtherDeviceAlreadySignedIn, ) } diff --git a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt index 9f67e8bc17..4db2aa9ad5 100644 --- a/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt +++ b/features/linknewdevice/impl/src/main/kotlin/io/element/android/features/linknewdevice/impl/screens/error/ErrorView.kt @@ -47,17 +47,26 @@ fun ErrorView( ) { val appName = LocalBuildMeta.current.applicationName BackHandler(onBack = onCancel) + val iconStyle = when (errorScreenType) { + ErrorScreenType.OtherDeviceAlreadySignedIn -> BigIcon.Style.SuccessSolid + else -> BigIcon.Style.AlertSolid + } FlowStepPage( modifier = modifier, - iconStyle = BigIcon.Style.AlertSolid, + iconStyle = iconStyle, title = titleText(errorScreenType, appName), subTitle = subtitleText(errorScreenType, appName), content = { Content(errorScreenType) }, buttons = { - Buttons( - onRetry = onRetry, - onCancel = onCancel, - ) + when (errorScreenType) { + ErrorScreenType.OtherDeviceAlreadySignedIn -> DoneButton( + onDone = onCancel, + ) + else -> Buttons( + onRetry = onRetry, + onCancel = onCancel, + ) + } }, ) } @@ -72,6 +81,7 @@ private fun titleText(errorScreenType: ErrorScreenType, appName: String) = when ErrorScreenType.Mismatch2Digits -> stringResource(id = R.string.screen_link_new_device_wrong_number_title) ErrorScreenType.SlidingSyncNotAvailable -> stringResource(id = R.string.screen_qr_code_login_error_sliding_sync_not_supported_title, appName) is ErrorScreenType.UnknownError -> stringResource(CommonStrings.common_something_went_wrong) + ErrorScreenType.OtherDeviceAlreadySignedIn -> stringResource(R.string.screen_qr_code_login_error_device_already_signed_in_title) } @Composable @@ -84,6 +94,7 @@ private fun subtitleText(errorScreenType: ErrorScreenType, appName: String) = wh ErrorScreenType.InsecureChannelDetected -> stringResource(id = R.string.screen_qr_code_login_connection_note_secure_state_description) ErrorScreenType.SlidingSyncNotAvailable -> stringResource(id = R.string.screen_qr_code_login_error_sliding_sync_not_supported_subtitle, appName) is ErrorScreenType.UnknownError -> stringResource(R.string.screen_qr_code_login_unknown_error_description) + ErrorScreenType.OtherDeviceAlreadySignedIn -> stringResource(R.string.screen_qr_code_login_error_device_already_signed_in_subtitle) } @Composable @@ -124,6 +135,17 @@ private fun Content(errorScreenType: ErrorScreenType) { } } +@Composable +private fun DoneButton( + onDone: () -> Unit, +) { + Button( + modifier = Modifier.fillMaxWidth(), + text = stringResource(CommonStrings.action_done), + onClick = onDone, + ) +} + @Composable private fun Buttons( onRetry: () -> Unit, diff --git a/features/linknewdevice/impl/src/main/res/values/localazy.xml b/features/linknewdevice/impl/src/main/res/values/localazy.xml index 321b168751..6ffcce227a 100644 --- a/features/linknewdevice/impl/src/main/res/values/localazy.xml +++ b/features/linknewdevice/impl/src/main/res/values/localazy.xml @@ -34,6 +34,8 @@ "If you encounter the same problem, try a different wifi network or use your mobile data instead of wifi" "If that doesn’t work, sign in manually" "Connection not secure" + "You’ll be asked to enter the two digits shown on this device." + "Enter the number below on your other device" "The sign in was cancelled on the other device." "Sign in request cancelled" "The sign in was declined on the other device." @@ -54,4 +56,5 @@ Try signing in manually, or scan the QR code with another device." "You need to give permission for %1$s to use your device’s camera in order to continue." "Allow camera access to scan the QR code" "An unexpected error occurred. Please try again." + "Waiting for your other device" diff --git a/features/login/impl/build.gradle.kts b/features/login/impl/build.gradle.kts index 12af922cbe..e739beb20a 100644 --- a/features/login/impl/build.gradle.kts +++ b/features/login/impl/build.gradle.kts @@ -69,7 +69,7 @@ dependencies { implementation(projects.libraries.permissions.api) implementation(projects.libraries.sessionStorage.api) implementation(projects.libraries.qrcode) - implementation(projects.libraries.oidc.api) + implementation(projects.libraries.oauth.api) implementation(projects.libraries.uiUtils) implementation(projects.libraries.wellknown.api) implementation(libs.androidx.browser) @@ -83,7 +83,7 @@ dependencies { testImplementation(projects.features.preferences.test) testImplementation(projects.libraries.featureflag.test) testImplementation(projects.libraries.matrix.test) - testImplementation(projects.libraries.oidc.test) + testImplementation(projects.libraries.oauth.test) testImplementation(projects.libraries.permissions.test) testImplementation(projects.libraries.sessionStorage.test) testImplementation(projects.libraries.wellknown.test) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt index fb384d505a..978d28dfa3 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt @@ -50,9 +50,9 @@ import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.annotations.AppCoroutineScope -import io.element.android.libraries.matrix.api.auth.OidcDetails -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow +import io.element.android.libraries.matrix.api.auth.OAuthDetails +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -64,7 +64,7 @@ class LoginFlowNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val accountProviderDataSource: AccountProviderDataSource, - private val oidcActionFlow: OidcActionFlow, + private val oAuthActionFlow: OAuthActionFlow, @AppCoroutineScope private val appCoroutineScope: CoroutineScope, private val elementClassicConnection: ElementClassicConnection, @@ -100,7 +100,7 @@ class LoginFlowNode( // by pressing back or by closing the Custom Chrome Tab. lifecycleScope.launch { delay(5000) - oidcActionFlow.post(OidcAction.GoBack(toUnblock = true)) + oAuthActionFlow.post(OAuthAction.GoBack(toUnblock = true)) } } } @@ -161,8 +161,8 @@ class LoginFlowNode( backstack.push(NavTarget.LoginPassword()) } - override fun navigateToOidc(oidcDetails: OidcDetails) { - navigateToMas(oidcDetails) + override fun navigateToOAuth(oAuthDetails: OAuthDetails) { + navigateToMas(oAuthDetails) } override fun navigateToCreateAccount(url: String) { @@ -197,8 +197,8 @@ class LoginFlowNode( callback.navigateToBugReport() } - override fun navigateToOidc(oidcDetails: OidcDetails) { - navigateToMas(oidcDetails) + override fun navigateToOAuth(oAuthDetails: OAuthDetails) { + navigateToMas(oAuthDetails) } override fun navigateToCreateAccount(url: String) { @@ -243,8 +243,8 @@ class LoginFlowNode( } NavTarget.ChooseAccountProvider -> { val callback = object : ChooseAccountProviderNode.Callback { - override fun navigateToOidc(oidcDetails: OidcDetails) { - navigateToMas(oidcDetails) + override fun navigateToOAuth(oAuthDetails: OAuthDetails) { + navigateToMas(oAuthDetails) } override fun navigateToCreateAccount(url: String) { @@ -270,8 +270,8 @@ class LoginFlowNode( isAccountCreation = navTarget.isAccountCreation, ) val callback = object : ConfirmAccountProviderNode.Callback { - override fun navigateToOidc(oidcDetails: OidcDetails) { - navigateToMas(oidcDetails) + override fun navigateToOAuth(oAuthDetails: OAuthDetails) { + navigateToMas(oAuthDetails) } override fun navigateToCreateAccount(url: String) { @@ -333,10 +333,10 @@ class LoginFlowNode( } } - private fun navigateToMas(oidcDetails: OidcDetails) { + private fun navigateToMas(oAuthDetails: OAuthDetails) { activity?.let { externalAppStarted = true - it.openUrlInChromeCustomTab(null, darkTheme, oidcDetails.url) + it.openUrlInChromeCustomTab(null, darkTheme, oAuthDetails.url) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ChangeServerError.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ChangeServerError.kt index 2f4af14237..560e6123c1 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ChangeServerError.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/error/ChangeServerError.kt @@ -41,7 +41,7 @@ sealed class ChangeServerError : Exception() { // AccountAlreadyLoggedIn error should not happen at this point is AuthenticationException.AccountAlreadyLoggedIn -> Error(messageStr = error.message) is AuthenticationException.Generic -> Error(messageStr = error.message) - is AuthenticationException.Oidc -> Error(messageStr = error.message) + is AuthenticationException.OAuth -> Error(messageStr = error.message) } } is AccountProviderAccessException.NeedElementProException -> NeedElementPro( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginHelper.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginHelper.kt index 78be770bfc..3c871a8a1d 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginHelper.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginHelper.kt @@ -23,9 +23,9 @@ import io.element.android.features.login.impl.web.WebClientUrlForAuthenticationR import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService -import io.element.android.libraries.matrix.api.auth.OidcPrompt -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow +import io.element.android.libraries.matrix.api.auth.OAuthPrompt +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow /** * This class is responsible for managing the login flow, including handling OIDC actions and @@ -35,7 +35,7 @@ import io.element.android.libraries.oidc.api.OidcActionFlow */ @Inject class LoginHelper( - private val oidcActionFlow: OidcActionFlow, + private val oAuthActionFlow: OAuthActionFlow, private val authenticationService: MatrixAuthenticationService, private val webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever, ) { @@ -44,9 +44,9 @@ class LoginHelper( @Composable fun collectLoginMode(): State> { LaunchedEffect(Unit) { - oidcActionFlow.collect { oidcAction -> - if (oidcAction != null) { - onOidcAction(oidcAction) + oAuthActionFlow.collect { oAuthAction -> + if (oAuthAction != null) { + onOAuthAction(oAuthAction) } } } @@ -73,11 +73,11 @@ class LoginHelper( throw it } }.map { matrixHomeServerDetails -> - if (matrixHomeServerDetails.supportsOidcLogin) { + if (matrixHomeServerDetails.supportsOAuthLogin) { // Retrieve the details right now - val oidcPrompt = if (isAccountCreation) OidcPrompt.Create else OidcPrompt.Login - LoginMode.Oidc( - authenticationService.getOidcUrl(prompt = oidcPrompt, loginHint = loginHint).getOrThrow() + val oAuthPrompt = if (isAccountCreation) OAuthPrompt.Create else OAuthPrompt.Login + LoginMode.OAuth( + authenticationService.getOAuthUrl(prompt = oAuthPrompt, loginHint = loginHint).getOrThrow() ) } else if (isAccountCreation) { val url = webClientUrlForAuthenticationRetriever.retrieve(homeserverUrl) @@ -99,16 +99,16 @@ class LoginHelper( ) } - private suspend fun onOidcAction(oidcAction: OidcAction) { - if (oidcAction is OidcAction.GoBack && oidcAction.toUnblock && loginModeState.value !is AsyncData.Loading) { + private suspend fun onOAuthAction(oAuthAction: OAuthAction) { + if (oAuthAction is OAuthAction.GoBack && oAuthAction.toUnblock && loginModeState.value !is AsyncData.Loading) { // Ignore GoBack action if the current state is not Loading. This GoBack action is coming from LoginFlowNode. // This can happen if there is an error, for instance attempt to login again on the same account. return } loginModeState.value = AsyncData.Loading() - when (oidcAction) { - is OidcAction.GoBack -> { - authenticationService.cancelOidcLogin() + when (oAuthAction) { + is OAuthAction.GoBack -> { + authenticationService.cancelOAuthLogin() .onSuccess { loginModeState.value = AsyncData.Uninitialized } @@ -116,13 +116,13 @@ class LoginHelper( loginModeState.value = AsyncData.Failure(failure) } } - is OidcAction.Success -> { - authenticationService.loginWithOidc(oidcAction.url) + is OAuthAction.Success -> { + authenticationService.loginWithOAuth(oAuthAction.url) .onFailure { failure -> loginModeState.value = AsyncData.Failure(failure) } } } - oidcActionFlow.reset() + oAuthActionFlow.reset() } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginMode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginMode.kt index 08e604ef20..5ea52e0ebd 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginMode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginMode.kt @@ -8,10 +8,10 @@ package io.element.android.features.login.impl.login -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails sealed interface LoginMode { data object PasswordLogin : LoginMode - data class Oidc(val oidcDetails: OidcDetails) : LoginMode + data class OAuth(val oAuthDetails: OAuthDetails) : LoginMode data class AccountCreation(val url: String) : LoginMode } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginModeView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginModeView.kt index f88e34bf4a..3549e17457 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginModeView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/login/LoginModeView.kt @@ -24,7 +24,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.LocalBuildMeta import io.element.android.libraries.matrix.api.auth.AuthenticationException -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.ui.strings.CommonStrings @Composable @@ -32,7 +32,7 @@ fun LoginModeView( loginMode: AsyncData, onClearError: () -> Unit, onLearnMoreClick: () -> Unit, - onOidcDetails: (OidcDetails) -> Unit, + onOAuthDetails: (OAuthDetails) -> Unit, onNeedLoginPassword: () -> Unit, onCreateAccountContinue: (url: String) -> Unit ) { @@ -118,7 +118,7 @@ fun LoginModeView( is AsyncData.Loading -> Unit // The Continue button shows the loading state is AsyncData.Success -> { when (val loginModeData = loginMode.data) { - is LoginMode.Oidc -> onOidcDetails(loginModeData.oidcDetails) + is LoginMode.OAuth -> onOAuthDetails(loginModeData.oAuthDetails) LoginMode.PasswordLogin -> onNeedLoginPassword() is LoginMode.AccountCreation -> onCreateAccountContinue(loginModeData.url) } @@ -137,7 +137,7 @@ internal fun LoginModeViewPreview(@PreviewParameter(LoginModeViewErrorProvider:: loginMode = AsyncData.Failure(error), onClearError = {}, onLearnMoreClick = {}, - onOidcDetails = {}, + onOAuthDetails = {}, onNeedLoginPassword = {}, onCreateAccountContinue = {} ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNode.kt index 613aa6aeb6..03264551a5 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNode.kt @@ -135,8 +135,8 @@ class QrCodeLoginFlowNode( is QrLoginException.SlidingSyncNotAvailable -> { backstack.replace(NavTarget.Error(QrCodeErrorScreenType.SlidingSyncNotAvailable)) } - is QrLoginException.OidcMetadataInvalid -> { - Timber.e(error, "OIDC metadata is invalid") + is QrLoginException.OAuthMetadataInvalid -> { + Timber.e(error, "OAuth metadata is invalid") backstack.replace(NavTarget.Error(QrCodeErrorScreenType.UnknownError)) } QrLoginException.CheckCodeAlreadySent, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderNode.kt index 5dc6ebbd6b..5f79f197d9 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderNode.kt @@ -20,7 +20,7 @@ import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.features.login.impl.util.openLearnMorePage import io.element.android.libraries.architecture.callback -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails @ContributesNode(AppScope::class) @AssistedInject @@ -31,7 +31,7 @@ class ChooseAccountProviderNode( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun navigateToLoginPassword() - fun navigateToOidc(oidcDetails: OidcDetails) + fun navigateToOAuth(oAuthDetails: OAuthDetails) fun navigateToCreateAccount(url: String) } @@ -45,7 +45,7 @@ class ChooseAccountProviderNode( state = state, modifier = modifier, onBackClick = ::navigateUp, - onOidcDetails = callback::navigateToOidc, + onOAuthDetails = callback::navigateToOAuth, onNeedLoginPassword = callback::navigateToLoginPassword, onLearnMoreClick = { openLearnMorePage(context) }, onCreateAccountContinue = callback::navigateToCreateAccount, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderView.kt index cdb80304a7..f05606dbc3 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderView.kt @@ -43,14 +43,14 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.TopAppBar -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.ui.strings.CommonStrings @Composable fun ChooseAccountProviderView( state: ChooseAccountProviderState, onBackClick: () -> Unit, - onOidcDetails: (OidcDetails) -> Unit, + onOAuthDetails: (OAuthDetails) -> Unit, onNeedLoginPassword: () -> Unit, onLearnMoreClick: () -> Unit, onCreateAccountContinue: (url: String) -> Unit, @@ -129,7 +129,7 @@ fun ChooseAccountProviderView( state.eventSink(ChooseAccountProviderEvents.ClearError) }, onLearnMoreClick = onLearnMoreClick, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onCreateAccountContinue = onCreateAccountContinue, ) @@ -144,7 +144,7 @@ internal fun ChooseAccountProviderViewPreview(@PreviewParameter(ChooseAccountPro state = state, onBackClick = { }, onLearnMoreClick = { }, - onOidcDetails = { }, + onOAuthDetails = { }, onNeedLoginPassword = { }, onCreateAccountContinue = { }, ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNode.kt index f2ff998652..cfbd86f363 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/ClassicFlowNode.kt @@ -31,7 +31,7 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.appyx.rememberFaderOrSliderTransitionHandler import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.createNode -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.matrix.api.core.UserId import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -54,7 +54,7 @@ class ClassicFlowNode( interface Callback : Plugin { fun navigateToOnBoarding(allowBackNavigation: Boolean) fun navigateToLoginPassword() - fun navigateToOidc(oidcDetails: OidcDetails) + fun navigateToOAuth(oAuthDetails: OAuthDetails) fun navigateToCreateAccount(url: String) } @@ -111,8 +111,8 @@ class ClassicFlowNode( callback.navigateToLoginPassword() } - override fun navigateToOidc(oidcDetails: OidcDetails) { - callback.navigateToOidc(oidcDetails) + override fun navigateToOAuth(oAuthDetails: OAuthDetails) { + callback.navigateToOAuth(oAuthDetails) } override fun navigateToCreateAccount(url: String) { diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicNode.kt index c42248a3f8..d5acca38ae 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicNode.kt @@ -21,7 +21,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.matrix.api.core.UserId @ContributesNode(AppScope::class) @@ -35,7 +35,7 @@ class LoginWithClassicNode( interface Callback : Plugin { fun navigateToOtherOptions() fun navigateToLoginPassword() - fun navigateToOidc(oidcDetails: OidcDetails) + fun navigateToOAuth(oAuthDetails: OAuthDetails) fun navigateToCreateAccount(url: String) fun navigateToMissingKeyBackup() } @@ -60,7 +60,7 @@ class LoginWithClassicNode( state = state, modifier = modifier, onOtherOptionsClick = callback::navigateToOtherOptions, - onOidcDetails = callback::navigateToOidc, + onOAuthDetails = callback::navigateToOAuth, onNeedLoginPassword = callback::navigateToLoginPassword, onLearnMoreClick = { openLearnMorePage(context) }, onCreateAccountContinue = callback::navigateToCreateAccount, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicView.kt index 6b5c48f1ec..b1ca50fe61 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/classic/loginwithclassic/LoginWithClassicView.kt @@ -49,7 +49,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.OutlinedButton import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings @@ -59,7 +59,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun LoginWithClassicView( state: LoginWithClassicState, onOtherOptionsClick: () -> Unit, - onOidcDetails: (OidcDetails) -> Unit, + onOAuthDetails: (OAuthDetails) -> Unit, onNeedLoginPassword: () -> Unit, onLearnMoreClick: () -> Unit, onCreateAccountContinue: (url: String) -> Unit, @@ -200,7 +200,7 @@ fun LoginWithClassicView( state.eventSink(LoginWithClassicEvent.ClearError) }, onLearnMoreClick = onLearnMoreClick, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onCreateAccountContinue = onCreateAccountContinue, ) @@ -212,7 +212,7 @@ internal fun LoginWithClassicViewPreview(@PreviewParameter(LoginWithClassicState LoginWithClassicView( state = state, onOtherOptionsClick = {}, - onOidcDetails = {}, + onOAuthDetails = {}, onNeedLoginPassword = {}, onLearnMoreClick = {}, onCreateAccountContinue = {}, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderNode.kt index e3643afbf2..928a493dc1 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderNode.kt @@ -22,7 +22,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails @ContributesNode(AppScope::class) @AssistedInject @@ -44,7 +44,7 @@ class ConfirmAccountProviderNode( interface Callback : Plugin { fun navigateToLoginPassword() - fun navigateToOidc(oidcDetails: OidcDetails) + fun navigateToOAuth(oAuthDetails: OAuthDetails) fun navigateToCreateAccount(url: String) fun navigateToChangeAccountProvider() } @@ -58,7 +58,7 @@ class ConfirmAccountProviderNode( ConfirmAccountProviderView( state = state, modifier = modifier, - onOidcDetails = callback::navigateToOidc, + onOAuthDetails = callback::navigateToOAuth, onNeedLoginPassword = callback::navigateToLoginPassword, onCreateAccountContinue = callback::navigateToCreateAccount, onChange = callback::navigateToChangeAccountProvider, 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 a175ab556d..c2525f3756 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 @@ -30,7 +30,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.TextButton -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings @@ -38,7 +38,7 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun ConfirmAccountProviderView( state: ConfirmAccountProviderState, - onOidcDetails: (OidcDetails) -> Unit, + onOAuthDetails: (OAuthDetails) -> Unit, onNeedLoginPassword: () -> Unit, onLearnMoreClick: () -> Unit, onCreateAccountContinue: (url: String) -> Unit, @@ -103,7 +103,7 @@ fun ConfirmAccountProviderView( eventSink(ConfirmAccountProviderEvents.ClearError) }, onLearnMoreClick = onLearnMoreClick, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onCreateAccountContinue = onCreateAccountContinue, ) @@ -117,7 +117,7 @@ internal fun ConfirmAccountProviderViewPreview( ) = ElementPreview { ConfirmAccountProviderView( state = state, - onOidcDetails = {}, + onOAuthDetails = {}, onNeedLoginPassword = {}, onCreateAccountContinue = {}, onLearnMoreClick = {}, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingNode.kt index 5572c412a0..99f7e86fd3 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingNode.kt @@ -22,7 +22,7 @@ import io.element.android.features.login.impl.util.openLearnMorePage import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.inputs -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails @ContributesNode(AppScope::class) @AssistedInject @@ -40,7 +40,7 @@ class OnBoardingNode( fun navigateToQrCode() fun navigateToBugReport() fun navigateToLoginPassword() - fun navigateToOidc(oidcDetails: OidcDetails) + fun navigateToOAuth(oAuthDetails: OAuthDetails) fun navigateToCreateAccount(url: String) fun navigateToDeveloperSettings() fun onDone() @@ -71,7 +71,7 @@ class OnBoardingNode( onCreateAccount = callback::navigateToSignUpFlow, onSignInWithQrCode = callback::navigateToQrCode, onReportProblem = callback::navigateToBugReport, - onOidcDetails = callback::navigateToOidc, + onOAuthDetails = callback::navigateToOAuth, onNeedLoginPassword = callback::navigateToLoginPassword, onLearnMoreClick = { openLearnMorePage(context) }, onCreateAccountContinue = callback::navigateToCreateAccount, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt index 5ee7ab6ac4..53c36ac4f8 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingView.kt @@ -50,7 +50,7 @@ import io.element.android.libraries.designsystem.theme.components.IconButton import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings @@ -68,7 +68,7 @@ fun OnBoardingView( onSignInWithQrCode: () -> Unit, onSignIn: (mustChooseAccountProvider: Boolean) -> Unit, onCreateAccount: () -> Unit, - onOidcDetails: (OidcDetails) -> Unit, + onOAuthDetails: (OAuthDetails) -> Unit, onNeedLoginPassword: () -> Unit, onLearnMoreClick: () -> Unit, onCreateAccountContinue: (url: String) -> Unit, @@ -82,7 +82,7 @@ fun OnBoardingView( state.eventSink(OnBoardingEvents.ClearError) }, onLearnMoreClick = onLearnMoreClick, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onCreateAccountContinue = onCreateAccountContinue, ) @@ -354,7 +354,7 @@ internal fun OnBoardingViewPreview( onSignIn = {}, onCreateAccount = {}, onReportProblem = {}, - onOidcDetails = {}, + onOAuthDetails = {}, onNeedLoginPassword = {}, onLearnMoreClick = {}, onCreateAccountContinue = {}, diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt index 86a629270f..a05194d008 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPointTest.kt @@ -17,7 +17,7 @@ import io.element.android.features.login.api.LoginEntryPoint import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.classic.FakeElementClassicConnection import io.element.android.features.preferences.test.FakePreferencesEntryPoint -import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow +import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.node.TestParentNode import kotlinx.coroutines.test.runTest @@ -39,7 +39,7 @@ class DefaultLoginEntryPointTest { buildContext = buildContext, plugins = plugins, accountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()), - oidcActionFlow = FakeOidcActionFlow(), + oAuthActionFlow = FakeOAuthActionFlow(), appCoroutineScope = backgroundScope, elementClassicConnection = FakeElementClassicConnection(), preferencesEntryPoint = FakePreferencesEntryPoint(), diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt index 1fb5d37627..274b58ee49 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenterTest.kt @@ -50,7 +50,7 @@ class ChangeServerPresenterTest { fun `present - change server ok`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) createPresenter( diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt index 9d2628005c..112d8d7108 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/qrcode/QrCodeLoginFlowNodeTest.kt @@ -79,7 +79,7 @@ class QrCodeLoginFlowNodeTest { qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.ConnectionInsecure) assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.InsecureChannelDetected)) - qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.OidcMetadataInvalid) + qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.OAuthMetadataInvalid) assertThat(flowNode.currentNavTarget()).isEqualTo(QrCodeLoginFlowNode.NavTarget.Error(QrCodeErrorScreenType.UnknownError)) qrCodeLoginManager.currentLoginStep.value = QrCodeLoginStep.Failed(QrLoginException.Unknown) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt index f7ff5d384d..c6610b212c 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderViewTest.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 import io.element.android.features.login.impl.accountprovider.anAccountProvider import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -84,7 +84,7 @@ class ChooseAccountProviderViewTest { private fun AndroidComposeTestRule.setChooseAccountProviderView( state: ChooseAccountProviderState, onBackClick: () -> Unit = EnsureNeverCalled(), - onOidcDetails: (OidcDetails) -> Unit = EnsureNeverCalledWithParam(), + onOAuthDetails: (OAuthDetails) -> Unit = EnsureNeverCalledWithParam(), onNeedLoginPassword: () -> Unit = EnsureNeverCalled(), onLearnMoreClick: () -> Unit = EnsureNeverCalled(), onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(), @@ -93,7 +93,7 @@ class ChooseAccountProviderViewTest { ChooseAccountProviderView( state = state, onBackClick = onBackClick, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onLearnMoreClick = onLearnMoreClick, onCreateAccountContinue = onCreateAccountContinue, diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt index 6372841250..a9045ab152 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenterTest.kt @@ -22,9 +22,9 @@ import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow -import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow +import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.test import kotlinx.coroutines.test.runTest @@ -74,7 +74,7 @@ class ConfirmAccountProviderPresenterTest { fun `present - continue oidc`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) val presenter = createConfirmAccountProviderPresenter( @@ -89,21 +89,21 @@ class ConfirmAccountProviderPresenterTest { val successState = awaitItem() assertThat(successState.submitEnabled).isFalse() assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) + assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) } } @Test - fun `present - oidc - cancel with failure`() = runTest { + fun `present - OAuth - cancel with failure`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) - val defaultOidcActionFlow = FakeOidcActionFlow() + val defaultOAuthActionFlow = FakeOAuthActionFlow() val presenter = createConfirmAccountProviderPresenter( matrixAuthenticationService = authenticationService, - defaultOidcActionFlow = defaultOidcActionFlow, + defaultOAuthActionFlow = defaultOAuthActionFlow, ) presenter.test { val initialState = awaitItem() @@ -114,25 +114,25 @@ class ConfirmAccountProviderPresenterTest { val successState = awaitItem() assertThat(successState.submitEnabled).isFalse() assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) - authenticationService.givenOidcCancelError(AN_EXCEPTION) - defaultOidcActionFlow.post(OidcAction.GoBack()) + assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) + authenticationService.givenOAuthCancelError(AN_EXCEPTION) + defaultOAuthActionFlow.post(OAuthAction.GoBack()) val cancelFailureState = awaitItem() assertThat(cancelFailureState.loginMode).isInstanceOf(AsyncData.Failure::class.java) } } @Test - fun `present - oidc - cancel with success`() = runTest { + fun `present - OAuth - cancel with success`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) - val defaultOidcActionFlow = FakeOidcActionFlow() + val defaultOAuthActionFlow = FakeOAuthActionFlow() val presenter = createConfirmAccountProviderPresenter( matrixAuthenticationService = authenticationService, - defaultOidcActionFlow = defaultOidcActionFlow, + defaultOAuthActionFlow = defaultOAuthActionFlow, ) presenter.test { val initialState = awaitItem() @@ -143,24 +143,24 @@ class ConfirmAccountProviderPresenterTest { val successState = awaitItem() assertThat(successState.submitEnabled).isFalse() assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) - defaultOidcActionFlow.post(OidcAction.GoBack()) + assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) + defaultOAuthActionFlow.post(OAuthAction.GoBack()) val cancelFinalState = awaitItem() assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java) } } @Test - fun `present - oidc - cancel to unblock`() = runTest { + fun `present - OAuth - cancel to unblock`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) - val defaultOidcActionFlow = FakeOidcActionFlow() + val defaultOAuthActionFlow = FakeOAuthActionFlow() val presenter = createConfirmAccountProviderPresenter( matrixAuthenticationService = authenticationService, - defaultOidcActionFlow = defaultOidcActionFlow, + defaultOAuthActionFlow = defaultOAuthActionFlow, ) presenter.test { val initialState = awaitItem() @@ -168,23 +168,23 @@ class ConfirmAccountProviderPresenterTest { val loadingState = awaitItem() assertThat(loadingState.submitEnabled).isTrue() assertThat(loadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java) - defaultOidcActionFlow.post(OidcAction.GoBack(toUnblock = true)) + defaultOAuthActionFlow.post(OAuthAction.GoBack(toUnblock = true)) val cancelFinalState = awaitItem() assertThat(cancelFinalState.loginMode).isInstanceOf(AsyncData.Uninitialized::class.java) } } @Test - fun `present - oidc - success with failure`() = runTest { + fun `present - OAuth - success with failure`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) - val defaultOidcActionFlow = FakeOidcActionFlow() + val defaultOAuthActionFlow = FakeOAuthActionFlow() val presenter = createConfirmAccountProviderPresenter( matrixAuthenticationService = authenticationService, - defaultOidcActionFlow = defaultOidcActionFlow, + defaultOAuthActionFlow = defaultOAuthActionFlow, ) presenter.test { val initialState = awaitItem() @@ -195,9 +195,9 @@ class ConfirmAccountProviderPresenterTest { val successState = awaitItem() assertThat(successState.submitEnabled).isFalse() assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) + assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) authenticationService.givenLoginError(AN_EXCEPTION) - defaultOidcActionFlow.post(OidcAction.Success("aUrl")) + defaultOAuthActionFlow.post(OAuthAction.Success("aUrl")) val cancelLoadingState = awaitItem() assertThat(cancelLoadingState.loginMode).isInstanceOf(AsyncData.Loading::class.java) val cancelFailureState = awaitItem() @@ -206,16 +206,16 @@ class ConfirmAccountProviderPresenterTest { } @Test - fun `present - oidc - success with success`() = runTest { + fun `present - OAuth - success with success`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) - val defaultOidcActionFlow = FakeOidcActionFlow() + val defaultOidcActionFlow = FakeOAuthActionFlow() val presenter = createConfirmAccountProviderPresenter( matrixAuthenticationService = authenticationService, - defaultOidcActionFlow = defaultOidcActionFlow, + defaultOAuthActionFlow = defaultOidcActionFlow, ) presenter.test { val initialState = awaitItem() @@ -226,8 +226,8 @@ class ConfirmAccountProviderPresenterTest { val successState = awaitItem() assertThat(successState.submitEnabled).isFalse() assertThat(successState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) - defaultOidcActionFlow.post(OidcAction.Success("aUrl")) + assertThat(successState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) + defaultOidcActionFlow.post(OAuthAction.Success("aUrl")) val successSuccessState = awaitItem() assertThat(successSuccessState.loginMode).isInstanceOf(AsyncData.Loading::class.java) } @@ -311,10 +311,10 @@ class ConfirmAccountProviderPresenterTest { } @Test - fun `present - confirm account creation with oidc is successful`() = runTest { + fun `present - confirm account creation with OAuth is successful`() = runTest { val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) val presenter = createConfirmAccountProviderPresenter( @@ -327,16 +327,16 @@ class ConfirmAccountProviderPresenterTest { skipItems(1) // Loading val submittedState = awaitItem() assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) + assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) } } @Test - fun `present - confirm account creation with oidc and url continues with oidc`() = runTest { + fun `present - confirm account creation with OAuth and url continues with OAuth`() = runTest { val aUrl = "aUrl" val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { - Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true)) + Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ) val presenter = createConfirmAccountProviderPresenter( @@ -350,12 +350,12 @@ class ConfirmAccountProviderPresenterTest { skipItems(1) // Loading val submittedState = awaitItem() assertThat(submittedState.loginMode).isInstanceOf(AsyncData.Success::class.java) - assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.Oidc::class.java) + assertThat(submittedState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) } } @Test - fun `present - confirm account creation without oidc and with url continuing with url`() = runTest { + fun `present - confirm account creation without OAuth and with url continuing with url`() = runTest { val aUrl = "aUrl" val authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { @@ -380,14 +380,14 @@ class ConfirmAccountProviderPresenterTest { params: ConfirmAccountProviderPresenter.Params = ConfirmAccountProviderPresenter.Params(isAccountCreation = false), accountProviderDataSource: AccountProviderDataSource = AccountProviderDataSource(FakeEnterpriseService()), matrixAuthenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(), - defaultOidcActionFlow: OidcActionFlow = FakeOidcActionFlow(), + defaultOAuthActionFlow: OAuthActionFlow = FakeOAuthActionFlow(), webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(), ) = ConfirmAccountProviderPresenter( params = params, accountProviderDataSource = accountProviderDataSource, loginHelper = createLoginHelper( authenticationService = matrixAuthenticationService, - oidcActionFlow = defaultOidcActionFlow, + oAuthActionFlow = defaultOAuthActionFlow, webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever, ), ) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenterTest.kt index 1fdfb7e070..8249694278 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenterTest.kt @@ -31,8 +31,8 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL_2 import io.element.android.libraries.matrix.test.A_LOGIN_HINT import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.oidc.api.OidcActionFlow -import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow +import io.element.android.libraries.oauth.api.OAuthActionFlow +import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore import io.element.android.libraries.sessionstorage.test.aSessionData @@ -312,11 +312,11 @@ private fun createPresenter( ) fun createLoginHelper( - oidcActionFlow: OidcActionFlow = FakeOidcActionFlow(), + oAuthActionFlow: OAuthActionFlow = FakeOAuthActionFlow(), authenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(), webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(), ): LoginHelper = LoginHelper( - oidcActionFlow = oidcActionFlow, + oAuthActionFlow = oAuthActionFlow, authenticationService = authenticationService, webClientUrlForAuthenticationRetriever = webClientUrlForAuthenticationRetriever, ) diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt index ad09445075..a8f0ccbb5a 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/onboarding/OnboardingViewTest.kt @@ -19,7 +19,7 @@ import com.google.testing.junit.testparameterinjector.TestParameter import io.element.android.features.login.impl.R import io.element.android.features.login.impl.login.LoginMode import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.matrix.api.auth.OidcDetails +import io.element.android.libraries.matrix.api.auth.OAuthDetails import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -224,14 +224,14 @@ class OnboardingViewTest { @Test fun `when success Oidc - the expected callback is invoked and the event is received`() { val eventSink = EventsRecorder() - val oidcDetails = OidcDetails("aUrl") - ensureCalledOnceWithParam(oidcDetails) { callback -> + val oAuthDetails = OAuthDetails("aUrl") + ensureCalledOnceWithParam(oAuthDetails) { callback -> rule.setOnboardingView( state = anOnBoardingState( - loginMode = AsyncData.Success(LoginMode.Oidc(oidcDetails)), + loginMode = AsyncData.Success(LoginMode.OAuth(oAuthDetails)), eventSink = eventSink, ), - onOidcDetails = callback, + onOAuthDetails = callback, ) } eventSink.assertSingle(OnBoardingEvents.ClearError) @@ -240,8 +240,8 @@ class OnboardingViewTest { @Test fun `when success AccountCreation - the expected callback is invoked and the event is received`() { val eventSink = EventsRecorder() - val oidcDetails = OidcDetails("aUrl") - ensureCalledOnceWithParam(oidcDetails.url) { callback -> + val oAuthDetails = OAuthDetails("aUrl") + ensureCalledOnceWithParam(oAuthDetails.url) { callback -> rule.setOnboardingView( state = anOnBoardingState( loginMode = AsyncData.Success(LoginMode.AccountCreation("aUrl")), @@ -261,7 +261,7 @@ class OnboardingViewTest { onSignIn: (Boolean) -> Unit = EnsureNeverCalledWithParam(), onCreateAccount: () -> Unit = EnsureNeverCalled(), onReportProblem: () -> Unit = EnsureNeverCalled(), - onOidcDetails: (OidcDetails) -> Unit = EnsureNeverCalledWithParam(), + onOAuthDetails: (OAuthDetails) -> Unit = EnsureNeverCalledWithParam(), onNeedLoginPassword: () -> Unit = EnsureNeverCalled(), onLearnMoreClick: () -> Unit = EnsureNeverCalled(), onCreateAccountContinue: (url: String) -> Unit = EnsureNeverCalledWithParam(), @@ -275,7 +275,7 @@ class OnboardingViewTest { onSignIn = onSignIn, onCreateAccount = onCreateAccount, onReportProblem = onReportProblem, - onOidcDetails = onOidcDetails, + onOAuthDetails = onOAuthDetails, onNeedLoginPassword = onNeedLoginPassword, onLearnMoreClick = onLearnMoreClick, onCreateAccountContinue = onCreateAccountContinue, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt index ef446e36cf..e10dd2e1bc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/actionlist/ActionListView.kt @@ -156,6 +156,7 @@ fun ActionListView( sheetState = sheetState, onDismissRequest = ::onDismiss, modifier = modifier, + scrollable = false, ) { ActionListViewContent( state = state, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt index 98e2bba3be..c14dd03f1e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/crypto/sendfailure/resolve/ResolveVerifiedUserSendFailureView.kt @@ -75,6 +75,7 @@ fun ResolveVerifiedUserSendFailureView( .navigationBarsPadding(), sheetState = sheetState, onDismissRequest = ::dismiss, + scrollable = true, ) { IconTitleSubtitleMolecule( modifier = Modifier.padding(24.dp), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt index 1fdb61f484..405e2b0be9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/AttachmentsBottomSheet.kt @@ -13,6 +13,8 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -74,7 +76,8 @@ internal fun AttachmentsBottomSheet( sheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true ), - onDismissRequest = { isVisible = false } + onDismissRequest = { isVisible = false }, + scrollable = false, ) { AttachmentSourcePickerMenu( state = state, @@ -97,6 +100,7 @@ private fun AttachmentSourcePickerMenu( modifier = Modifier .navigationBarsPadding() .imePadding() + .verticalScroll(rememberScrollState()) ) { ListItem( modifier = Modifier.clickable { state.eventSink(MessageComposerEvent.PickAttachmentSource.PhotoFromCamera) }, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt index f42a26cf65..4ac83c520b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/customreaction/CustomReactionBottomSheet.kt @@ -50,7 +50,8 @@ fun CustomReactionBottomSheet( ModalBottomSheet( onDismissRequest = ::onDismiss, sheetState = sheetState, - modifier = modifier + modifier = modifier, + scrollable = false, ) { val presenter = remember { EmojiPickerPresenter( diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt index 03ce564eff..2a902fd692 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/reactionsummary/ReactionSummaryView.kt @@ -90,7 +90,8 @@ fun ReactionSummaryView( if (state.target != null) { ModalBottomSheet( onDismissRequest = ::onDismiss, - modifier = modifier + modifier = modifier, + scrollable = false, ) { ReactionSummaryViewContent(summary = state.target) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt index b65e326045..9637298d58 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/receipt/bottomsheet/ReadReceiptBottomSheet.kt @@ -57,7 +57,8 @@ internal fun ReadReceiptBottomSheet( sheetState.hide() state.eventSink(ReadReceiptBottomSheetEvent.Dismiss) } - } + }, + scrollable = false, ) { ReadReceiptBottomSheetContent( state = state, diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt index e5d48ec175..d324f5eb3a 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.featureflag.test.FakeFeature import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.indicator.api.IndicatorService import io.element.android.libraries.indicator.test.FakeIndicatorService -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_SESSION_ID diff --git a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt index 269fdee664..2f8dab8029 100644 --- a/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt +++ b/features/rolesandpermissions/impl/src/main/kotlin/io/element/android/features/rolesandpermissions/impl/root/RolesAndPermissionsView.kt @@ -153,6 +153,7 @@ private fun ChangeOwnRoleBottomSheet( .navigationBarsPadding(), sheetState = sheetState, onDismissRequest = ::dismiss, + scrollable = true, ) { Text( modifier = Modifier.padding(14.dp), diff --git a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt index ac6c5bc4cb..884e421e1f 100644 --- a/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt +++ b/features/roommembermoderation/impl/src/main/kotlin/io/element/android/features/roommembermoderation/impl/RoomMemberModerationView.kt @@ -17,6 +17,8 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.systemBarsPadding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -224,9 +226,12 @@ private fun RoomMemberActionsBottomSheet( onDismiss() } }, + scrollable = false, ) { Column( - modifier = Modifier.padding(vertical = 16.dp) + modifier = Modifier + .padding(vertical = 16.dp) + .verticalScroll(rememberScrollState()) ) { Avatar( avatarData = user.getAvatarData(size = AvatarSize.RoomListManageUser), diff --git a/features/securebackup/impl/build.gradle.kts b/features/securebackup/impl/build.gradle.kts index b6117271f7..82f30fa5ce 100644 --- a/features/securebackup/impl/build.gradle.kts +++ b/features/securebackup/impl/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrixui) implementation(projects.libraries.designsystem) - implementation(projects.libraries.oidc.api) + implementation(projects.libraries.oauth.api) implementation(projects.libraries.uiStrings) implementation(projects.libraries.testtags) api(libs.statemachine) diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt index c4a007f1d5..4e2284890f 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.architecture.createNode import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope -import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle +import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -123,12 +123,12 @@ class ResetIdentityFlowNode( null -> { Timber.d("No reset handle return, the reset is done.") } - is IdentityOidcResetHandle -> { + is IdentityOAuthResetHandle -> { Timber.d("Launching reset confirmation in MAS") activity.openUrlInChromeCustomTab(null, darkTheme, handle.url) - Timber.d("Starting resetOidc") - resetJob = launch { handle.resetOidc() } - resetJob?.invokeOnCompletion { Timber.d("resetOidc ended") } + Timber.d("Starting resetOAuth") + resetJob = launch { handle.resetOAuth() } + resetJob?.invokeOnCompletion { Timber.d("resetOAuth ended") } } is IdentityPasswordResetHandle -> backstack.push(NavTarget.ResetPassword) } diff --git a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt index 396339adbb..95a57db93e 100644 --- a/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt +++ b/features/signedout/impl/src/main/kotlin/io/element/android/features/signedout/impl/SignedOutStateProvider.kt @@ -36,7 +36,7 @@ private fun aSessionData( accessToken = "anAccessToken", refreshToken = "aRefreshToken", homeserverUrl = "aHomeserverUrl", - oidcData = null, + oAuthData = null, loginTimestamp = null, isTokenValid = isTokenValid, loginType = LoginType.UNKNOWN, diff --git a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt index e4f8a4faf2..360c59881c 100644 --- a/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt +++ b/features/startchat/impl/src/main/kotlin/io/element/android/features/startchat/impl/joinbyaddress/JoinRoomByAddressView.kt @@ -13,8 +13,10 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -52,11 +54,13 @@ fun JoinRoomByAddressView( onDismissRequest = { state.eventSink(JoinRoomByAddressEvent.Dismiss) }, + scrollable = false, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(all = 16.dp), + .padding(all = 16.dp) + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, ) { RoomAddressField( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index edbfdc2489..681a9173c4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ telephoto = "0.19.0" haze = "1.7.2" # Dependency analysis -dependencyAnalysis = "3.7.0" +dependencyAnalysis = "3.9.0" # DI metro = "0.13.2" @@ -178,7 +178,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version # https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt # All new features should not be implemented in the pull request that upgrades the version, developers should # only fix API breaks and may add some TODOs. -matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.04.21" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:26.04.27" # Others coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } @@ -191,7 +191,7 @@ serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-jso kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0" showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" } showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" } -jsoup = "org.jsoup:jsoup:1.21.2" +jsoup = "org.jsoup:jsoup:1.22.2" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:2.2.0" timber = "com.jakewharton.timber:timber:5.0.1" @@ -222,7 +222,7 @@ color_picker = "io.mhssn:colorpicker:1.0.0" # Analytics posthog = "com.posthog:posthog-android:3.39.0" -sentry = "io.sentry:sentry-android:8.39.1" +sentry = "io.sentry:sentry-android:8.40.0" # main branch can be tested replacing the version with main-SNAPSHOT matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.33.2" @@ -234,7 +234,7 @@ sigpwned_emoji4j = "com.sigpwned:emoji4j-core:16.0.0" metro_runtime = { module = "dev.zacsweers.metro:runtime", version.ref = "metro" } # Element Call -element_call_embedded = "io.element.android:element-call-embedded:0.19.1" +element_call_embedded = "io.element.android:element-call-embedded:0.19.2" # Auto services google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/FlowStepPage.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/FlowStepPage.kt index b62f634ece..a29e1b743c 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/FlowStepPage.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/pages/FlowStepPage.kt @@ -71,7 +71,7 @@ fun FlowStepPage( }, header = { IconTitleSubtitleMolecule( - modifier = Modifier.padding(bottom = 16.dp), + modifier = Modifier.padding(bottom = 16.dp, start = 8.dp, end = 8.dp), title = title, subTitle = subTitle, iconStyle = iconStyle, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt index 34d119508a..9c3930ac64 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/SimpleModalBottomSheet.kt @@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -38,11 +40,13 @@ fun SimpleModalBottomSheet( onDismissRequest = onDismiss, modifier = modifier, sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + scrollable = false, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(16.dp), + .padding(16.dp) + .verticalScroll(rememberScrollState()), ) { Text( title, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt index 2c577ec6b7..689cba727f 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/ModalBottomSheet.kt @@ -10,10 +10,13 @@ package io.element.android.libraries.designsystem.theme.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme @@ -42,10 +45,15 @@ import io.element.android.libraries.designsystem.preview.sheetStateForPreview import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +/** + * For parameter [scrollable], set it to true if the content of the sheet does not already contain a scrollable component, such as a LazyColumn, + * to avoid nested scroll issues. In this case, the content will be wrapped in a Column with verticalScroll. + */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun ModalBottomSheet( onDismissRequest: () -> Unit, + scrollable: Boolean, modifier: Modifier = Modifier, sheetState: SheetState = rememberModalBottomSheetState(), shape: Shape = BottomSheetDefaults.ExpandedShape, @@ -79,8 +87,17 @@ fun ModalBottomSheet( scrimColor = scrimColor, dragHandle = dragHandle, contentWindowInsets = contentWindowInsets, - content = content, - ) + ) { + if (scrollable) { + Column( + modifier = Modifier.verticalScroll(rememberScrollState()), + ) { + content() + } + } else { + content() + } + } } @OptIn(ExperimentalMaterial3Api::class) @@ -91,13 +108,11 @@ fun SheetState.hide(coroutineScope: CoroutineScope, then: suspend () -> Unit) { } } -// This preview and its screenshots are blank, see: https://issuetracker.google.com/issues/283843380 @Preview(group = PreviewGroup.BottomSheets) @Composable internal fun ModalBottomSheetLightPreview() = ElementPreviewLight { ContentToPreview() } -// This preview and its screenshots are blank, see: https://issuetracker.google.com/issues/283843380 @Preview(group = PreviewGroup.BottomSheets) @Composable internal fun ModalBottomSheetDarkPreview() = @@ -112,6 +127,7 @@ private fun ContentToPreview() { ) { ModalBottomSheet( onDismissRequest = {}, + scrollable = false, ) { Text( text = "Sheet Content", diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt index 7878245aca..c8afba3603 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatter.kt @@ -77,26 +77,28 @@ class DefaultPinnedMessagesBannerFormatter( messageType.toPlainText(permalinkParser) } is VideoMessageType -> { - messageType.bestDescription.prefixWith(CommonStrings.common_video) + messageType.toPlainText(permalinkParser).prefixWith(CommonStrings.common_video) } is ImageMessageType -> { - messageType.bestDescription.prefixWith(CommonStrings.common_image) + messageType.toPlainText(permalinkParser).prefixWith(CommonStrings.common_image) } is StickerMessageType -> { - messageType.bestDescription.prefixWith(CommonStrings.common_sticker) + messageType.toPlainText(permalinkParser).prefixWith(CommonStrings.common_sticker) } is LocationMessageType -> { messageType.body.prefixWith(CommonStrings.common_shared_location) } is FileMessageType -> { - messageType.bestDescription.prefixWith(CommonStrings.common_file) + messageType.toPlainText(permalinkParser).prefixWith(CommonStrings.common_file) } is AudioMessageType -> { - messageType.bestDescription.prefixWith(CommonStrings.common_audio) + messageType.toPlainText(permalinkParser).prefixWith(CommonStrings.common_audio) } is VoiceMessageType -> { - // In this case, do not use bestDescription, because the filename is useless, only use the caption if available. - messageType.caption?.prefixWith(sp.getString(CommonStrings.common_voice_message)) + messageType + .toPlainText(permalinkParser, "") + .takeIf { it.isNotEmpty() } + ?.prefixWith(sp.getString(CommonStrings.common_voice_message)) ?: sp.getString(CommonStrings.common_voice_message) } is OtherMessageType -> { diff --git a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt index 3ecd7819e5..b9b6467c92 100644 --- a/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt +++ b/libraries/eventformatter/impl/src/main/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatter.kt @@ -139,26 +139,28 @@ class DefaultRoomLatestEventFormatter( messageType.toPlainText(permalinkParser) } is VideoMessageType -> { - messageType.bestDescription.prefixWith(sp.getString(CommonStrings.common_video)) + messageType.toPlainText(permalinkParser).prefixWith(sp.getString(CommonStrings.common_video)) } is ImageMessageType -> { - messageType.bestDescription.prefixWith(sp.getString(CommonStrings.common_image)) + messageType.toPlainText(permalinkParser).prefixWith(sp.getString(CommonStrings.common_image)) } is StickerMessageType -> { - messageType.bestDescription.prefixWith(sp.getString(CommonStrings.common_sticker)) + messageType.toPlainText(permalinkParser).prefixWith(sp.getString(CommonStrings.common_sticker)) } is LocationMessageType -> { sp.getString(CommonStrings.common_shared_location) } is FileMessageType -> { - messageType.bestDescription.prefixWith(sp.getString(CommonStrings.common_file)) + messageType.toPlainText(permalinkParser).prefixWith(sp.getString(CommonStrings.common_file)) } is AudioMessageType -> { - messageType.bestDescription.prefixWith(sp.getString(CommonStrings.common_audio)) + messageType.toPlainText(permalinkParser).prefixWith(sp.getString(CommonStrings.common_audio)) } is VoiceMessageType -> { - // In this case, do not use bestDescription, because the filename is useless, only use the caption if available. - messageType.caption?.prefixWith(sp.getString(CommonStrings.common_voice_message)) + messageType + .toPlainText(permalinkParser, "") + .takeIf { it.isNotEmpty() } + ?.prefixWith(sp.getString(CommonStrings.common_voice_message)) ?: sp.getString(CommonStrings.common_voice_message) } is OtherMessageType -> { 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 35fd7e8551..59fd7a4940 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 @@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaPreviewService import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.JoinedRoom diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt index c50ec09609..d5fd6a734a 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/AuthenticationException.kt @@ -16,6 +16,6 @@ sealed class AuthenticationException(message: String?) : Exception(message) { class InvalidServerName(message: String?) : AuthenticationException(message) class SlidingSyncVersion(message: String?) : AuthenticationException(message) class ServerUnreachable(message: String?) : AuthenticationException(message) - class Oidc(message: String?) : AuthenticationException(message) + class OAuth(message: String?) : AuthenticationException(message) class Generic(message: String?) : AuthenticationException(message) } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt index 7c82668242..04d1d13593 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixAuthenticationService.kt @@ -37,21 +37,21 @@ interface MatrixAuthenticationService { suspend fun importCreatedSession(externalSession: ExternalSession): Result /* - * OIDC part. + * OAuth part. */ /** - * Get the Oidc url to display to the user. + * Get the OAuth url to display to the user. */ - suspend fun getOidcUrl( - prompt: OidcPrompt, + suspend fun getOAuthUrl( + prompt: OAuthPrompt, loginHint: String?, - ): Result + ): Result /** - * Cancel Oidc login sequence. + * Cancel OAuth login sequence. */ - suspend fun cancelOidcLogin(): Result + suspend fun cancelOAuthLogin(): Result /** * Set the existing data about Element Classic session, if any. @@ -68,9 +68,9 @@ interface MatrixAuthenticationService { ): Boolean /** - * Attempt to login using the [callbackUrl] provided by the Oidc page. + * Attempt to log in using the [callbackUrl] provided by the OAuth page. */ - suspend fun loginWithOidc(callbackUrl: String): Result + suspend fun loginWithOAuth(callbackUrl: String): Result suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit): Result diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt index aa5ed9a41d..8dcb5c4a48 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetails.kt @@ -11,7 +11,7 @@ package io.element.android.libraries.matrix.api.auth data class MatrixHomeServerDetails( val url: String, val supportsPasswordLogin: Boolean, - val supportsOidcLogin: Boolean, + val supportsOAuthLogin: Boolean, ) { - val isSupported = supportsPasswordLogin || supportsOidcLogin + val isSupported = supportsPasswordLogin || supportsOAuthLogin } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcConfig.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthConfig.kt similarity index 97% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcConfig.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthConfig.kt index ee8b7ec50e..d3a42f42b9 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcConfig.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthConfig.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.api.auth import io.element.android.libraries.matrix.api.BuildConfig -object OidcConfig { +object OAuthConfig { const val CLIENT_URI = BuildConfig.CLIENT_URI // Note: host must match with the host of CLIENT_URI diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcDetails.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthDetails.kt similarity index 94% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcDetails.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthDetails.kt index c4fb87e3c2..d504f891ee 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcDetails.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthDetails.kt @@ -12,6 +12,6 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize -data class OidcDetails( +data class OAuthDetails( val url: String, ) : Parcelable diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcPrompt.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthPrompt.kt similarity index 81% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcPrompt.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthPrompt.kt index 8ddad9f52e..45b4e18533 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcPrompt.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthPrompt.kt @@ -8,12 +8,12 @@ package io.element.android.libraries.matrix.api.auth -sealed interface OidcPrompt { +sealed interface OAuthPrompt { /** * The Authorization Server should prompt the End-User for * reauthentication. */ - data object Login : OidcPrompt + data object Login : OAuthPrompt /** * The Authorization Server should prompt the End-User to create a user @@ -21,10 +21,10 @@ sealed interface OidcPrompt { * * Defined in [Initiating User Registration via OpenID Connect](https://openid.net/specs/openid-connect-prompt-create-1_0.html). */ - data object Create : OidcPrompt + data object Create : OAuthPrompt /** * An unknown value. */ - data class Unknown(val value: String) : OidcPrompt + data class Unknown(val value: String) : OAuthPrompt } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcRedirectUrlProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthRedirectUrlProvider.kt similarity index 89% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcRedirectUrlProvider.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthRedirectUrlProvider.kt index ad4d862474..669d47501d 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OidcRedirectUrlProvider.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/OAuthRedirectUrlProvider.kt @@ -8,6 +8,6 @@ package io.element.android.libraries.matrix.api.auth -interface OidcRedirectUrlProvider { +interface OAuthRedirectUrlProvider { fun provide(): String } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrLoginException.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrLoginException.kt index a3b567fa46..3f22244405 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrLoginException.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/auth/qrlogin/QrLoginException.kt @@ -15,7 +15,7 @@ sealed class QrLoginException : Exception() { data object Expired : QrLoginException() data object NotFound : QrLoginException() data object LinkingNotSupported : QrLoginException() - data object OidcMetadataInvalid : QrLoginException() + data object OAuthMetadataInvalid : QrLoginException() data object SlidingSyncNotAvailable : QrLoginException() data object OtherDeviceNotSignedIn : QrLoginException() data object CheckCodeAlreadySent : QrLoginException() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt index aefad517dc..333cfb709b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/encryption/EncryptionService.kt @@ -112,19 +112,19 @@ interface IdentityPasswordResetHandle : IdentityResetHandle { } /** - * A handle to reset the user's identity with an OIDC login type. + * A handle to reset the user's identity with an OAuth login type. */ -interface IdentityOidcResetHandle : IdentityResetHandle { +interface IdentityOAuthResetHandle : IdentityResetHandle { /** * The URL to open in a webview/custom tab to reset the identity. */ val url: String /** - * Reset the identity using the OIDC flow. + * Reset the identity using the OAuth flow. * * This method will block the coroutine it's running on and keep polling indefinitely until either the coroutine is cancelled, the [cancel] method is * called, or the identity is reset. */ - suspend fun resetOidc(): Result + suspend fun resetOAuth(): Result } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oauth/AccountManagementAction.kt similarity index 91% rename from libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt rename to libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oauth/AccountManagementAction.kt index e1c7764e58..6dd0f6e53c 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oidc/AccountManagementAction.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/oauth/AccountManagementAction.kt @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.matrix.api.oidc +package io.element.android.libraries.matrix.api.oauth import io.element.android.libraries.matrix.api.core.DeviceId diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt index 32a6f2e409..f3fefab9a8 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/JoinedRoom.kt @@ -196,9 +196,9 @@ interface JoinedRoom : BaseRoom { /** * Start sharing live location in this room. * @param durationMillis How long to share location (in milliseconds). - * @return Result indicating success or failure. + * @return Result containing the [EventId] of the beacon state event on success or an error on failure. */ - suspend fun startLiveLocationShare(durationMillis: Long): Result + suspend fun startLiveLocationShare(durationMillis: Long): Result /** * Stop sharing live location in this room. diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetailsTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetailsTest.kt index d4b360ef53..9babb7a738 100644 --- a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetailsTest.kt +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/auth/MatrixHomeServerDetailsTest.kt @@ -16,7 +16,7 @@ class MatrixHomeServerDetailsTest { @Test fun `if homeserver supports oidc, then it is supported`() { val sut = aMatrixHomeServerDetails( - supportsOidcLogin = true, + supportsOAuthLogin = true, supportsPasswordLogin = false, ) assertThat(sut.isSupported).isTrue() @@ -25,7 +25,7 @@ class MatrixHomeServerDetailsTest { @Test fun `if homeserver supports password, then it is supported`() { val sut = aMatrixHomeServerDetails( - supportsOidcLogin = false, + supportsOAuthLogin = false, supportsPasswordLogin = true, ) assertThat(sut.isSupported).isTrue() @@ -34,7 +34,7 @@ class MatrixHomeServerDetailsTest { @Test fun `if homeserver supports both, then it is supported`() { val sut = aMatrixHomeServerDetails( - supportsOidcLogin = true, + supportsOAuthLogin = true, supportsPasswordLogin = true, ) assertThat(sut.isSupported).isTrue() @@ -43,7 +43,7 @@ class MatrixHomeServerDetailsTest { @Test fun `if homeserver supports none, then it is not supported`() { val sut = aMatrixHomeServerDetails( - supportsOidcLogin = false, + supportsOAuthLogin = false, supportsPasswordLogin = false, ) assertThat(sut.isSupported).isFalse() 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 bb6806b5d4..5a1dc9da4b 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 @@ -31,7 +31,7 @@ import io.element.android.libraries.matrix.api.createroom.RoomPreset import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopHandler import io.element.android.libraries.matrix.api.linknewdevice.LinkMobileHandler import io.element.android.libraries.matrix.api.media.MatrixMediaLoader -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -59,7 +59,7 @@ import io.element.android.libraries.matrix.impl.media.RustMediaLoader import io.element.android.libraries.matrix.impl.media.RustMediaPreviewService import io.element.android.libraries.matrix.impl.notification.RustNotificationService import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService -import io.element.android.libraries.matrix.impl.oidc.toRustAction +import io.element.android.libraries.matrix.impl.oauth.toRustAction import io.element.android.libraries.matrix.impl.pushers.RustPushersService import io.element.android.libraries.matrix.impl.room.GetRoomResult import io.element.android.libraries.matrix.impl.room.NotJoinedRustRoom 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 933298bc6c..0bf26091c2 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 @@ -214,5 +214,5 @@ fun SessionData.toSession() = Session( deviceId = deviceId, homeserverUrl = homeserverUrl, slidingSyncVersion = SlidingSyncVersion.NATIVE, - oidcData = oidcData, + oauthData = oAuthData, ) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt index ebe0c5e4e8..20dbf76a31 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationException.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.impl.auth import io.element.android.libraries.matrix.api.auth.AuthenticationException import org.matrix.rustcomponents.sdk.ClientBuildException -import org.matrix.rustcomponents.sdk.OidcException +import org.matrix.rustcomponents.sdk.OAuthException fun Throwable.mapAuthenticationException(): AuthenticationException { return when (this) { @@ -29,12 +29,12 @@ fun Throwable.mapAuthenticationException(): AuthenticationException { is ClientBuildException.WellKnownLookupFailed -> AuthenticationException.Generic(message) is ClientBuildException.EventCache -> AuthenticationException.Generic(message) } - is OidcException -> when (this) { - is OidcException.Generic -> AuthenticationException.Oidc(message) - is OidcException.CallbackUrlInvalid -> AuthenticationException.Oidc(message) - is OidcException.Cancelled -> AuthenticationException.Oidc(message) - is OidcException.MetadataInvalid -> AuthenticationException.Oidc(message) - is OidcException.NotSupported -> AuthenticationException.Oidc(message) + is OAuthException -> when (this) { + is OAuthException.Generic -> AuthenticationException.OAuth(message) + is OAuthException.CallbackUrlInvalid -> AuthenticationException.OAuth(message) + is OAuthException.Cancelled -> AuthenticationException.OAuth(message) + is OAuthException.MetadataInvalid -> AuthenticationException.OAuth(message) + is OAuthException.NotSupported -> AuthenticationException.OAuth(message) } else -> AuthenticationException.Generic(message) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt index acf96d69d4..810b8d8e0d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetails.kt @@ -15,6 +15,6 @@ fun HomeserverLoginDetails.map(): MatrixHomeServerDetails = use { MatrixHomeServerDetails( url = url(), supportsPasswordLogin = supportsPasswordLogin(), - supportsOidcLogin = supportsOidcLogin(), + supportsOAuthLogin = supportsOauthLogin(), ) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProvider.kt new file mode 100644 index 0000000000..d80dea2e7f --- /dev/null +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProvider.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2023-2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.impl.auth + +import dev.zacsweers.metro.Inject +import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.matrix.api.auth.OAuthConfig +import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider +import org.matrix.rustcomponents.sdk.OAuthConfiguration + +@Inject +class OAuthConfigurationProvider( + private val buildMeta: BuildMeta, + private val oAuthRedirectUrlProvider: OAuthRedirectUrlProvider, +) { + fun get(): OAuthConfiguration = OAuthConfiguration( + clientName = buildMeta.applicationName, + redirectUri = oAuthRedirectUrlProvider.provide(), + clientUri = OAuthConfig.CLIENT_URI, + logoUri = OAuthConfig.LOGO_URI, + tosUri = OAuthConfig.TOS_URI, + policyUri = OAuthConfig.POLICY_URI, + staticRegistrations = OAuthConfig.STATIC_REGISTRATIONS, + ) +} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProvider.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProvider.kt deleted file mode 100644 index 6f9dd67b12..0000000000 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProvider.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.matrix.impl.auth - -import dev.zacsweers.metro.Inject -import io.element.android.libraries.core.meta.BuildMeta -import io.element.android.libraries.matrix.api.auth.OidcConfig -import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider -import org.matrix.rustcomponents.sdk.OidcConfiguration - -@Inject -class OidcConfigurationProvider( - private val buildMeta: BuildMeta, - private val oidcRedirectUrlProvider: OidcRedirectUrlProvider, -) { - fun get(): OidcConfiguration = OidcConfiguration( - clientName = buildMeta.applicationName, - redirectUri = oidcRedirectUrlProvider.provide(), - clientUri = OidcConfig.CLIENT_URI, - logoUri = OidcConfig.LOGO_URI, - tosUri = OidcConfig.TOS_URI, - policyUri = OidcConfig.POLICY_URI, - staticRegistrations = OidcConfig.STATIC_REGISTRATIONS, - ) -} diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcPrompt.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcPrompt.kt index e21d8d94c6..e97ddbee84 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcPrompt.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/OidcPrompt.kt @@ -8,13 +8,13 @@ package io.element.android.libraries.matrix.impl.auth -import io.element.android.libraries.matrix.api.auth.OidcPrompt -import org.matrix.rustcomponents.sdk.OidcPrompt as RustOidcPrompt +import io.element.android.libraries.matrix.api.auth.OAuthPrompt +import org.matrix.rustcomponents.sdk.OAuthPrompt as RustOAuthPrompt -internal fun OidcPrompt.toRustPrompt(): RustOidcPrompt { +internal fun OAuthPrompt.toRustPrompt(): RustOAuthPrompt { return when (this) { - OidcPrompt.Login -> RustOidcPrompt.Unknown("consent") - OidcPrompt.Create -> RustOidcPrompt.Create - is OidcPrompt.Unknown -> RustOidcPrompt.Unknown(value) + OAuthPrompt.Login -> RustOAuthPrompt.Unknown("consent") + OAuthPrompt.Create -> RustOAuthPrompt.Create + is OAuthPrompt.Unknown -> RustOAuthPrompt.Unknown(value) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt index 0603fddec4..3f8893138f 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeServerLoginCompatibilityChecker.kt @@ -31,8 +31,8 @@ class RustHomeServerLoginCompatibilityChecker( it.homeserverLoginDetails() } .use { - Timber.d("Homeserver $url | OIDC: ${it.supportsOidcLogin()} | Password: ${it.supportsPasswordLogin()} | SSO: ${it.supportsSsoLogin()}") - it.supportsOidcLogin() || it.supportsPasswordLogin() + Timber.d("Homeserver $url | OAuth: ${it.supportsOauthLogin()} | Password: ${it.supportsPasswordLogin()} | SSO: ${it.supportsSsoLogin()}") + it.supportsOauthLogin() || it.supportsPasswordLogin() } } } 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 9fe7c7cd1f..79793e4e77 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 @@ -19,8 +19,8 @@ import io.element.android.libraries.matrix.api.auth.AuthenticationException import io.element.android.libraries.matrix.api.auth.ElementClassicSession import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails -import io.element.android.libraries.matrix.api.auth.OidcDetails -import io.element.android.libraries.matrix.api.auth.OidcPrompt +import io.element.android.libraries.matrix.api.auth.OAuthDetails +import io.element.android.libraries.matrix.api.auth.OAuthPrompt import io.element.android.libraries.matrix.api.auth.SessionRestorationException import io.element.android.libraries.matrix.api.auth.external.ExternalSession import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData @@ -65,7 +65,7 @@ class RustMatrixAuthenticationService( private val sessionStore: SessionStore, private val rustMatrixClientFactory: RustMatrixClientFactory, private val passphraseGenerator: PassphraseGenerator, - private val oidcConfigurationProvider: OidcConfigurationProvider, + private val oAuthConfigurationProvider: OAuthConfigurationProvider, ) : MatrixAuthenticationService { // Any existing Element Classic session that we want to try to import secrets from during login. private var elementClassicSession: ElementClassicSession? = null @@ -253,15 +253,15 @@ class RustMatrixAuthenticationService( private var pendingOAuthAuthorizationData: OAuthAuthorizationData? = null - override suspend fun getOidcUrl( - prompt: OidcPrompt, + override suspend fun getOAuthUrl( + prompt: OAuthPrompt, loginHint: String?, - ): Result { + ): Result { return withContext(coroutineDispatchers.io) { runCatchingExceptions { val client = currentClient ?: error("You need to call `setHomeserver()` first") - val oAuthAuthorizationData = client.urlForOidc( - oidcConfiguration = oidcConfigurationProvider.get(), + val oAuthAuthorizationData = client.urlForOauth( + oauthConfiguration = oAuthConfigurationProvider.get(), prompt = prompt.toRustPrompt(), loginHint = loginHint, // If we want to restore a previous session for which we have encryption keys, we can pass the deviceId here. At the moment, we don't @@ -270,23 +270,23 @@ class RustMatrixAuthenticationService( ) val url = oAuthAuthorizationData.loginUrl() pendingOAuthAuthorizationData = oAuthAuthorizationData - OidcDetails(url) + OAuthDetails(url) }.mapFailure { failure -> - Timber.e(failure, "Failed to get OIDC URL") + Timber.e(failure, "Failed to get OAuth URL") failure.mapAuthenticationException() } } } - override suspend fun cancelOidcLogin(): Result { + override suspend fun cancelOAuthLogin(): Result { return withContext(coroutineDispatchers.io) { runCatchingExceptions { pendingOAuthAuthorizationData?.use { - currentClient?.abortOidcAuth(it) + currentClient?.abortOauthAuth(it) } pendingOAuthAuthorizationData = null }.mapFailure { failure -> - Timber.e(failure, "Failed to cancel OIDC login") + Timber.e(failure, "Failed to cancel OAuth login") failure.mapAuthenticationException() } } @@ -297,14 +297,14 @@ class RustMatrixAuthenticationService( } /** - * callbackUrl should be the uriRedirect from OidcClientMetadata (with all the parameters). + * callbackUrl should be the `url` from `OAuthAction` (with all the parameters). */ - override suspend fun loginWithOidc(callbackUrl: String): Result { + override suspend fun loginWithOAuth(callbackUrl: String): Result { return withContext(coroutineDispatchers.io) { runCatchingExceptions { val client = currentClient ?: error("You need to call `setHomeserver()` first") val currentSessionPaths = sessionPaths ?: error("You need to call `setHomeserver()` first") - client.loginWithOidcCallback( + client.loginWithOauthCallback( callbackUrl = callbackUrl, ) // Free the pending data since we won't use it to abort the flow anymore @@ -330,7 +330,7 @@ class RustMatrixAuthenticationService( SessionId(sessionData.userId) }.mapFailure { failure -> - Timber.e(failure, "Failed to login with OIDC") + Timber.e(failure, "Failed to login with OAuth") failure.mapAuthenticationException() } } @@ -355,7 +355,7 @@ class RustMatrixAuthenticationService( withContext(coroutineDispatchers.io) { val sdkQrCodeLoginData = (qrCodeData as SdkQrCodeLoginData).rustQrCodeData val emptySessionPaths = rotateSessionPath() - val oidcConfiguration = oidcConfigurationProvider.get() + val oAuthConfiguration = oAuthConfigurationProvider.get() val progressListener = object : QrLoginProgressListener { override fun onUpdate(state: QrLoginProgress) { Timber.d("QR Code login progress: $state") @@ -368,7 +368,7 @@ class RustMatrixAuthenticationService( qrCodeData = sdkQrCodeLoginData, ) client.newLoginWithQrCodeHandler( - oidcConfiguration = oidcConfiguration, + oauthConfiguration = oAuthConfiguration, ).use { it.scan( qrCodeData = qrCodeData.rustQrCodeData, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapper.kt index ae56cb10fa..23b9c6be5e 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapper.kt @@ -42,7 +42,7 @@ object QrErrorMapper { is RustHumanQrLoginException.OtherDeviceNotSignedIn -> QrLoginException.OtherDeviceNotSignedIn is RustHumanQrLoginException.LinkingNotSupported -> QrLoginException.LinkingNotSupported is RustHumanQrLoginException.Unknown -> QrLoginException.Unknown - is RustHumanQrLoginException.OidcMetadataInvalid -> QrLoginException.OidcMetadataInvalid + is RustHumanQrLoginException.OAuthMetadataInvalid -> QrLoginException.OAuthMetadataInvalid is RustHumanQrLoginException.SlidingSyncNotAvailable -> QrLoginException.SlidingSyncNotAvailable is RustHumanQrLoginException.CheckCodeAlreadySent -> QrLoginException.CheckCodeAlreadySent is RustHumanQrLoginException.CheckCodeCannotBeSent -> QrLoginException.CheckCodeCannotBeSent diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustIdentityResetHandle.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustIdentityResetHandle.kt index 4813ec1cc3..7ee9c7d0b3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustIdentityResetHandle.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/encryption/RustIdentityResetHandle.kt @@ -10,7 +10,7 @@ package io.element.android.libraries.matrix.impl.encryption import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.matrix.api.core.UserId -import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle +import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle import io.element.android.libraries.matrix.api.encryption.IdentityResetHandle import org.matrix.rustcomponents.sdk.AuthData @@ -25,7 +25,7 @@ object RustIdentityResetHandleFactory { return runCatchingExceptions { identityResetHandle?.let { when (val authType = identityResetHandle.authType()) { - is CrossSigningResetAuthType.Oidc -> RustOidcIdentityResetHandle(identityResetHandle, authType.info.approvalUrl) + is CrossSigningResetAuthType.OAuth -> RustIdentityOAuthResetHandle(identityResetHandle, authType.info.approvalUrl) // User interactive authentication (user + password) CrossSigningResetAuthType.Uiaa -> RustPasswordIdentityResetHandle(userId, identityResetHandle) } @@ -47,11 +47,11 @@ class RustPasswordIdentityResetHandle( } } -class RustOidcIdentityResetHandle( +class RustIdentityOAuthResetHandle( private val identityResetHandle: org.matrix.rustcomponents.sdk.IdentityResetHandle, override val url: String, -) : IdentityOidcResetHandle { - override suspend fun resetOidc(): Result { +) : IdentityOAuthResetHandle { + override suspend fun resetOAuth(): Result { return runCatchingExceptions { identityResetHandle.reset(null) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandler.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandler.kt index 211bdc3d4e..83e657eb07 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandler.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandler.kt @@ -54,6 +54,8 @@ class RustLinkDesktopHandler( } } ) + // We emit Done in case the progress listener was deallocated before scan() sent the Done + _linkDesktopStep.emit(LinkDesktopStep.Done) } catch (e: QrCodeDecodeException) { Timber.tag(tag.value).w(e, "Invalid QR code scanned") _linkDesktopStep.emit( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt index 0189987d96..6d212d4784 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandler.kt @@ -49,6 +49,8 @@ class RustLinkMobileHandler( } } ) + // We emit Done in case the progress listener was deallocated before generate() sent the Done + _linkMobileStep.emit(LinkMobileStep.Done) } catch (e: HumanQrGrantLoginException) { Timber.tag(tag.value).w(e, "Error during QR login grant") _linkMobileStep.emit(LinkMobileStep.Error(e.map())) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt index 3199ebf71a..dfda37d7e1 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/mapper/Session.kt @@ -27,7 +27,7 @@ internal fun Session.toSessionData( accessToken = accessToken, refreshToken = refreshToken, homeserverUrl = homeserverUrl ?: this.homeserverUrl, - oidcData = oidcData, + oAuthData = oauthData, loginTimestamp = Date(), isTokenValid = isTokenValid, loginType = loginType, @@ -52,7 +52,7 @@ internal fun ExternalSession.toSessionData( accessToken = accessToken, refreshToken = refreshToken, homeserverUrl = homeserverUrl, - oidcData = null, + oAuthData = null, loginTimestamp = Date(), isTokenValid = isTokenValid, loginType = loginType, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementAction.kt similarity index 86% rename from libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt rename to libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementAction.kt index f86c57543a..974ae08923 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementAction.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementAction.kt @@ -6,9 +6,9 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.matrix.impl.oidc +package io.element.android.libraries.matrix.impl.oauth -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction fun AccountManagementAction.toRustAction(): RustAccountManagementAction { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt index 6507cf38c8..87ef0815ce 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/JoinedRustRoom.kt @@ -516,10 +516,10 @@ class JoinedRustRoom( return innerRoom.liveLocationSharesFlow().timedByExpiry(systemClock::epochMillis) } - override suspend fun startLiveLocationShare(durationMillis: Long): Result = withContext(roomDispatcher) { + override suspend fun startLiveLocationShare(durationMillis: Long): Result = withContext(roomDispatcher) { runCatchingExceptions { innerRoom.startLiveLocationShare(durationMillis.toULong()) - } + }.map(::EventId) } override suspend fun stopLiveLocationShare(): Result = withContext(roomDispatcher) { @@ -538,7 +538,7 @@ class JoinedRustRoom( override fun destroy() { baseRoom.destroy() - liveInnerTimeline.destroy() + liveTimeline.close() threadsListService.destroy() Timber.d("Room $roomId destroyed") } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/location/LiveLocationSharesFlow.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/location/LiveLocationSharesFlow.kt index bae406a137..1a341d0dc2 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/location/LiveLocationSharesFlow.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/location/LiveLocationSharesFlow.kt @@ -16,8 +16,8 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.callbackFlow -import org.matrix.rustcomponents.sdk.LiveLocationShareListener import org.matrix.rustcomponents.sdk.LiveLocationShareUpdate +import org.matrix.rustcomponents.sdk.LiveLocationsListener import org.matrix.rustcomponents.sdk.RoomInterface import org.matrix.rustcomponents.sdk.LiveLocationShare as RustLiveLocationShare @@ -41,9 +41,9 @@ fun RoomInterface.liveLocationSharesFlow(): Flow> { } } return callbackFlow { - val liveLocationShares = liveLocationShares() + val liveLocationShares = liveLocationsObserver() val shares: MutableList = ArrayList() - val taskHandle = liveLocationShares.subscribe(object : LiveLocationShareListener { + val taskHandle = liveLocationShares.subscribe(object : LiveLocationsListener { override fun onUpdate(updates: List) { for (update in updates) { shares.applyUpdate(update) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationExceptionMappingTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationExceptionMappingTest.kt index 8449d9a6c3..cc5fb4a394 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationExceptionMappingTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/AuthenticationExceptionMappingTest.kt @@ -13,7 +13,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.auth.AuthenticationException import org.junit.Test import org.matrix.rustcomponents.sdk.ClientBuildException -import org.matrix.rustcomponents.sdk.OidcException +import org.matrix.rustcomponents.sdk.OAuthException class AuthenticationExceptionMappingTest { @Test @@ -64,17 +64,17 @@ class AuthenticationExceptionMappingTest { } @Test - fun `mapping Oidc exceptions map to the Oidc Kotlin`() { - assertThat(OidcException.Generic("Generic").mapAuthenticationException()) - .isException("Generic") - assertThat(OidcException.CallbackUrlInvalid("CallbackUrlInvalid").mapAuthenticationException()) - .isException("CallbackUrlInvalid") - assertThat(OidcException.Cancelled("Cancelled").mapAuthenticationException()) - .isException("Cancelled") - assertThat(OidcException.MetadataInvalid("MetadataInvalid").mapAuthenticationException()) - .isException("MetadataInvalid") - assertThat(OidcException.NotSupported("NotSupported").mapAuthenticationException()) - .isException("NotSupported") + fun `mapping Oidc exceptions map to the OAuth Kotlin`() { + assertThat(OAuthException.Generic("Generic").mapAuthenticationException()) + .isException("Generic") + assertThat(OAuthException.CallbackUrlInvalid("CallbackUrlInvalid").mapAuthenticationException()) + .isException("CallbackUrlInvalid") + assertThat(OAuthException.Cancelled("Cancelled").mapAuthenticationException()) + .isException("Cancelled") + assertThat(OAuthException.MetadataInvalid("MetadataInvalid").mapAuthenticationException()) + .isException("MetadataInvalid") + assertThat(OAuthException.NotSupported("NotSupported").mapAuthenticationException()) + .isException("NotSupported") } private inline fun ThrowableSubject.isException(message: String) { diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetailsKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetailsKtTest.kt index a5c7b2dbc8..63f573536c 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetailsKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/HomeserverDetailsKtTest.kt @@ -20,7 +20,7 @@ class HomeserverDetailsKtTest { val homeserverLoginDetails = FakeFfiHomeserverLoginDetails( url = "https://example.org", supportsPasswordLogin = true, - supportsOidcLogin = false + supportsOAuthLogin = false ) // When @@ -31,7 +31,7 @@ class HomeserverDetailsKtTest { MatrixHomeServerDetails( url = "https://example.org", supportsPasswordLogin = true, - supportsOidcLogin = false + supportsOAuthLogin = false ) ) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProviderTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProviderTest.kt similarity index 76% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProviderTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProviderTest.kt index 095cf54946..3b54f2d1f3 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OidcConfigurationProviderTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/OAuthConfigurationProviderTest.kt @@ -10,18 +10,18 @@ package io.element.android.libraries.matrix.impl.auth import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.auth.FAKE_REDIRECT_URL -import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider +import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider import io.element.android.libraries.matrix.test.core.aBuildMeta import org.junit.Test -class OidcConfigurationProviderTest { +class OAuthConfigurationProviderTest { @Test fun get() { - val result = OidcConfigurationProvider( + val result = OAuthConfigurationProvider( buildMeta = aBuildMeta( applicationName = "myName", ), - oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(), + oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(), ).get() assertThat(result.clientName).isEqualTo("myName") assertThat(result.redirectUri).isEqualTo(FAKE_REDIRECT_URL) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt index 50d1f3723b..903273113b 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustHomeserverLoginCompatibilityCheckerTest.kt @@ -18,8 +18,8 @@ import org.junit.Test class RustHomeserverLoginCompatibilityCheckerTest { @Test - fun `check - is valid if it supports OIDC login`() = runTest { - val sut = createChecker { FakeFfiHomeserverLoginDetails(supportsOidcLogin = true) } + fun `check - is valid if it supports OAuth login`() = runTest { + val sut = createChecker { FakeFfiHomeserverLoginDetails(supportsOAuthLogin = true) } assertThat(sut.check("https://matrix.host.org").getOrNull()).isTrue() } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationServiceTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationServiceTest.kt index f4ce7b1fdd..bff2711bc5 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationServiceTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/RustMatrixAuthenticationServiceTest.kt @@ -16,7 +16,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClient import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiClientBuilder import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiHomeserverLoginDetails import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory -import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider +import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.test.InMemorySessionStore @@ -64,9 +64,9 @@ class RustMatrixAuthenticationServiceTest { sessionStore = sessionStore, rustMatrixClientFactory = rustMatrixClientFactory, passphraseGenerator = FakePassphraseGenerator(), - oidcConfigurationProvider = OidcConfigurationProvider( + oAuthConfigurationProvider = OAuthConfigurationProvider( buildMeta = aBuildMeta(), - oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(), + oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(), ), ) } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapperTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapperTest.kt index 0ef20c82a6..4de5e55985 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapperTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/auth/qrlogin/QrErrorMapperTest.kt @@ -32,7 +32,7 @@ class QrErrorMapperTest { assertThat(QrErrorMapper.map(RustHumanQrLoginException.OtherDeviceNotSignedIn())).isEqualTo(QrLoginException.OtherDeviceNotSignedIn) assertThat(QrErrorMapper.map(RustHumanQrLoginException.LinkingNotSupported())).isEqualTo(QrLoginException.LinkingNotSupported) assertThat(QrErrorMapper.map(RustHumanQrLoginException.Unknown())).isEqualTo(QrLoginException.Unknown) - assertThat(QrErrorMapper.map(RustHumanQrLoginException.OidcMetadataInvalid())).isEqualTo(QrLoginException.OidcMetadataInvalid) + assertThat(QrErrorMapper.map(RustHumanQrLoginException.OAuthMetadataInvalid())).isEqualTo(QrLoginException.OAuthMetadataInvalid) assertThat(QrErrorMapper.map(RustHumanQrLoginException.SlidingSyncNotAvailable())).isEqualTo(QrLoginException.SlidingSyncNotAvailable) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt index 4db2db7107..82984c480d 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/NotificationItem.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl.fixtures.factories import io.element.android.libraries.matrix.api.core.ThreadId +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiTimelineEvent import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_USER_NAME @@ -68,6 +69,8 @@ internal fun aRustNotificationRoomInfo( isDirect: Boolean = false, joinRule: JoinRule? = null, isSpace: Boolean = false, + serviceMembers: List = emptyList(), + activeServiceMemberCount: Int = 0, ) = NotificationRoomInfo( displayName = displayName, avatarUrl = avatarUrl, @@ -78,6 +81,8 @@ internal fun aRustNotificationRoomInfo( isDirect = isDirect, joinRule = joinRule, isSpace = isSpace, + serviceMembers = serviceMembers.map { it.value }, + activeServiceMembersCount = activeServiceMemberCount.toULong(), ) internal fun aRustNotificationEventTimeline( diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomInfo.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomInfo.kt index 1b0cc12461..491614a7fc 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomInfo.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/RoomInfo.kt @@ -62,6 +62,7 @@ internal fun aRustRoomInfo( serviceMembers: List = emptyList(), isLowPriority: Boolean = false, activeRoomCallConsensusIntent: RtcCallIntentConsensus = RtcCallIntentConsensus.None, + activeServiceMembersCount: Int = 0, ) = RoomInfo( id = id, displayName = displayName, @@ -101,4 +102,5 @@ internal fun aRustRoomInfo( serviceMembers = serviceMembers, isLowPriority = isLowPriority, activeRoomCallConsensusIntent = activeRoomCallConsensusIntent, + activeServiceMembersCount = activeServiceMembersCount.toULong(), ) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/Session.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/Session.kt index 4671c457b0..af7f44597c 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/Session.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/Session.kt @@ -24,6 +24,6 @@ internal fun aRustSession( userId = A_USER_ID.value, deviceId = A_DEVICE_ID.value, homeserverUrl = A_HOMESERVER_URL, - oidcData = null, + oauthData = null, slidingSyncVersion = proxy, ) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiGrantLoginWithQrCodeHandler.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiGrantLoginWithQrCodeHandler.kt index cd0733695b..0899b16325 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiGrantLoginWithQrCodeHandler.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiGrantLoginWithQrCodeHandler.kt @@ -16,8 +16,8 @@ import org.matrix.rustcomponents.sdk.NoHandle import org.matrix.rustcomponents.sdk.QrCodeData class FakeFfiGrantLoginWithQrCodeHandler( - private val generateResult: () -> Unit = {}, - private val scanResult: (QrCodeData) -> Unit = {}, + private val generateResult: suspend () -> Unit = {}, + private val scanResult: suspend (QrCodeData) -> Unit = {}, ) : GrantLoginWithQrCodeHandler(NoHandle) { private var generateProgressListener: GrantGeneratedQrLoginProgressListener? = null private var scanProgressListener: GrantQrLoginProgressListener? = null diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiHomeserverLoginDetails.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiHomeserverLoginDetails.kt index ade3a2328f..5351fbc8df 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiHomeserverLoginDetails.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeFfiHomeserverLoginDetails.kt @@ -14,11 +14,11 @@ import org.matrix.rustcomponents.sdk.NoHandle class FakeFfiHomeserverLoginDetails( private val url: String = "https://example.org", private val supportsPasswordLogin: Boolean = false, - private val supportsOidcLogin: Boolean = false, + private val supportsOAuthLogin: Boolean = false, private val supportsSsoLogin: Boolean = false, ) : HomeserverLoginDetails(NoHandle) { override fun url(): String = url - override fun supportsOidcLogin(): Boolean = supportsOidcLogin + override fun supportsOauthLogin(): Boolean = supportsOAuthLogin override fun supportsPasswordLogin(): Boolean = supportsPasswordLogin override fun supportsSsoLogin(): Boolean = supportsSsoLogin } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandlerTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandlerTest.kt index a180e4d515..fd635e2da6 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandlerTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkDesktopHandlerTest.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.linknewdevice.ErrorType import io.element.android.libraries.matrix.api.linknewdevice.LinkDesktopStep import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiGrantLoginWithQrCodeHandler import io.element.android.libraries.matrix.test.QR_CODE_DATA +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher @@ -29,7 +30,13 @@ import org.matrix.rustcomponents.sdk.QrCodeDecodeException class RustLinkDesktopHandlerTest { @Test fun `handleScannedQrCode function works as expected`() = runTest { - val handler = FakeFfiGrantLoginWithQrCodeHandler() + val completable = CompletableDeferred() + val handler = FakeFfiGrantLoginWithQrCodeHandler( + scanResult = { + // Ensure that the coroutine is hold + completable.await() + } + ) val sut = createRustLinkDesktopHandler( handler, ) @@ -53,6 +60,36 @@ class RustLinkDesktopHandlerTest { handler.emitScanProgress(progress) assertThat(awaitItem()).isEqualTo(expectedStep) } + // scan returns, no new event is emitted + completable.complete(Unit) + expectNoEvents() + } + } + + @Test + fun `when scan does not emits the Done state, the code emits it`() = runTest { + val completable = CompletableDeferred() + val handler = FakeFfiGrantLoginWithQrCodeHandler( + scanResult = { + // Ensure that the coroutine is hold + completable.await() + } + ) + val sut = createRustLinkDesktopHandler( + handler, + ) + sut.linkDesktopStep.test { + val initialItem = awaitItem() + assertThat(initialItem).isEqualTo(LinkDesktopStep.Uninitialized) + backgroundScope.launch { + sut.handleScannedQrCode(QR_CODE_DATA) + } + runCurrent() + handler.emitScanProgress(GrantQrLoginProgress.Starting) + assertThat(awaitItem()).isEqualTo(LinkDesktopStep.Starting) + // scan returns, Done event is emitted + completable.complete(Unit) + assertThat(awaitItem()).isEqualTo(LinkDesktopStep.Done) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt index aa13996e8a..9f71cb7169 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/linknewdevice/RustLinkMobileHandlerTest.kt @@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiCheckCodeS import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiGrantLoginWithQrCodeHandler import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeFfiQrCodeData import io.element.android.libraries.matrix.test.QR_CODE_DATA_RECIPROCATE +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher @@ -30,7 +31,13 @@ import org.matrix.rustcomponents.sdk.HumanQrGrantLoginException class RustLinkMobileHandlerTest { @Test fun `start function works as expected`() = runTest { - val handler = FakeFfiGrantLoginWithQrCodeHandler() + val completable = CompletableDeferred() + val handler = FakeFfiGrantLoginWithQrCodeHandler( + generateResult = { + // Ensure that the coroutine is hold + completable.await() + } + ) val sut = createRustLinkMobileHandler( handler, ) @@ -56,6 +63,36 @@ class RustLinkMobileHandlerTest { handler.emitGenerateProgress(progress) assertThat(awaitItem()).isInstanceOf(expectedStepClass) } + // generate returns, no new event is emitted + completable.complete(Unit) + expectNoEvents() + } + } + + @Test + fun `when generates does not emits the Done state, the code emits it`() = runTest { + val completable = CompletableDeferred() + val handler = FakeFfiGrantLoginWithQrCodeHandler( + generateResult = { + // Ensure that the coroutine is hold + completable.await() + } + ) + val sut = createRustLinkMobileHandler( + handler, + ) + sut.linkMobileStep.test { + val initialItem = awaitItem() + assertThat(initialItem).isEqualTo(LinkMobileStep.Uninitialized) + backgroundScope.launch { + sut.start() + } + runCurrent() + handler.emitGenerateProgress(GrantGeneratedQrLoginProgress.Starting) + assertThat(awaitItem()).isEqualTo(LinkMobileStep.Starting) + // generate returns, Done event is emitted + completable.complete(Unit) + assertThat(awaitItem()).isEqualTo(LinkMobileStep.Done) } } diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt index e5fc8b154f..fb9ec6625b 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/mapper/SessionKtTest.kt @@ -36,7 +36,7 @@ class SessionKtTest { assertThat(result.refreshToken).isEqualTo("refreshToken") assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL) assertThat(result.isTokenValid).isTrue() - assertThat(result.oidcData).isNull() + assertThat(result.oAuthData).isNull() assertThat(result.loginType).isEqualTo(LoginType.PASSWORD) assertThat(result.loginTimestamp).isNotNull() assertThat(result.passphrase).isEqualTo(A_SECRET) @@ -82,7 +82,7 @@ class SessionKtTest { assertThat(result.refreshToken).isNull() assertThat(result.homeserverUrl).isEqualTo(A_HOMESERVER_URL) assertThat(result.isTokenValid).isTrue() - assertThat(result.oidcData).isNull() + assertThat(result.oAuthData).isNull() assertThat(result.loginType).isEqualTo(LoginType.PASSWORD) assertThat(result.loginTimestamp).isNotNull() assertThat(result.passphrase).isEqualTo(A_SECRET) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementActionKtTest.kt similarity index 90% rename from libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt rename to libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementActionKtTest.kt index 3637ef78cc..1495716e87 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oidc/AccountManagementActionKtTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/oauth/AccountManagementActionKtTest.kt @@ -6,10 +6,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.matrix.impl.oidc +package io.element.android.libraries.matrix.impl.oauth import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.test.A_DEVICE_ID import org.junit.Test import org.matrix.rustcomponents.sdk.AccountManagementAction as RustAccountManagementAction 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 742af160ae..26bc0af8c1 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 @@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaPreviewService import io.element.android.libraries.matrix.api.notification.NotificationService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.oidc.AccountManagementAction +import io.element.android.libraries.matrix.api.oauth.AccountManagementAction import io.element.android.libraries.matrix.api.pusher.PushersService import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.JoinedRoom diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeMatrixAuthenticationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeMatrixAuthenticationService.kt index 238ad2663d..3b2fdeafb1 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeMatrixAuthenticationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeMatrixAuthenticationService.kt @@ -12,8 +12,8 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.auth.ElementClassicSession import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails -import io.element.android.libraries.matrix.api.auth.OidcDetails -import io.element.android.libraries.matrix.api.auth.OidcPrompt +import io.element.android.libraries.matrix.api.auth.OAuthDetails +import io.element.android.libraries.matrix.api.auth.OAuthPrompt import io.element.android.libraries.matrix.api.auth.external.ExternalSession import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep @@ -26,7 +26,7 @@ import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.simulateLongTask -val A_OIDC_DATA = OidcDetails(url = "a-url") +val AN_OAUTH_DATA = OAuthDetails(url = "a-url") class FakeMatrixAuthenticationService( var matrixClientResult: ((SessionId) -> Result)? = null, @@ -37,8 +37,8 @@ class FakeMatrixAuthenticationService( private val setElementClassicSessionResult: (ElementClassicSession?) -> Unit = { lambdaError() }, private val doSecretsContainBackupKeyResult: (UserId, String, String) -> Boolean = { _, _, _ -> lambdaError() }, ) : MatrixAuthenticationService { - private var oidcError: Throwable? = null - private var oidcCancelError: Throwable? = null + private var oAuthError: Throwable? = null + private var oAuthCancelError: Throwable? = null private var loginError: Throwable? = null private var matrixClient: MatrixClient? = null private var onAuthenticationListener: ((MatrixClient) -> Unit)? = null @@ -70,18 +70,18 @@ class FakeMatrixAuthenticationService( return importCreatedSessionLambda(externalSession) } - override suspend fun getOidcUrl( - prompt: OidcPrompt, + override suspend fun getOAuthUrl( + prompt: OAuthPrompt, loginHint: String?, - ): Result = simulateLongTask { - oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA) + ): Result = simulateLongTask { + oAuthError?.let { Result.failure(it) } ?: Result.success(AN_OAUTH_DATA) } - override suspend fun cancelOidcLogin(): Result { - return oidcCancelError?.let { Result.failure(it) } ?: Result.success(Unit) + override suspend fun cancelOAuthLogin(): Result { + return oAuthCancelError?.let { Result.failure(it) } ?: Result.success(Unit) } - override suspend fun loginWithOidc(callbackUrl: String): Result = simulateLongTask { + override suspend fun loginWithOAuth(callbackUrl: String): Result = simulateLongTask { loginError?.let { Result.failure(it) } ?: run { onAuthenticationListener?.invoke(matrixClient ?: FakeMatrixClient()) Result.success(A_USER_ID) @@ -97,12 +97,12 @@ class FakeMatrixAuthenticationService( onAuthenticationListener = lambda } - fun givenOidcError(throwable: Throwable?) { - oidcError = throwable + fun givenOAuthError(throwable: Throwable?) { + oAuthError = throwable } - fun givenOidcCancelError(throwable: Throwable?) { - oidcCancelError = throwable + fun givenOAuthCancelError(throwable: Throwable?) { + oAuthCancelError = throwable } fun givenLoginError(throwable: Throwable?) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOidcRedirectUrlProvider.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOAuthRedirectUrlProvider.kt similarity index 75% rename from libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOidcRedirectUrlProvider.kt rename to libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOAuthRedirectUrlProvider.kt index 47c9b0951d..fcb28b48ba 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOidcRedirectUrlProvider.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeOAuthRedirectUrlProvider.kt @@ -8,12 +8,12 @@ package io.element.android.libraries.matrix.test.auth -import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider +import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider const val FAKE_REDIRECT_URL = "io.element.android:/" -class FakeOidcRedirectUrlProvider( +class FakeOAuthRedirectUrlProvider( private val provideResult: String = FAKE_REDIRECT_URL, -) : OidcRedirectUrlProvider { +) : OAuthRedirectUrlProvider { override fun provide() = provideResult } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/MatrixHomeServerDetails.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/MatrixHomeServerDetails.kt index 3b9573bcfc..56fd4de4c3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/MatrixHomeServerDetails.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/MatrixHomeServerDetails.kt @@ -14,9 +14,9 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL fun aMatrixHomeServerDetails( url: String = A_HOMESERVER_URL, supportsPasswordLogin: Boolean = false, - supportsOidcLogin: Boolean = false, + supportsOAuthLogin: Boolean = false, ) = MatrixHomeServerDetails( url = url, supportsPasswordLogin = supportsPasswordLogin, - supportsOidcLogin = supportsOidcLogin, + supportsOAuthLogin = supportsOAuthLogin, ) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeIdentityResetHandle.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeIdentityResetHandle.kt index 06ffeb547c..d65328d7fe 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeIdentityResetHandle.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/encryption/FakeIdentityResetHandle.kt @@ -8,16 +8,16 @@ package io.element.android.libraries.matrix.test.encryption -import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle +import io.element.android.libraries.matrix.api.encryption.IdentityOAuthResetHandle import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle -class FakeIdentityOidcResetHandle( +class FakeIdentityOAuthResetHandle( override val url: String = "", - var resetOidcLambda: () -> Result = { error("Not implemented") }, + var resetOAuthLambda: () -> Result = { error("Not implemented") }, var cancelLambda: () -> Unit = { error("Not implemented") }, -) : IdentityOidcResetHandle { - override suspend fun resetOidc(): Result { - return resetOidcLambda() +) : IdentityOAuthResetHandle { + override suspend fun resetOAuth(): Result { + return resetOAuthLambda() } override suspend fun cancel() { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt index 84497b38de..d1cd340641 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeJoinedRoom.kt @@ -34,6 +34,7 @@ import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.widget.MatrixWidgetDriver import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings +import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.room.threads.FakeThreadsListService import io.element.android.libraries.matrix.test.timeline.FakeTimeline @@ -238,8 +239,8 @@ class FakeJoinedRoom( return liveLocationSharesFlow } - override suspend fun startLiveLocationShare(durationMillis: Long): Result = simulateLongTask { - startLiveLocationShareResult(durationMillis) + override suspend fun startLiveLocationShare(durationMillis: Long): Result = simulateLongTask { + startLiveLocationShareResult(durationMillis).map { AN_EVENT_ID } } override suspend fun stopLiveLocationShare(): Result = simulateLongTask { diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt index 4628833bb4..880a7a9df6 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/AvatarActionBottomSheet.kt @@ -67,6 +67,7 @@ fun AvatarActionBottomSheet( }, modifier = modifier, sheetState = sheetState, + scrollable = false, ) { AvatarActionBottomSheetContent( actions = actions, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt index f63bda378b..d663177ee6 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/CreateDmConfirmationBottomSheet.kt @@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState @@ -74,11 +76,13 @@ fun CreateDmConfirmationBottomSheet( modifier = modifier, onDismissRequest = onDismiss, sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + scrollable = false, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(top = 24.dp, bottom = 16.dp, start = 16.dp, end = 16.dp), + .padding(top = 24.dp, bottom = 16.dp, start = 16.dp, end = 16.dp) + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, ) { if (isUserIdentityUnknown) { @@ -148,9 +152,11 @@ fun CreateDmConfirmationBottomSheet( @PreviewsDayNight @Composable -internal fun CreateDmConfirmationBottomSheetPreview(@PreviewParameter( - CreateDmConfirmationBottomSheetStateProvider::class -) state: CreateDmConfirmationBottomSheetState) = ElementPreview { +internal fun CreateDmConfirmationBottomSheetPreview( + @PreviewParameter( + CreateDmConfirmationBottomSheetStateProvider::class + ) state: CreateDmConfirmationBottomSheetState +) = ElementPreview { CreateDmConfirmationBottomSheet( matrixUser = state.matrixUser, isUserIdentityUnknown = state.isUserIdentityUnknown, @@ -166,7 +172,7 @@ data class CreateDmConfirmationBottomSheetState( class CreateDmConfirmationBottomSheetStateProvider : PreviewParameterProvider { override val values = sequenceOf( - CreateDmConfirmationBottomSheetState(matrixUser = aMatrixUser(), isUserIdentityUnknown = false), - CreateDmConfirmationBottomSheetState(matrixUser = aMatrixUser(), isUserIdentityUnknown = true), - ) + CreateDmConfirmationBottomSheetState(matrixUser = aMatrixUser(), isUserIdentityUnknown = false), + CreateDmConfirmationBottomSheetState(matrixUser = aMatrixUser(), isUserIdentityUnknown = true), + ) } diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocument.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocument.kt index ee9de51681..d29a28cba9 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocument.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToHtmlDocument.kt @@ -12,8 +12,10 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkData import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat -import io.element.android.wysiwyg.utils.HtmlToDomParser +import org.jsoup.Jsoup import org.jsoup.nodes.Document +import org.jsoup.nodes.Document.OutputSettings +import org.jsoup.safety.Safelist /** * Converts the HTML string [FormattedBody.body] to a [Document] by parsing it. @@ -34,9 +36,9 @@ fun FormattedBody.toHtmlDocument( ?.trimEnd() ?.let { formattedBody -> val dom = if (prefix != null) { - HtmlToDomParser.document("$prefix $formattedBody") + CustomHtmlToDomParser.document("$prefix $formattedBody") } else { - HtmlToDomParser.document(formattedBody) + CustomHtmlToDomParser.document(formattedBody) } // Prepend `@` to mentions @@ -60,3 +62,35 @@ private fun fixMentions( } } } + +/** Custom Html to DOM parser, based on the one included in the rich text editor library. */ +private object CustomHtmlToDomParser { + fun document(html: String): Document { + val outputSettings = OutputSettings().prettyPrint(false).indentAmount(0) + val cleanHtml = Jsoup.clean(html, "", safeList, outputSettings) + return Jsoup.parse(cleanHtml) + } + + private val safeList = Safelist() + .addTags( + "a", + "b", + "strong", + "i", + "em", + "u", + "del", + "code", + "ul", + "ol", + "li", + "pre", + "blockquote", + "p", + "br", + // Add custom `mx-reply` tag, even if it's just to remove its contents from the plain text version of the message + "mx-reply" + ) + .addAttributes("a", "href", "data-mention-type", "contenteditable") + .addAttributes("ol", "start") +} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainText.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainText.kt index d58d12b785..cf8b03b80d 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainText.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainText.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.matrix.ui.messages import io.element.android.libraries.matrix.api.permalink.PermalinkParser import io.element.android.libraries.matrix.api.timeline.item.event.FormattedBody import io.element.android.libraries.matrix.api.timeline.item.event.MessageFormat +import io.element.android.libraries.matrix.api.timeline.item.event.MessageTypeWithAttachment import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -26,6 +27,19 @@ fun TextMessageType.toPlainText( permalinkParser: PermalinkParser, ) = formatted?.toPlainText(permalinkParser) ?: body +/** + * Converts the HTML string in [MessageTypeWithAttachment.formattedCaption] to a plain text representation by parsing it and removing all formatting. + * If the caption is not formatted or the format is not [MessageFormat.HTML], the [MessageTypeWithAttachment.caption] is returned instead. + * If there is no caption, returns [default]. + */ +fun MessageTypeWithAttachment.toPlainText( + permalinkParser: PermalinkParser, + default: String = filename, +): String { + val plainTextFromFormatted = formattedCaption?.toPlainText(permalinkParser) + return plainTextFromFormatted ?: caption ?: default +} + /** * Converts the HTML string in [FormattedBody.body] to a plain text representation by parsing it and removing all formatting. * If the message is not formatted or the format is not [MessageFormat.HTML] we return `null`. @@ -51,6 +65,8 @@ fun Document.toPlainText(): String { return visitor.build() } +private const val FALLBACK_REPLY_NODE_TAG = "mx-reply" + private class PlainTextNodeVisitor : NodeVisitor { private val builder = StringBuilder() @@ -78,6 +94,9 @@ private class PlainTextNodeVisitor : NodeVisitor { } else { builder.append("• ") } + } else if (node is Element && node.tagName() == FALLBACK_REPLY_NODE_TAG) { + // Remove the fallback reply node and its contents so they aren't added to the plain text message + node.remove() } else if (node is Element && node.isBlock && builder.lastOrNull() != '\n') { builder.append("\n") } diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt index 607f825401..ce0ef4cf31 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/ToPlainTextTest.kt @@ -136,4 +136,19 @@ class ToPlainTextTest { ) assertThat(messageType.toPlainText(permalinkParser = FakePermalinkParser())).isEqualTo("This is the fallback text") } + + @Test + fun `TextMessageType toPlainText - ignores mx-reply element`() { + val messageType = TextMessageType( + body = "This is the fallback text", + formatted = FormattedBody( + format = MessageFormat.HTML, + body = """ + In reply to... + This is the message content. + """.trimIndent() + ) + ) + assertThat(messageType.toPlainText(permalinkParser = FakePermalinkParser())).isEqualTo("This is the message content.") + } } diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheet.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheet.kt index f13e2f1600..0cae7f0262 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheet.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDeleteConfirmationBottomSheet.kt @@ -59,7 +59,8 @@ fun MediaDeleteConfirmationBottomSheet( ModalBottomSheet( modifier = modifier, onDismissRequest = onDismiss, - sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + scrollable = false, ) { Column( modifier = Modifier diff --git a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheet.kt b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheet.kt index 9ce2dc4a7f..0c73bfd17c 100644 --- a/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheet.kt +++ b/libraries/mediaviewer/impl/src/main/kotlin/io/element/android/libraries/mediaviewer/impl/details/MediaDetailsBottomSheet.kt @@ -72,6 +72,7 @@ fun MediaDetailsBottomSheet( ModalBottomSheet( modifier = modifier, onDismissRequest = onDismiss, + scrollable = false, ) { Column( modifier = Modifier diff --git a/libraries/oidc/api/build.gradle.kts b/libraries/oauth/api/build.gradle.kts similarity index 87% rename from libraries/oidc/api/build.gradle.kts rename to libraries/oauth/api/build.gradle.kts index 8cc0125142..8c863db0bf 100644 --- a/libraries/oidc/api/build.gradle.kts +++ b/libraries/oauth/api/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } android { - namespace = "io.element.android.libraries.oidc.api" + namespace = "io.element.android.libraries.oauth.api" } dependencies { diff --git a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcAction.kt b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthAction.kt similarity index 54% rename from libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcAction.kt rename to libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthAction.kt index d7c061ab25..033516b93d 100644 --- a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcAction.kt +++ b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthAction.kt @@ -6,9 +6,9 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.api +package io.element.android.libraries.oauth.api -sealed interface OidcAction { - data class GoBack(val toUnblock: Boolean = false) : OidcAction - data class Success(val url: String) : OidcAction +sealed interface OAuthAction { + data class GoBack(val toUnblock: Boolean = false) : OAuthAction + data class Success(val url: String) : OAuthAction } diff --git a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcActionFlow.kt b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthActionFlow.kt similarity index 63% rename from libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcActionFlow.kt rename to libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthActionFlow.kt index 17340eb5ec..c6791e3197 100644 --- a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcActionFlow.kt +++ b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthActionFlow.kt @@ -6,12 +6,12 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.api +package io.element.android.libraries.oauth.api import kotlinx.coroutines.flow.FlowCollector -interface OidcActionFlow { - fun post(oidcAction: OidcAction) - suspend fun collect(collector: FlowCollector) +interface OAuthActionFlow { + fun post(oAuthAction: OAuthAction) + suspend fun collect(collector: FlowCollector) fun reset() } diff --git a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcIntentResolver.kt b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthIntentResolver.kt similarity index 68% rename from libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcIntentResolver.kt rename to libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthIntentResolver.kt index 97fa1baa27..2091a86db4 100644 --- a/libraries/oidc/api/src/main/kotlin/io/element/android/libraries/oidc/api/OidcIntentResolver.kt +++ b/libraries/oauth/api/src/main/kotlin/io/element/android/libraries/oauth/api/OAuthIntentResolver.kt @@ -6,10 +6,10 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.api +package io.element.android.libraries.oauth.api import android.content.Intent -interface OidcIntentResolver { - fun resolve(intent: Intent): OidcAction? +interface OAuthIntentResolver { + fun resolve(intent: Intent): OAuthAction? } diff --git a/libraries/oidc/impl/build.gradle.kts b/libraries/oauth/impl/build.gradle.kts similarity index 93% rename from libraries/oidc/impl/build.gradle.kts rename to libraries/oauth/impl/build.gradle.kts index e11ce11c70..d051c06497 100644 --- a/libraries/oidc/impl/build.gradle.kts +++ b/libraries/oauth/impl/build.gradle.kts @@ -16,7 +16,7 @@ plugins { } android { - namespace = "io.element.android.libraries.oidc.impl" + namespace = "io.element.android.libraries.oauth.impl" testOptions { unitTests { @@ -39,7 +39,7 @@ dependencies { implementation(platform(libs.network.retrofit.bom)) implementation(libs.network.retrofit) implementation(libs.serialization.json) - api(projects.libraries.oidc.api) + api(projects.libraries.oauth.api) testCommonDependencies(libs) testImplementation(projects.libraries.matrix.test) diff --git a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlow.kt b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlow.kt similarity index 58% rename from libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlow.kt rename to libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlow.kt index 6096ef7eef..6b23676059 100644 --- a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlow.kt +++ b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlow.kt @@ -6,26 +6,26 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.impl +package io.element.android.libraries.oauth.impl import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.MutableStateFlow @ContributesBinding(AppScope::class) @SingleIn(AppScope::class) -class DefaultOidcActionFlow : OidcActionFlow { - private val mutableStateFlow = MutableStateFlow(null) +class DefaultOAuthActionFlow : OAuthActionFlow { + private val mutableStateFlow = MutableStateFlow(null) - override fun post(oidcAction: OidcAction) { - mutableStateFlow.value = oidcAction + override fun post(oAuthAction: OAuthAction) { + mutableStateFlow.value = oAuthAction } - override suspend fun collect(collector: FlowCollector) { + override suspend fun collect(collector: FlowCollector) { mutableStateFlow.collect(collector) } diff --git a/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolver.kt b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolver.kt new file mode 100644 index 0000000000..c2a29e228c --- /dev/null +++ b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolver.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2023-2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.oauth.impl + +import android.content.Intent +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthIntentResolver + +@ContributesBinding(AppScope::class) +class DefaultOAuthIntentResolver( + private val oAuthUrlParser: OAuthUrlParser, +) : OAuthIntentResolver { + override fun resolve(intent: Intent): OAuthAction? { + return oAuthUrlParser.parse(intent.dataString.orEmpty()) + } +} diff --git a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/OidcUrlParser.kt b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt similarity index 51% rename from libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/OidcUrlParser.kt rename to libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt index 8933873dc2..e62dea696f 100644 --- a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/OidcUrlParser.kt +++ b/libraries/oauth/impl/src/main/kotlin/io/element/android/libraries/oauth/impl/OAuthUrlParser.kt @@ -6,37 +6,37 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.impl +package io.element.android.libraries.oauth.impl import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider -import io.element.android.libraries.oidc.api.OidcAction +import io.element.android.libraries.matrix.api.auth.OAuthRedirectUrlProvider +import io.element.android.libraries.oauth.api.OAuthAction -fun interface OidcUrlParser { - fun parse(url: String): OidcAction? +fun interface OAuthUrlParser { + fun parse(url: String): OAuthAction? } /** - * Simple parser for oidc url interception. + * Simple parser for OAuth url interception. * TODO Find documentation about the format. */ @ContributesBinding(AppScope::class) -class DefaultOidcUrlParser( - private val oidcRedirectUrlProvider: OidcRedirectUrlProvider, -) : OidcUrlParser { +class DefaultOAuthUrlParser( + private val oAuthRedirectUrlProvider: OAuthRedirectUrlProvider, +) : OAuthUrlParser { /** - * Return a OidcAction, or null if the url is not a OidcUrl. + * Return a [OAuthAction], or null if the url is not an OAuth url. * Note: * When user press button "Cancel", we get the url: * `io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO` * On success, we get: * `io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB` */ - override fun parse(url: String): OidcAction? { - if (url.startsWith(oidcRedirectUrlProvider.provide()).not()) return null - if (url.contains("error=access_denied")) return OidcAction.GoBack() - if (url.contains("code=")) return OidcAction.Success(url) + override fun parse(url: String): OAuthAction? { + if (url.startsWith(oAuthRedirectUrlProvider.provide()).not()) return null + if (url.contains("error=access_denied")) return OAuthAction.GoBack() + if (url.contains("code=")) return OAuthAction.Success(url) // Other case not supported, let's crash the app for now error("Not supported: $url") diff --git a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlowTest.kt b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlowTest.kt similarity index 58% rename from libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlowTest.kt rename to libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlowTest.kt index 387b9aceb0..817487b3ff 100644 --- a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcActionFlowTest.kt +++ b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthActionFlowTest.kt @@ -1,34 +1,33 @@ /* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.impl +package io.element.android.libraries.oauth.impl import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.oidc.api.OidcAction +import io.element.android.libraries.oauth.api.OAuthAction import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest import org.junit.Test -class DefaultOidcActionFlowTest { +class DefaultOAuthActionFlowTest { @Test fun `collect gets all the posted events`() = runTest { - val data = mutableListOf() - val sut = DefaultOidcActionFlow() + val data = mutableListOf() + val sut = DefaultOAuthActionFlow() backgroundScope.launch { sut.collect { action -> data.add(action) } } - sut.post(OidcAction.GoBack()) + sut.post(OAuthAction.GoBack()) delay(1) sut.reset() delay(1) - assertThat(data).containsExactly(OidcAction.GoBack(), null) + assertThat(data).containsExactly(OAuthAction.GoBack(), null) } } diff --git a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolverTest.kt b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt similarity index 64% rename from libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolverTest.kt rename to libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt index 64068030d7..ff34ae8220 100644 --- a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolverTest.kt +++ b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthIntentResolverTest.kt @@ -1,19 +1,18 @@ /* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.impl +package io.element.android.libraries.oauth.impl import android.app.Activity import android.content.Intent import androidx.core.net.toUri import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider -import io.element.android.libraries.oidc.api.OidcAction +import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider +import io.element.android.libraries.oauth.api.OAuthAction import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith @@ -21,36 +20,36 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment @RunWith(RobolectricTestRunner::class) -class DefaultOidcIntentResolverTest { +class DefaultOAuthIntentResolverTest { @Test - fun `test resolve oidc go back`() { - val sut = createDefaultOidcIntentResolver() + fun `test resolve OAuth go back`() { + val sut = createDefaultOAuthIntentResolver() val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW data = "io.element.android:/?error=access_denied&state=IFF1UETGye2ZA8pO".toUri() } val result = sut.resolve(intent) - assertThat(result).isEqualTo(OidcAction.GoBack()) + assertThat(result).isEqualTo(OAuthAction.GoBack()) } @Test - fun `test resolve oidc success`() { - val sut = createDefaultOidcIntentResolver() + fun `test resolve OAuth success`() { + val sut = createDefaultOAuthIntentResolver() val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW data = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB".toUri() } val result = sut.resolve(intent) assertThat(result).isEqualTo( - OidcAction.Success( + OAuthAction.Success( url = "io.element.android:/?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" ) ) } @Test - fun `test resolve oidc invalid`() { - val sut = createDefaultOidcIntentResolver() + fun `test resolve OAuth invalid`() { + val sut = createDefaultOAuthIntentResolver() val intent = Intent(RuntimeEnvironment.getApplication(), Activity::class.java).apply { action = Intent.ACTION_VIEW data = "io.element.android:/invalid".toUri() @@ -60,10 +59,10 @@ class DefaultOidcIntentResolverTest { } } - private fun createDefaultOidcIntentResolver(): DefaultOidcIntentResolver { - return DefaultOidcIntentResolver( - oidcUrlParser = DefaultOidcUrlParser( - oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(), + private fun createDefaultOAuthIntentResolver(): DefaultOAuthIntentResolver { + return DefaultOAuthIntentResolver( + oAuthUrlParser = DefaultOAuthUrlParser( + oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(), ), ) } diff --git a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcUrlParserTest.kt b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt similarity index 56% rename from libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcUrlParserTest.kt rename to libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt index 7f145c053d..6377414862 100644 --- a/libraries/oidc/impl/src/test/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcUrlParserTest.kt +++ b/libraries/oauth/impl/src/test/kotlin/io/element/android/libraries/oauth/impl/DefaultOAuthUrlParserTest.kt @@ -1,59 +1,58 @@ /* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. + * Copyright (c) 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.impl +package io.element.android.libraries.oauth.impl import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.test.auth.FAKE_REDIRECT_URL -import io.element.android.libraries.matrix.test.auth.FakeOidcRedirectUrlProvider -import io.element.android.libraries.oidc.api.OidcAction +import io.element.android.libraries.matrix.test.auth.FakeOAuthRedirectUrlProvider +import io.element.android.libraries.oauth.api.OAuthAction import org.junit.Assert import org.junit.Test -class DefaultOidcUrlParserTest { +class DefaultOAuthUrlParserTest { @Test fun `test empty url`() { - val sut = createDefaultOidcUrlParser() + val sut = createDefaultOAuthUrlParser() assertThat(sut.parse("")).isNull() } @Test fun `test regular url`() { - val sut = createDefaultOidcUrlParser() + val sut = createDefaultOAuthUrlParser() assertThat(sut.parse("https://matrix.org")).isNull() } @Test fun `test cancel url`() { - val sut = createDefaultOidcUrlParser() + val sut = createDefaultOAuthUrlParser() val aCancelUrl = "$FAKE_REDIRECT_URL?error=access_denied&state=IFF1UETGye2ZA8pO" - assertThat(sut.parse(aCancelUrl)).isEqualTo(OidcAction.GoBack()) + assertThat(sut.parse(aCancelUrl)).isEqualTo(OAuthAction.GoBack()) } @Test fun `test success url`() { - val sut = createDefaultOidcUrlParser() + val sut = createDefaultOAuthUrlParser() val aSuccessUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&code=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" - assertThat(sut.parse(aSuccessUrl)).isEqualTo(OidcAction.Success(aSuccessUrl)) + assertThat(sut.parse(aSuccessUrl)).isEqualTo(OAuthAction.Success(aSuccessUrl)) } @Test fun `test unknown url`() { - val sut = createDefaultOidcUrlParser() + val sut = createDefaultOAuthUrlParser() val anUnknownUrl = "$FAKE_REDIRECT_URL?state=IFF1UETGye2ZA8pO&goat=y6X1GZeqA3xxOWcTeShgv8nkgFJXyzWB" Assert.assertThrows(IllegalStateException::class.java) { assertThat(sut.parse(anUnknownUrl)) } } - private fun createDefaultOidcUrlParser(): DefaultOidcUrlParser { - return DefaultOidcUrlParser( - oidcRedirectUrlProvider = FakeOidcRedirectUrlProvider(), + private fun createDefaultOAuthUrlParser(): DefaultOAuthUrlParser { + return DefaultOAuthUrlParser( + oAuthRedirectUrlProvider = FakeOAuthRedirectUrlProvider(), ) } } diff --git a/libraries/oidc/test/build.gradle.kts b/libraries/oauth/test/build.gradle.kts similarity index 80% rename from libraries/oidc/test/build.gradle.kts rename to libraries/oauth/test/build.gradle.kts index efe32d404a..6850653ddc 100644 --- a/libraries/oidc/test/build.gradle.kts +++ b/libraries/oauth/test/build.gradle.kts @@ -11,11 +11,11 @@ plugins { } android { - namespace = "io.element.android.libraries.oidc.test" + namespace = "io.element.android.libraries.oauth.test" } dependencies { implementation(libs.coroutines.core) - api(projects.libraries.oidc.api) + api(projects.libraries.oauth.api) implementation(projects.tests.testutils) } diff --git a/libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/FakeOidcIntentResolver.kt b/libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/FakeOAuthIntentResolver.kt similarity index 50% rename from libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/FakeOidcIntentResolver.kt rename to libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/FakeOAuthIntentResolver.kt index 45b400868b..893289023e 100644 --- a/libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/FakeOidcIntentResolver.kt +++ b/libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/FakeOAuthIntentResolver.kt @@ -6,17 +6,17 @@ * Please see LICENSE files in the repository root for full details. */ -package io.element.android.libraries.oidc.test +package io.element.android.libraries.oauth.test import android.content.Intent -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcIntentResolver +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthIntentResolver import io.element.android.tests.testutils.lambda.lambdaError -class FakeOidcIntentResolver( - private val resolveResult: (Intent) -> OidcAction? = { lambdaError() } -) : OidcIntentResolver { - override fun resolve(intent: Intent): OidcAction? { +class FakeOAuthIntentResolver( + private val resolveResult: (Intent) -> OAuthAction? = { lambdaError() } +) : OAuthIntentResolver { + override fun resolve(intent: Intent): OAuthAction? { return resolveResult(intent) } } diff --git a/libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/customtab/FakeOAuthActionFlow.kt b/libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/customtab/FakeOAuthActionFlow.kt new file mode 100644 index 0000000000..5a5ca4369e --- /dev/null +++ b/libraries/oauth/test/src/main/kotlin/io/element/android/libraries/oauth/test/customtab/FakeOAuthActionFlow.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Element Creations Ltd. + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.oauth.test.customtab + +import io.element.android.libraries.oauth.api.OAuthAction +import io.element.android.libraries.oauth.api.OAuthActionFlow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.MutableStateFlow + +/** + * This is actually a copy of DefaultOAuthActionFlow. + */ +class FakeOAuthActionFlow : OAuthActionFlow { + private val mutableStateFlow = MutableStateFlow(null) + + override fun post(oAuthAction: OAuthAction) { + mutableStateFlow.value = oAuthAction + } + + override suspend fun collect(collector: FlowCollector) { + mutableStateFlow.collect(collector) + } + + override fun reset() { + mutableStateFlow.value = null + } +} diff --git a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolver.kt b/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolver.kt deleted file mode 100644 index 2a16030b3b..0000000000 --- a/libraries/oidc/impl/src/main/kotlin/io/element/android/libraries/oidc/impl/DefaultOidcIntentResolver.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2023-2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.oidc.impl - -import android.content.Intent -import dev.zacsweers.metro.AppScope -import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcIntentResolver - -@ContributesBinding(AppScope::class) -class DefaultOidcIntentResolver( - private val oidcUrlParser: OidcUrlParser, -) : OidcIntentResolver { - override fun resolve(intent: Intent): OidcAction? { - return oidcUrlParser.parse(intent.dataString.orEmpty()) - } -} diff --git a/libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/customtab/FakeOidcActionFlow.kt b/libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/customtab/FakeOidcActionFlow.kt deleted file mode 100644 index 5362aefa7c..0000000000 --- a/libraries/oidc/test/src/main/kotlin/io/element/android/libraries/oidc/test/customtab/FakeOidcActionFlow.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2025 Element Creations Ltd. - * Copyright 2025 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. - * Please see LICENSE files in the repository root for full details. - */ - -package io.element.android.libraries.oidc.test.customtab - -import io.element.android.libraries.oidc.api.OidcAction -import io.element.android.libraries.oidc.api.OidcActionFlow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.flow.MutableStateFlow - -/** - * This is actually a copy of DefaultOidcActionFlow. - */ -class FakeOidcActionFlow : OidcActionFlow { - private val mutableStateFlow = MutableStateFlow(null) - - override fun post(oidcAction: OidcAction) { - mutableStateFlow.value = oidcAction - } - - override suspend fun collect(collector: FlowCollector) { - mutableStateFlow.collect(collector) - } - - override fun reset() { - mutableStateFlow.value = null - } -} diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 44cf6edefc..d5c3f04348 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.push.impl.push import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn +import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.push.impl.db.PushRequest @@ -35,6 +36,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import timber.log.Timber private val loggerTag = LoggerTag("PushHandler", LoggerTag.PushLoggerTag) @@ -53,6 +55,7 @@ class DefaultPushHandler( private val workManagerScheduler: WorkManagerScheduler, private val syncPendingNotificationsRequestFactory: SyncPendingNotificationsRequestBuilder.Factory, resultProcessor: NotificationResultProcessor, + private val dispatchers: CoroutineDispatchers, ) : PushHandler { init { resultProcessor.start() @@ -64,7 +67,7 @@ class DefaultPushHandler( * @param pushData the data received in the push. * @param providerInfo the provider info. */ - override suspend fun handle(pushData: PushData, providerInfo: String): Boolean { + override suspend fun handle(pushData: PushData, providerInfo: String): Boolean = withContext(dispatchers.computation) { // Start measuring how long it takes to display a notification from when the push is received Timber.d("Calculating push-to-notification for event ${pushData.eventId}") val parent = analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.PushToNotification(pushData.eventId.value)) @@ -81,7 +84,7 @@ class DefaultPushHandler( } // Diagnostic Push - return if (pushData.eventId == DefaultTestPush.TEST_EVENT_ID) { + if (pushData.eventId == DefaultTestPush.TEST_EVENT_ID) { pushHistoryService.onDiagnosticPush(providerInfo) diagnosticPushHandler.handlePush() false @@ -90,7 +93,7 @@ class DefaultPushHandler( } } - override suspend fun handleInvalid(providerInfo: String, data: String) { + override suspend fun handleInvalid(providerInfo: String, data: String) = withContext(dispatchers.computation) { incrementPushDataStore.incrementPushCounter() pushHistoryService.onInvalidPushReceived(providerInfo, data) } diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt index a16568d400..f0dee4446c 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandlerTest.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.push.impl.push import app.cash.turbine.test +import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -40,7 +41,9 @@ import io.element.android.services.toolbox.test.systemclock.FakeSystemClock 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 io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -212,7 +215,7 @@ class DefaultPushHandlerTest { .isCalledOnce() } - private fun createDefaultPushHandler( + private fun TestScope.createDefaultPushHandler( incrementPushCounterResult: () -> Unit = { lambdaError() }, userPushStore: FakeUserPushStore = FakeUserPushStore(), pushClientSecret: PushClientSecret = FakePushClientSecret(), @@ -227,6 +230,7 @@ class DefaultPushHandlerTest { start = {}, stop = {}, ), + dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), ): DefaultPushHandler { return DefaultPushHandler( incrementPushDataStore = object : IncrementPushDataStore { @@ -246,7 +250,8 @@ class DefaultPushHandlerTest { resultProcessor = resultProcessor, syncPendingNotificationsRequestFactory = SyncPendingNotificationsRequestBuilder.Factory { FakeSyncPendingNotificationsRequestBuilder() - } + }, + dispatchers = dispatchers, ) } } diff --git a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt index 568dbe7e3a..88cf9558b3 100644 --- a/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt +++ b/libraries/session-storage/api/src/main/kotlin/io/element/android/libraries/sessionstorage/api/SessionData.kt @@ -24,8 +24,8 @@ data class SessionData( val refreshToken: String?, /** The homeserver URL of the session. */ val homeserverUrl: String, - /** The Open ID Connect info for this session, if any. */ - val oidcData: String?, + /** The Open Authorization info for this session, if any. */ + val oAuthData: String?, /** The timestamp of the last login. May be `null` in very old sessions. */ val loginTimestamp: Date?, /** Whether the [accessToken] is valid or not. */ diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt index ea69709bbd..316bf86c1c 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/SessionDataMapper.kt @@ -20,7 +20,7 @@ internal fun SessionData.toDbModel(): DbSessionData { accessToken = accessToken, refreshToken = refreshToken, homeserverUrl = homeserverUrl, - oidcData = oidcData, + oidcData = oAuthData, loginTimestamp = loginTimestamp?.time, isTokenValid = if (isTokenValid) 1L else 0L, loginType = loginType.name, @@ -41,7 +41,7 @@ internal fun DbSessionData.toApiModel(): SessionData { accessToken = accessToken, refreshToken = refreshToken, homeserverUrl = homeserverUrl, - oidcData = oidcData, + oAuthData = oidcData, loginTimestamp = loginTimestamp?.let { Date(it) }, isTokenValid = isTokenValid == 1L, loginType = LoginType.fromName(loginType ?: LoginType.UNKNOWN.name), diff --git a/libraries/session-storage/test/src/main/kotlin/io/element/android/libraries/sessionstorage/test/SessionData.kt b/libraries/session-storage/test/src/main/kotlin/io/element/android/libraries/sessionstorage/test/SessionData.kt index c791a20620..c5acd77755 100644 --- a/libraries/session-storage/test/src/main/kotlin/io/element/android/libraries/sessionstorage/test/SessionData.kt +++ b/libraries/session-storage/test/src/main/kotlin/io/element/android/libraries/sessionstorage/test/SessionData.kt @@ -30,7 +30,7 @@ fun aSessionData( accessToken = accessToken, refreshToken = refreshToken, homeserverUrl = "aHomeserverUrl", - oidcData = null, + oAuthData = null, loginTimestamp = null, isTokenValid = isTokenValid, loginType = LoginType.UNKNOWN, diff --git a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt index 23b4fae3a9..bec837664f 100644 --- a/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt +++ b/libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/CaptionWarningBottomSheet.kt @@ -12,6 +12,8 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -37,11 +39,13 @@ fun CaptionWarningBottomSheet( ModalBottomSheet( modifier = modifier, onDismissRequest = onDismiss, + scrollable = false, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp), + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(16.dp), ) { diff --git a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt index ce5c324ff4..f832136083 100644 --- a/plugins/src/main/kotlin/extension/DependencyHandleScope.kt +++ b/plugins/src/main/kotlin/extension/DependencyHandleScope.kt @@ -120,7 +120,7 @@ fun DependencyHandlerScope.allLibrariesImpl() { implementation(project(":libraries:troubleshoot:impl")) implementation(project(":libraries:fullscreenintent:impl")) implementation(project(":libraries:wellknown:impl")) - implementation(project(":libraries:oidc:impl")) + implementation(project(":libraries:oauth:impl")) implementation(project(":libraries:workmanager:impl")) implementation(project(":libraries:recentemojis:impl")) } diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png new file mode 100644 index 0000000000..6b4037b3eb --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c755a7dcfc2c9f48d449e570a3f1af1cde299fd90ddd4478e9a4c315cf03128 +size 23810 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png new file mode 100644 index 0000000000..e64ae4c3cf --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efa5408c3af0fcd39659b8d30b21ace43be46d2876815ad592f802a7887b5eb9 +size 23678 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png new file mode 100644 index 0000000000..82b04fc045 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fc512e71e168473e0e976be3e3e6cd24b455273257ad0adf970fc2641da43bb +size 25679 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png new file mode 100644 index 0000000000..f52d785548 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de71af50bba66a285b5ef44e1a4fe76ce6dc2e094c4c09ddf701deb9a5db898d +size 22025 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png new file mode 100644 index 0000000000..eef2177c3b --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88b3583d55c6855027f13a152a6fc414f6b9e11d65e5b5403463b84fafe38c3f +size 21891 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png new file mode 100644 index 0000000000..87d3f56720 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListContextMenu_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e64367832735139b68269a8c679b9c6f2b929b906124a0ee93735cbdd9202d6d +size 23826 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en.png deleted file mode 100644 index 70e3f6ae06..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:22e3dce5359ba6dd21bd1c17e4421b8341c51809843394c95a3d80db7a235309 -size 25774 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en.png deleted file mode 100644 index ddea584902..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenuContent_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:671a0a0ce5571cb460fba789b58ec1e38b63b26ba61c1daeb5cccb986eb424b4 -size 24768 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_0_en.png new file mode 100644 index 0000000000..686013e622 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a58c642983f209f2c4bb01ee0239c11edab299f48129800cbd41fe7a9032ad4 +size 26854 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_1_en.png new file mode 100644 index 0000000000..278dfc4ae5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43837ff4703be9631370b56097bd36006bce98d23f17db629742c957ce945e5a +size 42390 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_2_en.png new file mode 100644 index 0000000000..63a523b4ae --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b3025b589185d8d276bd3a809d8d94700268be1aec951fd02ff37072cef4998 +size 27431 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_0_en.png new file mode 100644 index 0000000000..d6392b8c0f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d7acb04225299d448edf35ad1f420ceafcabc7759a8f7d94ce11eca70781f79 +size 25339 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_1_en.png new file mode 100644 index 0000000000..bf799e5042 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56b210d5d8dc06de139735ca34f2b5a4e5e7d0db395dc2dbe7b1c9d479d8858d +size 40405 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_2_en.png new file mode 100644 index 0000000000..27a4cd57b0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListDeclineInviteMenu_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ff47c937641549f63948d114510644aad02723a55e752587a1037752a2b3972 +size 25966 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en.png deleted file mode 100644 index 9b17990dbe..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a81e2f9d2c3834004b49b925025478b886c065a12dc850f1c42733e457630b97 -size 22442 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en.png deleted file mode 100644 index 5b45fb30de..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3348885402696e4b8005740a452384223f60a64c524c32713cfbd9b3041e494 -size 22297 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en.png deleted file mode 100644 index 1ec1abe309..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Day_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a1a54d3171418082d8bdf442bb34c6b149e2707963f88dd7ea7cbff401534fc0 -size 23856 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en.png deleted file mode 100644 index e5a42fb07f..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_0_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3ea756319eeb2d9ab6ad2425498a7a9902acada24c3ab359f880b5934f2511e5 -size 21384 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en.png deleted file mode 100644 index 2388eb323d..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c75bbb8425fa4b01f9d0d9398d93785f2a149f4abb820dadbfadf17bf4a6673e -size 21077 diff --git a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en.png deleted file mode 100644 index 356ee32526..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.home.impl.roomlist_RoomListModalBottomSheetContent_Night_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:99defb3eb8530142a74c083d4f4ec2e592d465b3d2cf869e1710031ad6a805c9 -size 23136 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Day_0_en.png new file mode 100644 index 0000000000..18b186ce98 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23d54e777c8c9ade84bec155e3aef42f5b1c13b98a23ea6ecbd956d0090b5ad3 +size 32186 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Night_0_en.png new file mode 100644 index 0000000000..d1698e913f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.confirmation_CodeConfirmationView_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bde248827b1c53b66c5ea7112af24cac43aea378266e3d7b7ad8a5fa2047258 +size 31261 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png index 3832b8d087..19a824127e 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe92b35b0fe2e5481eeb497f2ada1a639cb1a66f937b4245798edffea75b1f5c -size 35932 +oid sha256:d30e200c3e73775ed7081d3fbdc9f8843c5a5bf9e5f1b9ab3535cc6f0ea7f1f6 +size 35946 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_4_en.png index 4821d3ab76..292e8f0ead 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f60e02e48d483fe8d6b2bdf46192ccc8911fad1e79c7ac1e0272824cc04d3d1c -size 35648 +oid sha256:90e602edde377f866071ec78f391bb7cd0d9b59bec79be91d6a42108f604a32d +size 35833 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_6_en.png index 720026f561..6c9c87f774 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60333d74c8d940b32621defc5cdb3c3776b2980c137244dd34304365ee9ff447 -size 24158 +oid sha256:ced04df939214952c513aa8b4ef4c7a02dfe3bb3bce81f9ec6ea1827f639bf3f +size 24471 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_7_en.png index 0fcd59d198..429daba97a 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5bec4c7d06dc2cc287d2165f588c6764e5314287119960947d7e24dbc19ce901 -size 23971 +oid sha256:018e6226239c439fc683eead0acb733d1e06eebad54b1a6c2b43d8cbd2e822cc +size 24324 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_8_en.png new file mode 100644 index 0000000000..14a6d77fe9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Day_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94e0cec5dac39083da711bdd30762eb84c794ecc41ab74f6dbe8cf5053402ea1 +size 22080 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png index 368e908499..f1f3896ab8 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f6bc4bb2233067ab6d07e596f8d5ca294501a47a21451a1115aa46e238b31a5 -size 34996 +oid sha256:a78b0677d896de960ce8ce7c5818b1d52004c91917c73c460a605e5e1342554f +size 35129 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_4_en.png index c9d622683c..51d6a1bc13 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:766e65cfceb2e9ff3895ecd5c2be2b80d7b2833b30a5c67a0075ef823bb77cc0 -size 34816 +oid sha256:31b97291b16fd0872891ad2341d95d34d8c0608f92e7a5e39b5f27d40769b111 +size 34955 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_6_en.png index ab0b09c575..3bd50c5655 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd50a4cb9848602b08b853f4fa36314b981a858b98349d68decfcbd6f402d719 -size 23631 +oid sha256:43cf679fbb9a83f14209e61129afb8e7f18a60f9bc127bfcf4f5dff05c79598e +size 24033 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_7_en.png index 4194458de9..2a85b2cf7f 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e2de9b362092dbd08deadac70591d4682304c69981fe27cbbeae4f26233d4aa -size 23444 +oid sha256:7ee6f9fbf05261efe52c247da3869c68c6e87f5132c52da72e56cf833ea6864d +size 23833 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_8_en.png new file mode 100644 index 0000000000..d36887d3e5 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.error_ErrorView_Night_8_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:144ea7ed8bba7d5ded34b5e00d7f3f036c4dc882be0cf8a644817ffee4c531f7 +size 21429 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en.png index 136812ccab..474a2b43a5 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11a877e3e4810777b7ddb15fa11b8410976142ee4fb5e9d4103f4248acf121cf -size 29685 +oid sha256:cc0409c3e6c60994c81d83c429bbfb7ebc4ee53ac4114d1913b089a8068ca51e +size 30046 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en.png index e04f62d6aa..fab5d228a6 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:471129545a85e702e8b59391f47630f128f80e819b042e91ee356684e4ae2438 -size 29680 +oid sha256:3670e0f777491b7f6101c3c1c3cc006e4848a8f6e481b9740fb42ee8807ccf9e +size 30024 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en.png index e5f8926345..764cb92eef 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a932c055ae0704cd62358c5442658c1cb059d7d3c0c56518de3e763c8eab3c52 -size 30355 +oid sha256:79b7dd684dcec4a06271eed34794e7546ba441ad2cc9796641ba570871e45cd3 +size 30659 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en.png index a1d475ecdd..9a795c080c 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ca49fb335880670a3b71fdd1f2e2be50e9a5a6677d2e17e9534c9724d9d55b1 -size 30534 +oid sha256:29233a6bad671608f5e1a1d20b24b454cfd70f8a846e4d9572cc86b8c7da45a0 +size 30843 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en.png index 116337e4be..58ae956b13 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be4f85040190c658d5734000e602b4cb43cb0a5ab2e2cea0a993959702c4722f -size 33681 +oid sha256:5d30ae8d9d3b3820dc17d7aff3bd5c6794f5a267993a5dae4dc601278ccaaa5c +size 33999 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en.png index bf1561d23e..7ba887d858 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29d7aac2eaef7850cc9b0f5583d6c9a8aef230525d40011a9a7cb5401b681d03 -size 33409 +oid sha256:bf5b6e85e57aef0d52253dc7563bbe0aae3f38e4a65e2fdc8e0460bccf26b006 +size 33722 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en.png index 99c888caba..a0404e5e72 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cb49a80d6ff771484743be2efc4900d053ccf84372614b98e9284d66d19056f -size 28895 +oid sha256:e0c446ba7fc8e0c0c68732ba34058b41e04d8641dcdbc83255f9417706044c8c +size 29067 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en.png index 4415136e95..fedf612386 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68845451924a562238f2c75dced10697cae75171d976e19c0de927eacfdc3210 -size 28853 +oid sha256:da2778e384c9f749e888690660f496b4af93b7cff6f93c9fef346580a477e1cf +size 29029 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en.png index 13df6a6877..6faf2d1cba 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5cc21d3fe55a5dba7b9e70d445877b07f0c88bee61fbd64f929a2321473ea8ad -size 29581 +oid sha256:62c79d08701dad73ab3f5f7744cd2683febeb34cb8bab986685e0cd8bd33c0f6 +size 29773 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en.png index 5e08ee2145..d4c10cf76f 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf6312a9e19892c9db949474cb9aa3b7572cc132d3d5474278abb3c4d91b7ab1 -size 29505 +oid sha256:fad2e4dbc822c79fbd8569dd8db7a5c08b335793aff6923129175bd4479cb218 +size 29744 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en.png index e84f38285e..ff882fdaea 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f24e410e2715019c5fbba40a2f79750781e8db0f4b36c772cb7b37f0d3b0d26f -size 32697 +oid sha256:7a85f79b0167efdc0277d05a41712c39d10115482242bb84a140c6647c28d85d +size 32895 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en.png index 16f85bba9f..1fbbba121f 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.number_EnterNumberView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd1e04c468c0daae10917f8e66a8e5a6ef8f72fa02f3ad4ca507b714dae7898d -size 32449 +oid sha256:865d4c7ff07834027411a76767aaaa8aa0febf529b910eaa51e5de9bd8a776fa +size 32641 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en.png index d6faf7dd8f..fb88b5b2a8 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b4a99e2ea65816e35ec8fb1cf40d8aafebb6fd5ae688911d7d009dda15cd0f9 -size 18123 +oid sha256:0ec014c00a19fb280f4e2047d873f1698eedde51a765948bd2652079921588a7 +size 18264 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en.png index db46722b7b..9bf1f8609c 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cfbe2c73c732d671278ed411d76915d04d6e7ffce130c2a6dbe30ea43628e231 -size 24247 +oid sha256:ba8f1717d752a93cdda51a6ee5e8bac043a4572aadc4d1c0dba2bfe80e6c55db +size 24372 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en.png index c0703e447a..139ae28bda 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9168cc32d47f15de0ce961d841d872181b8aadf5151d4b5fd4d305c87cdda75 -size 21597 +oid sha256:7bc87f28234d11c58f5b43a7f87ee4e5a5d631e5a41ba11756c057a2a5eea1ff +size 21745 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en.png index 457e334ac2..a36301f230 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:96448542138570c8615e24dd3b26be55145570c64ac9d410bbc4dac36280c345 -size 23769 +oid sha256:c97be1636f039afaab65c1b6858c439fcf47e6643681a886fd9c24ab6c7b0901 +size 23901 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en.png index 4621b6c95e..78e7e0d1bf 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:672e617ab62c72127a4c57bed6da8ba4710cfc24ca455ea6edc765d7a424a0f3 -size 33766 +oid sha256:90ca0d9059538259cd19e7e75f6adc11f21b3a1cc77aec8d5efaf3d55abf8505 +size 34006 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en.png index 52e64e87c3..e6153a4a2d 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:451565c6881885b51de299c2d71e77f78a62e68f96a75bc859050e64b87ef79e -size 17372 +oid sha256:1cd2061366439af2139a1ace15557ecdd8aa91c0d2f1e0adfc76a7d63e17133c +size 17615 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en.png index 5610b70d00..03c7fd3b0c 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:def1de8d3a76255e72e0d65dbbf6364f77c2764e2ac99b32a0145174cf0f3a28 -size 23244 +oid sha256:541b4cd380fee2f2a445fe25a1171492c865b10980dd79de70f42b0f3dc120c4 +size 23475 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en.png index 3784bbcac7..3cc9326747 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1bd9567f7a504590da66993a2da6771c1a4157bc37301510f6d91d62efed7c16 -size 20745 +oid sha256:b71e2ba137ec1ffc65c07fc836074f7fa0ef310fb81a15db905db819ea29dd0e +size 20980 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en.png index e511df48c7..d6bb6bcc8d 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d662774653bcec6246ac6529ec98bcff77b02e4a6a8ef42ed0a640fed3770dff -size 22698 +oid sha256:de97697d988d0cc25626c7e31f153a7dca6987215edbe2e42ec16367ea9b4b3c +size 22952 diff --git a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en.png index d35cdd7397..59789476b1 100644 --- a/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.linknewdevice.impl.screens.root_LinkNewDeviceRootView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee6a0cf330b30e4fdc7cb8b4268251850f2f112e1ad0ce4af1166341f04a0638 -size 32103 +oid sha256:9b3a92c98a93b1d9e7f127a13c664c7275e26030d59a0ebcd3641428d9a21683 +size 32303 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Day_0_en.png index 47145ebd49..3314252e26 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62df5826abbcd47bc2a18743f2baeef8c9c85ebc547660a9ae92328cd49499b0 -size 62768 +oid sha256:6e97cab70b9ee3e870154ad4ae4cf1bf0bb413facf8253f5f9fe9429eddf76b1 +size 60303 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Night_0_en.png index fa68b6c988..d58e079ced 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.classic.missingkeybackup_MissingKeyBackupView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c92a6ada8c2aa5991c28935dafd8e35a0c0efc2c40660c16105b3cf381914cdd -size 61097 +oid sha256:caaa2a0f4de455704a6b5c78e19c2f723be7deaeec470c77ff1e87df194dd95c +size 58620 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en.png index 878e97a06e..048c9beb26 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbcf2216fe8f2653d44df345c157eb66f54ff8767c210bfeab5719d6d70230a8 -size 31686 +oid sha256:647163b31578572c9bf4a63a1d110f732fc3b0c41c3991651996608d6265c536 +size 31960 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en.png index 05edb58b0f..d27a10bf39 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:324b1392f40bb408b6469e656e774f5b1f7cbd9bb6557ec7a2587a971b548ccc -size 31288 +oid sha256:6e447151f2a7aaf9052130d5b915e9aea8180880c66fa51afb06d212079a0ced +size 31159 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en.png index 096b521d75..4b7e849116 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1075e98dac6a50a282a39dfd5855833080becd377e1bf3f9db8fb20104bda80d -size 33479 +oid sha256:e215ffdf8ba90e3f7a047d25206dfef4a08d25137ee2e4d3e5c16f254282927c +size 33371 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en.png index e738c998a3..276d9919f7 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f55c2e968f464ba9593dc8841a0e633c2f0a75cb3f85857aa3b4b716770629e -size 30831 +oid sha256:76613fd85c3211bd2c96e50f2d481d2d994aad20368713c1da309d0147ce1101 +size 31015 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en.png index ae7ffe2dd4..c1da84be8e 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8484c5300a8da5b120a24513b29bdd697dd3edd7d6b7c91e5925aa55c6290fd -size 30366 +oid sha256:5f32133324f20fc97c3473ca6ea3b1705d3b0beab5bed11af9199e4f5b9ab124 +size 30410 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en.png index 1cf5572c4e..e06e5ccaaa 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.confirmation_QrCodeConfirmationView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8b87fe16a96a8c34b49aab481f65c3223fd098360048b7dcd1ee8bef85fdf378 -size 32650 +oid sha256:00556b6c310f63b548bc1a88b3b882a93412a2a7dacff008862faeb2ad572eb3 +size 32671 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en.png index 98039ad35b..d13b526c94 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:647b5d2512180674b14a93903de4ee0539720dc1ddc7eaadec23940aa8b3befa -size 35934 +oid sha256:c95c7e7f68133f25bca9c33246983cdd1b448ca822b1221eba54c171c8f2e051 +size 35898 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en.png index 9751c25cb4..aa8c5c7858 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:010a03fc52fb0ec9b39701d75ef26c7f23ba6195e7d3e0c4e2b7e03518425b57 -size 24287 +oid sha256:b4b6b193a6c9bd9188cde36056a512ebe10f9b24d07a33926b51876712b453b2 +size 24468 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en.png index 0fcd59d198..429daba97a 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5bec4c7d06dc2cc287d2165f588c6764e5314287119960947d7e24dbc19ce901 -size 23971 +oid sha256:018e6226239c439fc683eead0acb733d1e06eebad54b1a6c2b43d8cbd2e822cc +size 24324 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en.png index ce263c7d02..0fc27b0af4 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb22d79ff43ce9a1931537880829cf5d2c13aafe3c06136c80703f2599d676cf -size 35000 +oid sha256:ecc5f3820395a67eee396556344663844fb97dc843cda96b2545c954d133795f +size 35118 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en.png index 2c4de61a77..fb5e9a7448 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f3c16c9a89228f83eaaa7f9bdd7c0e36a333efb541738bd38411f9f853e20103 -size 23797 +oid sha256:dc0360e2705f3e029c1f8cabf91787a98f7d7b67e6d1f003c54ca4ffd52d08be +size 23961 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en.png index 4194458de9..2a85b2cf7f 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.error_QrCodeErrorView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e2de9b362092dbd08deadac70591d4682304c69981fe27cbbeae4f26233d4aa -size 23444 +oid sha256:7ee6f9fbf05261efe52c247da3869c68c6e87f5132c52da72e56cf833ea6864d +size 23833 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png index a1b5d1bb59..afd2b2cbe5 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:919595acfee379e3aaee66a3abba61515e8bee35a9fe0250a8a227f772109864 -size 49693 +oid sha256:94014619417d8c530dc80316c9aca36dc08997f516890d7199b24afa46e71c86 +size 50004 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png index 665a36ad0a..f86302a8ee 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:079ef0792efb31fbd773beb77a95bfa713213f8f5428ea1c12060094deac5442 -size 48620 +oid sha256:0a3d3c574589f06729b58775ca37bab9711c5566adff366d4a0196eaa7e10ab7 +size 47410 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png index 32d07be159..3ee9db165b 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:17cd489adfd7a417a6972f8e36a61ecb2bcaf2a045d33e4d2236004271d4d9ff -size 48317 +oid sha256:277665230a31e1a47489a5124efa6dcaf51a5a442f0e6d4dfb510ff4896c9bd0 +size 48738 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png index 9ad4c83991..ba4e6885b7 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.qrcode.intro_QrCodeIntroView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:215e1dbc213d493ee6e24712aa93c9a103f1148a3ea2858ff185dfdc7084ea3b -size 46546 +oid sha256:2044881fe3e54179333fc0b125972b2b410a4d3657faa10769b964e8ae0d2643 +size 45278 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png index d996699f1a..da7923cf50 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31e32566506ef9c6d34b144663b308a53f893b810960c50e394271ed5dc02fc0 -size 28564 +oid sha256:b1c09cbb0217a1fb844828590e7827c27a2e9a99ecf5aed225f4d1bd0e413c8d +size 29343 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png index 9df382c0db..68b16e509f 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6e129a426f95432f31ecb5776ae24e5fed7a3025217c70831dcab30ac270fc3 -size 33329 +oid sha256:6ee66772b20b9c1cacf1f9387c173f8170d0c132d6caddfbd389d254b2ae7aa5 +size 33977 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png index 68d54d002a..56510ac1e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2eb71eb5d1cac83a03abbdc6ac670cb96993da8825ab224b43e593ae4b6ee8f -size 53719 +oid sha256:3eed90dbcc789f3db882d61a31924668a42cf78e00cd634192a5bfb831f67190 +size 53659 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png index f71897a57b..3bc29fbe6e 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71e7b0aba9acb702371ed0eacd6d86735d47d02dfadc67e55079a454c9c8733f -size 30242 +oid sha256:228a9ed83c86a160fe494254ec654fc0bf1d6923e78f5de2b4057d386e25b333 +size 30750 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png index 68d54d002a..56510ac1e2 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2eb71eb5d1cac83a03abbdc6ac670cb96993da8825ab224b43e593ae4b6ee8f -size 53719 +oid sha256:3eed90dbcc789f3db882d61a31924668a42cf78e00cd634192a5bfb831f67190 +size 53659 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png index c34ec228cd..bdad7df7bc 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1c6a823d353aa2f63633bce1d0336239196f26136b532718fdf2c49c183fbe9 -size 38014 +oid sha256:64c4173147686886d5021cdaf6480644a5a520f81392ca84aa7ab5d705211bc7 +size 38682 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png index 651a16265f..f52aac7f1c 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:359b8ffc79afd24ba68c2e7c13ba551e9d63c72b787e530667cd5de5c16782f6 -size 48002 +oid sha256:c6c73dd018eb82fe9e54ffbe38dcc491938da69791f4ff32081b2dac7549a4b2 +size 47958 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png index 651a16265f..f52aac7f1c 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:359b8ffc79afd24ba68c2e7c13ba551e9d63c72b787e530667cd5de5c16782f6 -size 48002 +oid sha256:c6c73dd018eb82fe9e54ffbe38dcc491938da69791f4ff32081b2dac7549a4b2 +size 47958 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png index 12fa559ca5..4d2c26d91d 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84d3be38de70c774b36592543eb5636029b08f9a847566dea4f90979ec9be97c -size 27529 +oid sha256:0b0e1f00b98e463a97c9334da018ba944414526f771aa4ceaea18ab192a36863 +size 28080 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png index 543aa41952..a650636f24 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93f49929a2e696bfa8a8938107d3263dcda514f34c8b5eeb6315267126d138d0 -size 32095 +oid sha256:87e337a40741a5c7bdcb2015b8f82282ae69e1eff98e30641a02314660ecbd73 +size 32583 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png index 53bf92ea9c..62596baf31 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4701f103d24353378826f66e6d602b0bdf43904ef6b28ee03d25af4a1062411 -size 51650 +oid sha256:66a0dc249d2df7e52a6a5f7cb3f1a94be011164eaf23d365f548b99f093d3d14 +size 51681 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png index 68647ba764..f97ba2a853 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2223132d7446121d8bd37b3561fc24ce056aeffc8828b197a2be8c92ce64cd27 -size 29197 +oid sha256:aba88e94521e05328079fb2ac0b06fd97987f81694b3378f02c19a20bfae2572 +size 29636 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png index 53bf92ea9c..62596baf31 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4701f103d24353378826f66e6d602b0bdf43904ef6b28ee03d25af4a1062411 -size 51650 +oid sha256:66a0dc249d2df7e52a6a5f7cb3f1a94be011164eaf23d365f548b99f093d3d14 +size 51681 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png index d233b2890d..17526d949c 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7aa9c94a5f9c324a3229a5db951411fba6759aee18987d61f6ffc6d74ac79a60 -size 36665 +oid sha256:fd6d4b2d03d0e86a22c48f89f05c83b0e7622f4b6fc2a946ace1ef33e66b2e9a +size 37183 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png index 084de2c14a..bf33b63f8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a952926d397cab2a689e3f4096de103bbb3075f27dbe45fff311a153ab1c9ace -size 46181 +oid sha256:d8f9a50b522d34a29ec48fcef545a0880ff0f43d464f1874c3486adb9c79e202 +size 46251 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png index 084de2c14a..bf33b63f8a 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a952926d397cab2a689e3f4096de103bbb3075f27dbe45fff311a153ab1c9ace -size 46181 +oid sha256:d8f9a50b522d34a29ec48fcef545a0880ff0f43d464f1874c3486adb9c79e202 +size 46251 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en.png index de42fdfe94..fd32767a41 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:15f9aa77f9f8fe09a10e2e22b194f2ba505d56c9097db0872b317840c0fa84c4 -size 28661 +oid sha256:218a8bafb58855056ab07b05d45c87df482483c02a5144c0117c1159135e924a +size 28637 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en.png index 6ded082e3c..a3c91c139d 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f1762442b6dcd37d5710437239055e7d40d2b741cacd1045a3eacd327fc12ee -size 28053 +oid sha256:76f1e9db9260cb23bd80bce5f45bdf323a8d24cb87757d7a32f9c6e6b632913c +size 27993 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en.png index 6ded082e3c..a3c91c139d 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f1762442b6dcd37d5710437239055e7d40d2b741cacd1045a3eacd327fc12ee -size 28053 +oid sha256:76f1e9db9260cb23bd80bce5f45bdf323a8d24cb87757d7a32f9c6e6b632913c +size 27993 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en.png index 88df849ef5..6c8ad3018b 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea5df9ecebf686ac65c265d1b74e3a0a5169d1e308eaaf4f9c205a754d8bddcc -size 40150 +oid sha256:4fda40268a68acf664e90a48391658b8dedb3d7f5d5e6b76d680ab25180d5a55 +size 40121 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en.png index 58a01b25a3..4317869283 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06170ddb862b337c00d50a531caa1f673952cc0194cb38410d3aa7cc61d95c16 -size 27653 +oid sha256:6c8f9e633578f46a6b8126ea6dcbdb5c113dd0e1107fbc4d5b2206c2f5acfb1c +size 27835 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en.png index f346d344e0..eed9b50326 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc1a0fd307ba6ea9a9f578527bae5a074e5ad67035201d8aa7d85877ee697af5 -size 26690 +oid sha256:d55afb5f76aac3d1a8ff0f1c223502fc798dc0684f9d84df79256c41ca5ea1cc +size 26706 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en.png index f346d344e0..eed9b50326 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc1a0fd307ba6ea9a9f578527bae5a074e5ad67035201d8aa7d85877ee697af5 -size 26690 +oid sha256:d55afb5f76aac3d1a8ff0f1c223502fc798dc0684f9d84df79256c41ca5ea1cc +size 26706 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en.png index f38139bcf2..0b3c962498 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.reset.password_ResetIdentityPasswordView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:763ddaf10dfed74dbef17deccfa7037d8b643e9b8654409ce96e8192ab5ee38c -size 38418 +oid sha256:9410147c7a6a496fbd356b0dbc3b14998f20ddea6a2eeabb79b9600485285a80 +size 38628 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en.png index 21b17d8656..e1573dacb9 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:562e8457321ec1afe9ca9a2111ee19815aa25401cd925c0bcc880a25db99e0c4 -size 42100 +oid sha256:01d03620cae8382ee41703d7553913fbd1e463fcd55fd661e9b99087e14bf6b1 +size 42162 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en.png index c26e5c44c1..bea6d32d38 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4498edc796206821f346a2dfceb966f59f4b7adf513ae184c84d20b323ed0d67 -size 39800 +oid sha256:54d9e8714cbbc3785ccd25d6bff9c791d57acea007d6cb8774a4a5d61646b54f +size 39857 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png index e798d07cac..dd9010b013 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f3d6bcf6b603ea2e2a619f569960438337fe9e2ae9eea2657587cd211bbf278 -size 35444 +oid sha256:9f6ce15f59eba49738b9df2117764e760f2ddc06bd52f8386f6d78af307a4104 +size 34630 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en.png index fa0b46361e..3264a61179 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9c17b8ca9966e4239e5c5fb9d9e5f0f061bd8d7fbf3bd9c76ce6473af537d05 -size 40962 +oid sha256:9a0a377b34502fb55b3ee72468533914de3c68df62531a6f40a41984c94d0047 +size 40996 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en.png index 0072d95bed..6d6a189589 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e73375d44fcd158c7cc2cd0f97b49c8a0f2d523772cab58778ed7b31a8a0d5e -size 38602 +oid sha256:433de908676d053d3728b8cfe03636d082691059dbe4c15b950483cfdc3e1ce8 +size 38634 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png index b8629728ea..0d1e17b957 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupViewChange_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cb10d8ef6b7c6fd25e772428e03755f1c731197660ed7123b79c56629f74583 -size 33086 +oid sha256:56030e621f122f288b00dc642cf5ab4a3a09100cdcb92e068d8fc0f47f9a5328 +size 32421 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en.png index f3d5c2ec82..5c0a10cffc 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cef767ba47c98c5b693cfadef2ea0a260a35d3144c2dc26a3bb52bf632700d9c -size 44141 +oid sha256:61b6259baf820caca8eb8a28052142c56ee88a952148e204c25a53f709b87fe4 +size 44542 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en.png index 5c91aae383..599ce75592 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2ef46c819c931938a4fd856bb2fc697c964d4445d6cf9f8b5e2f341f22805061 -size 42001 +oid sha256:2f246482f43b0298e8948925fda23d9c306f56b484d42eeedbca1cce2dfb6bb2 +size 42382 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png index 214e107f12..224e1705c4 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de188fac87a59e6765360282655c081d7b93e7dfa47837b0c56dd77a9892ed03 -size 34616 +oid sha256:2ab51540f79f485e98b311210fc7d8b98ccb174b9e689587559878c245877f4a +size 38492 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en.png index 7f69976784..654f566376 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b53f00607190915bfb683c0bef1bd11f0804651fe6bf57bc9312afa20768a75 -size 42924 +oid sha256:b9962bf5c4f9870d51cd3eb3346bf0e2054c5f7e21111f57c7a7bb1938e81aab +size 43211 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en.png index 20dcda7f44..564035b900 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6cd74bb51213ae932addc3dbaff2bd20d877a249c46ac5bb7656e03566189b38 -size 40748 +oid sha256:fbf5c303797332b7419e1529ddaa8d1f2f1cd6ed2086654880c7702fc3d62070 +size 40971 diff --git a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png index 82f91a65d5..3d21f69991 100644 --- a/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.securebackup.impl.setup_SecureBackupSetupView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcad0014629c828846e05247a1ca0767c45906bc15378a00cb9d4e6cd7280dc1 -size 32380 +oid sha256:47fc45150924e2c1aacc86889824f7c0d7382af94ef420ff690871d75c7c3e23 +size 36212 diff --git a/tools/localazy/config.json b/tools/localazy/config.json index b38268e5f7..03ada90c4b 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -163,7 +163,9 @@ "screen_qr_code_login_connection_note_secure_state.*", "screen_qr_code_login_unknown_error_description", "screen_qr_code_login_invalid_scan_state_.*", - "screen_qr_code_login_no_camera_permission_state_.*" + "screen_qr_code_login_no_camera_permission_state_.*", + "screen_qr_code_login_device_code_.*", + "screen_qr_code_login_verify_code_loading" ] }, {