From 476e863734fb789b47bafb7899d4bf21ad5d37ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 07:53:31 +0000 Subject: [PATCH 01/17] Update plugin sonarqube to v7.5.0.8588 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d98f00b3a0..82c2495baf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -276,7 +276,7 @@ paparazzi = "app.cash.paparazzi:2.0.0-alpha05" roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } sqldelight = { id = "app.cash.sqldelight", version.ref = "sqldelight" } firebaseAppDistribution = { id = "com.google.firebase.appdistribution", version.ref = "firebaseAppDistribution" } -sonarqube = "org.sonarqube:7.4.0.8496" +sonarqube = "org.sonarqube:7.5.0.8588" licensee = "app.cash.licensee:1.14.1" compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } gms_google_services = { id = "com.google.gms.google-services", version = "4.5.0" } From 5b09fdf13f128b6b51c28b4a5a091c2f45f77916 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 11 Sep 2026 16:57:01 +0200 Subject: [PATCH 02/17] Replace git flow with regular git commands in the release script V2 The script was relying on the external git-flow tool and on a local `git config gitflow.*` initialisation, which made its behaviour depend on the machine setup and hid what was actually done to the branches. The release branch is now created with `git checkout -b`, and the release is finished with explicit merge, tag, back-merge and branch deletion commands. The merge and tag messages are provided explicitly so that the generated history stays identical to the previous releases. Each step now aborts the script with a clear message when it fails, instead of letting the script continue. Note that tools/release/release.sh (V1) still uses git flow. Co-Authored-By: Claude Opus 5 (1M context) --- tools/release/releaseV2.sh | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tools/release/releaseV2.sh b/tools/release/releaseV2.sh index 23f3910311..85d96414e9 100755 --- a/tools/release/releaseV2.sh +++ b/tools/release/releaseV2.sh @@ -5,7 +5,7 @@ # SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. # Please see LICENSE files in the repository root for full details. -# do not exit when any command fails (issue with git flow) +# do not exit when any command fails, failures are handled explicitly by the script set +e printf "\n================================================================================\n" @@ -63,6 +63,12 @@ if [ ${envError} == 1 ]; then exit 1 fi +# Abort the script with an error message. +fail() { + printf "\nFatal: %s\n" "$1" + exit 1 +} + # Handle the result of a version check. ${checkError} must be set to 1 when a check has failed. checkVersionResult() { if [[ ${checkError} -ne 0 ]]; then @@ -97,16 +103,6 @@ if [[ ${unmergedPrs} != "" ]]; then fi -# Check if git flow is enabled -gitFlowDevelop=$(git config gitflow.branch.develop) -if [[ ${gitFlowDevelop} != "" ]] -then - printf "Git flow is initialized\n" -else - printf "Git flow is not initialized. Initializing...\n" - ./tools/gitflow/gitflow-init.sh -fi - printf "OK\n" printf "\n================================================================================\n" @@ -149,7 +145,7 @@ versionReleaseNumber=$(echo "${version}" | cut -d "." -f3) printf "\n================================================================================\n" printf "Starting the release %s\n" "${version}" -git flow release start "${version}" +git checkout -b "release/${version}" develop # Note: in case the release is already started and the script is started again, checkout the release branch again. ret=$? @@ -160,7 +156,7 @@ if [[ $ret -ne 0 ]]; then read -r -p "Continue (yes/no) default to yes? " doContinue doContinue=${doContinue:-yes} if [ "${doContinue}" == "no" ]; then - printf "OK, exiting, you can start the release again with the command 'git flow release start %s'\n" "${version}" + printf "OK, exiting, you can start the release again with the command 'git checkout -b release/%s develop'\n" "${version}" exit 1 fi git checkout "release/${version}" @@ -197,10 +193,17 @@ git commit -a -m "Adding fastlane file for version ${version}" printf "\n================================================================================\n" printf "OK, finishing the release...\n" -# GIT_MERGE_AUTOEDIT avoids opening the editor for the 2 merge commits, whose default message is -# always used, and -m provides the message of the annotated tag. git flow appends the tag name to -# it, so the tag message ends up being "Release v${version}". -GIT_MERGE_AUTOEDIT=no git flow release finish -m "Release" "${version}" +# Merge the release branch into main, tag it, then merge the tag back into develop and delete the +# release branch. The merge messages are provided explicitly to keep the history consistent with +# the previous releases. +git checkout main || fail "unable to checkout main." +git merge --no-ff --no-edit -m "Merge branch 'release/${version}'" "release/${version}" \ + || fail "unable to merge the branch release/${version} into main. Please fix the conflicts and finish the release manually." +git tag -a "v${version}" -m "Release v${version}" || fail "unable to create the tag v${version}." +git checkout develop || fail "unable to checkout develop." +git merge --no-ff --no-edit -m "Merge tag 'v${version}' into develop" "v${version}" \ + || fail "unable to merge the tag v${version} into develop. Please fix the conflicts and finish the release manually." +git branch -d "release/${version}" || fail "unable to delete the branch release/${version}." printf "\n================================================================================\n" read -r -p "Done, push the branch 'main' and the new tag (yes/no) default to yes? " doPush From 6887092ce45bc16a8e1c301c7f51f9f0cc812df3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 2 Sep 2026 17:54:08 +0200 Subject: [PATCH 03/17] Replace String by AccountProvider to be able to get baseUrl and serverName. --- .../android/appconfig/AuthenticationConfig.kt | 7 - .../io/element/android/appnav/RootFlowNode.kt | 5 +- enterprise | 2 +- .../enterprise/api/EnterpriseService.kt | 30 ++-- .../impl/DefaultEnterpriseService.kt | 6 +- .../impl/DefaultEnterpriseServiceTest.kt | 15 +- .../enterprise/test/FakeEnterpriseService.kt | 18 ++- features/login/api/build.gradle.kts | 1 + .../AccountProviderAccessControl.kt | 6 +- .../DefaultAccountProviderAccessControl.kt | 20 +-- .../impl/accountprovider/AccountProvider.kt | 17 --- .../AccountProviderDataSource.kt | 31 ++--- .../AccountProviderPreviewParam.kt | 32 ++--- .../accountprovider/AccountProviderView.kt | 43 +----- .../SaveAccountProviderToHistory.kt | 9 +- .../impl/changeserver/ChangeServerEvent.kt | 2 +- .../changeserver/ChangeServerPresenter.kt | 11 +- .../ChooseAccountProviderEvent.kt | 2 +- .../ChooseAccountProviderPresenter.kt | 20 +-- .../ChooseAccountProviderState.kt | 2 +- .../ChooseAccountProviderStatePreviewParam.kt | 28 ++-- .../ChooseAccountProviderView.kt | 10 +- .../ConfirmAccountProviderPresenter.kt | 29 ++-- .../loginpassword/LoginPasswordState.kt | 2 +- .../LoginPasswordStatePreviewParam.kt | 6 +- .../loginpassword/LoginPasswordView.kt | 2 +- .../screens/onboarding/OnBoardingEvent.kt | 4 +- .../screens/onboarding/OnBoardingPresenter.kt | 45 +++--- .../screens/onboarding/OnBoardingState.kt | 3 +- .../onboarding/OnBoardingStatePreviewParam.kt | 9 +- .../impl/screens/onboarding/OnBoardingView.kt | 2 +- .../impl/src/main/res/drawable/ic_matrix.xml | 12 -- ...DefaultAccountProviderAccessControlTest.kt | 90 ++++++------ .../AccountProviderDataSourceTest.kt | 131 +++++++----------- .../SaveAccountProviderToHistoryTest.kt | 6 +- .../changeserver/ChangeServerPresenterTest.kt | 45 +++--- .../ChooseAccountProviderPresenterTest.kt | 25 +--- .../ChooseAccountProviderStateTest.kt | 8 +- .../ChooseAccountProviderViewTest.kt | 6 +- .../ConfirmAccountProviderPresenterTest.kt | 59 +++++--- .../LoginPasswordPresenterTest.kt | 6 +- .../onboarding/OnBoardingPresenterTest.kt | 79 +++++++++-- .../screens/onboarding/OnboardingViewTest.kt | 7 +- features/login/test/build.gradle.kts | 1 + .../FakeAccountProviderAccessControl.kt | 7 +- .../api/accountprovider/AccountProvider.kt | 67 +++++++++ .../accountprovider/AccountProviderTest.kt | 89 ++++++++++++ .../accountprovider/AccountProviderFixture.kt | 28 ++++ 48 files changed, 608 insertions(+), 477 deletions(-) delete mode 100644 features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProvider.kt delete mode 100644 features/login/impl/src/main/res/drawable/ic_matrix.xml create mode 100644 libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt create mode 100644 libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProviderTest.kt create mode 100644 libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/accountprovider/AccountProviderFixture.kt diff --git a/appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt b/appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt index 7432a6904f..a04abe1417 100644 --- a/appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt +++ b/appconfig/src/main/kotlin/io/element/android/appconfig/AuthenticationConfig.kt @@ -9,15 +9,8 @@ package io.element.android.appconfig object AuthenticationConfig { - const val MATRIX_ORG_URL = "https://matrix.org" - /** * URL with some docs that explain what's sliding sync and how to add it to your home server. */ const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md" - - /** - * Force a sliding sync proxy url, if not null, the proxy url in the .well-known file will be ignored. - */ - val SLIDING_SYNC_PROXY_URL: String? = null } 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 c9deaeb3b3..5f2dc837ad 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -52,11 +52,11 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.appyx.rememberDelegateTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.waitForChildAttached -import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.deeplink.api.DeeplinkData import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.ThreadId @@ -410,7 +410,8 @@ class RootFlowNode( } private suspend fun onLoginLink(params: LoginParams) { - if (accountProviderAccessControl.isAllowedToConnectToAccountProvider(params.accountProvider.ensureProtocol())) { + val accountProvider = AccountProvider.Generic(params.accountProvider) + if (accountProviderAccessControl.isAllowedToConnectToAccountProvider(accountProvider)) { // Is there a session already? val sessions = sessionStore.getAllSessions() if (sessions.isNotEmpty()) { diff --git a/enterprise b/enterprise index f463003f68..307b0fd01f 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit f463003f6813ad33fc00f80786bc83b6a7f0d8e2 +Subproject commit 307b0fd01f36191dddf6b51ed9ceb92887b360a2 diff --git a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt index 2cb4a356be..5483d1e60e 100644 --- a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt +++ b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt @@ -11,6 +11,7 @@ package io.element.android.features.enterprise.api import androidx.compose.ui.graphics.Color import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.libraries.matrix.api.ClientUrlContentFetcher +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.SessionId import kotlinx.coroutines.flow.Flow @@ -36,18 +37,21 @@ interface EnterpriseService { suspend fun tweakMasUrl(url: String, urlContentFetcher: ClientUrlContentFetcher): String /** - * Returns the list of homeservers the user is allowed to sign in to. - * - * If the list is empty or contains the special value [ANY_ACCOUNT_PROVIDER], the user is allowed to sign in to any homeserver. + * Returns the list of account provider the user is allowed to sign in to. */ - fun homeserverAllowList(): List + fun accountProviderAllowList(): List /** - * Whether the user is allowed to sign in to a given homeserver, according to [homeserverAllowList]. - * - * @param homeserverUrl the server the user is trying to use. + * Whether the user is allowed to sign in to any account provider. */ - suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean + fun canConnectToAnyAccountProvider(): Boolean + + /** + * Whether the user is allowed to sign in to a given homeserver, according to [accountProviderAllowList]. + * + * @param accountProvider the account provider the user is trying to use. + */ + suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider): Boolean /** * Whether the given homeserver enforces the use of Element Pro or a derived app. @@ -97,14 +101,4 @@ interface EnterpriseService { * @param sessionId the session whose channel is requested. */ fun getNoisyNotificationChannelId(sessionId: SessionId): String? - - companion object { - const val ANY_ACCOUNT_PROVIDER = "*" - } -} - -fun EnterpriseService.canConnectToAnyHomeserver(): Boolean { - return homeserverAllowList().let { - it.isEmpty() || it.contains(EnterpriseService.ANY_ACCOUNT_PROVIDER) - } } diff --git a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt index 6ccf70cd02..02fa9b282c 100644 --- a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt +++ b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt @@ -19,6 +19,7 @@ import io.element.android.libraries.core.extensions.mapCatchingExceptions import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.matrix.api.ClientUrlContentFetcher import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.SessionId import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -33,8 +34,9 @@ class DefaultEnterpriseService( ) : EnterpriseService { override suspend fun isEnterpriseUser(sessionId: SessionId) = false override suspend fun tweakMasUrl(url: String, urlContentFetcher: ClientUrlContentFetcher) = url - override fun homeserverAllowList(): List = emptyList() - override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true + override fun accountProviderAllowList(): List = emptyList() + override fun canConnectToAnyAccountProvider(): Boolean = true + override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider) = true override suspend fun isElementProEnforced(serverName: String): Boolean { val temporaryMatrixClient = temporaryMatrixClientFactory.create(serverName).getOrElse { return false } return temporaryMatrixClient.use { client -> diff --git a/features/enterprise/impl-foss/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt b/features/enterprise/impl-foss/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt index 026c9caf9e..f43284e0bd 100644 --- a/features/enterprise/impl-foss/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt +++ b/features/enterprise/impl-foss/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.test.A_HOMESERVER_URL import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClient import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory +import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderGeneric import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import kotlinx.coroutines.test.runTest @@ -26,15 +27,21 @@ import org.junit.Test class DefaultEnterpriseServiceTest { @Test - fun homeserverWhitelist() { + fun accountProviderAllowList() { val defaultEnterpriseService = createDefaultEnterpriseService() - assertThat(defaultEnterpriseService.homeserverAllowList()).isEmpty() + assertThat(defaultEnterpriseService.accountProviderAllowList()).isEmpty() } @Test - fun `isAllowedToConnectToHomeserver is true for all homeserver urls`() = runTest { + fun `canConnectToAnyAccountProvider is always true`() { val defaultEnterpriseService = createDefaultEnterpriseService() - assertThat(defaultEnterpriseService.isAllowedToConnectToHomeserver(A_HOMESERVER_URL)).isTrue() + assertThat(defaultEnterpriseService.canConnectToAnyAccountProvider()).isTrue() + } + + @Test + fun `isAllowedToConnectToAccountProvider is true for all account providers`() = runTest { + val defaultEnterpriseService = createDefaultEnterpriseService() + assertThat(defaultEnterpriseService.isAllowedToConnectToAccountProvider(anAccountProviderGeneric())).isTrue() } @Test diff --git a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt index a8efcb5873..3ca30d410d 100644 --- a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt +++ b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt @@ -13,6 +13,7 @@ import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.features.enterprise.api.BugReportUrl import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.matrix.api.ClientUrlContentFetcher +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask @@ -22,8 +23,9 @@ import kotlinx.coroutines.flow.asStateFlow class FakeEnterpriseService( private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() }, - private val defaultHomeserverListResult: () -> List = { emptyList() }, - private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() }, + private val accountProviderAllowListResult: () -> List = { emptyList() }, + private val canConnectToAnyAccountProviderResult: () -> Boolean = { true }, + private val isAllowedToConnectToAccountProviderResult: (AccountProvider) -> Boolean = { lambdaError() }, initialSemanticColors: SemanticColorsLightDark = SemanticColorsLightDark.default, initialBrandColor: Color? = null, private val overrideBrandColorResult: (SessionId?, String?) -> Unit = { _, _ -> lambdaError() }, @@ -44,12 +46,16 @@ class FakeEnterpriseService( tweakMasUrlResult(url, urlContentFetcher) } - override fun homeserverAllowList(): List { - return defaultHomeserverListResult() + override fun accountProviderAllowList(): List { + return accountProviderAllowListResult() } - override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean = simulateLongTask { - isAllowedToConnectToHomeserverResult(homeserverUrl) + override fun canConnectToAnyAccountProvider(): Boolean { + return canConnectToAnyAccountProviderResult() + } + + override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider): Boolean = simulateLongTask { + isAllowedToConnectToAccountProviderResult(accountProvider) } override suspend fun isElementProEnforced(serverName: String): Boolean = simulateLongTask { diff --git a/features/login/api/build.gradle.kts b/features/login/api/build.gradle.kts index 2a4e3ecb7c..a0683c814e 100644 --- a/features/login/api/build.gradle.kts +++ b/features/login/api/build.gradle.kts @@ -16,4 +16,5 @@ android { dependencies { implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) } diff --git a/features/login/api/src/main/kotlin/io/element/android/features/login/api/accesscontrol/AccountProviderAccessControl.kt b/features/login/api/src/main/kotlin/io/element/android/features/login/api/accesscontrol/AccountProviderAccessControl.kt index 0c35c1655f..55cfa4b1ba 100644 --- a/features/login/api/src/main/kotlin/io/element/android/features/login/api/accesscontrol/AccountProviderAccessControl.kt +++ b/features/login/api/src/main/kotlin/io/element/android/features/login/api/accesscontrol/AccountProviderAccessControl.kt @@ -8,6 +8,8 @@ package io.element.android.features.login.api.accesscontrol +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider + /** * Enforces the restriction an enterprise deployment can put on which account providers the user may sign in to. */ @@ -15,7 +17,7 @@ interface AccountProviderAccessControl { /** * Whether sign-in to this provider is permitted; `true` on a build with no such restriction. * - * @param accountProviderUrl the server the user is trying to use. + * @param accountProvider the account provider the user is trying to use. */ - suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String): Boolean + suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider): Boolean } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt index a3a475df2f..58fbeed4bc 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControl.kt @@ -14,16 +14,16 @@ import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.api.IsEnterpriseBuild import io.element.android.features.login.api.accesscontrol.AccountProviderAccessControl import io.element.android.features.login.impl.changeserver.AccountProviderAccessException +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider @ContributesBinding(AppScope::class) class DefaultAccountProviderAccessControl( private val isEnterpriseBuild: IsEnterpriseBuild, private val enterpriseService: EnterpriseService, ) : AccountProviderAccessControl { - override suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String) = try { + override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider) = try { assertIsAllowedToConnectToAccountProvider( - title = accountProviderUrl, - accountProviderUrl = accountProviderUrl, + accountProvider = accountProvider, ) true } catch (_: AccountProviderAccessException) { @@ -32,22 +32,22 @@ class DefaultAccountProviderAccessControl( @Throws(AccountProviderAccessException::class) suspend fun assertIsAllowedToConnectToAccountProvider( - title: String, - accountProviderUrl: String, + accountProvider: AccountProvider, ) { if (isEnterpriseBuild().not()) { // Ensure that Element Pro is not required for this account provider - if (enterpriseService.isElementProEnforced(accountProviderUrl)) { + if (enterpriseService.isElementProEnforced(accountProvider.serverNameOrBaseUrl())) { throw AccountProviderAccessException.NeedElementProException( - unauthorisedAccountProviderTitle = title, + unauthorisedAccountProviderTitle = accountProvider.friendlyServerName(), applicationId = ELEMENT_PRO_APPLICATION_ID, ) } } - if (enterpriseService.isAllowedToConnectToHomeserver(accountProviderUrl).not()) { + if (enterpriseService.isAllowedToConnectToAccountProvider(accountProvider).not()) { throw AccountProviderAccessException.UnauthorizedAccountProviderException( - unauthorisedAccountProviderTitle = title, - authorisedAccountProviderTitles = enterpriseService.homeserverAllowList(), + unauthorisedAccountProviderTitle = accountProvider.friendlyServerName(), + authorisedAccountProviderTitles = enterpriseService.accountProviderAllowList() + .map { it.friendlyServerName() }, ) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProvider.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProvider.kt deleted file mode 100644 index 7ca467da7d..0000000000 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProvider.kt +++ /dev/null @@ -1,17 +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.features.login.impl.accountprovider - -data class AccountProvider( - val url: String, - val title: String = url.removePrefix("https://").removePrefix("http://"), - val subtitle: String? = null, - val isPublic: Boolean = false, - val isMatrixOrg: Boolean = false, -) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSource.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSource.kt index 6d85f2c5ff..3e8e7657a4 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSource.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSource.kt @@ -11,10 +11,10 @@ package io.element.android.features.login.impl.accountprovider import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.Inject import dev.zacsweers.metro.SingleIn -import io.element.android.appconfig.AuthenticationConfig import io.element.android.features.enterprise.api.EnterpriseService -import io.element.android.features.enterprise.api.canConnectToAnyHomeserver import io.element.android.libraries.di.annotations.AppCoroutineScope +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.matrixOrgAccountProvider import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -33,11 +33,9 @@ class AccountProviderDataSource( ) { // The provider used when the user has not selected one: an enterprise/MDM-configured provider, // else matrix.org. The most recently used provider (from history) can override it, see init. - private val configuredAccountProvider = createAccountProvider( - url = enterpriseService.homeserverAllowList() - .firstOrNull { it != EnterpriseService.ANY_ACCOUNT_PROVIDER } - ?: AuthenticationConfig.MATRIX_ORG_URL - ) + private val configuredAccountProvider = enterpriseService.accountProviderAllowList() + .firstOrNull() + ?: matrixOrgAccountProvider private val accountProvider: MutableStateFlow = MutableStateFlow(configuredAccountProvider) @@ -46,7 +44,7 @@ class AccountProviderDataSource( // The account provider the user last explicitly selected (via [setAccountProvider] / [setUrl]). // Unlike [flow], this is not recomputed by [reset], so it survives to be persisted to history on a // successful sign-in even when the login flow is torn down in between (e.g. across an OAuth round-trip). - var lastSelectedAccountProviderUrl: String? = null + var lastSelectedAccountProvider: AccountProvider? = null private set init { @@ -66,28 +64,19 @@ class AccountProviderDataSource( * connect to any provider, otherwise the enterprise/MDM-configured provider. */ private suspend fun defaultAccountProvider(): AccountProvider { - if (!enterpriseService.canConnectToAnyHomeserver()) { + if (!enterpriseService.canConnectToAnyAccountProvider()) { return configuredAccountProvider } val lastUsedProvider = appPreferencesStore.getHomeserverHistoryFlow().first().firstOrNull() - return lastUsedProvider?.let { createAccountProvider(it) } ?: configuredAccountProvider + return lastUsedProvider?.let { AccountProvider.Generic(it) } ?: configuredAccountProvider } suspend fun setUrl(url: String) { - setAccountProvider(createAccountProvider(url)) + setAccountProvider(AccountProvider.Generic(url)) } suspend fun setAccountProvider(data: AccountProvider) { - lastSelectedAccountProviderUrl = data.url + lastSelectedAccountProvider = data accountProvider.emit(data) } - - private fun createAccountProvider(url: String): AccountProvider { - return AccountProvider( - url = url, - subtitle = null, - isPublic = url == AuthenticationConfig.MATRIX_ORG_URL, - isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL, - ) - } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderPreviewParam.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderPreviewParam.kt index c14827d1a6..aca64b9db7 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderPreviewParam.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderPreviewParam.kt @@ -9,27 +9,27 @@ package io.element.android.features.login.impl.accountprovider import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.appconfig.AuthenticationConfig +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider open class AccountProviderPreviewParam : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - anAccountProvider(), - anAccountProvider().copy(subtitle = null), - anAccountProvider().copy(subtitle = null, title = "invalid"), - anAccountProvider().copy(subtitle = null, title = "Other", isPublic = false, isMatrixOrg = false), - // Add other state here + anAccountProviderManaged(), ) } -fun anAccountProvider( - url: String = AuthenticationConfig.MATRIX_ORG_URL, - subtitle: String? = "Matrix.org is an open network for secure, decentralized communication.", - isPublic: Boolean = true, - isMatrixOrg: Boolean = true, -) = AccountProvider( - url = url, - subtitle = subtitle, - isPublic = isPublic, - isMatrixOrg = isMatrixOrg, +fun anAccountProviderManaged( + serverName: String = "matrix.org", + baseUrl: String = "https://matrix-client.matrix.org", + canUseServerName: Boolean = true, +) = AccountProvider.Managed( + serverName = serverName, + baseUrl = baseUrl, + canUseServerName = canUseServerName, +) + +fun anAccountProviderGeneric( + serverName: String = "matrix.org", +) = AccountProvider.Generic( + serverName = serverName, ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderView.kt index 09b423f713..8365e9286c 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderView.kt @@ -14,17 +14,14 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.semantics.Role import androidx.compose.ui.tooling.preview.PreviewParameter 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.login.impl.R import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize import io.element.android.libraries.designsystem.preview.ElementPreview @@ -32,6 +29,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider /** * https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?type=design&node-id=604-60817 @@ -60,37 +58,19 @@ fun AccountProviderView( .heightIn(min = 44.dp), verticalAlignment = Alignment.CenterVertically ) { - if (item.isMatrixOrg) { - RoundedIconAtom( - size = RoundedIconAtomSize.Medium, - resourceId = R.drawable.ic_matrix, - tint = Color.Unspecified, - ) - } else { - RoundedIconAtom( - size = RoundedIconAtomSize.Medium, - imageVector = CompoundIcons.Host(), - tint = ElementTheme.colors.iconPrimary, - ) - } + RoundedIconAtom( + size = RoundedIconAtomSize.Medium, + imageVector = CompoundIcons.Host(), + tint = ElementTheme.colors.iconPrimary, + ) Text( modifier = Modifier .padding(start = 16.dp) .weight(1f), - text = item.title, + text = item.friendlyServerName(), style = ElementTheme.typography.fontBodyLgMedium, color = ElementTheme.colors.textPrimary, ) - if (item.isPublic) { - Icon( - modifier = Modifier - .padding(start = 10.dp) - .size(16.dp), - imageVector = CompoundIcons.Public(), - contentDescription = null, - tint = ElementTheme.colors.iconSecondary, - ) - } if (selected) { Icon( modifier = Modifier @@ -101,15 +81,6 @@ fun AccountProviderView( ) } } - if (item.subtitle != null) { - Text( - modifier = Modifier - .padding(start = 46.dp, bottom = 12.dp, end = 26.dp), - text = item.subtitle, - style = ElementTheme.typography.fontBodyMdRegular, - color = ElementTheme.colors.textSecondary, - ) - } } } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistory.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistory.kt index b3b99115cc..14c1b0346b 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistory.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistory.kt @@ -25,8 +25,11 @@ class SaveAccountProviderToHistory( suspend operator fun invoke() { // Persist the provider the user actually selected, not the currently-exposed default: the latter can be // reset back to the history default while the login flow is torn down across an OAuth round-trip. - val url = accountProviderDataSource.lastSelectedAccountProviderUrl - ?: accountProviderDataSource.flow.value.url - appPreferencesStore.addHomeserverToHistory(url) + val accountProvider = accountProviderDataSource.lastSelectedAccountProvider + ?: accountProviderDataSource.flow.value + // Persist the sanitized name the user knows the provider by rather than its base url, which can be an + // internal client API url (e.g. matrix.org resolves to matrix-client.matrix.org) the user would not + // recognise, and so that the same provider is not stored twice with and without its scheme. + appPreferencesStore.addHomeserverToHistory(accountProvider.serverNameOrBaseUrl()) } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerEvent.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerEvent.kt index f3fd02713f..d1b68190c6 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerEvent.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerEvent.kt @@ -8,7 +8,7 @@ package io.element.android.features.login.impl.changeserver -import io.element.android.features.login.impl.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider sealed interface ChangeServerEvent { data class ChangeServer(val accountProvider: AccountProvider) : ChangeServerEvent diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenter.kt index 9106d6e1c4..2e3a4c73b8 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/changeserver/ChangeServerPresenter.kt @@ -14,13 +14,13 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import dev.zacsweers.metro.Inject import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.error.ChangeServerError import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissionGate import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails @@ -38,7 +38,7 @@ class ChangeServerPresenter( } val gateState = localNetworkPermissionGate.present( - urlOf = { provider -> provider.url }, + urlOf = { provider -> provider.serverNameOrBaseUrl() }, onProceed = { provider -> changeServer(provider, changeServerAction) }, ) @@ -63,11 +63,8 @@ class ChangeServerPresenter( changeServerAction: MutableState>, ) { suspend { - defaultAccountProviderAccessControl.assertIsAllowedToConnectToAccountProvider( - title = data.title, - accountProviderUrl = data.url, - ) - val details = authenticationService.setHomeserver(data.url).getOrThrow() + defaultAccountProviderAccessControl.assertIsAllowedToConnectToAccountProvider(data) + val details = authenticationService.setHomeserver(data.serverNameOrBaseUrl()).getOrThrow() if (!details.isSupported) { throw ChangeServerError.UnsupportedServer } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderEvent.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderEvent.kt index bb50f123cb..d3fddeeb1f 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderEvent.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderEvent.kt @@ -8,7 +8,7 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider -import io.element.android.features.login.impl.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider sealed interface ChooseAccountProviderEvent { data class SelectAccountProvider(val accountProvider: AccountProvider) : ChooseAccountProviderEvent diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt index e2863a295a..8984216ac8 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenter.kt @@ -14,14 +14,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import dev.zacsweers.metro.Inject -import io.element.android.appconfig.AuthenticationConfig import io.element.android.features.enterprise.api.EnterpriseService -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.login.LoginModeEvent import io.element.android.features.login.impl.login.LoginModeState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.core.uri.ensureProtocol +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import kotlinx.collections.immutable.toImmutableList @Inject @@ -41,7 +39,7 @@ class ChooseAccountProviderPresenter( loginModeState.eventSink( LoginModeEvent.Submit( isAccountCreation = false, - homeserverUrl = provider.url, + homeserverUrl = provider.serverNameOrBaseUrl(), resolvedHomeserverUrl = null, loginHint = null, ) @@ -59,18 +57,8 @@ class ChooseAccountProviderPresenter( } val staticAccountProviderList = remember { - // The list cannot contains ANY_ACCOUNT_PROVIDER ("*") and cannot be empty at this point - enterpriseService.homeserverAllowList() - .map { it.ensureProtocol() } - .map { url -> - AccountProvider( - url = url, - subtitle = null, - isPublic = url == AuthenticationConfig.MATRIX_ORG_URL, - isMatrixOrg = url == AuthenticationConfig.MATRIX_ORG_URL, - ) - } - .toImmutableList() + // The list cannot be empty at this point + enterpriseService.accountProviderAllowList().toImmutableList() } return ChooseAccountProviderState( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt index 398e32d687..b1e84fe8ec 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderState.kt @@ -8,9 +8,9 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.login.LoginModeState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import kotlinx.collections.immutable.ImmutableList data class ChooseAccountProviderState( diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStatePreviewParam.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStatePreviewParam.kt index ceb1cfd6ea..9dc99b466c 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStatePreviewParam.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStatePreviewParam.kt @@ -9,31 +9,22 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.login.impl.accountprovider.AccountProvider -import io.element.android.features.login.impl.accountprovider.anAccountProvider +import io.element.android.features.login.impl.accountprovider.anAccountProviderManaged import io.element.android.features.login.impl.login.LoginModeState import io.element.android.features.login.impl.login.aLoginModeState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import kotlinx.collections.immutable.toImmutableList open class ChooseAccountProviderStatePreviewParam : PreviewParameterProvider { - private val server1 = anAccountProvider( - url = "https://server1.io", - subtitle = null, - isPublic = false, - isMatrixOrg = false, + private val server1 = anAccountProviderManaged( + baseUrl = "https://server1.io", ) - private val server2 = anAccountProvider( - url = "https://server2.io", - subtitle = null, - isPublic = false, - isMatrixOrg = false, + private val server2 = anAccountProviderManaged( + baseUrl = "https://server2.io", ) - private val server3 = anAccountProvider( - url = "https://server3.io", - subtitle = null, - isPublic = false, - isMatrixOrg = false, + private val server3 = anAccountProviderManaged( + baseUrl = "https://server3.io", ) override val values: Sequence get() = sequenceOf( @@ -61,13 +52,12 @@ open class ChooseAccountProviderStatePreviewParam : PreviewParameterProvider = listOf( - anAccountProvider() + anAccountProviderManaged() ), selectedAccountProvider: AccountProvider? = null, loginModeState: LoginModeState = aLoginModeState(), 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 552165a7b2..c2d0bd05b2 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 @@ -96,16 +96,8 @@ fun ChooseAccountProviderView( ) state.accountProviders.forEach { item -> - val alteredItem = if (item.isMatrixOrg) { - // Set the subtitle from the resource - item.copy( - subtitle = stringResource(id = R.string.screen_change_account_provider_matrix_org_subtitle), - ) - } else { - item - } AccountProviderView( - item = alteredItem, + item = item, selected = item == state.selectedAccountProvider, onClick = { state.eventSink(ChooseAccountProviderEvent.SelectAccountProvider(item)) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt index 627620ff31..201571a8ff 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/confirmaccountprovider/ConfirmAccountProviderPresenter.kt @@ -20,9 +20,7 @@ import androidx.compose.runtime.setValue import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject -import io.element.android.appconfig.AuthenticationConfig import io.element.android.features.enterprise.api.EnterpriseService -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.changeserver.ChangeServerEvent import io.element.android.features.login.impl.changeserver.ChangeServerState @@ -30,8 +28,11 @@ import io.element.android.features.login.impl.login.LoginModeEvent import io.element.android.features.login.impl.login.LoginModeState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.uri.ensureProtocol +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.matrixOrgAccountProvider import io.element.android.libraries.matrix.api.core.MatrixPatterns import io.element.android.libraries.preferences.api.store.AppPreferencesStore +import kotlinx.coroutines.flow.map @AssistedInject class ConfirmAccountProviderPresenter( @@ -56,23 +57,25 @@ class ConfirmAccountProviderPresenter( val accountProvider by accountProviderDataSource.flow.collectAsState() val loginModeState = loginModePresenter.present() val changeServerState = changeServerPresenter.present() - val homeserverHistory by appPreferencesStore.getHomeserverHistoryFlow().collectAsState(emptyList()) + val homeserverHistory by remember { + appPreferencesStore.getHomeserverHistoryFlow().map { history -> + history.map { AccountProvider.Generic(it) } + } + }.collectAsState(emptyList()) // The account providers offered for autocomplete: previously-used ones first, then the // enterprise/MDM-configured allow-list, then matrix.org (always available, even before any sign-in). - // The "*" wildcard is a routing marker, not a real provider, so it is filtered out. Everything is - // rendered without the https:// scheme (added back at connection time). + // Everything is rendered without the https:// scheme (added back at connection time). val autocompleteCandidates = remember(homeserverHistory) { - (homeserverHistory + enterpriseService.homeserverAllowList() + AuthenticationConfig.MATRIX_ORG_URL) - .filter { it != EnterpriseService.ANY_ACCOUNT_PROVIDER } - .map { it.withoutScheme() } + (homeserverHistory + enterpriseService.accountProviderAllowList() + matrixOrgAccountProvider) + .map { it.friendlyServerName() } .distinct() } // Editable input, seeded from the current (history-defaulted) account provider until the user edits it. // Displayed without the scheme, so the field shows e.g. "matrix.org" rather than "https://matrix.org". var userInput by rememberSaveable { mutableStateOf(null) } - val accountProviderInput = userInput ?: accountProvider.url.withoutScheme() + val accountProviderInput = userInput ?: accountProvider.friendlyServerName() // Offer the first candidate that the current input is a (case-insensitive) prefix of. val accountProviderSuggestion = remember(accountProviderInput, autocompleteCandidates) { @@ -134,7 +137,7 @@ class ConfirmAccountProviderPresenter( val accountProviderUrl = host.ensureProtocol() submittedAccountProvider = accountProviderUrl changeServerState.eventSink( - ChangeServerEvent.ChangeServer(AccountProvider(url = accountProviderUrl)) + ChangeServerEvent.ChangeServer(AccountProvider.Generic(host)) ) } ConfirmAccountProviderEvent.ClearError -> { @@ -154,9 +157,3 @@ class ConfirmAccountProviderPresenter( ) } } - -/** - * The host part of an account provider URL, i.e. the value with any `https://` / `http://` scheme removed. - * Returns the input unchanged when it has no scheme (e.g. `matrix.org`). - */ -private fun String.withoutScheme(): String = substringAfter("://") diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordState.kt index db04e7b7ba..13d189af6f 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordState.kt @@ -9,8 +9,8 @@ package io.element.android.features.login.impl.screens.loginpassword import android.os.Parcelable -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.SessionId import kotlinx.parcelize.Parcelize diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordStatePreviewParam.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordStatePreviewParam.kt index ba48e57b5d..bae4ed4df3 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordStatePreviewParam.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordStatePreviewParam.kt @@ -9,9 +9,9 @@ package io.element.android.features.login.impl.screens.loginpassword import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.login.impl.accountprovider.AccountProvider -import io.element.android.features.login.impl.accountprovider.anAccountProvider +import io.element.android.features.login.impl.accountprovider.anAccountProviderManaged import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.api.core.SessionId open class LoginPasswordStatePreviewParam : PreviewParameterProvider { @@ -26,7 +26,7 @@ open class LoginPasswordStatePreviewParam : PreviewParameterProvider = AsyncData.Uninitialized, eventSink: (LoginPasswordEvent) -> Unit = {}, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt index 9a2dc3097b..c2a983a692 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordView.kt @@ -131,7 +131,7 @@ fun LoginPasswordView( iconStyle = BigIcon.Style.Default(CompoundIcons.UserProfileSolid()), title = stringResource( id = R.string.screen_account_provider_signin_title, - state.accountProvider.title + state.accountProvider.friendlyServerName() ), subTitle = stringResource(id = R.string.screen_login_subtitle) ) diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingEvent.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingEvent.kt index 4b3993e2d1..6d5979946d 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingEvent.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingEvent.kt @@ -8,9 +8,11 @@ package io.element.android.features.login.impl.screens.onboarding +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider + sealed interface OnBoardingEvent { data class OnSignIn( - val defaultAccountProvider: String + val defaultAccountProvider: AccountProvider ) : OnBoardingEvent data object OnVersionClick : OnBoardingEvent diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt index 7e48ae22e8..c108aa1de0 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt @@ -22,7 +22,6 @@ import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedInject import io.element.android.appconfig.OnBoardingConfig import io.element.android.features.enterprise.api.EnterpriseService -import io.element.android.features.enterprise.api.canConnectToAnyHomeserver import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.login.LoginModeEvent @@ -31,6 +30,7 @@ import io.element.android.features.rageshake.api.RageshakeFeatureAvailability import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.ui.utils.MultipleTapToUnlock import kotlinx.coroutines.launch @@ -59,27 +59,34 @@ class OnBoardingPresenter( @Composable override fun present(): OnBoardingState { val localCoroutineScope = rememberCoroutineScope() - val forcedAccountProvider = remember { - // If homeserverAllowList() returns a singleton list, this is the default account provider. - // In this case, the user can sign in using this homeserver, or use QrCode login - enterpriseService.homeserverAllowList().singleOrNull() + val canConnectToAnyAccountProvider = remember { + enterpriseService.canConnectToAnyAccountProvider() } - val canConnectToAnyHomeserver = remember { - enterpriseService.canConnectToAnyHomeserver() + val forcedAccountProvider = remember { + // If accountProviderAllowList() returns a singleton list, and the user is not free to use another + // account provider, this is the default account provider. + // In this case, the user can sign in using this homeserver, or use QrCode login + if (canConnectToAnyAccountProvider) { + null + } else { + enterpriseService.accountProviderAllowList().singleOrNull() + } } val mustChooseAccountProvider = remember { - !canConnectToAnyHomeserver && enterpriseService.homeserverAllowList().size > 1 + !canConnectToAnyAccountProvider && enterpriseService.accountProviderAllowList().size > 1 } - val linkAccountProvider by produceState(initialValue = null) { + val linkAccountProvider by produceState(initialValue = null) { // Account provider from the link, if allowed by the enterprise service - value = params.accountProvider?.takeIf { - try { - defaultAccountProviderAccessControl.assertIsAllowedToConnectToAccountProvider(it, it) - true - } catch (_: Exception) { - false + value = params.accountProvider + ?.let { AccountProvider.Generic(it) } + ?.takeIf { + try { + defaultAccountProviderAccessControl.assertIsAllowedToConnectToAccountProvider(it) + true + } catch (_: Exception) { + false + } } - } } val defaultAccountProvider = remember(linkAccountProvider) { // If there is a forced account provider, this is the default account provider @@ -105,11 +112,11 @@ class OnBoardingPresenter( when (event) { is OnBoardingEvent.OnSignIn -> localCoroutineScope.launch { // Ensure that the current account provider is set - accountProviderDataSource.setUrl(event.defaultAccountProvider) + accountProviderDataSource.setAccountProvider(event.defaultAccountProvider) loginModeState.eventSink( LoginModeEvent.Submit( isAccountCreation = false, - homeserverUrl = event.defaultAccountProvider, + homeserverUrl = event.defaultAccountProvider.serverNameOrBaseUrl(), resolvedHomeserverUrl = null, loginHint = params.loginHint?.takeIf { forcedAccountProvider == null }, ) @@ -134,7 +141,7 @@ class OnBoardingPresenter( defaultAccountProvider = defaultAccountProvider, mustChooseAccountProvider = mustChooseAccountProvider, canLoginWithQrCode = canLoginWithQrCode, - canCreateAccount = defaultAccountProvider == null && canConnectToAnyHomeserver && OnBoardingConfig.CAN_CREATE_ACCOUNT, + canCreateAccount = defaultAccountProvider == null && canConnectToAnyAccountProvider && OnBoardingConfig.CAN_CREATE_ACCOUNT, canReportBug = canReportBug && showReportBug, loginModeState = loginModeState, version = buildMeta.versionName, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingState.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingState.kt index 97ebed67f6..87d4605ceb 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingState.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingState.kt @@ -11,13 +11,14 @@ package io.element.android.features.login.impl.screens.onboarding import androidx.annotation.DrawableRes import io.element.android.features.login.impl.login.LoginModeState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider data class OnBoardingState( val isAddingAccount: Boolean, val showBackButton: Boolean, val showDeveloperSettings: Boolean, val productionApplicationName: String, - val defaultAccountProvider: String?, + val defaultAccountProvider: AccountProvider?, val mustChooseAccountProvider: Boolean, val canLoginWithQrCode: Boolean, val canCreateAccount: Boolean, diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingStatePreviewParam.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingStatePreviewParam.kt index c7d89b21d5..09a2c8a245 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingStatePreviewParam.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingStatePreviewParam.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.login.impl.login.LoginModeState import io.element.android.features.login.impl.login.aLoginModeState import io.element.android.libraries.designsystem.R +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider open class OnBoardingStatePreviewParam : PreviewParameterProvider { override val values: Sequence @@ -22,7 +23,11 @@ open class OnBoardingStatePreviewParam : PreviewParameterProvider - - - diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt index fbfae984fc..86bbd0eadb 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accesscontrol/DefaultAccountProviderAccessControlTest.kt @@ -11,19 +11,30 @@ package io.element.android.features.login.impl.accesscontrol import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.login.impl.changeserver.AccountProviderAccessException +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2 import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_URL +import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderManaged import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows import org.junit.Test class DefaultAccountProviderAccessControlTest { + /** + * The account provider the assertions are run against: its server name is the title reported by the exceptions, + * its base url is what the enterprise service is queried with. + */ + private fun anAccountProviderUnderTest() = anAccountProviderManaged( + serverName = AN_ACCOUNT_PROVIDER, + baseUrl = AN_ACCOUNT_PROVIDER_URL, + ) + @Test fun `foss build should not allow using account provider that enforce enterprise build`() { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, enterpriseService = FakeEnterpriseService(isElementProEnforcedResult = { true }), ) accessControl.expectNeedElementProException() @@ -34,7 +45,7 @@ class DefaultAccountProviderAccessControlTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, // false here. - isAllowedToConnectToHomeserver = false, + isAllowedToConnectToAccountProvider = false, enterpriseService = FakeEnterpriseService(isElementProEnforcedResult = { true }), ) accessControl.expectNeedElementProException() @@ -44,9 +55,9 @@ class DefaultAccountProviderAccessControlTest { fun `foss build should allow using account provider that does not enforce enterprise build`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false } ), ) @@ -57,7 +68,7 @@ class DefaultAccountProviderAccessControlTest { fun `foss build should allow using account provider twith missing key in wellknown`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, ) accessControl.expectAllowed() } @@ -66,7 +77,7 @@ class DefaultAccountProviderAccessControlTest { fun `foss build should allow using account provider with missing wellknown`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, ) accessControl.expectAllowed() } @@ -75,12 +86,12 @@ class DefaultAccountProviderAccessControlTest { fun `foss build should not allow using account provider that do not enforce enterprise build but is not allowed`() { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = false, - isAllowedToConnectToHomeserver = false, - allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2), + isAllowedToConnectToAccountProvider = false, + allowedAccountProviders = listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)), enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { false }, + isAllowedToConnectToAccountProviderResult = { false }, isElementProEnforcedResult = { false }, - defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)) }, ), ) accessControl.expectUnauthorizedAccountProviderException() @@ -90,9 +101,9 @@ class DefaultAccountProviderAccessControlTest { fun `enterprise build should allow using account provider that enforce enterprise build`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = true, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { true }, ), ) @@ -103,9 +114,9 @@ class DefaultAccountProviderAccessControlTest { fun `enterprise build should allow using account provider that do not enforce enterprise build`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = true, - isAllowedToConnectToHomeserver = true, + isAllowedToConnectToAccountProvider = true, enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), ) @@ -116,12 +127,12 @@ class DefaultAccountProviderAccessControlTest { fun `enterprise build should not allow using account provider that enforce enterprise build but is not allowed`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = true, - isAllowedToConnectToHomeserver = false, - allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2), + isAllowedToConnectToAccountProvider = false, + allowedAccountProviders = listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)), enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { false }, + isAllowedToConnectToAccountProviderResult = { false }, isElementProEnforcedResult = { true }, - defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)) }, ), ) accessControl.expectUnauthorizedAccountProviderException() @@ -131,12 +142,12 @@ class DefaultAccountProviderAccessControlTest { fun `enterprise build should not allow using account provider that do not enforce enterprise build but is not allowed`() = runTest { val accessControl = createDefaultAccountProviderAccessControl( isEnterpriseBuild = true, - isAllowedToConnectToHomeserver = false, - allowedAccountProviders = listOf(AN_ACCOUNT_PROVIDER_2), + isAllowedToConnectToAccountProvider = false, + allowedAccountProviders = listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)), enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { false }, + isAllowedToConnectToAccountProviderResult = { false }, isElementProEnforcedResult = { false }, - defaultHomeserverListResult = { listOf(AN_ACCOUNT_PROVIDER_2) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = AN_ACCOUNT_PROVIDER_2)) }, ), ) accessControl.expectUnauthorizedAccountProviderException() @@ -144,11 +155,11 @@ class DefaultAccountProviderAccessControlTest { private fun createDefaultAccountProviderAccessControl( isEnterpriseBuild: Boolean = false, - isAllowedToConnectToHomeserver: Boolean = false, - allowedAccountProviders: List = emptyList(), + isAllowedToConnectToAccountProvider: Boolean = false, + allowedAccountProviders: List = emptyList(), enterpriseService: FakeEnterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { isAllowedToConnectToHomeserver }, - defaultHomeserverListResult = { allowedAccountProviders }, + isAllowedToConnectToAccountProviderResult = { isAllowedToConnectToAccountProvider }, + accountProviderAllowListResult = { allowedAccountProviders }, isElementProEnforcedResult = { false }, ) ) = DefaultAccountProviderAccessControl( @@ -159,19 +170,14 @@ class DefaultAccountProviderAccessControlTest { private fun DefaultAccountProviderAccessControl.expectNeedElementProException() { val exception = assertThrows(AccountProviderAccessException.NeedElementProException::class.java) { runTest { - assertIsAllowedToConnectToAccountProvider( - title = AN_ACCOUNT_PROVIDER, - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + assertIsAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) } } assertThat(exception.unauthorisedAccountProviderTitle).isEqualTo(AN_ACCOUNT_PROVIDER) assertThat(exception.applicationId).isEqualTo("io.element.enterprise") runTest { assertThat( - isAllowedToConnectToAccountProvider( - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + isAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) ).isFalse() } } @@ -179,34 +185,24 @@ class DefaultAccountProviderAccessControlTest { private fun DefaultAccountProviderAccessControl.expectUnauthorizedAccountProviderException() { val exception = assertThrows(AccountProviderAccessException.UnauthorizedAccountProviderException::class.java) { runTest { - assertIsAllowedToConnectToAccountProvider( - title = AN_ACCOUNT_PROVIDER, - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + assertIsAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) } } assertThat(exception.unauthorisedAccountProviderTitle).isEqualTo(AN_ACCOUNT_PROVIDER) assertThat(exception.authorisedAccountProviderTitles).containsExactly(AN_ACCOUNT_PROVIDER_2) runTest { assertThat( - isAllowedToConnectToAccountProvider( - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + isAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) ).isFalse() } } private suspend fun DefaultAccountProviderAccessControl.expectAllowed() { // If no exception is thrown, the test passes - assertIsAllowedToConnectToAccountProvider( - title = AN_ACCOUNT_PROVIDER, - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + assertIsAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) runTest { assertThat( - isAllowedToConnectToAccountProvider( - accountProviderUrl = AN_ACCOUNT_PROVIDER_URL, - ) + isAllowedToConnectToAccountProvider(anAccountProviderUnderTest()) ).isTrue() } } diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSourceTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSourceTest.kt index 30e25c8c3e..ff03d79989 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSourceTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/AccountProviderDataSourceTest.kt @@ -10,9 +10,10 @@ package io.element.android.features.login.impl.accountprovider import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.appconfig.AuthenticationConfig -import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.matrixOrgAccountProvider +import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderManaged import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.tests.testutils.WarmUpRule import kotlinx.coroutines.test.runTest @@ -24,61 +25,24 @@ class AccountProviderDataSourceTest { val warmUpRule = WarmUpRule() @Test - fun `present - initial state`() = runTest { + fun `present - initial state - matrix org is the default when nothing is configured`() = runTest { val sut = anAccountProviderDataSource() sut.flow.test { - val initialState = awaitItem() - assertThat(initialState).isEqualTo( - AccountProvider( - url = AuthenticationConfig.MATRIX_ORG_URL, - title = "matrix.org", - subtitle = null, - isPublic = true, - isMatrixOrg = true, - ) - ) + assertThat(awaitItem()).isEqualTo(matrixOrgAccountProvider) } } @Test - fun `present - initial state - matrix org`() = runTest { + fun `present - initial state - the first configured account provider is the default`() = runTest { val sut = anAccountProviderDataSource( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(AuthenticationConfig.MATRIX_ORG_URL) } + accountProviderAllowListResult = { + listOf(anAccountProviderManaged(serverName = "first.org"), anAccountProviderManaged(serverName = "second.org")) + } ), ) sut.flow.test { - val initialState = awaitItem() - assertThat(initialState).isEqualTo( - AccountProvider( - url = AuthenticationConfig.MATRIX_ORG_URL, - title = "matrix.org", - subtitle = null, - isPublic = true, - isMatrixOrg = true, - ) - ) - } - } - - @Test - fun `present - ensure that default homeserver is not star char`() = runTest { - val sut = anAccountProviderDataSource( - enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(EnterpriseService.ANY_ACCOUNT_PROVIDER, AuthenticationConfig.MATRIX_ORG_URL) } - ), - ) - sut.flow.test { - val initialState = awaitItem() - assertThat(initialState).isEqualTo( - AccountProvider( - url = AuthenticationConfig.MATRIX_ORG_URL, - title = "matrix.org", - subtitle = null, - isPublic = true, - isMatrixOrg = true, - ) - ) + assertThat(awaitItem()).isEqualTo(anAccountProviderManaged(serverName = "first.org")) } } @@ -86,22 +50,11 @@ class AccountProviderDataSourceTest { fun `present - user change and reset`() = runTest { val sut = anAccountProviderDataSource() sut.flow.test { - val initialState = awaitItem() - assertThat(initialState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) - sut.setAccountProvider(AccountProvider(url = "https://example.com")) - val changedState = awaitItem() - assertThat(changedState).isEqualTo( - AccountProvider( - url = "https://example.com", - title = "example.com", - subtitle = null, - isPublic = false, - isMatrixOrg = false, - ) - ) + assertThat(awaitItem()).isEqualTo(matrixOrgAccountProvider) + sut.setAccountProvider(AccountProvider.Generic("https://example.com")) + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://example.com")) sut.reset() - val resetState = awaitItem() - assertThat(resetState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(awaitItem()).isEqualTo(matrixOrgAccountProvider) } } @@ -109,22 +62,23 @@ class AccountProviderDataSourceTest { fun `present - set url and reset`() = runTest { val sut = anAccountProviderDataSource() sut.flow.test { - val initialState = awaitItem() - assertThat(initialState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(awaitItem()).isEqualTo(matrixOrgAccountProvider) sut.setUrl(url = "https://example.com") - val changedState = awaitItem() - assertThat(changedState).isEqualTo( - AccountProvider( - url = "https://example.com", - title = "example.com", - subtitle = null, - isPublic = false, - isMatrixOrg = false, - ) + assertThat(awaitItem()).isEqualTo( + AccountProvider.Generic("https://example.com") ) sut.reset() - val resetState = awaitItem() - assertThat(resetState.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(awaitItem()).isEqualTo(matrixOrgAccountProvider) + } + } + + @Test + fun `present - a provider set by the user is stored as they input it`() = runTest { + val sut = anAccountProviderDataSource() + sut.flow.test { + skipItems(1) + sut.setUrl(url = "example.com") + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("example.com")) } } @@ -136,7 +90,7 @@ class AccountProviderDataSourceTest { ), ) sut.flow.test { - assertThat(awaitItem().url).isEqualTo("https://example.com") + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://example.com")) } } @@ -144,14 +98,31 @@ class AccountProviderDataSourceTest { fun `present - history is ignored when the account provider is enforced`() = runTest { val sut = anAccountProviderDataSource( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf("https://enforced.org") } + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = "enforced.org")) }, + canConnectToAnyAccountProviderResult = { false }, ), appPreferencesStore = InMemoryAppPreferencesStore( homeserverHistory = listOf("https://example.com"), ), ) sut.flow.test { - assertThat(awaitItem().url).isEqualTo("https://enforced.org") + assertThat(awaitItem()).isEqualTo(anAccountProviderManaged(serverName = "enforced.org")) + } + } + + @Test + fun `present - history wins over the configured provider when other providers are allowed`() = runTest { + val sut = anAccountProviderDataSource( + enterpriseService = FakeEnterpriseService( + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = "preferred.org")) }, + canConnectToAnyAccountProviderResult = { true }, + ), + appPreferencesStore = InMemoryAppPreferencesStore( + homeserverHistory = listOf("https://example.com"), + ), + ) + sut.flow.test { + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://example.com")) } } @@ -163,11 +134,11 @@ class AccountProviderDataSourceTest { ), ) sut.flow.test { - assertThat(awaitItem().url).isEqualTo("https://example.com") + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://example.com")) sut.setUrl("https://other.com") - assertThat(awaitItem().url).isEqualTo("https://other.com") + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://other.com")) sut.reset() - assertThat(awaitItem().url).isEqualTo("https://example.com") + assertThat(awaitItem()).isEqualTo(AccountProvider.Generic("https://example.com")) } } } diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistoryTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistoryTest.kt index 0af8188f3f..604e01acfe 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistoryTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/accountprovider/SaveAccountProviderToHistoryTest.kt @@ -20,7 +20,7 @@ class SaveAccountProviderToHistoryTest { val warmUpRule = WarmUpRule() @Test - fun `invoke saves the current account provider url to history`() = runTest { + fun `invoke saves the current account provider server name to history`() = runTest { val appPreferencesStore = InMemoryAppPreferencesStore() val accountProviderDataSource = anAccountProviderDataSource() accountProviderDataSource.setUrl("https://example.com") @@ -29,7 +29,7 @@ class SaveAccountProviderToHistoryTest { sut() assertThat(appPreferencesStore.getHomeserverHistoryFlow().first()) - .containsExactly("https://example.com") + .containsExactly("example.com") } @Test @@ -45,6 +45,6 @@ class SaveAccountProviderToHistoryTest { sut() assertThat(appPreferencesStore.getHomeserverHistoryFlow().first()) - .containsExactly("https://example.com") + .containsExactly("example.com") } } 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 44a3bbd5cb..f43a575d37 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 @@ -12,14 +12,15 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.anAccountProviderDataSource import io.element.android.features.login.impl.error.ChangeServerError import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissionGate import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_HOMESERVER_URL +import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderManaged import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionDialog @@ -57,13 +58,13 @@ class ChangeServerPresenterTest { createPresenter( authenticationService = authenticationService, enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), ).test { val initialState = awaitItem() assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized) - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val loadingState = awaitItem() assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java) val successState = awaitItem() @@ -80,14 +81,14 @@ class ChangeServerPresenterTest { ) createPresenter( enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), authenticationService = authenticationService, ).test { val initialState = awaitItem() assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized) - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val loadingState = awaitItem() assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java) val failureState = awaitItem() @@ -108,14 +109,14 @@ class ChangeServerPresenterTest { ) createPresenter( enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), authenticationService = authenticationService, ).test { val initialState = awaitItem() assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized) - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val loadingState = awaitItem() assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java) val failureState = awaitItem() @@ -128,30 +129,30 @@ class ChangeServerPresenterTest { @Test fun `present - change server not allowed error`() = runTest { - val isAllowedToConnectToHomeserverResult = lambdaRecorder { false } + val isAllowedToConnectToAccountProviderResult = lambdaRecorder { false } createPresenter( enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = isAllowedToConnectToHomeserverResult, - defaultHomeserverListResult = { listOf("element.io") }, + isAllowedToConnectToAccountProviderResult = isAllowedToConnectToAccountProviderResult, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = "element.io")) }, isElementProEnforcedResult = { false }, ), ).test { val initialState = awaitItem() assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized) - val anAccountProvider = AccountProvider(url = A_HOMESERVER_URL) + val anAccountProvider = AccountProvider.Generic(A_HOMESERVER_URL) initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(anAccountProvider)) val loadingState = awaitItem() assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java) val failureState = awaitItem() assertThat( (failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).unauthorisedAccountProviderTitle - ).isEqualTo(anAccountProvider.title) + ).isEqualTo(anAccountProvider.serverNameOrBaseUrl()) assertThat( (failureState.changeServerAction.errorOrNull() as ChangeServerError.UnauthorizedAccountProvider).authorisedAccountProviderTitles ).containsExactly("element.io") - isAllowedToConnectToHomeserverResult.assertions() + isAllowedToConnectToAccountProviderResult.assertions() .isCalledOnce() - .with(value(A_HOMESERVER_URL)) + .with(value(AccountProvider.Generic(A_HOMESERVER_URL))) } } @@ -166,14 +167,14 @@ class ChangeServerPresenterTest { ).test { val initialState = awaitItem() assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized) - val anAccountProvider = AccountProvider(url = A_HOMESERVER_URL) + val anAccountProvider = AccountProvider.Generic(A_HOMESERVER_URL) initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(anAccountProvider)) // Skip loading state skipItems(1) val failureState = awaitItem() assertThat( (failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).unauthorisedAccountProviderTitle - ).isEqualTo(anAccountProvider.title) + ).isEqualTo(anAccountProvider.serverNameOrBaseUrl()) assertThat( (failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).applicationId ).isEqualTo("io.element.enterprise") @@ -188,13 +189,13 @@ class ChangeServerPresenterTest { ) createPresenter( authenticationService = authenticationService, - enterpriseService = FakeEnterpriseService(isAllowedToConnectToHomeserverResult = { true }), + enterpriseService = FakeEnterpriseService(isAllowedToConnectToAccountProviderResult = { true }), localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(shouldPrompt = true), permissionsPresenter = FakePermissionsPresenter(), ).test { val initialState = awaitItem() assertThat(initialState.localNetworkPermissionDialog).isEqualTo(LocalNetworkPermissionDialog.None) - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val promptState = expectMostRecentItem() // Dialog is shown, permission has not been requested yet, setHomeserver has not been called. assertThat(promptState.localNetworkPermissionDialog).isNotEqualTo(LocalNetworkPermissionDialog.None) @@ -208,12 +209,12 @@ class ChangeServerPresenterTest { authenticationService = FakeMatrixAuthenticationService( setHomeserverResult = { Result.success(aMatrixHomeServerDetails(supportsOAuthLogin = true)) }, ), - enterpriseService = FakeEnterpriseService(isAllowedToConnectToHomeserverResult = { true }), + enterpriseService = FakeEnterpriseService(isAllowedToConnectToAccountProviderResult = { true }), localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(shouldPrompt = true), permissionsPresenter = FakePermissionsPresenter(), ).test { val initialState = awaitItem() - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val promptState = expectMostRecentItem() assertThat(promptState.localNetworkPermissionDialog).isNotEqualTo(LocalNetworkPermissionDialog.None) promptState.eventSink.invoke(ChangeServerEvent.DismissLocalNetworkPermission) @@ -231,12 +232,12 @@ class ChangeServerPresenterTest { val permissionsPresenter = FakePermissionsPresenter() createPresenter( authenticationService = authenticationService, - enterpriseService = FakeEnterpriseService(isAllowedToConnectToHomeserverResult = { true }, isElementProEnforcedResult = { false }), + enterpriseService = FakeEnterpriseService(isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }), localNetworkPermissionAdvisor = FakeLocalNetworkPermissionAdvisor(shouldPrompt = true), permissionsPresenter = permissionsPresenter, ).test { val initialState = awaitItem() - initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider(url = A_HOMESERVER_URL))) + initialState.eventSink.invoke(ChangeServerEvent.ChangeServer(AccountProvider.Generic(A_HOMESERVER_URL))) val promptState = expectMostRecentItem() assertThat(promptState.localNetworkPermissionDialog).isNotEqualTo(LocalNetworkPermissionDialog.None) permissionsPresenter.setPermissionGranted() diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenterTest.kt index 78f4293489..17711cc469 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderPresenterTest.kt @@ -11,14 +11,13 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService -import io.element.android.features.login.impl.accountprovider.AccountProvider import io.element.android.features.login.impl.login.LoginModePresenter import io.element.android.features.login.impl.screens.onboarding.createLoginModePresenter import io.element.android.libraries.architecture.AsyncData -import io.element.android.libraries.core.uri.ensureProtocol import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2 import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_3 import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.accountprovider.anAccountProviderManaged import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.test @@ -33,18 +32,8 @@ class ChooseAccountProviderPresenterTest { companion object { private const val ACCOUNT_PROVIDER_FROM_CONFIG_1 = AN_ACCOUNT_PROVIDER_2 private const val ACCOUNT_PROVIDER_FROM_CONFIG_2 = AN_ACCOUNT_PROVIDER_3 - val accountProvider1 = AccountProvider( - url = ACCOUNT_PROVIDER_FROM_CONFIG_1.ensureProtocol(), - subtitle = null, - isPublic = false, - isMatrixOrg = false, - ) - val accountProvider2 = AccountProvider( - url = ACCOUNT_PROVIDER_FROM_CONFIG_2.ensureProtocol(), - subtitle = null, - isPublic = false, - isMatrixOrg = false, - ) + val accountProvider1 = anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG_1) + val accountProvider2 = anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG_2) } @Test @@ -61,7 +50,7 @@ class ChooseAccountProviderPresenterTest { fun `present - initial state`() = runTest { val presenter = createPresenter( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG_1, ACCOUNT_PROVIDER_FROM_CONFIG_2) }, + accountProviderAllowListResult = { listOf(accountProvider1, accountProvider2) }, ), ) presenter.test { @@ -79,7 +68,7 @@ class ChooseAccountProviderPresenterTest { val authenticationService = FakeMatrixAuthenticationService() val presenter = createPresenter( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG_1, ACCOUNT_PROVIDER_FROM_CONFIG_2) }, + accountProviderAllowListResult = { listOf(accountProvider1, accountProvider2) }, ), loginModePresenter = createLoginModePresenter( authenticationService = authenticationService, @@ -103,7 +92,7 @@ class ChooseAccountProviderPresenterTest { ) val presenter = createPresenter( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG_1, ACCOUNT_PROVIDER_FROM_CONFIG_2) }, + accountProviderAllowListResult = { listOf(accountProvider1, accountProvider2) }, ), loginModePresenter = createLoginModePresenter( authenticationService = authenticationService, @@ -136,7 +125,7 @@ class ChooseAccountProviderPresenterTest { val authenticationService = FakeMatrixAuthenticationService() val presenter = createPresenter( enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG_1, ACCOUNT_PROVIDER_FROM_CONFIG_2) }, + accountProviderAllowListResult = { listOf(accountProvider1, accountProvider2) }, ), loginModePresenter = createLoginModePresenter( authenticationService = authenticationService, diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateTest.kt index a5cb54e7e1..c4af8f9544 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/chooseaccountprovider/ChooseAccountProviderStateTest.kt @@ -9,7 +9,7 @@ package io.element.android.features.login.impl.screens.chooseaccountprovider import com.google.common.truth.Truth.assertThat -import io.element.android.features.login.impl.accountprovider.anAccountProvider +import io.element.android.features.login.impl.accountprovider.anAccountProviderManaged import io.element.android.features.login.impl.login.LoginMode import io.element.android.features.login.impl.login.aLoginModeState import io.element.android.libraries.architecture.AsyncData @@ -27,7 +27,7 @@ class ChooseAccountProviderStateTest { @Test fun `submitEnabled returns true when there is a selectedAccountProvider`() { val sut = aChooseAccountProviderState( - selectedAccountProvider = anAccountProvider(), + selectedAccountProvider = anAccountProviderManaged(), ) assertThat(sut.submitEnabled).isTrue() } @@ -35,7 +35,7 @@ class ChooseAccountProviderStateTest { @Test fun `submitEnabled returns false when there is a selectedAccountProvider but there is an error`() { val sut = aChooseAccountProviderState( - selectedAccountProvider = anAccountProvider(), + selectedAccountProvider = anAccountProviderManaged(), loginModeState = aLoginModeState(loginMode = AsyncData.Failure(Throwable("Error"))), ) assertThat(sut.submitEnabled).isFalse() @@ -44,7 +44,7 @@ class ChooseAccountProviderStateTest { @Test fun `submitEnabled returns false when there is a selectedAccountProvider but the result is successful`() { val sut = aChooseAccountProviderState( - selectedAccountProvider = anAccountProvider(), + selectedAccountProvider = anAccountProviderManaged(), loginModeState = aLoginModeState(loginMode = AsyncData.Success(LoginMode.PasswordLogin)), ) assertThat(sut.submitEnabled).isFalse() 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 4ef7a71966..9bb8da717e 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.ExperimentalTestApi import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.v2.runAndroidComposeUiTest -import io.element.android.features.login.impl.accountprovider.anAccountProvider +import io.element.android.features.login.impl.accountprovider.anAccountProviderManaged import io.element.android.features.login.impl.login.aLoginModeState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.matrix.api.auth.OAuthDetails @@ -57,11 +57,11 @@ class ChooseAccountProviderViewTest : RobolectricTest() { ChooseAccountProviderPresenterTest.accountProvider1, ChooseAccountProviderPresenterTest.accountProvider2, ), - selectedAccountProvider = anAccountProvider(), + selectedAccountProvider = anAccountProviderManaged(), eventSink = eventSink, ), ) - onNodeWithText(ChooseAccountProviderPresenterTest.accountProvider1.title).performClick() + onNodeWithText(ChooseAccountProviderPresenterTest.accountProvider1.friendlyServerName()).performClick() eventSink.assertSingle(ChooseAccountProviderEvent.SelectAccountProvider(ChooseAccountProviderPresenterTest.accountProvider1)) } 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 19afbe0f28..9bccb2c261 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 @@ -10,7 +10,6 @@ package io.element.android.features.login.impl.screens.confirmaccountprovider import app.cash.turbine.ReceiveTurbine import com.google.common.truth.Truth.assertThat -import io.element.android.appconfig.AuthenticationConfig import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl @@ -24,6 +23,7 @@ import io.element.android.features.login.impl.screens.onboarding.createLoginMode import io.element.android.libraries.architecture.AsyncData 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.accountprovider.anAccountProviderManaged import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails import io.element.android.libraries.oauth.api.OAuthAction @@ -44,6 +44,11 @@ class ConfirmAccountProviderPresenterTest { @get:Rule val warmUpRule = WarmUpRule() + companion object { + private const val MATRIX_ORG_SERVER_NAME = "matrix.org" + private const val MATRIX_ORG_URL = "https://matrix.org" + } + @Test fun `present - initial test`() = runTest { val presenter = createConfirmAccountProviderPresenter() @@ -68,7 +73,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isEqualTo(LoginMode.PasswordLogin) cancelAndIgnoreRemainingEvents() @@ -87,7 +92,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) cancelAndIgnoreRemainingEvents() @@ -108,7 +113,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) authenticationService.givenOAuthCancelError(AN_EXCEPTION) @@ -133,7 +138,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) defaultOAuthActionFlow.post(OAuthAction.GoBack()) @@ -157,7 +162,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) awaitLoginMode { it is AsyncData.Loading } defaultOAuthActionFlow.post(OAuthAction.GoBack(toUnblock = true)) val cancelFinalState = awaitLoginMode { it is AsyncData.Uninitialized } @@ -180,7 +185,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) authenticationService.givenLoginError(AN_EXCEPTION) @@ -205,7 +210,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val successState = awaitLoginMode { it is AsyncData.Success } assertThat(successState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) defaultOidcActionFlow.post(OAuthAction.Success("aUrl")) @@ -227,7 +232,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink.invoke(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) // The account provider validation fails, so the login is never attempted. val failureState = awaitState { it.changeServerState.changeServerAction is AsyncData.Failure } assertThat(failureState.loginModeState.loginMode).isEqualTo(AsyncData.Uninitialized) @@ -249,7 +254,7 @@ class ConfirmAccountProviderPresenterTest { val initialState = awaitItem() // Submit will return an error while validating the account provider - initialState.eventSink(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) // Check an error was returned val submittedState = awaitState { it.changeServerState.changeServerAction is AsyncData.Failure } @@ -274,7 +279,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) // Check an error was returned val submittedState = awaitLoginMode { it is AsyncData.Failure } assertThat(submittedState.loginModeState.loginMode.errorOrNull()).isInstanceOf(AccountCreationNotSupported::class.java) @@ -299,7 +304,7 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) val submittedState = awaitLoginMode { it is AsyncData.Success } assertThat(submittedState.loginModeState.loginMode.dataOrNull()).isInstanceOf(LoginMode.OAuth::class.java) cancelAndIgnoreRemainingEvents() @@ -344,7 +349,7 @@ class ConfirmAccountProviderPresenterTest { val suggestionState = awaitState { it.accountProviderSuggestion != null } suggestionState.eventSink(ConfirmAccountProviderEvent.Continue("randomcommunity.org")) awaitLoginMode { it is AsyncData.Success } - assertThat(submittedUrls.first()).isEqualTo("https://randomcommunity.org") + assertThat(submittedUrls.first()).isEqualTo("randomcommunity.org") cancelAndIgnoreRemainingEvents() } } @@ -375,8 +380,7 @@ class ConfirmAccountProviderPresenterTest { val presenter = createConfirmAccountProviderPresenter( appPreferencesStore = InMemoryAppPreferencesStore(homeserverHistory = emptyList()), enterpriseService = FakeEnterpriseService( - // Preferred servers plus the "*" (any) wildcard: the wildcard is filtered out, the rest complete. - defaultHomeserverListResult = { listOf("https://element.io", EnterpriseService.ANY_ACCOUNT_PROVIDER) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = "element.io")) }, ), ) presenter.test { @@ -387,6 +391,19 @@ class ConfirmAccountProviderPresenterTest { } } + @Test + fun `present - offers the previously used servers without the scheme as autocomplete suggestions`() = runTest { + val presenter = createConfirmAccountProviderPresenter( + appPreferencesStore = InMemoryAppPreferencesStore(homeserverHistory = listOf("https://previous.org")), + ) + presenter.test { + val initialState = awaitItem() + initialState.eventSink(ConfirmAccountProviderEvent.UserInputChanged("prev")) + val suggestionState = awaitState { it.accountProviderInput == "prev" } + assertThat(suggestionState.accountProviderSuggestion).isEqualTo("previous.org") + } + } + @Test fun `present - offers matrix_org without the scheme as an autocomplete suggestion`() = runTest { val presenter = createConfirmAccountProviderPresenter( @@ -432,7 +449,7 @@ class ConfirmAccountProviderPresenterTest { val initialState = awaitItem() initialState.eventSink(ConfirmAccountProviderEvent.Continue("matrix.org")) awaitLoginMode { it is AsyncData.Success } - assertThat(submittedUrls.first()).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(submittedUrls.first()).isEqualTo(MATRIX_ORG_SERVER_NAME) cancelAndIgnoreRemainingEvents() } } @@ -453,9 +470,9 @@ class ConfirmAccountProviderPresenterTest { ) presenter.test { val initialState = awaitItem() - initialState.eventSink(ConfirmAccountProviderEvent.Continue(AuthenticationConfig.MATRIX_ORG_URL)) + initialState.eventSink(ConfirmAccountProviderEvent.Continue(MATRIX_ORG_URL)) awaitLoginMode { it is AsyncData.Success } - assertThat(submittedUrls).containsExactly(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(submittedUrls).containsExactly(MATRIX_ORG_SERVER_NAME) cancelAndIgnoreRemainingEvents() } } @@ -474,7 +491,7 @@ class ConfirmAccountProviderPresenterTest { val initialState = awaitItem() initialState.eventSink(ConfirmAccountProviderEvent.Continue("@alice:example.org")) awaitLoginMode { it is AsyncData.Success } - assertThat(submittedUrls.first()).isEqualTo("https://example.org") + assertThat(submittedUrls.first()).isEqualTo("example.org") assertThat(authenticationService.getOAuthUrlLoginHint).isEqualTo("mxid:@alice:example.org") cancelAndIgnoreRemainingEvents() } @@ -494,7 +511,7 @@ class ConfirmAccountProviderPresenterTest { val initialState = awaitItem() initialState.eventSink(ConfirmAccountProviderEvent.Continue("@alice:example.org:8448")) awaitLoginMode { it is AsyncData.Success } - assertThat(submittedUrls.first()).isEqualTo("https://example.org:8448") + assertThat(submittedUrls.first()).isEqualTo("example.org:8448") cancelAndIgnoreRemainingEvents() } } @@ -570,7 +587,7 @@ class ConfirmAccountProviderPresenterTest { accountProviderDataSource = accountProviderDataSource, defaultAccountProviderAccessControl = DefaultAccountProviderAccessControl( enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), isEnterpriseBuild = { false }, diff --git a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordPresenterTest.kt b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordPresenterTest.kt index b12c9ec667..015ece9e23 100644 --- a/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordPresenterTest.kt +++ b/features/login/impl/src/test/kotlin/io/element/android/features/login/impl/screens/loginpassword/LoginPasswordPresenterTest.kt @@ -9,11 +9,11 @@ package io.element.android.features.login.impl.screens.loginpassword import com.google.common.truth.Truth.assertThat -import io.element.android.appconfig.AuthenticationConfig import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource import io.element.android.features.login.impl.accountprovider.SaveAccountProviderToHistory import io.element.android.features.login.impl.accountprovider.anAccountProviderDataSource import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.matrixOrgAccountProvider import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_PASSWORD @@ -39,7 +39,7 @@ class LoginPasswordPresenterTest { fun `present - initial state`() = runTest { createLoginPasswordPresenter().test { val initialState = awaitItem() - assertThat(initialState.accountProvider.url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) + assertThat(initialState.accountProvider).isEqualTo(matrixOrgAccountProvider) assertThat(initialState.formState).isEqualTo(LoginFormState.Default) assertThat(initialState.loginAction).isEqualTo(AsyncData.Uninitialized) assertThat(initialState.submitEnabled).isFalse() @@ -127,7 +127,7 @@ class LoginPasswordPresenterTest { val loggedInState = awaitItem() assertThat(loggedInState.loginAction).isEqualTo(AsyncData.Success(A_SESSION_ID)) assertThat(appPreferencesStore.getHomeserverHistoryFlow().first()) - .containsExactly(AuthenticationConfig.MATRIX_ORG_URL) + .containsExactly(matrixOrgAccountProvider.serverName) } } 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 1088a87538..4fecc3ada8 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 @@ -9,7 +9,6 @@ package io.element.android.features.login.impl.screens.onboarding import com.google.common.truth.Truth.assertThat -import io.element.android.appconfig.AuthenticationConfig import io.element.android.appconfig.OnBoardingConfig import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.api.IsEnterpriseBuild @@ -22,6 +21,8 @@ import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissio import io.element.android.features.login.impl.login.LoginModePresenter import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider +import io.element.android.libraries.matrix.api.accountprovider.matrixOrgAccountProvider import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2 @@ -30,6 +31,7 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_HOMESERVER_URL 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.accountprovider.anAccountProviderManaged import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService import io.element.android.libraries.matrix.test.core.aBuildMeta import io.element.android.libraries.oauth.api.OAuthActionFlow @@ -82,7 +84,8 @@ class OnBoardingPresenterTest { val presenter = createPresenter( buildMeta = buildMeta, enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG, EnterpriseService.ANY_ACCOUNT_PROVIDER) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG)) }, + canConnectToAnyAccountProviderResult = { true }, ), ) presenter.test { @@ -184,15 +187,16 @@ class OnBoardingPresenterTest { showBackButton = false, ), enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG, EnterpriseService.ANY_ACCOUNT_PROVIDER) }, - isAllowedToConnectToHomeserverResult = { true }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG)) }, + canConnectToAnyAccountProviderResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), ) presenter.test { skipItems(3) awaitItem().also { - assertThat(it.defaultAccountProvider).isEqualTo(ACCOUNT_PROVIDER_FROM_LINK) + assertThat(it.defaultAccountProvider).isEqualTo(AccountProvider.Generic(ACCOUNT_PROVIDER_FROM_LINK)) assertThat(it.canLoginWithQrCode).isFalse() assertThat(it.canCreateAccount).isFalse() } @@ -208,8 +212,14 @@ class OnBoardingPresenterTest { showBackButton = false, ), enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG, ACCOUNT_PROVIDER_FROM_CONFIG_2) }, - isAllowedToConnectToHomeserverResult = { false }, + accountProviderAllowListResult = { + listOf( + anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG), + anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG_2) + ) + }, + canConnectToAnyAccountProviderResult = { false }, + isAllowedToConnectToAccountProviderResult = { false }, ), ) presenter.test { @@ -231,19 +241,60 @@ class OnBoardingPresenterTest { showBackButton = false, ), enterpriseService = FakeEnterpriseService( - defaultHomeserverListResult = { listOf(ACCOUNT_PROVIDER_FROM_CONFIG) }, + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG)) }, + canConnectToAnyAccountProviderResult = { false }, ) ) presenter.test { skipItems(1) awaitItem().also { - assertThat(it.defaultAccountProvider).isEqualTo(ACCOUNT_PROVIDER_FROM_CONFIG) + assertThat(it.defaultAccountProvider).isEqualTo(anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG)) assertThat(it.canLoginWithQrCode).isTrue() assertThat(it.canCreateAccount).isFalse() } } } + @Test + fun `present - a single configured account provider is not forced when the user may use another one`() = runTest { + // A singleton allow list only forces the account provider when the user is not free to use another one. + val presenter = createPresenter( + enterpriseService = FakeEnterpriseService( + accountProviderAllowListResult = { listOf(anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG)) }, + canConnectToAnyAccountProviderResult = { true }, + ), + ) + presenter.test { + awaitItem().also { + assertThat(it.defaultAccountProvider).isNull() + assertThat(it.mustChooseAccountProvider).isFalse() + } + skipItems(1) + } + } + + @Test + fun `present - the user must choose when several account providers are configured and enforced`() = runTest { + val presenter = createPresenter( + enterpriseService = FakeEnterpriseService( + accountProviderAllowListResult = { + listOf( + anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG), + anAccountProviderManaged(serverName = ACCOUNT_PROVIDER_FROM_CONFIG_2) + ) + }, + canConnectToAnyAccountProviderResult = { false }, + ), + ) + presenter.test { + awaitItem().also { + assertThat(it.defaultAccountProvider).isNull() + assertThat(it.mustChooseAccountProvider).isTrue() + } + skipItems(1) + } + } + @Test fun `present - default account provider - login and clear error`() = runTest { val authenticationService = FakeMatrixAuthenticationService( @@ -259,7 +310,7 @@ class OnBoardingPresenterTest { showBackButton = false, ), enterpriseService = FakeEnterpriseService( - isAllowedToConnectToHomeserverResult = { true }, + isAllowedToConnectToAccountProviderResult = { true }, isElementProEnforcedResult = { false }, ), loginModePresenter = createLoginModePresenter( @@ -270,12 +321,12 @@ class OnBoardingPresenterTest { presenter.test { skipItems(3) awaitItem().also { - assertThat(it.defaultAccountProvider).isEqualTo(A_HOMESERVER_URL) - assertThat(accountProviderDataSource.flow.first().url).isEqualTo(AuthenticationConfig.MATRIX_ORG_URL) - it.eventSink(OnBoardingEvent.OnSignIn(A_HOMESERVER_URL_2)) + assertThat(it.defaultAccountProvider).isEqualTo(AccountProvider.Generic(A_HOMESERVER_URL)) + assertThat(accountProviderDataSource.flow.first()).isEqualTo(matrixOrgAccountProvider) + it.eventSink(OnBoardingEvent.OnSignIn(AccountProvider.Generic(A_HOMESERVER_URL_2))) skipItems(1) // Loading // Account data source has been updated - assertThat(accountProviderDataSource.flow.first().url).isEqualTo(A_HOMESERVER_URL_2) + assertThat(accountProviderDataSource.flow.first()).isEqualTo(AccountProvider.Generic(A_HOMESERVER_URL_2)) // Check an error was returned val submittedState = awaitItem() assertThat(submittedState.loginModeState.loginMode).isInstanceOf(AsyncData.Failure::class.java) 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 88c9acf55f..c7cc2b9f03 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 @@ -23,6 +23,7 @@ import io.element.android.features.login.impl.R import io.element.android.features.login.impl.login.LoginMode import io.element.android.features.login.impl.login.aLoginModeState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider 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 @@ -134,13 +135,13 @@ class OnboardingViewTest : RobolectricTestParameter() { val eventSink = EventsRecorder() setOnboardingView( state = anOnBoardingState( - defaultAccountProvider = "element.io", + defaultAccountProvider = AccountProvider.Generic("element.io"), eventSink = eventSink, ), ) val buttonText = activity!!.getString(R.string.screen_onboarding_sign_in_to, "element.io") onNodeWithText(buttonText).performClick() - eventSink.assertSingle(OnBoardingEvent.OnSignIn("element.io")) + eventSink.assertSingle(OnBoardingEvent.OnSignIn(AccountProvider.Generic("element.io"))) } @Test @@ -148,7 +149,7 @@ class OnboardingViewTest : RobolectricTestParameter() { val eventSink = EventsRecorder() setOnboardingView( state = anOnBoardingState( - defaultAccountProvider = "element.io", + defaultAccountProvider = AccountProvider.Generic("element.io"), loginModeState = aLoginModeState(loginMode = AsyncData.Failure(AN_EXCEPTION)), eventSink = eventSink, ), diff --git a/features/login/test/build.gradle.kts b/features/login/test/build.gradle.kts index 4cbf0910db..41c231a594 100644 --- a/features/login/test/build.gradle.kts +++ b/features/login/test/build.gradle.kts @@ -16,6 +16,7 @@ android { dependencies { implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) implementation(projects.features.login.api) implementation(projects.tests.testutils) } diff --git a/features/login/test/src/main/kotlin/io/element/android/features/login/test/accesscontrol/FakeAccountProviderAccessControl.kt b/features/login/test/src/main/kotlin/io/element/android/features/login/test/accesscontrol/FakeAccountProviderAccessControl.kt index 9ebd3be7fc..2864669e7f 100644 --- a/features/login/test/src/main/kotlin/io/element/android/features/login/test/accesscontrol/FakeAccountProviderAccessControl.kt +++ b/features/login/test/src/main/kotlin/io/element/android/features/login/test/accesscontrol/FakeAccountProviderAccessControl.kt @@ -8,12 +8,13 @@ package io.element.android.features.login.test.accesscontrol import io.element.android.features.login.api.accesscontrol.AccountProviderAccessControl +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.tests.testutils.lambda.lambdaError class FakeAccountProviderAccessControl( - private val isAllowedToConnectToAccountProviderResult: (String) -> Boolean = { lambdaError() }, + private val isAllowedToConnectToAccountProviderResult: (AccountProvider) -> Boolean = { lambdaError() }, ) : AccountProviderAccessControl { - override suspend fun isAllowedToConnectToAccountProvider(accountProviderUrl: String): Boolean { - return isAllowedToConnectToAccountProviderResult(accountProviderUrl) + override suspend fun isAllowedToConnectToAccountProvider(accountProvider: AccountProvider): Boolean { + return isAllowedToConnectToAccountProviderResult(accountProvider) } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt new file mode 100644 index 0000000000..828676285a --- /dev/null +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt @@ -0,0 +1,67 @@ +/* + * 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.matrix.api.accountprovider + +sealed interface AccountProvider { + /** + * An account provider that was input by the user. + */ + data class Generic( + val serverName: String, + ) : AccountProvider + + /** + * An account provider that is provided by the app. + */ + data class Managed( + val serverName: String, + val baseUrl: String, + val canUseServerName: Boolean, + ) : AccountProvider + + fun serverNameOrBaseUrl(): String { + return when (this) { + is Generic -> serverName + is Managed -> if (canUseServerName) serverName else baseUrl + }.sanitized() + } + + fun friendlyServerName(): String { + return when (this) { + is Generic -> serverName + is Managed -> serverName + }.sanitized() + } + + /** + * The user may reach an allowed account provider by either of its identifiers: the server name it is known by + * (what the user types, e.g. `element.io`) or the base url its client API lives at (e.g. `https://element.ems.host`). + */ + fun matches(other: AccountProvider): Boolean { + return serverNameOrBaseUrl() == other.serverNameOrBaseUrl() + } + + /** + * Sanitizes the string with the following rules: + * - Trim any whitespace. + * - Lowercase the string. + * - Removes a https scheme (treating it as implicit). + * - Remove any trailing slashes. + */ + private fun String.sanitized(): String { + return trim() + .lowercase() + // Intentionally continue to show http:// as an indicator (and for history). + .removePrefix("https://") + .removeSuffix("/") + } +} + +val matrixOrgAccountProvider = AccountProvider.Generic( + serverName = "matrix.org", +) diff --git a/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProviderTest.kt b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProviderTest.kt new file mode 100644 index 0000000000..0268eaed2b --- /dev/null +++ b/libraries/matrix/api/src/test/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProviderTest.kt @@ -0,0 +1,89 @@ +/* + * 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.matrix.api.accountprovider + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class AccountProviderTest { + @Test + fun `serverNameOrBaseUrl of a generic account provider is the server name the user input`() { + assertThat(AccountProvider.Generic("matrix.org").serverNameOrBaseUrl()).isEqualTo("matrix.org") + } + + @Test + fun `serverNameOrBaseUrl of a managed account provider is its server name when it can be used`() { + val accountProvider = AccountProvider.Managed( + serverName = "element.io", + baseUrl = "https://element.ems.host", + canUseServerName = true, + ) + assertThat(accountProvider.serverNameOrBaseUrl()).isEqualTo("element.io") + } + + @Test + fun `serverNameOrBaseUrl of a managed account provider is its base url when the server name cannot be used`() { + val accountProvider = AccountProvider.Managed( + serverName = "element.io", + baseUrl = "https://element.ems.host", + canUseServerName = false, + ) + assertThat(accountProvider.serverNameOrBaseUrl()).isEqualTo("element.ems.host") + } + + @Test + fun `matrixOrgAccountProvider is known by its server name`() { + assertThat(matrixOrgAccountProvider.serverNameOrBaseUrl()).isEqualTo("matrix.org") + } + + @Test + fun `serverNameOrBaseUrl trims, lowercases and drops the implicit https scheme and a trailing slash`() { + assertThat(AccountProvider.Generic(" MATRIX.org ").serverNameOrBaseUrl()).isEqualTo("matrix.org") + assertThat(AccountProvider.Generic("https://matrix.org").serverNameOrBaseUrl()).isEqualTo("matrix.org") + assertThat(AccountProvider.Generic("https://matrix.org/").serverNameOrBaseUrl()).isEqualTo("matrix.org") + } + + @Test + fun `serverNameOrBaseUrl keeps an explicit http scheme as an indicator`() { + assertThat(AccountProvider.Generic("http://localhost:8080").serverNameOrBaseUrl()).isEqualTo("http://localhost:8080") + } + + @Test + fun `matches ignores the scheme, the case and a trailing slash`() { + val typed = AccountProvider.Generic("Element.io/") + assertThat(typed.matches(AccountProvider.Generic("https://element.io"))).isTrue() + assertThat( + typed.matches( + AccountProvider.Managed(serverName = "element.io", baseUrl = "https://element.ems.host", canUseServerName = true) + ) + ).isTrue() + } + + @Test + fun `matches a managed provider that cannot use its server name only through its base url`() { + val managed = AccountProvider.Managed( + serverName = "element.io", + baseUrl = "https://element.ems.host", + canUseServerName = false, + ) + assertThat(AccountProvider.Generic("element.ems.host").matches(managed)).isTrue() + assertThat(AccountProvider.Generic("element.io").matches(managed)).isFalse() + } + + @Test + fun `matches is false for a different account provider`() { + val typed = AccountProvider.Generic("element.io") + assertThat(typed.matches(AccountProvider.Generic("matrix.org"))).isFalse() + // A managed provider that can use its server name is not reached through its base url. + assertThat( + typed.matches( + AccountProvider.Managed(serverName = "other.io", baseUrl = "https://element.io", canUseServerName = true) + ) + ).isFalse() + } +} diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/accountprovider/AccountProviderFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/accountprovider/AccountProviderFixture.kt new file mode 100644 index 0000000000..3c9cb7033d --- /dev/null +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/accountprovider/AccountProviderFixture.kt @@ -0,0 +1,28 @@ +/* + * 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.matrix.test.accountprovider + +import io.element.android.libraries.matrix.api.accountprovider.AccountProvider +import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER +import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_URL + +fun anAccountProviderGeneric( + serverName: String = AN_ACCOUNT_PROVIDER, +) = AccountProvider.Generic( + serverName = serverName, +) + +fun anAccountProviderManaged( + baseUrl: String = AN_ACCOUNT_PROVIDER_URL, + serverName: String = AN_ACCOUNT_PROVIDER, + canUseServerName: Boolean = true, +) = AccountProvider.Managed( + serverName = serverName, + baseUrl = baseUrl, + canUseServerName = canUseServerName, +) From bf70bb3e5077d6d81647b481d18d6f82949614a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 14 Sep 2026 11:30:23 +0200 Subject: [PATCH 04/17] Update ref --- enterprise | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise b/enterprise index 307b0fd01f..72abbbf4e1 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 307b0fd01f36191dddf6b51ed9ceb92887b360a2 +Subproject commit 72abbbf4e1b16c9079396245bca6a366fea40895 From aa69321898543de94ab61f506ae34b0e7c8e1eec Mon Sep 17 00:00:00 2001 From: ElementBot Date: Mon, 14 Sep 2026 12:36:16 +0000 Subject: [PATCH 05/17] Update screenshots --- ...ogin.impl.accountprovider_AccountProviderView_Day_0_en.png | 4 ++-- ...ogin.impl.accountprovider_AccountProviderView_Day_1_en.png | 3 --- ...ogin.impl.accountprovider_AccountProviderView_Day_2_en.png | 3 --- ...ogin.impl.accountprovider_AccountProviderView_Day_3_en.png | 3 --- ...in.impl.accountprovider_AccountProviderView_Night_0_en.png | 4 ++-- ...in.impl.accountprovider_AccountProviderView_Night_1_en.png | 3 --- ...in.impl.accountprovider_AccountProviderView_Night_2_en.png | 3 --- ...in.impl.accountprovider_AccountProviderView_Night_3_en.png | 3 --- ...ooseaccountprovider_ChooseAccountProviderView_Day_0_en.png | 4 ++-- ...ooseaccountprovider_ChooseAccountProviderView_Day_1_en.png | 4 ++-- ...ooseaccountprovider_ChooseAccountProviderView_Day_2_en.png | 4 ++-- ...seaccountprovider_ChooseAccountProviderView_Night_0_en.png | 4 ++-- ...seaccountprovider_ChooseAccountProviderView_Night_1_en.png | 4 ++-- ...seaccountprovider_ChooseAccountProviderView_Night_2_en.png | 4 ++-- ...nts.preview.imageeditor_AttachmentImageEditorView_2_en.png | 4 ++-- ...nts.preview.imageeditor_AttachmentImageEditorView_5_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_0_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_1_en.png | 4 ++-- ...rypto.identity_MessagesViewWithIdentityChange_Day_2_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_0_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_1_en.png | 4 ++-- ...pto.identity_MessagesViewWithIdentityChange_Night_2_en.png | 4 ++-- ...re.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png | 4 ++-- ...re.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png | 4 ++-- ....resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png | 4 ++-- ....resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png | 4 ++-- ...meline.components.event_ATimelineItemEventRow_Day_0_en.png | 4 ++-- ...line.components.event_ATimelineItemEventRow_Night_0_en.png | 4 ++-- ....components_TimelineItemEventRowDisambiguated_Day_0_en.png | 4 ++-- ...omponents_TimelineItemEventRowDisambiguated_Night_0_en.png | 4 ++-- ...ents_TimelineItemEventRowWithReplyInformative_Day_0_en.png | 4 ++-- ...ents_TimelineItemEventRowWithReplyInformative_Day_1_en.png | 4 ++-- ...ts_TimelineItemEventRowWithReplyInformative_Night_0_en.png | 4 ++-- ...ts_TimelineItemEventRowWithReplyInformative_Night_1_en.png | 4 ++-- ...components_TimelineItemEventRowWithReplyOther_Day_0_en.png | 4 ++-- ...components_TimelineItemEventRowWithReplyOther_Day_1_en.png | 4 ++-- ...mponents_TimelineItemEventRowWithReplyOther_Night_0_en.png | 4 ++-- ...mponents_TimelineItemEventRowWithReplyOther_Night_1_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_0_en.png | 4 ++-- ...ine.components_TimelineItemEventRowWithReply_Day_10_en.png | 4 ++-- ...ine.components_TimelineItemEventRowWithReply_Day_11_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_1_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_2_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_3_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_4_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_5_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_6_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_7_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_8_en.png | 4 ++-- ...line.components_TimelineItemEventRowWithReply_Day_9_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_0_en.png | 4 ++-- ...e.components_TimelineItemEventRowWithReply_Night_10_en.png | 4 ++-- ...e.components_TimelineItemEventRowWithReply_Night_11_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_1_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_2_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_3_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_4_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_5_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_6_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_7_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_8_en.png | 4 ++-- ...ne.components_TimelineItemEventRowWithReply_Night_9_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_0_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_10_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_11_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_1_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_2_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_3_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_4_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_5_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_6_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_7_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_8_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Day_9_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_0_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_10_en.png | 4 ++-- .../features.messages.impl_MessagesView_Night_11_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_1_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_2_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_3_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_4_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_5_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_6_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_7_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_8_en.png | 4 ++-- .../images/features.messages.impl_MessagesView_Night_9_en.png | 4 ++-- ...references.impl.blockedusers_BlockedUsersView_Day_4_en.png | 4 ++-- ...references.impl.blockedusers_BlockedUsersView_Day_5_en.png | 4 ++-- ...ferences.impl.blockedusers_BlockedUsersView_Night_4_en.png | 4 ++-- ...ferences.impl.blockedusers_BlockedUsersView_Night_5_en.png | 4 ++-- ...es.preferences.impl.userstatus_UserStatusView_Day_5_en.png | 4 ++-- ...es.preferences.impl.userstatus_UserStatusView_Day_6_en.png | 4 ++-- ....preferences.impl.userstatus_UserStatusView_Night_5_en.png | 4 ++-- ....preferences.impl.userstatus_UserStatusView_Night_6_en.png | 4 ++-- ...embermoderation.impl_RoomMemberModerationView_Day_5_en.png | 4 ++-- ...embermoderation.impl_RoomMemberModerationView_Day_7_en.png | 4 ++-- ...bermoderation.impl_RoomMemberModerationView_Night_5_en.png | 4 ++-- ...bermoderation.impl_RoomMemberModerationView_Night_7_en.png | 4 ++-- ...eme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png | 4 ++-- ...e.components_HorizontalFloatingToolbarNoFab_Night_0_en.png | 4 ++-- ...em.theme.components_HorizontalFloatingToolbar_Day_0_en.png | 4 ++-- ....theme.components_HorizontalFloatingToolbar_Night_0_en.png | 4 ++-- 102 files changed, 192 insertions(+), 210 deletions(-) delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png delete mode 100644 tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png index 0b20380cd5..b91b3b97b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49371b85e60a5e0465c0ba1537293f6c071962c498579bd71b42763671c8dc01 -size 18148 +oid sha256:6200774d91495f1ef0b49440b8836148f60736c510ffab7d28c7f0b9b38634bf +size 6596 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png deleted file mode 100644 index cbe30336d4..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:78ef17d2f96d5544ecc8213fe1b7f78ddf263557855901f00f152a0b543c1a6f -size 7746 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png deleted file mode 100644 index 447de4de32..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ce777b1c6895caacc21adf4f6c10c71f75a2c6d31a617afe1c7f49d10c5141b3 -size 6929 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png deleted file mode 100644 index ae99061ada..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Day_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f49c89cde78d8d8971d5866f3cef2fef51bc36d1844b0364c950dc2afb188c5b -size 5707 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png index 359e866105..82412586b2 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:759f68aae091a43f54d597e386a5503692f99ed9c3908450dfadf59999047d01 -size 17272 +oid sha256:8553d2b2b795ca403f340881b0c12a30bd7f0871cbb924a6987550a87cdad8fa +size 6437 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png deleted file mode 100644 index 3f58435f8a..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_1_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0591f839e4605cbc51746f9d479a0bfc37e078178e6b2d1395db07dc8a7e1261 -size 7382 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png deleted file mode 100644 index abcf602e31..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_2_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a57866d169c69ba68365ef8cfd4739ec95f8a8aecf4805ec68b2f247f3f698dd -size 6627 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png deleted file mode 100644 index fe5123f403..0000000000 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.accountprovider_AccountProviderView_Night_3_en.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:db8eda0daf8e2038c2c69ff945e686a9e5ff271d8dc4f30987f14f7acb22ae85 -size 5625 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png index 7869ed3dc5..95fd48ffda 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8098b9ff6c4d08d8cc61bc51e391a5a17e9791d7236d2d7cf652a6b855c87b97 -size 22501 +oid sha256:30f64c99d3bae9f34fdc855293070933e3c96ff6ea635892a4dc9f29a6e8e62c +size 22387 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png index c1f55034ec..d2d67db632 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94878580a4ffff7c4d437eba1c62184aa61435420d6c85488fefc53e33e1e150 -size 23497 +oid sha256:99d101dae150cf33fa9a2c5782ae18811c6238d74b35c27e54227bff1e32b28b +size 23390 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png index a960bff528..8b7f161b7e 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:31cee1e647c74c67740320180af54509e466ad162ed56894695b038ccbe35103 -size 24017 +oid sha256:867ca4eacdbd56ea23d2b3ac619159a46fcb1670ab9a63f433cb7e44c8ceac63 +size 23910 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png index fc8aeb2409..bc0bf3ca43 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bdca1cc8a99976a8c4a297192650a496a4347dc27c73d1950f693be1cf2cabf -size 22005 +oid sha256:c0bb15955a7bb7ce2fecfc8227ece62c31021a3af3311bb9234d4d468a3384d8 +size 21850 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png index aa2b293c3b..de02c4d9bf 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:604243eb5409e170a760cda08fca1662b7694c6920f7b18da8d4c4f9d60ffe9a -size 22915 +oid sha256:b1b70aeb18d6e3e6d8d61081135dd015fb8d6a88fa4129605541097b4274cdb0 +size 22747 diff --git a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png index 1f6dce1201..8b2c3b9bfa 100644 --- a/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.login.impl.screens.chooseaccountprovider_ChooseAccountProviderView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d3bb32677abc81ffcb892839c5609f27637a9ea8081460d3f95751a03f125aa -size 23426 +oid sha256:403b8e7c3488f0edbfd53afba758b3cda0638f80167c1a84ea46b75100b8a4be +size 23264 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png index 8edee63bc1..3192cf2a5e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de82970da241172b94f822f8792e6fc721dcfc7f0f67e3523962e253e9750884 -size 255933 +oid sha256:1885bbe8b0ea497ac20d7bcdd0c6a93ba0533e898378d35e1cafdc8c9924fd56 +size 279984 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png index ccfdd7d9ed..f899ad5d43 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.attachments.preview.imageeditor_AttachmentImageEditorView_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe6cb72de5079be2ac02ec39f74bac0d20492cd6f5509b71ad9cfc4cc52955d3 -size 326468 +oid sha256:1ca032575e4ebd75a2ebc5a4cb9f966e48cdfa56f4ff42d6d9309fa3577a1adb +size 310609 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png index 5f51b27f5e..693a36b7dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3274314ab9e39c23a6b9d66adf80ac8bb7b364ce60a300f96582374a18bc821f -size 54590 +oid sha256:3dbb8ef39b6a7a0c2f576d8bd101aa97c89da696f23e6d5836846494471c01a1 +size 55799 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png index e1f6ee6430..b1850a50a5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e27c7c51fe07cca51b92a601aa9c58deab609bfa5e82f8f6f88eaab6ae59ec3 -size 64307 +oid sha256:f1dd0da147212e13a6c0ad5ad8f85ce55666c444076c238ea27eba5605cfab1f +size 56909 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png index 5289eaca63..4185f46b51 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65f9ee083a73669a0d3f9d88141a610ea53f3c39e89d8f706d414b04555b4764 -size 59321 +oid sha256:085963fcb425147d35a9ad947a7a3e4ba4712bd3d2f32e93099ff15cffe83b88 +size 64761 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png index d3f7da6320..2e70435fa5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a94a4cc176b5d52ef9b21339749324adeef9857b6cdaa2ae973903e2408662a -size 55904 +oid sha256:7a3667390d9d88894bbdd5d72b0b714b29c9ff160653e310e97b0da87b6ba8b0 +size 54724 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png index bd3b0196d6..0f6de1b844 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f7f7415abbe51858f938e16ad03c6aab983fb3d5e2a53a028bae3c031446646 -size 67848 +oid sha256:28512b0fda0b71b98eab03cee15c9d3163825b1a3545670cfa277ddd5434c87a +size 58417 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png index f4d51ccc61..6c774d4cec 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.identity_MessagesViewWithIdentityChange_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a8f5aaaa7ebb0e61b07867590d99a8791c5d04cad1ce0f334d23dce6f26c6e6 -size 67276 +oid sha256:6ed6a5f1a2055e19a6b8fb0af4738845bd2184f755c323022c52154cdfa07e05 +size 60909 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png index bd73e322ab..02d0fc8eeb 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 -size 3657 +oid sha256:f77d8243c23d3f37dff86dec53671cbde9fafe1314f6e6b445abdfe47d751ad6 +size 56187 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png index 93622cedfe..bd73e322ab 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87193a7c9eb9d40234970e5f5be02e80f2b3ffe91e2c9ca6afd58b8bccdd5911 -size 55075 +oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 +size 3657 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png index bd73e322ab..0cf6c10c4e 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 -size 3657 +oid sha256:49f0bb16d3d57b59242e704e3dd4e8885c59721a42129837ff6a4f0d7d02de11 +size 54433 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png index bd73e322ab..adec213a8c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.crypto.sendfailure.resolve_ResolveVerifiedUserSendFailureView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12020ba97720f2374f9ace172693f08be01522e4ca30d3970efa91d802581e81 -size 3657 +oid sha256:8ebee4aec3dbab6e1bb05fda7c5e423f0e931560743d0f0ccbac6b70fa9ad808 +size 52921 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png index 0ab00359b7..12bd190dd1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b5e6f4c5ec97e67bb20f03f25f18d9f32d5d1aed5ff30d161b331894ad03443 -size 647384 +oid sha256:ce15ca9f89274620728715e3448ce671e2253f4fed22a44035460e9a3709ca0b +size 647404 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png index 0ccdcbb603..160d58f9ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components.event_ATimelineItemEventRow_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0424685437a433b35b589668b409d55f26ab41bcae01af0121a54033c56a8c2 -size 646194 +oid sha256:c4e7b28b78cfbcbb6abf00317eea945859ac6465cecf81a3ad15801b0de721e4 +size 646216 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png index ab6392a424..0435f55de6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94f89a37549a3f198442db467bc7d8539f0b5649d97927bfe731f090d6dfb03d -size 379505 +oid sha256:ff839731834d7d0c94fa9a2c412014ddbaeaa053c5af1c8cbd00a3f3a583f364 +size 379511 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png index f0b5506b89..9cbd5c1d95 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowDisambiguated_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:04ea6c2947a21d3d4a3d43e9c4750c4f2a49056536a4da3f34c95df8353e9de3 -size 377990 +oid sha256:d0e170b4bea262de612bf3374d475fcd25470ff91b7554d20809c51857a78cec +size 377963 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png index 3ac59caeea..1f0fdabe6d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a94d5198e27338675c0e15df5874ba3272ee315b8d77291dc7ccc7c754ed1f4 -size 365082 +oid sha256:b8bb5a6de6601da8d7fe59f110a054577e2e25dae4bb449f60c04e7d7a1b9551 +size 365073 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png index 195aa04fe2..86018764ac 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:76e5ae44362792d570cd82f3910c8bd0acde509b8418c5892e0385e7d636f042 -size 370223 +oid sha256:8344427a0fe87cbf0883ff53a9ee4dcf90976a7011f6618d85961df48b2c53a9 +size 370228 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png index 29771235f0..058a3992c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60b9f2b920cd2a2a414805d1f0f77925232d9ae60bd607fa18d4395cda2dd73d -size 363291 +oid sha256:00fe1e676086766a3eac3e4457eff52c989789fc5d8d0df2624c019ed25ce9af +size 363322 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png index db4ea8296a..c6d4541184 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyInformative_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f0d24b8011564ee7a8b2f8c2e6a24eda668ee42d451d862f884acb7926aa06c -size 368529 +oid sha256:c00e504593d8eb61b598f05f46ee4d591757975a80c0b4227b240847d2cd4868 +size 368510 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png index 94428abb56..84d9d4e5c3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36d7cf2510d546d2b330b1d1b1674ce58df0558c547e443794a1e7b2222add87 -size 347897 +oid sha256:7c609a633ab23eae5729ecb57a17a385bac65e81cbf0180c01e0847f1028039e +size 347890 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png index 5400a98a50..40fa5d563f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:40a23ddff1fe46a486a5d34d94e0e67ec14d0b2b9c6bee2ddbadc17ce0948b7b -size 367131 +oid sha256:3ff97eb99daf65f74b469d51b93bd77d304d0c780b9406e1c4d7893b71e3c68d +size 367163 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png index 22ff4965d1..bac23aab98 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:787151f8f242a8794a804bf14831f6ca680814d617e85feb3652103e8a0f20cd -size 346565 +oid sha256:e30686c7c037ef102717e0316543faf4d3ed2671c21eca96a667150daab380d6 +size 346614 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png index c3b6a086fe..2348755afd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReplyOther_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e615c14cd23f3efd217ec20ce05ed32be76dc3317091e8221f1a72a5a594d92 -size 364175 +oid sha256:e907f67ef884edb61df187f0f229ed4ff4cb31f8c276f807698f861c0e7a4c27 +size 364124 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png index 67490ba700..01d4dca84b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4431e2d9f30123949ea5676ce60f642234adcf9b5a33f2acc3f80ebf6609a66 -size 369730 +oid sha256:ef2bf449671b652cb152b3baab92ab100eab77a54229ab49daeab156f2f484d0 +size 369724 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png index 1600afff71..f0dfbc3321 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:273351cc9c533b2424859a0de00a8a3786628abc3a88175705c4205dedf7e9aa -size 354737 +oid sha256:f7a6302320bd1e4258e03487539bf46b0b12781dfc8a22b3f9f267017a6146fa +size 354751 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png index c4943b892c..e38cf03ad6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c410e853089cc2c4a2c48a00dd9a8babc8095aed72bb4625057444710559c6c -size 368129 +oid sha256:41a0e404dea7f52359b24b3ec3926b1405429b165cfed44c63b3922ea6d3cb46 +size 368114 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png index b5dac8434c..68f8148879 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a92f8af94682facac66d4aacb6e49f345561c15be2f8b689041b78aeaaae831 -size 345062 +oid sha256:6ca8cf82aa8ab1bdad56a27584b27789402aeb7ad8fadd038280a376fb75a72c +size 345094 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png index 1b99468924..8aa2cca147 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a9509411777f342261cab58b92a022b3c9f8f0f7a9e4d0527120a91976575f0 -size 357733 +oid sha256:02ecb903124273e24151ea2088f6b99144f7dcadba00a582b6210dd23835b5c9 +size 357743 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png index cececc229a..b5032c29b3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0c6dafaa41849af00d5097a85bd88e3a054a0a9e41c0466a08e6ff8dd6102b2 -size 356857 +oid sha256:dce23463c335d01eb67293cfcede5d85e96ab2ba035cc9a188d42e8e6866bc63 +size 356831 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png index 14a40a5676..a332744358 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a11044fe90227f1f316a1ade8587e545bb620e11cca76865fc2eb83cdb817fc5 -size 364655 +oid sha256:588967869cbd25ed8b82aff5618175660a8a9e45a5a861b1c7867cf1913f575b +size 364646 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png index d7b969fd5b..133fd3903f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2528df873713755f542f61cd794080929586c1bd5f316c0378ce9e837c21d50b -size 397145 +oid sha256:426d1c844a8c88281c5fa4c61916d93278fdfd38f8cdf2dc54bf1a821f2de3eb +size 397167 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png index 63bd9c3f6d..0041a870b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6cd94664f89bdad2a9761ea8b20acb83fed3ed7cb5be41af8fe4852643c0bfc -size 356175 +oid sha256:a2bd77c08be705c66225f16c29fd6826decd92b41922d0f8ffc0d1a63d8c59d2 +size 356193 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png index 9fcf389708..f67906a37c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9daeee1aaa04247da3c8bb5aaae9947aab1ed2d2057995e53d6ebdb63e5cd356 -size 355848 +oid sha256:ffa68c8398d789444151855496e5df4ffa03218a383db6ea46fd4f979829b823 +size 355831 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png index d235670def..6e83d6491d 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a00bd766a00b7e7c6615fc53bf469b3ca5056a6c514c096431ae38d99d604306 -size 364845 +oid sha256:34152c742abc486a48234e22101833bc163cf11979890d06aac41e68e3c404d0 +size 364846 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png index 0021619c44..b10f9741b9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b23d3a37774283067a8919b8c332b1bb5a79e90dceb7216b484b985491282e5 -size 355389 +oid sha256:3ec1b0244dab22414c6719b3309426e13128d0c70fb67dc66cd8a60d42521fd0 +size 355411 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png index 422c324695..77abe20982 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1df8d22766981fc76d6d767dc3f40d98cadc7c51be20417b067b91af604232b -size 367884 +oid sha256:5c3d87862c6d7fc88d0f23cd54c5b9f77028992fdd7c282a195b964dd17e85ac +size 367855 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png index 448bcec677..1d34761a9b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe0daf9161bc2da194992a2fc9505bf2009c5dbed78cdb35d2eb7ed1380a7df5 -size 353037 +oid sha256:f7d9b5fc0ff5d7828ad6f4dc0c9bd9520b4920553da97ed7b4e030ee844c0208 +size 353054 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png index c081fa16a5..5243218ae3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a92bcf5885322e11a706071969fb674b1f6e60e021af153aaa125baa4a602ae -size 366285 +oid sha256:9a85db2f5958db867578663533f204b2e803372d470da890fd8056ffed0cf46c +size 366254 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png index 47a9a6b630..b6d1f07279 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:54372845e922d047408dd960d048b9b5eae2263d589117d8e7d197741aa34f32 -size 342827 +oid sha256:4bee12a6bdb18fea5ac6997671bfcb903296da7278cf69b2456330066ca31dfb +size 342870 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png index 5560c21967..ceca184bd7 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af4a48ee80535f2c0a226c4ffa4344054fb63b7b0a88ea2c030a4eb8dd5e9644 -size 356078 +oid sha256:8e82011a72f36889c53ab61ed2b9947c7fb5f868c9b7010904fc10f4ca587082 +size 356082 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png index 5cc5cfe4fc..5cdad1df92 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6524cc87257cc9d3f135904f4e14594b56df695e71fe576418d2319c472d710b -size 355285 +oid sha256:9e2d8caf5aaae7d3406c703288e491f328552f0acd18e56afd5265b4ceaf1cd1 +size 355272 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png index e9d85990e8..a431a9429a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66d4b6ea4a697735bbb0fac936b89cde99c5077973ba828894bf50b5dae233b3 -size 362848 +oid sha256:93c2df04d65f6078ce3f7067fbae8a7317ec42ed0fc013dee962a3953269f3b7 +size 362813 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png index b51a89586b..0eb106f4a9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e642229c58169775fe702769a306bbef22698516ae6f7ac75a761213c3f195fa -size 395446 +oid sha256:217ac95bf476c53d2dc6d3d0143b21312bf38b8ab86c8dfd4f9360582b584f9d +size 395476 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png index aa322fc2e4..ae8495618a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5fae87094ea13b14e2dc7c16ca96e4f8096ff39e962799468fb4ead4c666620f -size 354381 +oid sha256:08057fdc1e1184720b438ddd2a8753f00791baf2456cc30b45de8e6bdeb57e8e +size 354404 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png index 40105c1498..9d617f6688 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ed24d190f10c079f8cf176404372d40eb25cc78ce595a22febc540315057b86 -size 354075 +oid sha256:dabad9dcd5b8f0d4bb964a0187ad7c94b023b04552dacd29a077daddfd48d550 +size 354052 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png index 0cfd1dc985..1a8ea3e4e9 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:545c9e8933e420cc3f8fbba0fbd5162c946c65a20721faeb77c568596ca720cd -size 363045 +oid sha256:66aba7b4271a990fac85b0bbc7cbdc371fa1e38a4da5bb4e2f62a80b21cb3a8f +size 363012 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png index c9227ebf94..c8306263a0 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_TimelineItemEventRowWithReply_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e614f4a8657637c584a283d69124236d00fe1251c2b8d739c5688a57a6fd152e -size 353693 +oid sha256:756f0cff90ddd61adce2f467c0384d74d430f6d51c091e4980e45bcc9ee6f0fd +size 353705 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png index 7a5e5e1512..144411969f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e3467a7606a5a7beaafb510faf008ed567b1e3a9915ede6e2ec09c491af0bb9 -size 56552 +oid sha256:84415250503d5e586af7b7504aaa915c1e24dec0a3d28446487c474c354e05c9 +size 55534 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png index 843adcdff0..52e023ec49 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:446ae29cbb211665f6d91129a7dee0f718b407fcb2a64d3f2c0e962e1cb47af7 -size 50168 +oid sha256:c8420417cf8ba717747dead34b9646515f35eb94e1f71aa952b77c3ff433043e +size 49684 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png index ee23a7111d..adabb6dde5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38ae233a128e887efc48da73be3d6ce50a7095601315ed49a3c9cb209ffdda26 -size 58352 +oid sha256:9b071ba6e99b68dcc75f5aaed3a879f2e30614c954b88c6dc05e1dfec57f1079 +size 65771 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png index 2a5991cf59..6c2a7e8460 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:115c725873fb206d8f732a8297a6548ba4fa45d7328196b79a2d9e35545de7d5 -size 40347 +oid sha256:984536295516b542ec6aecf7d07baa3c6dfebbc66403b6d4258a6217616cec93 +size 39991 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png index 7ce91f4684..a1dc68a3d5 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b749e1260d6ba2b7fef5ae9efd58612f6d67d1788f6c1e5cebc22d58d0fd7b7 -size 58563 +oid sha256:871d92a7565dd233ea87d53658be4e5202775def8e17fea8d386b8975c3b065e +size 53868 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png index f6456f0ec1..479d07ae5f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22153168f6f3e84ab789faea29c94fffbc1a5e4c1b9a98deccb0460192fdde23 -size 57213 +oid sha256:0d4f03ac10bbb676d272dba906e758b25d633a1da1e249fe23ba825f8d2f4901 +size 55298 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png index 6a3ffb84b6..c90dc8d08f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:48b91e52306daa750b4b5792535e1f1865ae3b74a36215376a51dafdd0dcd506 -size 54837 +oid sha256:e48a364a28a67d7d090faa23ef88b27dbd47f0a2f552857490728cb6952ce08b +size 53454 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png index abf8eb7086..6c0a7b4edc 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e79e1cc59ba62ca8eb99300eb520b05d7ac6d52c077e3010c03b474865b15f4 -size 58374 +oid sha256:f5aa22c3d79a392625ae231abc046f07f7cdabd91613d5e6f07aede5382aba9b +size 60410 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png index 5d4f5bdaeb..ac1d94a4dd 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08fb14008b08d86755c3473e7194ef0a39bb73c3f0d48122ca80c6a019ec98eb -size 48676 +oid sha256:be5b086ab6934bae88b39987bc51e709c5adb81bdd04fa028e97832c725fd68a +size 50219 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png index b3af9d831a..2209fcb54f 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce795c4e32a1be3d57f6b1c87588d8c7ed0442996ab9d8a96f1ec5a07627e598 -size 59663 +oid sha256:bd0de7412503e93c33cf92dde0cff38bb68555ef176080d913320af5e4942e7a +size 58642 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png index 2c88d322d4..82ef5e7d6a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:963fcec9647d0e5e57bd3fbe3edd389c17be7558c1da7e93fa44f34db34307ee -size 57726 +oid sha256:41c4bd5cd1bcbedd91de0a64967fb3f3e03b5f0937ae1ea1a93a7c4a1b24a4a0 +size 56262 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png index 281aad62a7..135d84dd90 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85f6f4c64f67faa99b9af65307a0cd3b46a68db52503c9c929375408597995d9 -size 62094 +oid sha256:4ff538a81d013fdc90dd7be466f710088eea93e081d23448b0731d301a4a3bb2 +size 60702 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png index cfa6e4dbc3..89fc6708d2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a3281f35461edb900ea434c68543dc684a5fad7dab7c9aabac510bc59d442b3 -size 56479 +oid sha256:89467c5b84d0a15210d4013013598d9994d3005a2299e44583d78355e6718ad8 +size 55538 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png index 5f3a619097..17df34a50a 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19d14e3d779b163053c28e66d3381f0cabe3b540744606e955cd733f9e044089 -size 51713 +oid sha256:6548f5bf1906e1dddcbcc03bb8f76b42e604075751ea8efbc3ead826bf4cfad7 +size 51258 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png index 6e8468054f..b3109663f2 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:262e8d4b8daa2d25593834fd0ab5d7019b0a3dd13707aa96e0701bf9240c6525 -size 59809 +oid sha256:10bce6df962a5198f019f509b1cdb55e28195587de4b74742ddc29833f1333a4 +size 69216 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png index b32ee34f99..1ff5ace3e3 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bde66c53d81f882cde9ed527e8ff82c7e9d6cb1199b440d4b721659f7189bb42 -size 38906 +oid sha256:8d875f83a3a1977e2a2cf151dcf9d731108a8590eb3643eb057727421eb1e955 +size 38812 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png index f4ab74029b..f425dd2c4c 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:51a5b682243b969bc2d7d609decb823b0509d240f3ff14ee78319260af76a47f -size 58740 +oid sha256:bd6dc088e16f722b36c2198d6a8611af87dec2451f94ca3c2b6880b97f709b98 +size 54095 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png index 3974618f39..b0cd5bc6d4 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:718d5c9f24c114f3bf88e000b637ea19598d7bb9b97001ba137fc12a6a1285e4 -size 52608 +oid sha256:5e900ff75d02c9db4200e2032444dd7e2f8635973cca3389dd96d7d2bb734061 +size 50757 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png index 0ad1e67deb..486d5da5c6 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82e6e38576a507b19e58fce9dda0734ec00bcedcb0baf8f4c7919dbaaf7d2b85 -size 55046 +oid sha256:e482603e6d03fffb57d4eb135edb6209c748c51b1f07e638a4ccf133b1b87a79 +size 52920 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png index a009d0f584..5a877a59e1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:478851e9e2e8c80095aa552b98a5d574749200ff49899c9472c913b07459c4b5 -size 53758 +oid sha256:5a582219d3143acb08563193bf7106e1ee8f6612e359d0a192e9a2f67c6799e3 +size 55375 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png index f82a7a8219..0383bb8f95 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22ea7fe121a63b35a2c2bb47609e692f8bf2b913871a6baf3d420c04334c6c4a -size 44344 +oid sha256:7c88b3ed8cc69dee59d4d0a726a9e383d00f2815b6525315f7dcd96f9c25ec2a +size 45618 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png index 7261c9b671..952751a962 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cf3d727da78b39ecf24d4df7db0884af9008db67cc92274849c1b0978f87726 -size 59252 +oid sha256:ed13a2778b8ced86ee41d5460d274b42b714a87f59749e3b26bf75114ef40dd9 +size 58265 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png index cfa62a6626..0f7fe2db38 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfe848e4c365cf4b4d663145f74e5f8b3f47a4c8994961c530603f0248400316 -size 57117 +oid sha256:a576d52b840730334a38046cf8b57993693fc760b4fbdc00376cb48b7268d76e +size 55890 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png index 89065e6bf0..4d6afdbbb1 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a966c9a1fa4fdd933f4ef9239592e90458a2819ff4a45c857714d2e38c0df5b2 -size 64405 +oid sha256:35069d4fae829d9afe479308dd72ad025fa011290d23133a231f4e70f601ee75 +size 62987 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png index 7cca911c45..074820e157 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 -size 52770 +oid sha256:7caacb336793b8ae4b83e9a10a82325e25e8b3c036f881898ed28688250eb6e0 +size 55744 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png index 2af459c158..7cca911c45 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28a95d4b7ebca92c4e0467f3ecd9acdaf7f6257604d190f5d088a9a25e87d637 -size 55305 +oid sha256:26e14b77fa3c3aeaea58782309e6de8b9047e07945009322990ebf5f4c283309 +size 52770 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png index 616c06bf46..a68f886f73 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ce2519906f1aaf34700ca9ba4bdeaa72030f1f5aff3f7e24352a1435ac67d98 -size 53966 +oid sha256:e5a2e306087a967849f61872b56a83f194d1a76df5723f0bbae6e6e2f4a98c63 +size 55725 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png index 616c06bf46..36d19c6b72 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.blockedusers_BlockedUsersView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ce2519906f1aaf34700ca9ba4bdeaa72030f1f5aff3f7e24352a1435ac67d98 -size 53966 +oid sha256:7dfa2767c55a81d3f121b8fa55443b7b05f9369e91639b80e0be349863799ad7 +size 55438 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_5_en.png index 82f344f714..2c15fd6a37 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d96eefa01a5de803b0cc9d9109c20df86eaff01b73ff24a91945b43d53d5d01 -size 11960 +oid sha256:7260abe16fc2ab4f6ada97ea0f756dc5c9908ff3b61d6ec1723ffde302bb3dc5 +size 11955 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_6_en.png index fdd8fcd5a5..7c422591ad 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22678a2a8505e1d9d5bfcb44459b6fac69c11a4bf72fae09c48ffa2e54f5a110 -size 12128 +oid sha256:2e16fc1daa0f284c442f66591e1d1f59161272a67998d26740b0b403bfe82495 +size 11866 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_5_en.png index f6e27475da..acb8afa74a 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ee89826c8aa2ac0371ed31959243f62bf9968806a7b27117cd7b4d849423a33 -size 11667 +oid sha256:bed7565420e11c43acc06896ef298683d2f2dd1dc16c430eab7018e9ead9937a +size 11652 diff --git a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_6_en.png index b1bb69efb8..e0a4cb1c97 100644 --- a/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.preferences.impl.userstatus_UserStatusView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e27cb9e501ccbac54926f0252b4098867643a2d2683c5b267f86ad99edf6f5d7 -size 11817 +oid sha256:87811df502c760816e74beb006341627857c39380ce715f1a747ac9fce77b226 +size 11516 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png index 73b8b8e50c..5c597300e4 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e8a3ad99763929d2783147814e44fa9ec7e7efb7b99949e3580f23c38fb5d971 -size 9398 +oid sha256:21aee17ee9a292bb2f0d3d2ec2db565ebb8d5df753454a5a002f033ed5ed39c5 +size 3853 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png index 5c597300e4..f8a1f24b34 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:21aee17ee9a292bb2f0d3d2ec2db565ebb8d5df753454a5a002f033ed5ed39c5 -size 3853 +oid sha256:1342b6427f5b2e3075ae3ccee60bf1d3b11afaccf3e152643d6ef2d65c21b54e +size 9108 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png index d47bf90664..4ae7279fe7 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:520cae2544153ba45f8fe4b021286c2d22da06aa1b60be7f1b13879723ff994c -size 3664 +oid sha256:410a8596d4c70b9a3856d959d6d71ade8e831e8581ff410c9900957a93b3eb50 +size 8114 diff --git a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png index a87d89c701..d47bf90664 100644 --- a/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.roommembermoderation.impl_RoomMemberModerationView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f3a0cb5d9bae6725a1c527f3d9575aabf85d3edf63a28d9faa23f4f0b65e2d0 -size 7624 +oid sha256:520cae2544153ba45f8fe4b021286c2d22da06aa1b60be7f1b13879723ff994c +size 3664 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png index ee5c582240..58546b8522 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75de341f705bb22955f9399180519b65ad59c2e1917317d56e50ea4db78f35bc -size 12102 +oid sha256:30357bf18792db5ab20085010251170a724ffe8c00313facd04ee704e806af64 +size 10982 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png index 52fd9b9693..fedead0fa8 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbarNoFab_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58b9491aaa5554b89d86c62a5c9c44975367538c6baa5562f8dc5768f76d8264 -size 8705 +oid sha256:4811667dec0f32accc5e2c8a5dd5c0b34017fcff8d1e0376ee7a4708426bca0f +size 9838 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png index 38ad0e4b56..83302d6ba4 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:326d59cf768b2dbd96eb7964d54c8eda509a5cd57c6e62087625e3314da0bb4d -size 13658 +oid sha256:16dee1dfe746cd40dac9fe8f0af3ecb42cd14bab5cc490917b589beed065ed1b +size 14686 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png index 687e0d436a..4da2a98aca 100644 --- a/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.theme.components_HorizontalFloatingToolbar_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d57df7110371c9224e232b707d6a1b10ce14afcb56c803a78220792f2a0d4cf2 -size 11354 +oid sha256:ef0dc4d53daeb986f378b6e4d85928b4b6729336c89cf21e642c88c53688a3ab +size 10292 From 3d198d8065030820f0ad2ed06fff65d6928112f3 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 14 Sep 2026 15:19:14 +0200 Subject: [PATCH 06/17] Fix flaky test in `TimelinePresenterTest` (#7702) The problem seemed to be sometimes the background work to switch from live timeline to a focused event timeline wasn't finished in time and an assertion failed from time to time. By providing the coroutine to run this on we can pass a `TestScope` and force it to reliably run immediately instead in unit tests. --- .../features/messages/impl/MessagesNode.kt | 9 +++- .../impl/threads/ThreadedMessagesNode.kt | 9 +++- .../impl/timeline/TimelineController.kt | 8 +++- .../messages/impl/MessagesPresenterTest.kt | 7 ++- ...essageComposerPresenterSlashCommandTest.kt | 8 +++- .../MessageComposerPresenterTest.kt | 8 +++- .../impl/timeline/TimelineControllerTest.kt | 43 +++++++++++++++---- .../impl/timeline/TimelinePresenterTest.kt | 13 +++++- 8 files changed, 87 insertions(+), 18 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 97d3465ce7..e0213f2fb5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -51,6 +51,7 @@ import io.element.android.libraries.androidutils.system.toast 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.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.annotations.ApplicationContext @@ -103,6 +104,7 @@ class MessagesNode( private val roomMemberModerationRenderer: RoomMemberModerationRenderer, private val eventContentValidationCache: EventContentValidationCache, private val emojiPickerRenderer: EmojiPickerRenderer, + private val dispatchers: CoroutineDispatchers, ) : Node(buildContext, plugins = plugins), MessagesNavigator { data class Inputs( val focusedEventId: EventId?, @@ -111,7 +113,12 @@ class MessagesNode( private val inputs = inputs() private val callback: Callback = callback() - private val timelineController = TimelineController(room, room.liveTimeline) + private val timelineController = TimelineController( + room = room, + liveTimeline = room.liveTimeline, + roomCoroutineScope = room.roomCoroutineScope, + dispatchers = dispatchers, + ) private val presenter = presenterFactory.create( navigator = this, composerPresenter = messageComposerPresenterFactory.create(timelineController, this, threadRoot = null), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt index cf3c701015..b5542ec4be 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/threads/ThreadedMessagesNode.kt @@ -54,6 +54,7 @@ import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.di.RoomScope import io.element.android.libraries.emoji.api.picker.EmojiPickerRenderer @@ -95,6 +96,7 @@ class ThreadedMessagesNode( private val appNavigationStateService: AppNavigationStateService, private val roomMemberModerationRenderer: RoomMemberModerationRenderer, private val emojiPickerRenderer: EmojiPickerRenderer, + private val dispatchers: CoroutineDispatchers, ) : Node(buildContext, plugins = plugins), MessagesNavigator { data class Inputs( val threadRootEventId: ThreadId, @@ -113,7 +115,12 @@ class ThreadedMessagesNode( */ private suspend fun createPresenter(): Presenter { val threadedTimeline = room.createTimeline(CreateTimelineParams.Threaded(threadRootEventId = inputs.threadRootEventId)).getOrThrow() - val timelineController = TimelineController(room, threadedTimeline) + val timelineController = TimelineController( + room, + liveTimeline = threadedTimeline, + roomCoroutineScope = room.roomCoroutineScope, + dispatchers = dispatchers, + ) this.timelineController = timelineController return presenterFactory.create( navigator = this, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt index e41ac7bee7..05f7a06054 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineController.kt @@ -12,7 +12,10 @@ import dev.zacsweers.metro.ContributesBinding import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.binding import io.element.android.features.messages.impl.timeline.di.LiveTimeline +import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.di.annotations.RoomCoroutineScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.room.CreateTimelineParams @@ -23,7 +26,6 @@ import io.element.android.libraries.matrix.api.timeline.TimelineProvider import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -47,8 +49,10 @@ import java.util.Optional class TimelineController( private val room: JoinedRoom, @LiveTimeline private val liveTimeline: Timeline, + @RoomCoroutineScope private val roomCoroutineScope: CoroutineScope, + dispatchers: CoroutineDispatchers, ) : Closeable, TimelineProvider { - private val coroutineScope = CoroutineScope(SupervisorJob()) + private val coroutineScope = roomCoroutineScope.childScope(dispatchers.computation, "TimelineController") private val liveTimelineFlow = flowOf(liveTimeline) private val detachedTimelineFlow = MutableStateFlow>(Optional.empty()) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 4c0abc0a34..949443f1f7 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -1484,7 +1484,12 @@ class MessagesPresenterTest { clipboardHelper = clipboardHelper, htmlConverterProvider = FakeHtmlConverterProvider(), buildMeta = aBuildMeta(), - timelineController = TimelineController(joinedRoom, timeline), + timelineController = TimelineController( + room = joinedRoom, + liveTimeline = timeline, + roomCoroutineScope = backgroundScope, + dispatchers = coroutineDispatchers, + ), permalinkParser = permalinkParser, analyticsService = analyticsService, encryptionService = encryptionService, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt index faf0bbe6ed..a8f6c338f5 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterSlashCommandTest.kt @@ -65,6 +65,7 @@ import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.test +import io.element.android.tests.testutils.testCoroutineDispatchers import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -307,7 +308,12 @@ class MessageComposerPresenterSlashCommandTest { permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionPresenter), permalinkParser = permalinkParser, permalinkBuilder = permalinkBuilder, - timelineController = TimelineController(room, timeline), + timelineController = TimelineController( + room = room, + liveTimeline = timeline, + roomCoroutineScope = backgroundScope, + dispatchers = testCoroutineDispatchers(), + ), draftService = draftService, mentionSpanProvider = mentionSpanProvider, pillificationHelper = textPillificationHelper, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index 4170ae41ab..6744cdebbb 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -113,6 +113,7 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.robolectric.RobolectricTest import io.element.android.tests.testutils.test +import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.waitForPredicate import io.mockk.mockk import kotlinx.collections.immutable.ImmutableList @@ -1707,7 +1708,12 @@ class MessageComposerPresenterTest : RobolectricTest() { permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionPresenter), permalinkParser = permalinkParser, permalinkBuilder = permalinkBuilder, - timelineController = TimelineController(room, timeline), + timelineController = TimelineController( + room = room, + liveTimeline = timeline, + roomCoroutineScope = backgroundScope, + dispatchers = testCoroutineDispatchers(), + ), draftService = draftService, mentionSpanProvider = mentionSpanProvider, pillificationHelper = textPillificationHelper, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt index bc36766bac..d00062ba6b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineControllerTest.kt @@ -21,8 +21,10 @@ import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder +import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test @@ -35,7 +37,10 @@ class TimelineControllerTest { liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { awaitItem().also { state -> @@ -74,7 +79,10 @@ class TimelineControllerTest { } } ) - val sut = TimelineController(joinedRoom, liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { awaitItem().also { state -> @@ -102,7 +110,10 @@ class TimelineControllerTest { val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { awaitItem().also { state -> assertThat(state).isEqualTo(liveTimeline) @@ -121,7 +132,10 @@ class TimelineControllerTest { liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { awaitItem().also { state -> assertThat(state).isEqualTo(liveTimeline) @@ -149,7 +163,10 @@ class TimelineControllerTest { val joinedRoom = FakeJoinedRoom( liveTimeline = liveTimeline ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) assertThat(sut.timelineItems().first()).hasSize(1) } @@ -171,7 +188,10 @@ class TimelineControllerTest { liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { sut.focusOnEvent(AN_EVENT_ID, null) awaitItem().also { state -> @@ -196,7 +216,10 @@ class TimelineControllerTest { liveTimeline = liveTimeline, createTimelineResult = { Result.success(detachedTimeline) } ) - val sut = TimelineController(room = joinedRoom, liveTimeline = liveTimeline) + val sut = createTimelineController( + room = joinedRoom, + liveTimeline = liveTimeline, + ) sut.activeTimelineFlow().test { awaitItem().also { state -> @@ -220,12 +243,14 @@ class TimelineControllerTest { } } -internal fun createTimelineController( +internal fun TestScope.createTimelineController( room: FakeJoinedRoom = FakeJoinedRoom(liveTimeline = FakeTimeline()), liveTimeline: Timeline = FakeTimeline(name = "live"), ): TimelineController { return TimelineController( room = room, - liveTimeline = liveTimeline + liveTimeline = liveTimeline, + roomCoroutineScope = backgroundScope, + dispatchers = testCoroutineDispatchers(), ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 290246ffb9..60f13f4ea8 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -1079,7 +1079,11 @@ class TimelinePresenterTest { val focusedState = consumeItemsUntilPredicate { it.focusRequestState == FocusRequestState.Success(AN_EVENT_ID) }.last() assertThat(focusedState.isLive).isFalse() initialState.eventSink.invoke(TimelineEvent.LoadMore(Timeline.PaginationDirection.FORWARDS)) - advanceUntilIdle() + + // Give some time for any potential pagination to be called, but it should not be called because the focused event is not rendered yet. + // Also, given enough time, a new state should be emitted with isLive = false, because we switched to a focused event timeline. + runCurrent() + assert(paginateLambda).isNeverCalled() assertThat(expectMostRecentItem().isLive).isFalse() } @@ -1906,7 +1910,12 @@ class TimelinePresenterTest { sendPollResponseAction = sendPollResponseAction, sessionPreferencesStore = sessionPreferencesStore, timelineItemIndexer = timelineItemIndexer, - timelineController = TimelineController(room, timeline), + timelineController = TimelineController( + room = room, + liveTimeline = timeline, + roomCoroutineScope = backgroundScope, + dispatchers = testCoroutineDispatchers(), + ), resolveVerifiedUserSendFailurePresenter = resolveVerifiedUserSendFailurePresenter, typingNotificationPresenter = { aTypingNotificationState() }, roomCallStatePresenter = { aStandByCallState() }, From f9a493ef0c1d9b847201f4f75ce4874d8882f098 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 14 Sep 2026 16:55:25 +0200 Subject: [PATCH 07/17] Add Kdoc on data class AccountProvider --- enterprise | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise b/enterprise index 72abbbf4e1..7f157d8fa2 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 72abbbf4e1b16c9079396245bca6a366fea40895 +Subproject commit 7f157d8fa2c77ad95f9c86f4cac20446c00cf2f3 From 84b6224e4dea5436be9fe5a43ad7443b58699ee8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 14 Sep 2026 17:18:18 +0200 Subject: [PATCH 08/17] Update ref --- enterprise | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise b/enterprise index 7f157d8fa2..0b2a44594f 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 7f157d8fa2c77ad95f9c86f4cac20446c00cf2f3 +Subproject commit 0b2a44594f22b49b42d77818981bb0d4ad68e11c From 600a989854dde728bf9d18ed49bacd5c155e2829 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 16:09:23 +0000 Subject: [PATCH 09/17] Update kotlinpoet to v2.4.0 (#7709) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6602dbdf14..29b0c0c171 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ android_gradle_plugin = "9.3.2" # When updating this, please also update the version in the file ./idea/kotlinc.xml kotlin = "2.4.10" -kotlinpoet = "2.3.0" +kotlinpoet = "2.4.0" ksp = "2.3.11" firebaseAppDistribution = "5.3.0" From f97dac2d5b488c580d111dd05605e8863d5e6fef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 14 Sep 2026 18:09:52 +0200 Subject: [PATCH 10/17] Update ref Point to the enterprise submodule rebased on main, which brings the X.509 feature, and resolves the MdmData conflict between the new UseX509 entry and the split of AccountProvider into AccountProviderServerName, AccountProviderManagedBaseUrl and AccountProviderManagedCanUseServerName. Co-Authored-By: Claude Opus 5 (1M context) --- enterprise | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise b/enterprise index 0b2a44594f..2f6b36a314 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 0b2a44594f22b49b42d77818981bb0d4ad68e11c +Subproject commit 2f6b36a3144229bedda773737ede1c0723388171 From 7aa43411e052d8606f309624af0f8e7f5c6a7d95 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Mon, 14 Sep 2026 18:14:46 +0200 Subject: [PATCH 11/17] Reduce parallel JVMs spawned for tests (#7701) * Set `maxParallelForks = 1` for most tests, except for screenshot ones It turns out the Robolectric setup penalty compounds the more parallel JVMs you spawn. Using 1 JVM vs 8 was up to 2.5x faster in local tests. * Split the roborazzi tests tasks config and CI step --- .github/workflows/tests.yml | 3 +++ build.gradle.kts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bbf8fdf811..4bb11596fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -78,6 +78,9 @@ jobs: - name: ⚙️ Run screenshot tests run: ./gradlew :tests:uitests:verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES + - name: ⚙️ Run Compound screenshot tests + run: ./gradlew :libraries:compound:verifyRoborazziDebug $CI_GRADLE_ARG_PROPERTIES + - name: ⚙️ Generate kover coverage report run: ./gradlew :koverXmlReportMerged :koverHtmlReportMerged :koverVerifyAll -x testDebugUnitTest $CI_GRADLE_ARG_PROPERTIES diff --git a/build.gradle.kts b/build.gradle.kts index 876383e325..725033a6ea 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -153,7 +153,10 @@ allprojects { maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) val isScreenshotTest = project.gradle.startParameter.taskNames.any { it.contains("paparazzi", ignoreCase = true) } + val isRoborazziTest = project.gradle.startParameter.taskNames.any { it.contains("roborazzi", ignoreCase = true) } if (isScreenshotTest) { + // Paparazzi tests benefit from parallelisation, so we can use half the available cores to run them in parallel. + maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) // Increase heap size for screenshot tests maxHeapSize = "2g" // Record all the languages? @@ -165,9 +168,22 @@ allprojects { exclude("translations/*.class") } } else { + // Robolectric and Compose pay a 5 to 30 seconds bootstrap cost per test JVM (instrumenting + // android-all, then warming up the Compose runtime). That cost is paid once per JVM and then + // amortised over every test class the JVM runs, so splitting a module across several forks + // re-pays it for each fork instead of saving time. Keep a single fork per module and let + // Gradle parallelise by running many modules' test tasks concurrently instead. + maxParallelForks = 1 + // Disable screenshot tests by default exclude("ui/*.class") exclude("translations/*.class") + if (isRoborazziTest.not()) { + // Roborazzi screenshot tests (:libraries:compound) live in a `screenshot` package, which + // the two patterns above do not match, so they used to run on every plain unit test run. + // They are verified by the dedicated `verifyRoborazziDebug` task instead. + exclude("**/screenshot/**") + } } } } From 5b0d7bf5a78106325704f6ee31396f975de3dad4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 14 Sep 2026 18:30:29 +0200 Subject: [PATCH 12/17] Log errors and fix quality issues --- enterprise | 2 +- .../login/impl/screens/onboarding/OnBoardingPresenter.kt | 4 +++- .../libraries/matrix/api/accountprovider/AccountProvider.kt | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/enterprise b/enterprise index 2f6b36a314..e4f10a779c 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit 2f6b36a3144229bedda773737ede1c0723388171 +Subproject commit e4f10a779c1c79feebc96477ad65b576b5d96eda diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt index c108aa1de0..84db4283b4 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/screens/onboarding/OnBoardingPresenter.kt @@ -34,6 +34,7 @@ import io.element.android.libraries.matrix.api.accountprovider.AccountProvider import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.ui.utils.MultipleTapToUnlock import kotlinx.coroutines.launch +import timber.log.Timber @AssistedInject class OnBoardingPresenter( @@ -83,7 +84,8 @@ class OnBoardingPresenter( try { defaultAccountProviderAccessControl.assertIsAllowedToConnectToAccountProvider(it) true - } catch (_: Exception) { + } catch (e: Exception) { + Timber.e(e, "Failed to check account provider from link, assuming not allowed") false } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt index 828676285a..9eb6912d26 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt @@ -31,6 +31,9 @@ sealed interface AccountProvider { }.sanitized() } + /** + * Return the server name, to be used in the UI. + */ fun friendlyServerName(): String { return when (this) { is Generic -> serverName From dc466f1f5cc5eada7df2c6b841acc60973e6703f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 05:09:14 +0000 Subject: [PATCH 13/17] Update roborazzi to v1.74.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2eea188edd..2b9a7392c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ accompanist = "0.37.3" # Test test_core = "1.7.0" -roborazzi = "1.73.0" +roborazzi = "1.74.0" # Jetbrain datetime = "0.8.0" From c92bf4bc4360bcd59755d160ebae0542bf60424b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Sep 2026 09:11:40 +0200 Subject: [PATCH 14/17] Sealed interface must be immutable when uses in Composable function parameters. --- .../libraries/matrix/api/accountprovider/AccountProvider.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt index 9eb6912d26..c2d103b3f2 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/accountprovider/AccountProvider.kt @@ -7,6 +7,9 @@ package io.element.android.libraries.matrix.api.accountprovider +import androidx.compose.runtime.Immutable + +@Immutable sealed interface AccountProvider { /** * An account provider that was input by the user. From fd315318a065d397d4edb63555899625b6901b55 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Sep 2026 09:15:38 +0200 Subject: [PATCH 15/17] Update ref to main branch. --- enterprise | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise b/enterprise index e4f10a779c..6b422f4c8e 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit e4f10a779c1c79feebc96477ad65b576b5d96eda +Subproject commit 6b422f4c8e9e9e5557056e8a861fe3bfd9338f24 From 3e861cc64645a286a5455e0b47032b1a25b2f49d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 15 Sep 2026 13:56:33 +0200 Subject: [PATCH 16/17] Do not report detekt LargeClass issues on test classes (#7713) detekt's default configuration excludes test source sets from `TooManyFunctions` and `StringLiteralDuplication`, but not from `LargeClass`, so large test classes were reported and had to carry a `@Suppress("LargeClass")` annotation. Add the same kind of exclusion to the `LargeClass` rule in `tools/detekt/detekt.yml` and remove the 24 now-redundant suppressions from test files. The two remaining suppressions are in production code, where the rule still applies. Co-authored-by: Claude Opus 5 (1M context) --- .../features/home/impl/roomlist/RoomListPresenterTest.kt | 1 - .../invitepeople/impl/DefaultInvitePeoplePresenterTest.kt | 1 - .../android/features/joinroom/impl/JoinRoomPresenterTest.kt | 1 - .../android/features/messages/impl/MessagesPresenterTest.kt | 1 - .../element/android/features/messages/impl/MessagesViewTest.kt | 1 - .../messages/impl/actionlist/ActionListPresenterTest.kt | 1 - .../impl/attachments/AttachmentsPreviewPresenterTest.kt | 1 - .../impl/messagecomposer/MessageComposerPresenterTest.kt | 1 - .../features/messages/impl/timeline/TimelinePresenterTest.kt | 1 - .../factories/event/TimelineItemContentMessageFactoryTest.kt | 1 - .../messages/impl/typing/TypingNotificationPresenterTest.kt | 1 - .../composer/DefaultVoiceMessageComposerPresenterTest.kt | 1 - .../impl/notifications/NotificationSettingsPresenterTest.kt | 1 - .../features/roomdetails/impl/RoomDetailsPresenterTest.kt | 1 - .../roomdetailsedit/impl/RoomDetailsEditPresenterTest.kt | 1 - .../impl/root/SecurityAndPrivacyPresenterTest.kt | 1 - .../impl/DefaultPinnedMessagesBannerFormatterTest.kt | 1 - .../eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt | 1 - .../eventformatter/impl/RtcNotificationContentFormatterTest.kt | 1 - .../matrix/ui/messages/reply/InReplyToMetadataKtTest.kt | 1 - .../mediaviewer/impl/datasource/EventItemFactoryTest.kt | 1 - .../mediaviewer/impl/viewer/MediaViewerPresenterTest.kt | 1 - .../impl/notifications/DefaultNotifiableEventResolverTest.kt | 1 - .../android/libraries/push/impl/push/DefaultPushHandlerTest.kt | 1 - tools/detekt/detekt.yml | 2 ++ 25 files changed, 2 insertions(+), 24 deletions(-) diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt index 9bc8719a8b..5245a164d1 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenterTest.kt @@ -91,7 +91,6 @@ import org.junit.Rule import org.junit.Test import kotlin.time.Duration.Companion.seconds -@Suppress("LargeClass") class RoomListPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt index 39cfc3afba..30d6eaf844 100644 --- a/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt +++ b/features/invitepeople/impl/src/test/kotlin/io/element/android/features/invitepeople/impl/DefaultInvitePeoplePresenterTest.kt @@ -59,7 +59,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -@Suppress("LargeClass") internal class DefaultInvitePeoplePresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt index 3c104e47ae..3edaf649e4 100644 --- a/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt +++ b/features/joinroom/impl/src/test/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenterTest.kt @@ -70,7 +70,6 @@ import org.junit.Rule import org.junit.Test import java.util.Optional -@Suppress("LargeClass") class JoinRoomPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt index 949443f1f7..78e9aba2d0 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesPresenterTest.kt @@ -125,7 +125,6 @@ import org.junit.Test import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -@Suppress("LargeClass") class MessagesPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt index f662da0eb0..677b2ac10b 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt @@ -90,7 +90,6 @@ import org.junit.Test import org.robolectric.annotation.Config import kotlin.time.Duration.Companion.milliseconds -@Suppress("LargeClass") class MessagesViewTest : RobolectricTest() { @Test fun `clicking on back invoke expected callback`() = runAndroidComposeUiTest { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt index e987a32480..66e57da1fa 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/actionlist/ActionListPresenterTest.kt @@ -54,7 +54,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -@Suppress("LargeClass") class ActionListPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt index 8370ec516f..c9f6aa9631 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/attachments/AttachmentsPreviewPresenterTest.kt @@ -82,7 +82,6 @@ import org.junit.Test import java.io.File import kotlin.io.path.createTempFile -@Suppress("LargeClass") class AttachmentsPreviewPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index 6744cdebbb..3253e6088d 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -127,7 +127,6 @@ import org.junit.Test import uniffi.wysiwyg_composer.MentionsState import java.io.File -@Suppress("LargeClass") class MessageComposerPresenterTest : RobolectricTest() { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 60f13f4ea8..aa4198d156 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -103,7 +103,6 @@ import java.util.Date import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -@Suppress("LargeClass") @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) class TimelinePresenterTest { @get:Rule diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt index 0c6c81a513..15b624aeff 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -83,7 +83,6 @@ import org.junit.Test import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes -@Suppress("LargeClass") class TimelineItemContentMessageFactoryTest : RobolectricTest() { @Test fun `test create OtherMessageType`() = runTest { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt index 62e596bc21..cdce1f2483 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/typing/TypingNotificationPresenterTest.kt @@ -30,7 +30,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test -@Suppress("LargeClass") class TypingNotificationPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt index fb44bb4e80..baedfa33b6 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/voicemessages/composer/DefaultVoiceMessageComposerPresenterTest.kt @@ -63,7 +63,6 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -@Suppress("LargeClass") class DefaultVoiceMessageComposerPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenterTest.kt index 6a201fe3fa..8b32ef993c 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenterTest.kt @@ -45,7 +45,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import kotlin.time.Duration.Companion.milliseconds -@Suppress("LargeClass") class NotificationSettingsPresenterTest { @Test fun `present - ensures initial state is correct`() = runTest { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt index 51a6f97ab0..8d6ef8d518 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenterTest.kt @@ -68,7 +68,6 @@ import org.junit.Rule import org.junit.Test import kotlin.time.Duration.Companion.milliseconds -@Suppress("LargeClass") @ExperimentalCoroutinesApi class RoomDetailsPresenterTest { @get:Rule diff --git a/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditPresenterTest.kt b/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditPresenterTest.kt index 656cc92265..5d46f26230 100644 --- a/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditPresenterTest.kt +++ b/features/roomdetailsedit/impl/src/test/kotlin/io/element/android/features/roomdetailsedit/impl/RoomDetailsEditPresenterTest.kt @@ -50,7 +50,6 @@ import org.junit.Rule import org.junit.Test import java.io.File -@Suppress("LargeClass") @ExperimentalCoroutinesApi class RoomDetailsEditPresenterTest { @get:Rule diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt index 0b5133fe6a..8cdba871be 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenterTest.kt @@ -43,7 +43,6 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.test.runTest import org.junit.Test -@Suppress("LargeClass") class SecurityAndPrivacyPresenterTest { @Test fun `present - initial states`() = runTest { diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt index 38517dab33..981f53ebfe 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultPinnedMessagesBannerFormatterTest.kt @@ -57,7 +57,6 @@ import org.junit.Test import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@Suppress("LargeClass") class DefaultPinnedMessagesBannerFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt index c293b67975..8b92d881a9 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/DefaultRoomLatestEventFormatterTest.kt @@ -58,7 +58,6 @@ import org.junit.Test import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@Suppress("LargeClass") class DefaultRoomLatestEventFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient diff --git a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt index 9a79f78413..207de5bf6b 100644 --- a/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt +++ b/libraries/eventformatter/impl/src/test/kotlin/io/element/android/libraries/eventformatter/impl/RtcNotificationContentFormatterTest.kt @@ -21,7 +21,6 @@ import org.junit.Test import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@Suppress("LargeClass") class RtcNotificationContentFormatterTest : RobolectricTest() { private lateinit var context: Context private lateinit var fakeMatrixClient: FakeMatrixClient diff --git a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt index 64e647ab19..46a012baff 100644 --- a/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt +++ b/libraries/matrixui/src/test/kotlin/io/element/android/libraries/matrix/ui/messages/reply/InReplyToMetadataKtTest.kt @@ -54,7 +54,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import kotlin.time.Duration.Companion.minutes -@Suppress("LargeClass") class InReplyToMetadataKtTest : RobolectricTest() { @Test fun `any message content`() = runTest { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt index 4f02637a62..3003e5d46e 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/datasource/EventItemFactoryTest.kt @@ -62,7 +62,6 @@ import kotlinx.collections.immutable.toImmutableList import org.junit.Test import kotlin.time.Duration.Companion.seconds -@Suppress("LargeClass") class EventItemFactoryTest { @Test fun `create check all null cases`() { diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt index be577362bd..ed710df50b 100644 --- a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/viewer/MediaViewerPresenterTest.kt @@ -64,7 +64,6 @@ private val TESTED_MEDIA_INFO = anApkMediaInfo( senderId = A_USER_ID, ) -@Suppress("LargeClass") class MediaViewerPresenterTest { @get:Rule val warmUpRule = WarmUpRule() diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt index 5918329c40..d25dd23d9d 100644 --- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt +++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotifiableEventResolverTest.kt @@ -69,7 +69,6 @@ import org.junit.Test import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config -@Suppress("LargeClass") class DefaultNotifiableEventResolverTest : RobolectricTest() { @Test fun `resolve event no session`() = runTest { 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 f0dee4446c..68fc55909b 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 @@ -52,7 +52,6 @@ import kotlin.time.Duration.Companion.milliseconds private const val A_PUSHER_INFO = "info" -@Suppress("LargeClass") class DefaultPushHandlerTest { @Test fun `check handleInvalid behavior`() = runTest { diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml index 147eca01d0..9c9bcd248b 100644 --- a/tools/detekt/detekt.yml +++ b/tools/detekt/detekt.yml @@ -175,6 +175,8 @@ complexity: active: true LargeClass: active: true + # Do not report large test classes. + excludes: [ '**/test/**', '**/androidTest/**' ] naming: VariableNaming: From 35af1fca485bacdd3896b5f236c1a6fe018513a9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 08:38:38 +0200 Subject: [PATCH 17/17] Update dependency io.element.android:element-call-embedded to v0.26.0 (#7715) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b9a7392c7..62794efded 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -238,7 +238,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.25.0" +element_call_embedded = "io.element.android:element-call-embedded:0.26.0" # Auto services google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" }