diff --git a/.maestro/tests/account/login.yaml b/.maestro/tests/account/login.yaml index dcb5cd3223..69833a985e 100644 --- a/.maestro/tests/account/login.yaml +++ b/.maestro/tests/account/login.yaml @@ -23,7 +23,8 @@ appId: ${MAESTRO_APP_ID} - inputText: ${MAESTRO_PASSWORD} - pressKey: Enter - tapOn: "Continue" +- runFlow: ../assertions/assertSessionVerificationDisplayed.yaml +- runFlow: ./verifySession.yaml - runFlow: ../assertions/assertAnalyticsDisplayed.yaml - tapOn: "Not now" - runFlow: ../assertions/assertHomeDisplayed.yaml -- runFlow: ./verifySession.yaml diff --git a/.maestro/tests/account/verifySession.yaml b/.maestro/tests/account/verifySession.yaml index eeb0489e3e..5449f4f7da 100644 --- a/.maestro/tests/account/verifySession.yaml +++ b/.maestro/tests/account/verifySession.yaml @@ -1,6 +1,5 @@ appId: ${MAESTRO_APP_ID} --- -- tapOn: "Continue" - takeScreenshot: build/maestro/150-Verify - tapOn: "Enter recovery key" - tapOn: @@ -8,4 +7,3 @@ appId: ${MAESTRO_APP_ID} - inputText: ${MAESTRO_RECOVERY_KEY} - hideKeyboard - tapOn: "Confirm" -- runFlow: ../assertions/assertHomeDisplayed.yaml diff --git a/.maestro/tests/assertions/assertSessionVerificationDisplayed.yaml b/.maestro/tests/assertions/assertSessionVerificationDisplayed.yaml new file mode 100644 index 0000000000..85785ac968 --- /dev/null +++ b/.maestro/tests/assertions/assertSessionVerificationDisplayed.yaml @@ -0,0 +1,5 @@ +appId: ${MAESTRO_APP_ID} +--- +- extendedWaitUntil: + visible: "Confirm that it's you" + timeout: 10000 diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInEventProcessor.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInEventProcessor.kt index b59c1cebdf..22300b7714 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInEventProcessor.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInEventProcessor.kt @@ -19,8 +19,6 @@ package io.element.android.appnav import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.room.RoomMembershipObserver -import io.element.android.libraries.matrix.api.verification.SessionVerificationService -import io.element.android.libraries.matrix.api.verification.VerificationFlowState import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -34,16 +32,12 @@ import javax.inject.Inject class LoggedInEventProcessor @Inject constructor( private val snackbarDispatcher: SnackbarDispatcher, roomMembershipObserver: RoomMembershipObserver, - sessionVerificationService: SessionVerificationService, ) { private var observingJob: Job? = null private val displayLeftRoomMessage = roomMembershipObserver.updates .map { !it.isUserInRoom } - private val displayVerificationSuccessfulMessage = sessionVerificationService.verificationFlowState - .map { it == VerificationFlowState.Finished } - fun observeEvents(coroutineScope: CoroutineScope) { observingJob = coroutineScope.launch { displayLeftRoomMessage @@ -52,13 +46,6 @@ class LoggedInEventProcessor @Inject constructor( displayMessage(CommonStrings.common_current_user_left_room) } .launchIn(this) - - displayVerificationSuccessfulMessage - .filter { it } - .onEach { - displayMessage(CommonStrings.common_verification_complete) - } - .launchIn(this) } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index a9dd485285..2027f2868a 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -45,6 +45,7 @@ import io.element.android.appnav.room.RoomFlowNode import io.element.android.appnav.room.RoomLoadedFlowNode import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.ftue.api.FtueEntryPoint +import io.element.android.features.ftue.api.state.FtueService import io.element.android.features.ftue.api.state.FtueState import io.element.android.features.invitelist.api.InviteListEntryPoint import io.element.android.features.lockscreen.api.LockScreenEntryPoint @@ -56,13 +57,13 @@ import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint import io.element.android.features.roomlist.api.RoomListEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint -import io.element.android.features.verifysession.api.VerifySessionEntryPoint import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.waitForChildAttached import io.element.android.libraries.deeplink.DeeplinkData import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher +import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.MAIN_SPACE @@ -75,6 +76,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize @@ -88,14 +91,13 @@ class LoggedInFlowNode @AssistedInject constructor( private val preferencesEntryPoint: PreferencesEntryPoint, private val createRoomEntryPoint: CreateRoomEntryPoint, private val appNavigationStateService: AppNavigationStateService, - private val verifySessionEntryPoint: VerifySessionEntryPoint, private val secureBackupEntryPoint: SecureBackupEntryPoint, private val inviteListEntryPoint: InviteListEntryPoint, private val ftueEntryPoint: FtueEntryPoint, private val coroutineScope: CoroutineScope, private val networkMonitor: NetworkMonitor, private val notificationDrawerManager: NotificationDrawerManager, - private val ftueState: FtueState, + private val ftueService: FtueService, private val lockScreenEntryPoint: LockScreenEntryPoint, private val lockScreenStateService: LockScreenService, private val roomDirectoryEntryPoint: RoomDirectoryEntryPoint, @@ -103,7 +105,7 @@ class LoggedInFlowNode @AssistedInject constructor( snackbarDispatcher: SnackbarDispatcher, ) : BaseFlowNode( backstack = BackStack( - initialElement = NavTarget.RoomList, + initialElement = NavTarget.Placeholder, savedStateMap = buildContext.savedStateMap, ), permanentNavModel = PermanentNavModel( @@ -121,7 +123,6 @@ class LoggedInFlowNode @AssistedInject constructor( private val loggedInFlowProcessor = LoggedInEventProcessor( snackbarDispatcher, matrixClient.roomMembershipObserver(), - matrixClient.sessionVerificationService(), ) override fun onBuilt() { @@ -133,9 +134,15 @@ class LoggedInFlowNode @AssistedInject constructor( appNavigationStateService.onNavigateToSpace(id, MAIN_SPACE) loggedInFlowProcessor.observeEvents(coroutineScope) - if (ftueState.shouldDisplayFlow.value) { - backstack.push(NavTarget.Ftue) - } + ftueService.state + .onEach { ftueState -> + when (ftueState) { + is FtueState.Unknown -> Unit // Nothing to do + is FtueState.Incomplete -> backstack.safeRoot(NavTarget.Ftue) + is FtueState.Complete -> backstack.safeRoot(NavTarget.RoomList) + } + } + .launchIn(lifecycleScope) }, onStop = { coroutineScope.launch { @@ -191,6 +198,9 @@ class LoggedInFlowNode @AssistedInject constructor( } sealed interface NavTarget : Parcelable { + @Parcelize + data object Placeholder : NavTarget + @Parcelize data object LoggedInPermanent : NavTarget @@ -214,9 +224,6 @@ class LoggedInFlowNode @AssistedInject constructor( @Parcelize data object CreateRoom : NavTarget - @Parcelize - data object VerifySession : NavTarget - @Parcelize data class SecureBackup( val initialElement: SecureBackupEntryPoint.InitialTarget = SecureBackupEntryPoint.InitialTarget.Root @@ -234,6 +241,7 @@ class LoggedInFlowNode @AssistedInject constructor( override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { + NavTarget.Placeholder -> createNode(buildContext) NavTarget.LoggedInPermanent -> { createNode(buildContext) } @@ -256,10 +264,6 @@ class LoggedInFlowNode @AssistedInject constructor( backstack.push(NavTarget.CreateRoom) } - override fun onSessionVerificationClicked() { - backstack.push(NavTarget.VerifySession) - } - override fun onSessionConfirmRecoveryKeyClicked() { backstack.push(NavTarget.SecureBackup(initialElement = SecureBackupEntryPoint.InitialTarget.EnterRecoveryKey)) } @@ -308,10 +312,6 @@ class LoggedInFlowNode @AssistedInject constructor( plugins().forEach { it.onOpenBugReport() } } - override fun onVerifyClicked() { - backstack.push(NavTarget.VerifySession) - } - override fun onSecureBackupClicked() { backstack.push(NavTarget.SecureBackup()) } @@ -338,25 +338,6 @@ class LoggedInFlowNode @AssistedInject constructor( .callback(callback) .build() } - NavTarget.VerifySession -> { - val callback = object : VerifySessionEntryPoint.Callback { - override fun onEnterRecoveryKey() { - backstack.replace( - NavTarget.SecureBackup( - initialElement = SecureBackupEntryPoint.InitialTarget.EnterRecoveryKey - ) - ) - } - - override fun onDone() { - backstack.pop() - } - } - verifySessionEntryPoint - .nodeBuilder(this, buildContext) - .callback(callback) - .build() - } is NavTarget.SecureBackup -> { secureBackupEntryPoint.nodeBuilder(this, buildContext) .params(SecureBackupEntryPoint.Params(initialElement = navTarget.initialElement)) @@ -381,7 +362,7 @@ class LoggedInFlowNode @AssistedInject constructor( ftueEntryPoint.nodeBuilder(this, buildContext) .callback(object : FtueEntryPoint.Callback { override fun onFtueFlowFinished() { - backstack.pop() + lifecycleScope.launch { attachRoomList() } } }) .build() @@ -398,20 +379,23 @@ class LoggedInFlowNode @AssistedInject constructor( } } - suspend fun attachRoot(): Node { - return attachChild { + suspend fun attachRoomList() { + if (!canShowRoomList()) return + attachChild { backstack.singleTop(NavTarget.RoomList) } } - suspend fun attachRoom(roomId: RoomId): RoomFlowNode { - return attachChild { + suspend fun attachRoom(roomId: RoomId) { + if (!canShowRoomList()) return + attachChild { backstack.singleTop(NavTarget.RoomList) backstack.push(NavTarget.Room(roomId)) } } internal suspend fun attachInviteList(deeplinkData: DeeplinkData.InviteList) = withContext(lifecycleScope.coroutineContext) { + if (!canShowRoomList()) return@withContext notificationDrawerManager.clearMembershipNotificationForSession(deeplinkData.sessionId) backstack.singleTop(NavTarget.RoomList) backstack.push(NavTarget.InviteList) @@ -420,13 +404,17 @@ class LoggedInFlowNode @AssistedInject constructor( } } + private fun canShowRoomList(): Boolean { + return ftueService.state.value is FtueState.Complete + } + @Composable override fun View(modifier: Modifier) { Box(modifier = modifier) { val lockScreenState by lockScreenStateService.lockState.collectAsState() + val isFtueDisplayed by ftueService.state.collectAsState() BackstackView() - val isFtueDisplayed by ftueState.shouldDisplayFlow.collectAsState() - if (!isFtueDisplayed) { + if (isFtueDisplayed is FtueState.Complete) { PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent) } if (lockScreenState == LockScreenLockState.Locked) { @@ -434,4 +422,10 @@ class LoggedInFlowNode @AssistedInject constructor( } } } + + @ContributesNode(AppScope::class) + class PlaceholderNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + ) : Node(buildContext, plugins = plugins) } 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 e4ecdd8864..d310a02b99 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -288,7 +288,7 @@ class RootFlowNode @AssistedInject constructor( .attachSession() .apply { when (deeplinkData) { - is DeeplinkData.Root -> attachRoot() + is DeeplinkData.Root -> attachRoomList() is DeeplinkData.Room -> attachRoom(deeplinkData.roomId) is DeeplinkData.InviteList -> attachInviteList(deeplinkData) } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt index a9c4a6ecf8..7cb1d634b8 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt @@ -27,22 +27,32 @@ import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.roomlist.RoomListService +import io.element.android.libraries.matrix.api.verification.SessionVerificationService +import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.push.api.PushService +import kotlinx.coroutines.flow.map import javax.inject.Inject class LoggedInPresenter @Inject constructor( private val matrixClient: MatrixClient, private val networkMonitor: NetworkMonitor, private val pushService: PushService, + private val sessionVerificationService: SessionVerificationService, ) : Presenter { @Composable override fun present(): LoggedInState { - LaunchedEffect(Unit) { - // Ensure pusher is registered - // TODO Manually select push provider for now - val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect - val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect - pushService.registerWith(matrixClient, pushProvider, distributor) + val isVerified by remember { + sessionVerificationService.sessionVerifiedStatus.map { it == SessionVerifiedStatus.Verified } + }.collectAsState(initial = false) + + LaunchedEffect(isVerified) { + if (isVerified) { + // Ensure pusher is registered + // TODO Manually select push provider for now + val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect + val distributor = pushProvider.getDistributors().firstOrNull() ?: return@LaunchedEffect + pushService.registerWith(matrixClient, pushProvider, distributor) + } } val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState() diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt index 0da579aa76..df17053512 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt @@ -25,6 +25,7 @@ import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService +import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.push.test.FakePushService import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.consumeItemsUntilPredicate @@ -71,6 +72,7 @@ class LoggedInPresenterTest { matrixClient = FakeMatrixClient(roomListService = roomListService), networkMonitor = FakeNetworkMonitor(networkStatus), pushService = FakePushService(), + sessionVerificationService = FakeSessionVerificationService(), ) } } diff --git a/changelog.d/2580.feature b/changelog.d/2580.feature new file mode 100644 index 0000000000..8d3ede2ccc --- /dev/null +++ b/changelog.d/2580.feature @@ -0,0 +1 @@ +Move session verification to the after login flow and make it mandatory. diff --git a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueState.kt b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt similarity index 53% rename from features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueState.kt rename to features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt index cd172669cc..77dd258b22 100644 --- a/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueState.kt +++ b/features/ftue/api/src/main/kotlin/io/element/android/features/ftue/api/state/FtueService.kt @@ -18,8 +18,25 @@ package io.element.android.features.ftue.api.state import kotlinx.coroutines.flow.StateFlow -interface FtueState { - val shouldDisplayFlow: StateFlow +/** + * Service to manage the First Time User Experience state (aka Onboarding). + */ +interface FtueService { + /** The current state of the FTUE. */ + val state: StateFlow + /** Reset the FTUE state. */ suspend fun reset() } + +/** The state of the FTUE. */ +sealed interface FtueState { + /** The FTUE state is unknown, nothing to do for now. */ + data object Unknown : FtueState + + /** The FTUE state is incomplete. The FTUE flow should be displayed. */ + data object Incomplete : FtueState + + /** The FTUE state is complete. The FTUE flow should not be displayed anymore. */ + data object Complete : FtueState +} diff --git a/features/ftue/impl/build.gradle.kts b/features/ftue/impl/build.gradle.kts index 1719aecbe1..06251cfe5d 100644 --- a/features/ftue/impl/build.gradle.kts +++ b/features/ftue/impl/build.gradle.kts @@ -42,6 +42,8 @@ dependencies { implementation(projects.libraries.uiStrings) implementation(projects.libraries.testtags) implementation(projects.features.analytics.api) + implementation(projects.features.securebackup.api) + implementation(projects.features.verifysession.api) implementation(projects.services.analytics.api) implementation(projects.features.lockscreen.api) implementation(projects.libraries.permissions.api) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt index 652b6dddd4..cb77100d94 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt @@ -34,7 +34,8 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.features.analytics.api.AnalyticsEntryPoint import io.element.android.features.ftue.api.FtueEntryPoint import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode -import io.element.android.features.ftue.impl.state.DefaultFtueState +import io.element.android.features.ftue.impl.sessionverification.FtueSessionVerificationFlowNode +import io.element.android.features.ftue.impl.state.DefaultFtueService import io.element.android.features.ftue.impl.state.FtueStep import io.element.android.features.lockscreen.api.LockScreenEntryPoint import io.element.android.libraries.architecture.BackstackView @@ -55,7 +56,7 @@ import kotlinx.parcelize.Parcelize class FtueFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val ftueState: DefaultFtueState, + private val ftueState: DefaultFtueService, private val analyticsEntryPoint: AnalyticsEntryPoint, private val analyticsService: AnalyticsService, private val lockScreenEntryPoint: LockScreenEntryPoint, @@ -72,6 +73,9 @@ class FtueFlowNode @AssistedInject constructor( @Parcelize data object Placeholder : NavTarget + @Parcelize + data object SessionVerification : NavTarget + @Parcelize data object NotificationsOptIn : NavTarget @@ -106,6 +110,14 @@ class FtueFlowNode @AssistedInject constructor( NavTarget.Placeholder -> { createNode(buildContext) } + NavTarget.SessionVerification -> { + val callback = object : FtueSessionVerificationFlowNode.Callback { + override fun onDone() { + lifecycleScope.launch { moveToNextStep() } + } + } + createNode(buildContext, listOf(callback)) + } NavTarget.NotificationsOptIn -> { val callback = object : NotificationsOptInNode.Callback { override fun onNotificationsOptInFinished() { @@ -133,6 +145,9 @@ class FtueFlowNode @AssistedInject constructor( private fun moveToNextStep() { when (ftueState.getNextStep()) { + FtueStep.SessionVerification -> { + backstack.newRoot(NavTarget.SessionVerification) + } FtueStep.NotificationsOptIn -> { backstack.newRoot(NavTarget.NotificationsOptIn) } diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/FtueSessionVerificationFlowNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/FtueSessionVerificationFlowNode.kt new file mode 100644 index 0000000000..53e7b32995 --- /dev/null +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/FtueSessionVerificationFlowNode.kt @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.ftue.impl.sessionverification + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.push +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.features.securebackup.api.SecureBackupEntryPoint +import io.element.android.features.verifysession.api.VerifySessionEntryPoint +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.di.SessionScope +import kotlinx.parcelize.Parcelize + +@ContributesNode(SessionScope::class) +class FtueSessionVerificationFlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val verifySessionEntryPoint: VerifySessionEntryPoint, + private val secureBackupEntryPoint: SecureBackupEntryPoint, +) : BaseFlowNode( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins, +) { + sealed interface NavTarget : Parcelable { + @Parcelize + data object Root : NavTarget + + @Parcelize + data object EnterRecoveryKey : NavTarget + } + + interface Callback : Plugin { + fun onDone() + } + + private val callback = plugins().first() + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + is NavTarget.Root -> { + verifySessionEntryPoint.nodeBuilder(this, buildContext) + .callback(object : VerifySessionEntryPoint.Callback { + override fun onEnterRecoveryKey() { + backstack.push(NavTarget.EnterRecoveryKey) + } + + override fun onDone() { + callback.onDone() + } + }) + .build() + } + is NavTarget.EnterRecoveryKey -> { + secureBackupEntryPoint.nodeBuilder(this, buildContext) + .params(SecureBackupEntryPoint.Params(SecureBackupEntryPoint.InitialTarget.EnterRecoveryKey)) + .callback(object : SecureBackupEntryPoint.Callback { + override fun onDone() { + callback.onDone() + } + }) + .build() + } + } + } + + @Composable + override fun View(modifier: Modifier) { + BackstackView() + } +} diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt similarity index 74% rename from features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt rename to features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt index f1a1c84545..384d518452 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueState.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/state/DefaultFtueService.kt @@ -20,9 +20,12 @@ import android.Manifest import android.os.Build import androidx.annotation.VisibleForTesting import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.ftue.api.state.FtueService import io.element.android.features.ftue.api.state.FtueState import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.verification.SessionVerificationService +import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.permissions.api.PermissionStateProvider import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider @@ -35,14 +38,15 @@ import kotlinx.coroutines.runBlocking import javax.inject.Inject @ContributesBinding(SessionScope::class) -class DefaultFtueState @Inject constructor( +class DefaultFtueService @Inject constructor( private val sdkVersionProvider: BuildVersionSdkIntProvider, coroutineScope: CoroutineScope, private val analyticsService: AnalyticsService, private val permissionStateProvider: PermissionStateProvider, private val lockScreenService: LockScreenService, -) : FtueState { - override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete()) + private val sessionVerificationService: SessionVerificationService, +) : FtueService { + override val state = MutableStateFlow(FtueState.Unknown) override suspend fun reset() { analyticsService.reset() @@ -52,6 +56,10 @@ class DefaultFtueState @Inject constructor( } init { + sessionVerificationService.sessionVerifiedStatus + .onEach { updateState() } + .launchIn(coroutineScope) + analyticsService.didAskUserConsent() .onEach { updateState() } .launchIn(coroutineScope) @@ -59,7 +67,12 @@ class DefaultFtueState @Inject constructor( fun getNextStep(currentStep: FtueStep? = null): FtueStep? = when (currentStep) { - null -> if (shouldAskNotificationPermissions()) { + null -> if (isSessionNotVerified()) { + FtueStep.SessionVerification + } else { + getNextStep(FtueStep.SessionVerification) + } + FtueStep.SessionVerification -> if (shouldAskNotificationPermissions()) { FtueStep.NotificationsOptIn } else { getNextStep(FtueStep.NotificationsOptIn) @@ -79,12 +92,21 @@ class DefaultFtueState @Inject constructor( private fun isAnyStepIncomplete(): Boolean { return listOf( + { isSessionNotVerified() }, { shouldAskNotificationPermissions() }, { needsAnalyticsOptIn() }, { shouldDisplayLockscreenSetup() }, ).any { it() } } + private fun isSessionVerificationServiceReady(): Boolean { + return sessionVerificationService.sessionVerifiedStatus.value != SessionVerifiedStatus.Unknown + } + + private fun isSessionNotVerified(): Boolean { + return sessionVerificationService.sessionVerifiedStatus.value == SessionVerifiedStatus.NotVerified + } + private fun needsAnalyticsOptIn(): Boolean { // We need this function to not be suspend, so we need to load the value through runBlocking return runBlocking { analyticsService.didAskUserConsent().first().not() } @@ -109,11 +131,16 @@ class DefaultFtueState @Inject constructor( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal fun updateState() { - shouldDisplayFlow.value = isAnyStepIncomplete() + state.value = when { + !isSessionVerificationServiceReady() -> FtueState.Unknown + isAnyStepIncomplete() -> FtueState.Incomplete + else -> FtueState.Complete + } } } sealed interface FtueStep { + data object SessionVerification : FtueStep data object NotificationsOptIn : FtueStep data object AnalyticsOptIn : FtueStep data object LockscreenSetup : FtueStep diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTests.kt similarity index 70% rename from features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt rename to features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTests.kt index 1f0b817850..f3f21836b9 100644 --- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueStateTests.kt +++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/DefaultFtueServiceTests.kt @@ -17,11 +17,15 @@ package io.element.android.features.ftue.impl import android.os.Build +import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.features.ftue.impl.state.DefaultFtueState +import io.element.android.features.ftue.api.state.FtueState +import io.element.android.features.ftue.impl.state.DefaultFtueService import io.element.android.features.ftue.impl.state.FtueStep import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.features.lockscreen.test.FakeLockScreenService +import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus +import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.permissions.impl.FakePermissionStateProvider import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService @@ -32,38 +36,51 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.test.runTest import org.junit.Test -class DefaultFtueStateTests { +class DefaultFtueServiceTests { @Test - fun `given any check being false, should display flow is true`() = runTest { + fun `given any check being false and session verification state being loaded, FtueState is Incomplete`() = runTest { + val sessionVerificationService = FakeSessionVerificationService().apply { + givenVerifiedStatus(SessionVerifiedStatus.Unknown) + } val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) - val state = createState(coroutineScope) + val state = createState(coroutineScope, sessionVerificationService) - assertThat(state.shouldDisplayFlow.value).isTrue() + state.state.test { + // Verification state is unknown, we don't display the flow yet + assertThat(awaitItem()).isEqualTo(FtueState.Unknown) + + // Verification state is known, we should display the flow if any check is false + sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.NotVerified) + assertThat(awaitItem()).isEqualTo(FtueState.Incomplete) + } // Cleanup coroutineScope.cancel() } @Test - fun `given all checks being true, should display flow is false`() = runTest { + fun `given all checks being true, FtueState is Complete`() = runTest { val analyticsService = FakeAnalyticsService() + val sessionVerificationService = FakeSessionVerificationService() val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true) val lockScreenService = FakeLockScreenService() val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) val state = createState( coroutineScope = coroutineScope, + sessionVerificationService = sessionVerificationService, analyticsService = analyticsService, permissionStateProvider = permissionStateProvider, lockScreenService = lockScreenService, ) + sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) analyticsService.setDidAskUserConsent() permissionStateProvider.setPermissionGranted() lockScreenService.setIsPinSetup(true) state.updateState() - assertThat(state.shouldDisplayFlow.value).isFalse() + assertThat(state.state.value).isEqualTo(FtueState.Complete) // Cleanup coroutineScope.cancel() @@ -71,6 +88,9 @@ class DefaultFtueStateTests { @Test fun `traverse flow`() = runTest { + val sessionVerificationService = FakeSessionVerificationService().apply { + givenVerifiedStatus(SessionVerifiedStatus.NotVerified) + } val analyticsService = FakeAnalyticsService() val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false) val lockScreenService = FakeLockScreenService() @@ -78,12 +98,17 @@ class DefaultFtueStateTests { val state = createState( coroutineScope = coroutineScope, + sessionVerificationService = sessionVerificationService, analyticsService = analyticsService, permissionStateProvider = permissionStateProvider, lockScreenService = lockScreenService, ) val steps = mutableListOf() + // Session verification + steps.add(state.getNextStep(steps.lastOrNull())) + sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) + // Notifications opt in steps.add(state.getNextStep(steps.lastOrNull())) permissionStateProvider.setPermissionGranted() @@ -100,6 +125,7 @@ class DefaultFtueStateTests { steps.add(state.getNextStep(steps.lastOrNull())) assertThat(steps).containsExactly( + FtueStep.SessionVerification, FtueStep.NotificationsOptIn, FtueStep.LockscreenSetup, FtueStep.AnalyticsOptIn, @@ -114,17 +140,20 @@ class DefaultFtueStateTests { @Test fun `if a check for a step is true, start from the next one`() = runTest { val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) + val sessionVerificationService = FakeSessionVerificationService() val analyticsService = FakeAnalyticsService() val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false) val lockScreenService = FakeLockScreenService() val state = createState( coroutineScope = coroutineScope, + sessionVerificationService = sessionVerificationService, analyticsService = analyticsService, permissionStateProvider = permissionStateProvider, lockScreenService = lockScreenService, ) - // Skip first 2 steps + // Skip first 3 steps + sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) permissionStateProvider.setPermissionGranted() lockScreenService.setIsPinSetup(true) @@ -140,16 +169,19 @@ class DefaultFtueStateTests { @Test fun `if version is older than 13 we don't display the notification opt in screen`() = runTest { val coroutineScope = CoroutineScope(coroutineContext + SupervisorJob()) + val sessionVerificationService = FakeSessionVerificationService() val analyticsService = FakeAnalyticsService() val lockScreenService = FakeLockScreenService() val state = createState( sdkIntVersion = Build.VERSION_CODES.M, + sessionVerificationService = sessionVerificationService, coroutineScope = coroutineScope, analyticsService = analyticsService, lockScreenService = lockScreenService, ) + sessionVerificationService.givenVerifiedStatus(SessionVerifiedStatus.Verified) lockScreenService.setIsPinSetup(true) assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn) @@ -163,14 +195,16 @@ class DefaultFtueStateTests { private fun createState( coroutineScope: CoroutineScope, + sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(), analyticsService: AnalyticsService = FakeAnalyticsService(), permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false), lockScreenService: LockScreenService = FakeLockScreenService(), // First version where notification permission is required sdkIntVersion: Int = Build.VERSION_CODES.TIRAMISU, - ) = DefaultFtueState( - sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion), + ) = DefaultFtueService( coroutineScope = coroutineScope, + sessionVerificationService = sessionVerificationService, + sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion), analyticsService = analyticsService, permissionStateProvider = permissionStateProvider, lockScreenService = lockScreenService, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 67915bf9d4..3cd525c614 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -33,7 +33,6 @@ import io.element.android.features.messages.impl.MessagesNavigator import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager import io.element.android.features.poll.api.actions.EndPollAction import io.element.android.features.poll.api.actions.SendPollResponseAction @@ -41,15 +40,11 @@ import io.element.android.features.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.core.EventId -import io.element.android.libraries.matrix.api.encryption.BackupState -import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.roomMembers import io.element.android.libraries.matrix.api.timeline.ReceiptType import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin -import io.element.android.libraries.matrix.api.verification.SessionVerificationService -import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.CoroutineScope @@ -68,8 +63,6 @@ class TimelinePresenter @AssistedInject constructor( private val dispatchers: CoroutineDispatchers, private val appScope: CoroutineScope, @Assisted private val navigator: MessagesNavigator, - private val verificationService: SessionVerificationService, - private val encryptionService: EncryptionService, private val redactedVoiceMessageManager: RedactedVoiceMessageManager, private val sendPollResponseAction: SendPollResponseAction, private val endPollAction: EndPollAction, @@ -101,21 +94,9 @@ class TimelinePresenter @AssistedInject constructor( val prevMostRecentItemId = rememberSaveable { mutableStateOf(null) } val newItemState = remember { mutableStateOf(NewEventState.None) } - val sessionVerifiedStatus by verificationService.sessionVerifiedStatus.collectAsState() - val keyBackupState by encryptionService.backupStateStateFlow.collectAsState() - val isSendPublicReadReceiptsEnabled by sessionPreferencesStore.isSendPublicReadReceiptsEnabled().collectAsState(initial = true) val renderReadReceipts by sessionPreferencesStore.isRenderReadReceiptsEnabled().collectAsState(initial = true) - val sessionState by remember { - derivedStateOf { - SessionState( - isSessionVerified = sessionVerifiedStatus == SessionVerifiedStatus.Verified, - isKeyBackupEnabled = keyBackupState == BackupState.ENABLED - ) - } - } - fun handleEvents(event: TimelineEvents) { when (event) { TimelineEvents.LoadMore -> localScope.paginateBackwards() @@ -184,7 +165,6 @@ class TimelinePresenter @AssistedInject constructor( timelineItems = timelineItems, renderReadReceipts = renderReadReceipts, newEventState = newItemState.value, - sessionState = sessionState, eventSink = { handleEvents(it) } ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt index ab9d93d678..4e2f9b8d42 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineState.kt @@ -19,7 +19,6 @@ package io.element.android.features.messages.impl.timeline import androidx.compose.runtime.Immutable import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import kotlinx.collections.immutable.ImmutableList @@ -32,7 +31,6 @@ data class TimelineState( val highlightedEventId: EventId?, val paginationState: MatrixTimeline.PaginationState, val newEventState: NewEventState, - val sessionState: SessionState, val eventSink: (TimelineEvents) -> Unit ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index aa35b620b9..ae7f62ebd7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -29,7 +29,6 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemStateEventContent import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemTextContent import io.element.android.features.messages.impl.timeline.model.virtual.aTimelineItemDaySeparatorModel -import io.element.android.features.messages.impl.timeline.session.aSessionState import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.matrix.api.core.EventId @@ -58,10 +57,6 @@ fun aTimelineState( renderReadReceipts = renderReadReceipts, highlightedEventId = null, newEventState = NewEventState.None, - sessionState = aSessionState( - isSessionVerified = true, - isKeyBackupEnabled = true, - ), eventSink = eventSink, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt index 5869238753..56a2676f43 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineView.kt @@ -148,7 +148,6 @@ fun TimelineView( onMoreReactionsClick = onMoreReactionsClicked, onReadReceiptClick = onReadReceiptClick, onTimestampClicked = onTimestampClicked, - sessionState = state.sessionState, eventSink = state.eventSink, onSwipeToReply = onSwipeToReply, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt index bc05882f1b..a5d42d5dbf 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemGroupedEventsRow.kt @@ -32,8 +32,6 @@ import io.element.android.features.messages.impl.timeline.components.group.Group import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewState import io.element.android.features.messages.impl.timeline.components.receipt.TimelineItemReadReceiptView import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.session.SessionState -import io.element.android.features.messages.impl.timeline.session.aSessionState import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.matrix.api.core.EventId @@ -46,7 +44,6 @@ fun TimelineItemGroupedEventsRow( renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, highlightedItem: String?, - sessionState: SessionState, onClick: (TimelineItem.Event) -> Unit, onLongClick: (TimelineItem.Event) -> Unit, inReplyToClick: (EventId) -> Unit, @@ -74,7 +71,6 @@ fun TimelineItemGroupedEventsRow( highlightedItem = highlightedItem, renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, - sessionState = sessionState, onClick = onClick, onLongClick = onLongClick, inReplyToClick = inReplyToClick, @@ -99,7 +95,6 @@ private fun TimelineItemGroupedEventsRowContent( highlightedItem: String?, renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, - sessionState: SessionState, onClick: (TimelineItem.Event) -> Unit, onLongClick: (TimelineItem.Event) -> Unit, inReplyToClick: (EventId) -> Unit, @@ -133,7 +128,6 @@ private fun TimelineItemGroupedEventsRowContent( renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, highlightedItem = highlightedItem, - sessionState = sessionState, onClick = onClick, onLongClick = onLongClick, inReplyToClick = inReplyToClick, @@ -174,7 +168,6 @@ internal fun TimelineItemGroupedEventsRowContentExpandedPreview() = ElementPrevi highlightedItem = null, renderReadReceipts = true, isLastOutgoingMessage = false, - sessionState = aSessionState(), onClick = {}, onLongClick = {}, inReplyToClick = {}, @@ -200,7 +193,6 @@ internal fun TimelineItemGroupedEventsRowContentCollapsePreview() = ElementPrevi highlightedItem = null, renderReadReceipts = true, isLastOutgoingMessage = false, - sessionState = aSessionState(), onClick = {}, onLongClick = {}, inReplyToClick = {}, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt index 5146c87df6..89b223dafe 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemRow.kt @@ -23,7 +23,6 @@ import io.element.android.features.messages.impl.timeline.TimelineRoomInfo import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent -import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId @@ -34,7 +33,6 @@ internal fun TimelineItemRow( renderReadReceipts: Boolean, isLastOutgoingMessage: Boolean, highlightedItem: String?, - sessionState: SessionState, onUserDataClick: (UserId) -> Unit, onLinkClicked: (String) -> Unit, onClick: (TimelineItem.Event) -> Unit, @@ -53,7 +51,6 @@ internal fun TimelineItemRow( is TimelineItem.Virtual -> { TimelineItemVirtualRow( virtual = timelineItem, - sessionState = sessionState, modifier = modifier, ) } @@ -100,7 +97,6 @@ internal fun TimelineItemRow( renderReadReceipts = renderReadReceipts, isLastOutgoingMessage = isLastOutgoingMessage, highlightedItem = highlightedItem, - sessionState = sessionState, onClick = onClick, onLongClick = onLongClick, inReplyToClick = inReplyToClick, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemVirtualRow.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemVirtualRow.kt index 5ef3c2ef2c..306c11aaba 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemVirtualRow.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemVirtualRow.kt @@ -25,17 +25,15 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemDaySeparatorModel import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemEncryptedHistoryBannerVirtualModel import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemReadMarkerModel -import io.element.android.features.messages.impl.timeline.session.SessionState @Composable fun TimelineItemVirtualRow( virtual: TimelineItem.Virtual, - sessionState: SessionState, modifier: Modifier = Modifier ) { when (virtual.model) { is TimelineItemDaySeparatorModel -> TimelineItemDaySeparatorView(virtual.model, modifier) TimelineItemReadMarkerModel -> TimelineItemReadMarkerView() - is TimelineItemEncryptedHistoryBannerVirtualModel -> TimelineEncryptedHistoryBannerView(sessionState, modifier) + is TimelineItemEncryptedHistoryBannerVirtualModel -> TimelineEncryptedHistoryBannerView(modifier) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt index c555352864..db0dd1ae9a 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/virtual/TimelineEncryptedHistoryBannerView.kt @@ -16,7 +16,6 @@ package io.element.android.features.messages.impl.timeline.components.virtual -import androidx.annotation.StringRes import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -29,20 +28,16 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource -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.messages.impl.R -import io.element.android.features.messages.impl.timeline.session.SessionState -import io.element.android.features.messages.impl.timeline.session.SessionStateProvider import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon @Composable fun TimelineEncryptedHistoryBannerView( - sessionState: SessionState, modifier: Modifier = Modifier, ) { Row( @@ -61,26 +56,15 @@ fun TimelineEncryptedHistoryBannerView( tint = ElementTheme.colors.iconInfoPrimary ) Text( - text = stringResource(sessionState.toStringResId()), + text = stringResource(R.string.screen_room_encrypted_history_banner), style = ElementTheme.typography.fontBodyMdMedium, color = ElementTheme.colors.textInfoPrimary ) } } -@StringRes -private fun SessionState.toStringResId(): Int { - return when { - isSessionVerified.not() -> R.string.screen_room_encrypted_history_banner_unverified - isKeyBackupEnabled.not() -> R.string.screen_room_encrypted_history_banner - else -> R.string.screen_room_encrypted_history_banner // TODO strings need to be updated - } -} - @PreviewsDayNight @Composable -internal fun EncryptedHistoryBannerViewPreview( - @PreviewParameter(SessionStateProvider::class) sessionState: SessionState, -) = ElementPreview { - TimelineEncryptedHistoryBannerView(sessionState = sessionState) +internal fun EncryptedHistoryBannerViewPreview() = ElementPreview { + TimelineEncryptedHistoryBannerView() } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/session/SessionStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/session/SessionStateProvider.kt deleted file mode 100644 index 2dd27d5456..0000000000 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/session/SessionStateProvider.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.features.messages.impl.timeline.session - -import androidx.compose.ui.tooling.preview.PreviewParameterProvider - -open class SessionStateProvider : PreviewParameterProvider { - override val values: Sequence - get() = sequenceOf( - aSessionState(isSessionVerified = false, isKeyBackupEnabled = false), - aSessionState(isSessionVerified = true, isKeyBackupEnabled = false), - aSessionState(isSessionVerified = true, isKeyBackupEnabled = true), - ) -} - -internal fun aSessionState( - isSessionVerified: Boolean = false, - isKeyBackupEnabled: Boolean = false, -) = SessionState( - isSessionVerified = isSessionVerified, - isKeyBackupEnabled = isKeyBackupEnabled, -) 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 6cceb6b5b5..237c7f357a 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 @@ -76,13 +76,11 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.core.aBuildMeta -import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomMember -import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.mediapickers.test.FakePickerProvider import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer import io.element.android.libraries.mediaupload.api.MediaSender @@ -745,8 +743,6 @@ class MessagesPresenterTest { dispatchers = coroutineDispatchers, appScope = this, navigator = navigator, - encryptionService = FakeEncryptionService(), - verificationService = FakeSessionVerificationService(), redactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), endPollAction = endPollAction, sendPollResponseAction = FakeSendPollResponseAction(), 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 5ee6ca8aa0..2485e57172 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 @@ -26,7 +26,6 @@ import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory import io.element.android.features.messages.impl.timeline.model.NewEventState import io.element.android.features.messages.impl.timeline.model.TimelineItem -import io.element.android.features.messages.impl.timeline.session.SessionState import io.element.android.features.messages.impl.voicemessages.timeline.FakeRedactedVoiceMessageManager import io.element.android.features.messages.impl.voicemessages.timeline.RedactedVoiceMessageManager import io.element.android.features.messages.impl.voicemessages.timeline.aRedactedMatrixTimeline @@ -47,13 +46,11 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem -import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.ui.components.aMatrixUserList import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.awaitLastSequentialItem @@ -89,7 +86,6 @@ class TimelinePresenterTest { assertThat(initialState.timelineItems).isEmpty() val loadedNoTimelineState = awaitItem() assertThat(loadedNoTimelineState.timelineItems).isEmpty() - assertThat(loadedNoTimelineState.sessionState).isEqualTo(SessionState(isSessionVerified = false, isKeyBackupEnabled = false)) } } @@ -512,8 +508,6 @@ class TimelinePresenterTest { dispatchers = testCoroutineDispatchers(), appScope = this, navigator = messagesNavigator, - encryptionService = FakeEncryptionService(), - verificationService = FakeSessionVerificationService(), redactedVoiceMessageManager = redactedVoiceMessageManager, endPollAction = endPollAction, sendPollResponseAction = sendPollResponseAction, diff --git a/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt index 0577412604..e488d911ed 100644 --- a/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt +++ b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt @@ -45,7 +45,6 @@ interface PreferencesEntryPoint : FeatureEntryPoint { interface Callback : Plugin { fun onOpenBugReport() - fun onVerifyClicked() fun onSecureBackupClicked() fun onOpenRoomNotificationSettings(roomId: RoomId) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index 1dc5f650fd..b93e02dd39 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -115,10 +115,6 @@ class PreferencesFlowNode @AssistedInject constructor( plugins().forEach { it.onOpenBugReport() } } - override fun onVerifyClicked() { - plugins().forEach { it.onVerifyClicked() } - } - override fun onSecureBackupClicked() { plugins().forEach { it.onSecureBackupClicked() } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt index 3bd762794d..11f3fc3dd3 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootNode.kt @@ -44,7 +44,6 @@ class PreferencesRootNode @AssistedInject constructor( ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun onOpenBugReport() - fun onVerifyClicked() fun onSecureBackupClicked() fun onOpenAnalytics() fun onOpenAbout() @@ -61,10 +60,6 @@ class PreferencesRootNode @AssistedInject constructor( plugins().forEach { it.onOpenBugReport() } } - private fun onVerifyClicked() { - plugins().forEach { it.onVerifyClicked() } - } - private fun onSecureBackupClicked() { plugins().forEach { it.onSecureBackupClicked() } } @@ -138,7 +133,6 @@ class PreferencesRootNode @AssistedInject constructor( onOpenRageShake = this::onOpenBugReport, onOpenAnalytics = this::onOpenAnalytics, onOpenAbout = this::onOpenAbout, - onVerifyClicked = this::onVerifyClicked, onSecureBackupClicked = this::onSecureBackupClicked, onOpenDeveloperSettings = this::onOpenDeveloperSettings, onOpenAdvancedSettings = this::onOpenAdvancedSettings, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt index f80ee11aba..20c28427a8 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenter.kt @@ -74,7 +74,7 @@ class PreferencesRootPresenter @Inject constructor( } // We should display the 'complete verification' option if the current session can be verified - val showCompleteVerification by sessionVerificationService.canVerifySessionFlow.collectAsState(false) + val canVerifyUserSession by sessionVerificationService.canVerifySessionFlow.collectAsState(false) val showSecureBackupIndicator by indicatorService.showSettingChatBackupIndicator() @@ -102,8 +102,7 @@ class PreferencesRootPresenter @Inject constructor( myUser = matrixUser.value, version = versionFormatter.get(), deviceId = matrixClient.deviceId, - showCompleteVerification = showCompleteVerification, - showSecureBackup = !showCompleteVerification, + showSecureBackup = !canVerifyUserSession, showSecureBackupBadge = showSecureBackupIndicator, accountManagementUrl = accountManagementUrl.value, devicesManagementUrl = devicesManagementUrl.value, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootState.kt index eabdc80da0..336690638d 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootState.kt @@ -24,7 +24,6 @@ data class PreferencesRootState( val myUser: MatrixUser, val version: String, val deviceId: String?, - val showCompleteVerification: Boolean, val showSecureBackup: Boolean, val showSecureBackupBadge: Boolean, val accountManagementUrl: String?, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootStateProvider.kt index b688a493b6..3373cb6ba0 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootStateProvider.kt @@ -27,7 +27,6 @@ fun aPreferencesRootState( myUser = myUser, version = "Version 1.1 (1)", deviceId = "ILAKNDNASDLK", - showCompleteVerification = true, showSecureBackup = true, showSecureBackupBadge = true, accountManagementUrl = "aUrl", diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt index 293889e868..c6283158f2 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootView.kt @@ -51,7 +51,6 @@ import io.element.android.libraries.ui.strings.CommonStrings fun PreferencesRootView( state: PreferencesRootState, onBackPressed: () -> Unit, - onVerifyClicked: () -> Unit, onSecureBackupClicked: () -> Unit, onManageAccountClicked: (url: String) -> Unit, onOpenAnalytics: () -> Unit, @@ -81,13 +80,6 @@ fun PreferencesRootView( }, user = state.myUser, ) - if (state.showCompleteVerification) { - ListItem( - headlineContent = { Text(text = stringResource(CommonStrings.common_verify_device)) }, - leadingContent = ListItemContent.Icon(IconSource.Vector(CompoundIcons.CheckCircle())), - onClick = onVerifyClicked - ) - } if (state.showSecureBackup) { ListItem( headlineContent = { Text(stringResource(id = CommonStrings.common_chat_backup)) }, @@ -95,8 +87,6 @@ fun PreferencesRootView( trailingContent = ListItemContent.Badge.takeIf { state.showSecureBackupBadge }, onClick = onSecureBackupClicked, ) - } - if (state.showCompleteVerification || state.showSecureBackup) { HorizontalDivider() } if (state.accountManagementUrl != null) { @@ -232,7 +222,6 @@ private fun ContentToPreview(matrixUser: MatrixUser) { onOpenDeveloperSettings = {}, onOpenAdvancedSettings = {}, onOpenAbout = {}, - onVerifyClicked = {}, onSecureBackupClicked = {}, onManageAccountClicked = {}, onOpenNotificationSettings = {}, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt index 2d590b90c1..9227eef364 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/tasks/ClearCacheUseCase.kt @@ -22,7 +22,7 @@ import android.content.Context import coil.Coil import coil.annotation.ExperimentalCoilApi import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.features.ftue.api.state.FtueState +import io.element.android.features.ftue.api.state.FtueService import io.element.android.features.preferences.impl.DefaultCacheService import io.element.android.features.roomlist.api.migration.MigrationScreenStore import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -45,7 +45,7 @@ class DefaultClearCacheUseCase @Inject constructor( private val coroutineDispatchers: CoroutineDispatchers, private val defaultCacheIndexProvider: DefaultCacheService, private val okHttpClient: Provider, - private val ftueState: FtueState, + private val ftueService: FtueService, private val migrationScreenStore: MigrationScreenStore, ) : ClearCacheUseCase { override suspend fun invoke() = withContext(coroutineDispatchers.io) { @@ -61,7 +61,7 @@ class DefaultClearCacheUseCase @Inject constructor( // Clear app cache context.cacheDir.deleteRecursively() // Clear some settings - ftueState.reset() + ftueService.reset() // Clear migration screen store migrationScreenStore.reset() // Ensure the app is restarted diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt index 3288e94eb4..8bc6e92328 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt @@ -92,7 +92,6 @@ class PreferencesRootPresenterTest { ) ) assertThat(initialState.version).isEqualTo("A Version") - assertThat(loadedState.showCompleteVerification).isTrue() assertThat(loadedState.showSecureBackup).isFalse() assertThat(loadedState.showSecureBackupBadge).isTrue() assertThat(loadedState.accountManagementUrl).isNull() diff --git a/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/RoomListEntryPoint.kt b/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/RoomListEntryPoint.kt index c3b2ff36a2..b5d1c1299f 100644 --- a/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/RoomListEntryPoint.kt +++ b/features/roomlist/api/src/main/kotlin/io/element/android/features/roomlist/api/RoomListEntryPoint.kt @@ -33,7 +33,6 @@ interface RoomListEntryPoint : FeatureEntryPoint { fun onRoomClicked(roomId: RoomId) fun onCreateRoomClicked() fun onSettingsClicked() - fun onSessionVerificationClicked() fun onSessionConfirmRecoveryKeyClicked() fun onInvitesClicked() fun onRoomSettingsClicked(roomId: RoomId) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListNode.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListNode.kt index a9740bcfcb..e9af66d331 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListNode.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListNode.kt @@ -64,10 +64,6 @@ class RoomListNode @AssistedInject constructor( plugins().forEach { it.onCreateRoomClicked() } } - private fun onSessionVerificationClicked() { - plugins().forEach { it.onSessionVerificationClicked() } - } - private fun onSessionConfirmRecoveryKeyClicked() { plugins().forEach { it.onSessionConfirmRecoveryKeyClicked() } } @@ -104,7 +100,6 @@ class RoomListNode @AssistedInject constructor( onRoomClicked = this::onRoomClicked, onSettingsClicked = this::onOpenSettings, onCreateRoomClicked = this::onCreateRoomClicked, - onVerifyClicked = this::onSessionVerificationClicked, onConfirmRecoveryKeyClicked = this::onSessionConfirmRecoveryKeyClicked, onInvitesClicked = this::onInvitesClicked, onRoomSettingsClicked = this::onRoomSettingsClicked, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt index 900e640981..0b5d07dc69 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt @@ -58,7 +58,6 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.api.sync.SyncService import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.timeline.ReceiptType -import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analyticsproviders.api.trackers.captureInteraction import kotlinx.collections.immutable.toPersistentList @@ -92,7 +91,6 @@ class RoomListPresenter @Inject constructor( private val analyticsService: AnalyticsService, ) : Presenter { private val encryptionService: EncryptionService = client.encryptionService() - private val sessionVerificationService: SessionVerificationService = client.sessionVerificationService() private val syncService: SyncService = client.syncService() @Composable @@ -159,19 +157,12 @@ class RoomListPresenter @Inject constructor( securityBannerDismissed: Boolean, ): State { val currentSecurityBannerDismissed by rememberUpdatedState(securityBannerDismissed) - val canVerifySession by sessionVerificationService.canVerifySessionFlow.collectAsState(initial = false) - val isLastDevice by encryptionService.isLastDevice.collectAsState() val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState() val syncState by syncService.syncState.collectAsState() return remember { derivedStateOf { when { currentSecurityBannerDismissed -> SecurityBannerState.None - canVerifySession -> if (isLastDevice) { - SecurityBannerState.RecoveryKeyConfirmation - } else { - SecurityBannerState.SessionVerification - } recoveryState == RecoveryState.INCOMPLETE && syncState == SyncState.Running -> SecurityBannerState.RecoveryKeyConfirmation else -> SecurityBannerState.None diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt index 250f1c8e87..62f59b4eaa 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListState.kt @@ -63,7 +63,6 @@ enum class InvitesState { enum class SecurityBannerState { None, - SessionVerification, RecoveryKeyConfirmation, } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index 00f6833f02..c80430f9fe 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -45,7 +45,6 @@ open class RoomListStateProvider : PreviewParameterProvider { aRoomListState(contentState = aRoomsContentState(invitesState = InvitesState.NewInvites)), aRoomListState(contextMenu = aContextMenuShown(roomName = "A nice room name")), aRoomListState(contextMenu = aContextMenuShown(isFavorite = true)), - aRoomListState(contentState = aRoomsContentState(securityBannerState = SecurityBannerState.SessionVerification)), aRoomListState(contentState = aRoomsContentState(securityBannerState = SecurityBannerState.RecoveryKeyConfirmation)), aRoomListState(contentState = anEmptyContentState()), aRoomListState(contentState = aSkeletonContentState()), diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt index e0a3fc5201..881d06411e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt @@ -53,7 +53,6 @@ fun RoomListView( state: RoomListState, onRoomClicked: (RoomId) -> Unit, onSettingsClicked: () -> Unit, - onVerifyClicked: () -> Unit, onConfirmRecoveryKeyClicked: () -> Unit, onCreateRoomClicked: () -> Unit, onInvitesClicked: () -> Unit, @@ -86,7 +85,6 @@ fun RoomListView( RoomListScaffold( modifier = Modifier.padding(top = topPadding), state = state, - onVerifyClicked = onVerifyClicked, onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked, onRoomClicked = onRoomClicked, onRoomLongClicked = { onRoomLongClicked(it) }, @@ -115,7 +113,6 @@ fun RoomListView( @Composable private fun RoomListScaffold( state: RoomListState, - onVerifyClicked: () -> Unit, onConfirmRecoveryKeyClicked: () -> Unit, onRoomClicked: (RoomId) -> Unit, onRoomLongClicked: (RoomListRoomSummary) -> Unit, @@ -154,7 +151,6 @@ private fun RoomListScaffold( contentState = state.contentState, filtersState = state.filtersState, eventSink = state.eventSink, - onVerifyClicked = onVerifyClicked, onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked, onRoomClicked = ::onRoomClicked, onRoomLongClicked = onRoomLongClicked, @@ -193,7 +189,6 @@ internal fun RoomListViewPreview(@PreviewParameter(RoomListStateProvider::class) state = state, onRoomClicked = {}, onSettingsClicked = {}, - onVerifyClicked = {}, onConfirmRecoveryKeyClicked = {}, onCreateRoomClicked = {}, onInvitesClicked = {}, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RequestVerificationHeader.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RequestVerificationHeader.kt deleted file mode 100644 index d3ad6db206..0000000000 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RequestVerificationHeader.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.features.roomlist.impl.components - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import io.element.android.features.roomlist.impl.R -import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule -import io.element.android.libraries.designsystem.preview.ElementPreview -import io.element.android.libraries.designsystem.preview.PreviewsDayNight - -@Composable -internal fun RequestVerificationHeader( - onVerifyClicked: () -> Unit, - onDismissClicked: () -> Unit, - modifier: Modifier = Modifier, -) { - DialogLikeBannerMolecule( - modifier = modifier, - title = stringResource(R.string.session_verification_banner_title), - content = stringResource(R.string.session_verification_banner_message), - onSubmitClicked = onVerifyClicked, - onDismissClicked = onDismissClicked, - ) -} - -@PreviewsDayNight -@Composable -internal fun RequestVerificationHeaderPreview() = ElementPreview { - RequestVerificationHeader( - onVerifyClicked = {}, - onDismissClicked = {}, - ) -} diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt index 1bb5af4e7a..552ff008a0 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt @@ -73,7 +73,6 @@ fun RoomListContentView( contentState: RoomListContentState, filtersState: RoomListFiltersState, eventSink: (RoomListEvents) -> Unit, - onVerifyClicked: () -> Unit, onConfirmRecoveryKeyClicked: () -> Unit, onRoomClicked: (RoomListRoomSummary) -> Unit, onRoomLongClicked: (RoomListRoomSummary) -> Unit, @@ -103,7 +102,6 @@ fun RoomListContentView( state = contentState, filtersState = filtersState, eventSink = eventSink, - onVerifyClicked = onVerifyClicked, onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked, onRoomClicked = onRoomClicked, onRoomLongClicked = onRoomLongClicked, @@ -161,7 +159,6 @@ private fun RoomsView( state: RoomListContentState.Rooms, filtersState: RoomListFiltersState, eventSink: (RoomListEvents) -> Unit, - onVerifyClicked: () -> Unit, onConfirmRecoveryKeyClicked: () -> Unit, onRoomClicked: (RoomListRoomSummary) -> Unit, onRoomLongClicked: (RoomListRoomSummary) -> Unit, @@ -177,7 +174,6 @@ private fun RoomsView( RoomsViewList( state = state, eventSink = eventSink, - onVerifyClicked = onVerifyClicked, onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked, onRoomClicked = onRoomClicked, onRoomLongClicked = onRoomLongClicked, @@ -191,7 +187,6 @@ private fun RoomsView( private fun RoomsViewList( state: RoomListContentState.Rooms, eventSink: (RoomListEvents) -> Unit, - onVerifyClicked: () -> Unit, onConfirmRecoveryKeyClicked: () -> Unit, onRoomClicked: (RoomListRoomSummary) -> Unit, onRoomLongClicked: (RoomListRoomSummary) -> Unit, @@ -222,14 +217,6 @@ private fun RoomsViewList( contentPadding = PaddingValues(bottom = 80.dp) ) { when (state.securityBannerState) { - SecurityBannerState.SessionVerification -> { - item { - RequestVerificationHeader( - onVerifyClicked = onVerifyClicked, - onDismissClicked = { eventSink(RoomListEvents.DismissRequestVerificationPrompt) } - ) - } - } SecurityBannerState.RecoveryKeyConfirmation -> { item { ConfirmRecoveryKeyBanner( @@ -316,10 +303,10 @@ internal fun RoomListContentViewPreview(@PreviewParameter(RoomListContentStatePr filterSelectionStates = RoomListFilter.entries.map { FilterSelectionState(it, isSelected = true) } ), eventSink = {}, - onVerifyClicked = { }, - onConfirmRecoveryKeyClicked = { }, + onConfirmRecoveryKeyClicked = {}, onRoomClicked = {}, onRoomLongClicked = {}, - onCreateRoomClicked = { }, - onInvitesClicked = { }) + onCreateRoomClicked = {}, + onInvitesClicked = {} + ) } diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index 6b5877a010..0f2c288a63 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -239,52 +239,28 @@ class RoomListPresenterTests { } } - @Test - fun `present - handle RecoveryKeyConfirmation last session`() = runTest { - val scope = CoroutineScope(context = coroutineContext + SupervisorJob()) - val roomListService = FakeRoomListService().apply { - postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) - } - val presenter = createRoomListPresenter( - coroutineScope = scope, - client = FakeMatrixClient( - encryptionService = FakeEncryptionService().apply { - emitIsLastDevice(true) - }, - roomListService = roomListService - ), - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val eventSink = consumeItemsUntilPredicate { - it.contentState is RoomListContentState.Rooms - }.last().eventSink - // For the last session, the state is not SessionVerification, but RecoveryKeyConfirmation - assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.RecoveryKeyConfirmation) - eventSink(RoomListEvents.DismissRequestVerificationPrompt) - assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.None) - scope.cancel() - } - } - @Test fun `present - handle DismissRequestVerificationPrompt`() = runTest { val scope = CoroutineScope(context = coroutineContext + SupervisorJob()) val roomListService = FakeRoomListService().apply { postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) } + val encryptionService = FakeEncryptionService().apply { + emitRecoveryState(RecoveryState.INCOMPLETE) + } + val syncService = FakeSyncService(initialState = SyncState.Running) val presenter = createRoomListPresenter( - client = FakeMatrixClient(roomListService = roomListService), + client = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService, syncService = syncService), coroutineScope = scope, ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - val eventSink = consumeItemsUntilPredicate { + val eventWithContentAsRooms = consumeItemsUntilPredicate { it.contentState is RoomListContentState.Rooms - }.last().eventSink - assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.SessionVerification) + }.last() + val eventSink = eventWithContentAsRooms.eventSink + assertThat(eventWithContentAsRooms.contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.RecoveryKeyConfirmation) eventSink(RoomListEvents.DismissRequestVerificationPrompt) assertThat(awaitItem().contentAsRooms().securityBannerState).isEqualTo(SecurityBannerState.None) scope.cancel() @@ -342,10 +318,10 @@ class RoomListPresenterTests { moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { - consumeItemsUntilPredicate { + val firstItem = consumeItemsUntilPredicate { it.contentState is RoomListContentState.Rooms - } - assertThat(awaitItem().contentAsRooms().invitesState).isEqualTo(InvitesState.NoInvites) + }.last() + assertThat(firstItem.contentAsRooms().invitesState).isEqualTo(InvitesState.NoInvites) inviteStateFlow.value = InvitesState.SeenInvites assertThat(awaitItem().contentAsRooms().invitesState).isEqualTo(InvitesState.SeenInvites) diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListViewTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListViewTest.kt index c860b6fc42..2dbec36395 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListViewTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListViewTest.kt @@ -43,35 +43,6 @@ import org.junit.runner.RunWith class RoomListViewTest { @get:Rule val rule = createAndroidComposeRule() - @Test - fun `clicking on close verification banner emits the expected Event`() { - val eventsRecorder = EventsRecorder() - rule.setRoomListView( - state = aRoomListState( - contentState = aRoomsContentState(securityBannerState = SecurityBannerState.SessionVerification), - eventSink = eventsRecorder, - ) - ) - val close = rule.activity.getString(CommonStrings.action_close) - rule.onNodeWithContentDescription(close).performClick() - eventsRecorder.assertSingle(RoomListEvents.DismissRequestVerificationPrompt) - } - - @Test - fun `clicking on continue verification banner invokes the expected callback`() { - val eventsRecorder = EventsRecorder(expectEvents = false) - ensureCalledOnce { callback -> - rule.setRoomListView( - state = aRoomListState( - contentState = aRoomsContentState(securityBannerState = SecurityBannerState.SessionVerification), - eventSink = eventsRecorder, - ), - onVerifyClicked = callback, - ) - rule.clickOn(CommonStrings.action_continue) - } - } - @Test fun `clicking on close recovery key banner emits the expected Event`() { val eventsRecorder = EventsRecorder() @@ -185,7 +156,6 @@ private fun AndroidComposeTestRule.setRoomL state: RoomListState, onRoomClicked: (RoomId) -> Unit = EnsureNeverCalledWithParam(), onSettingsClicked: () -> Unit = EnsureNeverCalled(), - onVerifyClicked: () -> Unit = EnsureNeverCalled(), onConfirmRecoveryKeyClicked: () -> Unit = EnsureNeverCalled(), onCreateRoomClicked: () -> Unit = EnsureNeverCalled(), onInvitesClicked: () -> Unit = EnsureNeverCalled(), @@ -198,7 +168,6 @@ private fun AndroidComposeTestRule.setRoomL state = state, onRoomClicked = onRoomClicked, onSettingsClicked = onSettingsClicked, - onVerifyClicked = onVerifyClicked, onConfirmRecoveryKeyClicked = onConfirmRecoveryKeyClicked, onCreateRoomClicked = onCreateRoomClicked, onInvitesClicked = onInvitesClicked, diff --git a/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupEntryPoint.kt b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupEntryPoint.kt index 1fee6418a9..8a00063fef 100644 --- a/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupEntryPoint.kt +++ b/features/securebackup/api/src/main/kotlin/io/element/android/features/securebackup/api/SecureBackupEntryPoint.kt @@ -19,6 +19,7 @@ package io.element.android.features.securebackup.api import android.os.Parcelable import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin import io.element.android.libraries.architecture.FeatureEntryPoint import io.element.android.libraries.architecture.NodeInputs import kotlinx.parcelize.Parcelize @@ -36,8 +37,13 @@ interface SecureBackupEntryPoint : FeatureEntryPoint { fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + interface Callback : Plugin { + fun onDone() + } + interface NodeBuilder { fun params(params: Params): NodeBuilder + fun callback(callback: Callback): NodeBuilder fun build(): Node } } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPoint.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPoint.kt index e3d5fde961..d238560463 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPoint.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/DefaultSecureBackupEntryPoint.kt @@ -36,6 +36,11 @@ class DefaultSecureBackupEntryPoint @Inject constructor() : SecureBackupEntryPoi return this } + override fun callback(callback: SecureBackupEntryPoint.Callback): SecureBackupEntryPoint.NodeBuilder { + plugins += callback + return this + } + override fun build(): Node { return parentNode.createNode(buildContext, plugins) } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index 172c6672e5..b698d2719f 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -22,7 +22,9 @@ import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted import dagger.assisted.AssistedInject @@ -74,6 +76,8 @@ class SecureBackupFlowNode @AssistedInject constructor( data object EnterRecoveryKey : NavTarget } + private val callback = plugins().firstOrNull() + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { NavTarget.Root -> { @@ -119,7 +123,16 @@ class SecureBackupFlowNode @AssistedInject constructor( createNode(buildContext) } NavTarget.EnterRecoveryKey -> { - createNode(buildContext) + val callback = object : SecureBackupEnterRecoveryKeyNode.Callback { + override fun onEnterRecoveryKeySuccess() { + if (callback != null) { + callback.onDone() + } else { + backstack.pop() + } + } + } + createNode(buildContext, plugins = listOf(callback)) } } } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyNode.kt index 8c6ae282fa..597ab4c14e 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/enter/SecureBackupEnterRecoveryKeyNode.kt @@ -17,48 +17,36 @@ package io.element.android.features.securebackup.impl.enter import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode -import io.element.android.features.securebackup.impl.R -import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher -import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.di.SessionScope -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch @ContributesNode(SessionScope::class) class SecureBackupEnterRecoveryKeyNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: SecureBackupEnterRecoveryKeyPresenter, - private val snackbarDispatcher: SnackbarDispatcher, ) : Node(buildContext, plugins = plugins) { + interface Callback : Plugin { + fun onEnterRecoveryKeySuccess() + } + + private val callback = plugins().first() + @Composable override fun View(modifier: Modifier) { - val coroutineScope = rememberCoroutineScope() val state = presenter.present() SecureBackupEnterRecoveryKeyView( state = state, modifier = modifier, - onDone = { - coroutineScope.postSuccessSnackbar() - navigateUp() - }, + onDone = callback::onEnterRecoveryKeySuccess, onBackClicked = ::navigateUp, ) } - - private fun CoroutineScope.postSuccessSnackbar() = launch { - snackbarDispatcher.post( - SnackbarMessage( - messageResId = R.string.screen_recovery_key_confirm_success - ) - ) - } } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt index cc97faa6e3..d2e8ad39da 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt @@ -53,7 +53,7 @@ class VerifySelfSessionNode @AssistedInject constructor( state = state, modifier = modifier, onEnterRecoveryKey = ::onEnterRecoveryKey, - goBack = ::onDone, + onFinished = ::onDone, ) } } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt index 2a7740d8d0..a060469199 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt @@ -68,10 +68,10 @@ class VerifySelfSessionPresenter @Inject constructor( when (event) { VerifySelfSessionViewEvents.RequestVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.RequestVerification) VerifySelfSessionViewEvents.StartSasVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.StartSasVerification) - VerifySelfSessionViewEvents.Restart -> stateAndDispatch.dispatchAction(StateMachineEvent.Restart) VerifySelfSessionViewEvents.ConfirmVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.AcceptChallenge) VerifySelfSessionViewEvents.DeclineVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.DeclineChallenge) - VerifySelfSessionViewEvents.CancelAndClose -> stateAndDispatch.dispatchAction(StateMachineEvent.Cancel) + VerifySelfSessionViewEvents.Cancel -> stateAndDispatch.dispatchAction(StateMachineEvent.Cancel) + VerifySelfSessionViewEvents.Reset -> stateAndDispatch.dispatchAction(StateMachineEvent.Reset) } } return VerifySelfSessionState( @@ -118,7 +118,7 @@ class VerifySelfSessionPresenter @Inject constructor( private fun CoroutineScope.observeVerificationService() { sessionVerificationService.verificationFlowState.onEach { verificationAttemptState -> when (verificationAttemptState) { - VerificationFlowState.Initial -> stateMachine.dispatch(VerifySelfSessionStateMachine.Event.Restart) + VerificationFlowState.Initial -> stateMachine.dispatch(VerifySelfSessionStateMachine.Event.Reset) VerificationFlowState.AcceptedVerificationRequest -> { stateMachine.dispatch(VerifySelfSessionStateMachine.Event.DidAcceptVerificationRequest) } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateMachine.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateMachine.kt index 2a1c63370e..29a484521a 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateMachine.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateMachine.kt @@ -20,24 +20,35 @@ package io.element.android.features.verifysession.impl import com.freeletics.flowredux.dsl.FlowReduxStateMachine +import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.core.data.tryOrNull +import io.element.android.libraries.matrix.api.encryption.EncryptionService +import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.SessionVerificationService import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.timeout import javax.inject.Inject +import kotlin.time.Duration.Companion.seconds import com.freeletics.flowredux.dsl.State as MachineState +@OptIn(FlowPreview::class) class VerifySelfSessionStateMachine @Inject constructor( private val sessionVerificationService: SessionVerificationService, + private val encryptionService: EncryptionService, ) : FlowReduxStateMachine( initialState = State.Initial ) { init { spec { inState { - on { _: Event.RequestVerification, state: MachineState -> + on { _: Event.RequestVerification, state -> state.override { State.RequestingVerification } } - on { _: Event.StartSasVerification, state: MachineState -> + on { _: Event.StartSasVerification, state -> state.override { State.StartingSasVerification } } } @@ -45,12 +56,9 @@ class VerifySelfSessionStateMachine @Inject constructor( onEnterEffect { sessionVerificationService.requestVerification() } - on { _: Event.DidAcceptVerificationRequest, state: MachineState -> + on { _: Event.DidAcceptVerificationRequest, state -> state.override { State.VerificationRequestAccepted } } - on { _: Event.DidFail, state: MachineState -> - state.override { State.Initial } - } } inState { onEnterEffect { @@ -58,25 +66,28 @@ class VerifySelfSessionStateMachine @Inject constructor( } } inState { - on { _: Event.StartSasVerification, state: MachineState -> + on { _: Event.StartSasVerification, state -> state.override { State.StartingSasVerification } } } inState { - on { _: Event.Restart, state: MachineState -> + on { _: Event.RequestVerification, state -> state.override { State.RequestingVerification } } + on { _: Event.Reset, state -> + state.override { State.Initial } + } } inState { - on { event: Event.DidReceiveChallenge, state: MachineState -> + on { event: Event.DidReceiveChallenge, state -> state.override { State.Verifying.ChallengeReceived(event.data) } } } inState { - on { _: Event.AcceptChallenge, state: MachineState -> + on { _: Event.AcceptChallenge, state -> state.override { State.Verifying.Replying(state.snapshot.data, accept = true) } } - on { _: Event.DeclineChallenge, state: MachineState -> + on { _: Event.DeclineChallenge, state -> state.override { State.Verifying.Replying(state.snapshot.data, accept = false) } } } @@ -88,11 +99,21 @@ class VerifySelfSessionStateMachine @Inject constructor( sessionVerificationService.declineVerification() } } - on { _: Event.DidAcceptChallenge, state: MachineState -> + on { _: Event.DidAcceptChallenge, state -> + // If a key backup exists, wait until it's restored or a timeout happens + val hasBackup = encryptionService.doesBackupExistOnServer().getOrNull().orFalse() + if (hasBackup) { + tryOrNull { + encryptionService.recoveryStateStateFlow.filter { it == RecoveryState.ENABLED } + .timeout(10.seconds) + .first() + } + } state.override { State.Completed } } } inState { + // TODO The 'Canceling' -> 'Canceled' transitions doesn't seem to work anymore, check if something changed in the Rust SDK onEnterEffect { sessionVerificationService.cancelVerification() } @@ -102,21 +123,24 @@ class VerifySelfSessionStateMachine @Inject constructor( state.override { State.SasVerificationStarted } } on { _: Event.Cancel, state: MachineState -> - if (state.snapshot in sequenceOf( - State.Initial, - State.Completed, - State.Canceled - )) { - state.noChange() - } else { - state.override { State.Canceling } + when (state.snapshot) { + State.Initial, State.Completed, State.Canceled -> state.noChange() + // For some reason `cancelVerification` is not calling its delegate `didCancel` method so we don't pass from + // `Canceling` state to `Canceled` automatically anymore + else -> { + sessionVerificationService.cancelVerification() + state.override { State.Canceled } + } } } on { _: Event.DidCancel, state: MachineState -> state.override { State.Canceled } } on { _: Event.DidFail, state: MachineState -> - state.override { State.Canceled } + when (state.snapshot) { + is State.RequestingVerification -> state.override { State.Initial } + else -> state.override { State.Canceled } + } } } } @@ -190,7 +214,7 @@ class VerifySelfSessionStateMachine @Inject constructor( /** Request failed. */ data object DidFail : Event - /** Restart the verification flow. */ - data object Restart : Event + /** Reset the verification flow to the initial state. */ + data object Reset : Event } } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt index 69fdfc5dfc..7a1ad12b09 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt @@ -30,9 +30,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -42,15 +39,16 @@ import androidx.compose.ui.text.style.TextOverflow 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.verifysession.impl.emoji.toEmojiResource import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule -import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage +import io.element.android.libraries.designsystem.components.BigIcon +import io.element.android.libraries.designsystem.components.PageTitle import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button -import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.matrix.api.verification.SessionVerificationData @@ -62,36 +60,37 @@ import io.element.android.features.verifysession.impl.VerifySelfSessionState.Ver fun VerifySelfSessionView( state: VerifySelfSessionState, onEnterRecoveryKey: () -> Unit, - goBack: () -> Unit, + onFinished: () -> Unit, modifier: Modifier = Modifier, ) { - fun goBackAndCancelIfNeeded() { - state.eventSink(VerifySelfSessionViewEvents.CancelAndClose) - goBack() - } - if (state.verificationFlowStep is FlowStep.Completed) { - goBack() + fun resetFlow() { + state.eventSink(VerifySelfSessionViewEvents.Reset) } BackHandler { - goBackAndCancelIfNeeded() + when (state.verificationFlowStep) { + is FlowStep.Canceled -> resetFlow() + is FlowStep.AwaitingOtherDeviceResponse, FlowStep.Ready -> state.eventSink(VerifySelfSessionViewEvents.Cancel) + is FlowStep.Verifying -> { + if (!state.verificationFlowStep.state.isLoading()) { + state.eventSink(VerifySelfSessionViewEvents.DeclineVerification) + } + } + else -> Unit + } } val verificationFlowStep = state.verificationFlowStep - val buttonsVisible by remember(verificationFlowStep) { - derivedStateOf { verificationFlowStep != FlowStep.AwaitingOtherDeviceResponse && verificationFlowStep != FlowStep.Completed } - } HeaderFooterPage( modifier = modifier, header = { HeaderContent(verificationFlowStep = verificationFlowStep) }, footer = { - if (buttonsVisible) { - BottomMenu( - screenState = state, - goBack = ::goBackAndCancelIfNeeded, - onEnterRecoveryKey = onEnterRecoveryKey - ) - } + BottomMenu( + screenState = state, + goBack = ::resetFlow, + onEnterRecoveryKey = onEnterRecoveryKey, + onFinished = onFinished, + ) } ) { Content(flowState = verificationFlowStep) @@ -100,40 +99,38 @@ fun VerifySelfSessionView( @Composable private fun HeaderContent(verificationFlowStep: FlowStep) { - val iconResourceId = when (verificationFlowStep) { - is FlowStep.Initial -> R.drawable.ic_verification_devices - FlowStep.Canceled -> R.drawable.ic_verification_warning - FlowStep.AwaitingOtherDeviceResponse -> R.drawable.ic_verification_waiting - FlowStep.Ready, is FlowStep.Verifying, FlowStep.Completed -> R.drawable.ic_verification_emoji + val iconStyle = when (verificationFlowStep) { + is FlowStep.Initial, FlowStep.AwaitingOtherDeviceResponse -> BigIcon.Style.Default(CompoundIcons.LockSolid()) + FlowStep.Canceled -> BigIcon.Style.AlertSolid + FlowStep.Ready, is FlowStep.Verifying -> BigIcon.Style.Default(CompoundIcons.Reaction()) + FlowStep.Completed -> BigIcon.Style.SuccessSolid } val titleTextId = when (verificationFlowStep) { - is FlowStep.Initial -> R.string.screen_session_verification_open_existing_session_title + is FlowStep.Initial, FlowStep.AwaitingOtherDeviceResponse -> R.string.screen_identity_confirmation_title FlowStep.Canceled -> CommonStrings.common_verification_cancelled - FlowStep.AwaitingOtherDeviceResponse -> R.string.screen_session_verification_waiting_to_accept_title - FlowStep.Ready, - FlowStep.Completed -> R.string.screen_session_verification_compare_emojis_title + FlowStep.Ready -> R.string.screen_session_verification_compare_emojis_title + FlowStep.Completed -> R.string.screen_identity_confirmed_title is FlowStep.Verifying -> when (verificationFlowStep.data) { is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_title is SessionVerificationData.Emojis -> R.string.screen_session_verification_compare_emojis_title } } val subtitleTextId = when (verificationFlowStep) { - is FlowStep.Initial -> R.string.screen_session_verification_open_existing_session_subtitle + is FlowStep.Initial, FlowStep.AwaitingOtherDeviceResponse -> R.string.screen_identity_confirmation_subtitle FlowStep.Canceled -> R.string.screen_session_verification_cancelled_subtitle - FlowStep.AwaitingOtherDeviceResponse -> R.string.screen_session_verification_waiting_to_accept_subtitle FlowStep.Ready -> R.string.screen_session_verification_ready_subtitle - FlowStep.Completed -> R.string.screen_session_verification_compare_emojis_subtitle + FlowStep.Completed -> R.string.screen_identity_confirmation_subtitle is FlowStep.Verifying -> when (verificationFlowStep.data) { is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_subtitle is SessionVerificationData.Emojis -> R.string.screen_session_verification_compare_emojis_subtitle } } - IconTitleSubtitleMolecule( + PageTitle( modifier = Modifier.padding(top = 60.dp), - iconResourceId = iconResourceId, + iconStyle = iconStyle, title = stringResource(id = titleTextId), - subTitle = stringResource(id = subtitleTextId) + subtitle = stringResource(id = subtitleTextId) ) } @@ -141,20 +138,12 @@ private fun HeaderContent(verificationFlowStep: FlowStep) { private fun Content(flowState: FlowStep) { Column(Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) { when (flowState) { - is FlowStep.Initial, FlowStep.Ready, FlowStep.Canceled, FlowStep.Completed -> Unit - FlowStep.AwaitingOtherDeviceResponse -> ContentWaiting() + is FlowStep.Initial, FlowStep.AwaitingOtherDeviceResponse, FlowStep.Ready, FlowStep.Canceled, FlowStep.Completed -> Unit is FlowStep.Verifying -> ContentVerifying(flowState) } } } -@Composable -private fun ContentWaiting() { - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { - CircularProgressIndicator() - } -} - @Composable private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) { when (verificationFlowStep.data) { @@ -212,76 +201,102 @@ private fun BottomMenu( screenState: VerifySelfSessionState, onEnterRecoveryKey: () -> Unit, goBack: () -> Unit, + onFinished: () -> Unit, ) { val verificationViewState = screenState.verificationFlowStep val eventSink = screenState.eventSink val isVerifying = (verificationViewState as? FlowStep.Verifying)?.state is AsyncData.Loading - val positiveButtonTitle = when (verificationViewState) { - is FlowStep.Initial -> R.string.screen_session_verification_positive_button_initial - FlowStep.Canceled -> R.string.screen_session_verification_positive_button_canceled + + when (verificationViewState) { + is FlowStep.Initial -> { + BottomMenu( + positiveButtonTitle = stringResource(R.string.screen_identity_use_another_device), + onPositiveButtonClicked = { eventSink(VerifySelfSessionViewEvents.RequestVerification) }, + negativeButtonTitle = stringResource(R.string.screen_session_verification_enter_recovery_key), + onNegativeButtonClicked = onEnterRecoveryKey, + ) + } + is FlowStep.Canceled -> { + BottomMenu( + positiveButtonTitle = stringResource(R.string.screen_session_verification_positive_button_canceled), + onPositiveButtonClicked = { eventSink(VerifySelfSessionViewEvents.RequestVerification) }, + negativeButtonTitle = stringResource(CommonStrings.action_cancel), + onNegativeButtonClicked = goBack, + ) + } + is FlowStep.Ready -> { + BottomMenu( + positiveButtonTitle = stringResource(CommonStrings.action_start), + onPositiveButtonClicked = { eventSink(VerifySelfSessionViewEvents.StartSasVerification) }, + negativeButtonTitle = stringResource(CommonStrings.action_cancel), + onNegativeButtonClicked = goBack, + ) + } + is FlowStep.AwaitingOtherDeviceResponse -> { + BottomMenu( + positiveButtonTitle = stringResource(R.string.screen_identity_waiting_on_other_device), + onPositiveButtonClicked = {}, + isLoading = true, + ) + } is FlowStep.Verifying -> { - if (isVerifying) { - R.string.screen_session_verification_positive_button_verifying_ongoing + val positiveButtonTitle = if (isVerifying) { + stringResource(R.string.screen_session_verification_positive_button_verifying_ongoing) } else { - R.string.screen_session_verification_they_match + stringResource(R.string.screen_session_verification_they_match) } + BottomMenu( + positiveButtonTitle = positiveButtonTitle, + onPositiveButtonClicked = { + if (!isVerifying) { + eventSink(VerifySelfSessionViewEvents.ConfirmVerification) + } + }, + negativeButtonTitle = stringResource(R.string.screen_session_verification_they_dont_match), + onNegativeButtonClicked = { eventSink(VerifySelfSessionViewEvents.DeclineVerification) }, + isLoading = isVerifying, + ) } - FlowStep.Ready -> CommonStrings.action_start - else -> null - } - val negativeButtonTitle = when (verificationViewState) { - is FlowStep.Initial -> CommonStrings.action_cancel - FlowStep.Canceled -> CommonStrings.action_cancel - is FlowStep.Verifying -> R.string.screen_session_verification_they_dont_match - else -> null - } - val negativeButtonEnabled = !isVerifying - - val positiveButtonEvent = when (verificationViewState) { - is FlowStep.Initial -> VerifySelfSessionViewEvents.RequestVerification - FlowStep.Ready -> VerifySelfSessionViewEvents.StartSasVerification - is FlowStep.Verifying -> if (!isVerifying) VerifySelfSessionViewEvents.ConfirmVerification else null - FlowStep.Canceled -> VerifySelfSessionViewEvents.Restart - else -> null - } - - val negativeButtonCallback: () -> Unit = when (verificationViewState) { - is FlowStep.Verifying -> { - { eventSink(VerifySelfSessionViewEvents.DeclineVerification) } + is FlowStep.Completed -> { + BottomMenu( + positiveButtonTitle = stringResource(CommonStrings.action_continue), + onPositiveButtonClicked = onFinished, + ) } - else -> goBack } +} +@Composable +private fun BottomMenu( + positiveButtonTitle: String?, + onPositiveButtonClicked: () -> Unit, + modifier: Modifier = Modifier, + negativeButtonTitle: String? = null, + negativeButtonEnabled: Boolean = negativeButtonTitle != null, + onNegativeButtonClicked: () -> Unit = {}, + isLoading: Boolean = false, +) { ButtonColumnMolecule( - modifier = Modifier.padding(bottom = 20.dp) + modifier = modifier.padding(bottom = 16.dp) ) { if (positiveButtonTitle != null) { Button( - text = stringResource(positiveButtonTitle), - showProgress = isVerifying, + text = positiveButtonTitle, + showProgress = isLoading, modifier = Modifier.fillMaxWidth(), - onClick = { positiveButtonEvent?.let { eventSink(it) } } + onClick = onPositiveButtonClicked, ) } if (negativeButtonTitle != null) { TextButton( - text = stringResource(negativeButtonTitle), + text = negativeButtonTitle, modifier = Modifier.fillMaxWidth(), - onClick = negativeButtonCallback, + onClick = onNegativeButtonClicked, enabled = negativeButtonEnabled, ) - } - if (verificationViewState is FlowStep.Initial && verificationViewState.canEnterRecoveryKey) { - Text( - text = stringResource(id = CommonStrings.common_or), - color = ElementTheme.colors.textSecondary, - ) - TextButton( - text = stringResource(R.string.screen_session_verification_enter_recovery_key), - modifier = Modifier.fillMaxWidth(), - onClick = onEnterRecoveryKey, - ) + } else { + Spacer(modifier = Modifier.height(48.dp)) } } } @@ -292,6 +307,6 @@ internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionSta VerifySelfSessionView( state = state, onEnterRecoveryKey = {}, - goBack = {}, + onFinished = {}, ) } diff --git a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt index 8f9c69085c..2b86ca6f18 100644 --- a/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt +++ b/features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt @@ -19,8 +19,8 @@ package io.element.android.features.verifysession.impl sealed interface VerifySelfSessionViewEvents { data object RequestVerification : VerifySelfSessionViewEvents data object StartSasVerification : VerifySelfSessionViewEvents - data object Restart : VerifySelfSessionViewEvents data object ConfirmVerification : VerifySelfSessionViewEvents data object DeclineVerification : VerifySelfSessionViewEvents - data object CancelAndClose : VerifySelfSessionViewEvents + data object Cancel : VerifySelfSessionViewEvents + data object Reset : VerifySelfSessionViewEvents } diff --git a/features/verifysession/impl/src/main/res/drawable/ic_verification_devices.xml b/features/verifysession/impl/src/main/res/drawable/ic_verification_devices.xml deleted file mode 100644 index 8ae6dd30fa..0000000000 --- a/features/verifysession/impl/src/main/res/drawable/ic_verification_devices.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/features/verifysession/impl/src/main/res/drawable/ic_verification_emoji.xml b/features/verifysession/impl/src/main/res/drawable/ic_verification_emoji.xml deleted file mode 100644 index 82583a4011..0000000000 --- a/features/verifysession/impl/src/main/res/drawable/ic_verification_emoji.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/features/verifysession/impl/src/main/res/drawable/ic_verification_waiting.xml b/features/verifysession/impl/src/main/res/drawable/ic_verification_waiting.xml deleted file mode 100644 index 5b9f2e3cfc..0000000000 --- a/features/verifysession/impl/src/main/res/drawable/ic_verification_waiting.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/features/verifysession/impl/src/main/res/drawable/ic_verification_warning.xml b/features/verifysession/impl/src/main/res/drawable/ic_verification_warning.xml deleted file mode 100644 index 882ac62cd7..0000000000 --- a/features/verifysession/impl/src/main/res/drawable/ic_verification_warning.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/features/verifysession/impl/src/main/res/values/localazy.xml b/features/verifysession/impl/src/main/res/values/localazy.xml index b46954f42b..9fea2d98df 100644 --- a/features/verifysession/impl/src/main/res/values/localazy.xml +++ b/features/verifysession/impl/src/main/res/values/localazy.xml @@ -1,5 +1,11 @@ + "Verify this device to set up secure messaging." + "Confirm that it\'s you" + "Now you can read or send messages securely, and anyone you chat with can also trust this device." + "Device verified" + "Use another device" + "Waiting on other device…" "Something doesn’t seem right. Either the request timed out or the request was denied." "Confirm that the emojis below match those shown on your other session." "Compare emojis" diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt index ad128b450d..025e782e8f 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTests.kt @@ -106,13 +106,13 @@ class VerifySelfSessionPresenterTests { val initialState = awaitItem() assertThat(initialState.verificationFlowStep).isEqualTo(VerificationStep.Initial(false)) val eventSink = initialState.eventSink - eventSink(VerifySelfSessionViewEvents.CancelAndClose) + eventSink(VerifySelfSessionViewEvents.Cancel) expectNoEvents() } } @Test - fun `present - A fail in the flow cancels it`() = runTest { + fun `present - A failure when verifying cancels it`() = runTest { val service = FakeSessionVerificationService() val presenter = createVerifySelfSessionPresenter(service) moleculeFlow(RecompositionMode.Immediate) { @@ -128,6 +128,21 @@ class VerifySelfSessionPresenterTests { } } + @Test + fun `present - A fail when requesting verification resets the state to the initial one`() = runTest { + val service = FakeSessionVerificationService() + val presenter = createVerifySelfSessionPresenter(service) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + service.shouldFail = true + awaitItem().eventSink(VerifySelfSessionViewEvents.RequestVerification) + service.shouldFail = false + assertThat(awaitItem().verificationFlowStep).isInstanceOf(VerificationStep.AwaitingOtherDeviceResponse::class.java) + assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Initial(false)) + } + } + @Test fun `present - Canceling the flow once it's verifying cancels it`() = runTest { val service = FakeSessionVerificationService() @@ -136,8 +151,7 @@ class VerifySelfSessionPresenterTests { presenter.present() }.test { val state = requestVerificationAndAwaitVerifyingState(service) - state.eventSink(VerifySelfSessionViewEvents.CancelAndClose) - assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) + state.eventSink(VerifySelfSessionViewEvents.Cancel) assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) } } @@ -165,13 +179,30 @@ class VerifySelfSessionPresenterTests { val state = requestVerificationAndAwaitVerifyingState(service) service.givenVerificationFlowState(VerificationFlowState.Canceled) assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) - state.eventSink(VerifySelfSessionViewEvents.Restart) + state.eventSink(VerifySelfSessionViewEvents.RequestVerification) // Went back to requesting verification assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse) cancelAndIgnoreRemainingEvents() } } + @Test + fun `present - Go back after cancelation returns to initial state`() = runTest { + val service = FakeSessionVerificationService() + val presenter = createVerifySelfSessionPresenter(service) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val state = requestVerificationAndAwaitVerifyingState(service) + service.givenVerificationFlowState(VerificationFlowState.Canceled) + assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Canceled) + state.eventSink(VerifySelfSessionViewEvents.Reset) + // Went back to initial state + assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Initial(false)) + cancelAndIgnoreRemainingEvents() + } + } + @Test fun `present - When verification is approved, the flow completes if there is no error`() = runTest { val emojis = listOf( @@ -247,7 +278,7 @@ class VerifySelfSessionPresenterTests { return VerifySelfSessionPresenter( sessionVerificationService = service, encryptionService = encryptionService, - stateMachine = VerifySelfSessionStateMachine(service), + stateMachine = VerifySelfSessionStateMachine(service, encryptionService), ) } } diff --git a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt index 4dfad8c9c9..1ca5bca32f 100644 --- a/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt +++ b/features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt @@ -36,45 +36,98 @@ class VerifySelfSessionViewTest { @get:Rule val rule = createAndroidComposeRule() @Test - fun `clicking on cancel calls the expected callback and emits the expected Event`() { + fun `back key pressed - when canceled resets the flow`() { val eventsRecorder = EventsRecorder() - ensureCalledOnce { callback -> - rule.setContent { - VerifySelfSessionView( - aVerifySelfSessionState( - verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial(true), - eventSink = eventsRecorder - ), - onEnterRecoveryKey = EnsureNeverCalled(), - goBack = callback, - ) - } - rule.clickOn(CommonStrings.action_cancel) + rule.setContent { + VerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.Canceled, + eventSink = eventsRecorder + ), + onEnterRecoveryKey = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), + ) } - eventsRecorder.assertSingle(VerifySelfSessionViewEvents.CancelAndClose) + rule.pressBackKey() + eventsRecorder.assertSingle(VerifySelfSessionViewEvents.Reset) } @Test - fun `clicking on back key calls the expected callback and emits the expected Event`() { + fun `back key pressed - when awaiting response cancels the verification`() { val eventsRecorder = EventsRecorder() - ensureCalledOnce { callback -> - rule.setContent { - VerifySelfSessionView( - aVerifySelfSessionState( - verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial(true), - eventSink = eventsRecorder - ), - onEnterRecoveryKey = EnsureNeverCalled(), - goBack = callback, - ) - } - rule.pressBackKey() + rule.setContent { + VerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.AwaitingOtherDeviceResponse, + eventSink = eventsRecorder + ), + onEnterRecoveryKey = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), + ) } - eventsRecorder.assertSingle(VerifySelfSessionViewEvents.CancelAndClose) + rule.pressBackKey() + eventsRecorder.assertSingle(VerifySelfSessionViewEvents.Cancel) } @Test - fun `when flow is completed, the expected callback is invoked`() { + fun `back key pressed - when ready to verify cancels the verification`() { + val eventsRecorder = EventsRecorder() + rule.setContent { + VerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.Ready, + eventSink = eventsRecorder + ), + onEnterRecoveryKey = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), + ) + } + rule.pressBackKey() + eventsRecorder.assertSingle(VerifySelfSessionViewEvents.Cancel) + } + + @Test + fun `back key pressed - when verifying and not loading declines the verification`() { + val eventsRecorder = EventsRecorder() + rule.setContent { + VerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying( + data = aEmojisSessionVerificationData(), + state = AsyncData.Uninitialized, + ), + eventSink = eventsRecorder + ), + onEnterRecoveryKey = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), + ) + } + rule.pressBackKey() + eventsRecorder.assertSingle(VerifySelfSessionViewEvents.DeclineVerification) + } + + @Test + fun `back key pressed - when verifying and loading does nothing`() { + val eventsRecorder = EventsRecorder() + rule.setContent { + VerifySelfSessionView( + aVerifySelfSessionState( + verificationFlowStep = VerifySelfSessionState.VerificationStep.Verifying( + data = aEmojisSessionVerificationData(), + state = AsyncData.Loading(), + ), + eventSink = eventsRecorder + ), + onEnterRecoveryKey = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), + ) + } + rule.pressBackKey() + eventsRecorder.assertEmpty() + } + + @Test + fun `when flow is completed and the user clicks on the continue button, the expected callback is invoked`() { val eventsRecorder = EventsRecorder(expectEvents = false) ensureCalledOnce { callback -> rule.setContent { @@ -84,9 +137,10 @@ class VerifySelfSessionViewTest { eventSink = eventsRecorder ), onEnterRecoveryKey = EnsureNeverCalled(), - goBack = callback, + onFinished = callback, ) } + rule.clickOn(CommonStrings.action_continue) } } @@ -102,7 +156,7 @@ class VerifySelfSessionViewTest { eventSink = eventsRecorder ), onEnterRecoveryKey = callback, - goBack = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), ) } rule.clickOn(R.string.screen_session_verification_enter_recovery_key) @@ -122,7 +176,7 @@ class VerifySelfSessionViewTest { eventSink = eventsRecorder ), onEnterRecoveryKey = EnsureNeverCalled(), - goBack = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), ) } rule.clickOn(R.string.screen_session_verification_they_match) @@ -142,7 +196,7 @@ class VerifySelfSessionViewTest { eventSink = eventsRecorder ), onEnterRecoveryKey = EnsureNeverCalled(), - goBack = EnsureNeverCalled(), + onFinished = EnsureNeverCalled(), ) } rule.clickOn(R.string.screen_session_verification_they_dont_match) diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/IconTitleSubtitleMolecule.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/IconTitleSubtitleMolecule.kt index 1dc7230973..b90cf80aaa 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/IconTitleSubtitleMolecule.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/molecules/IconTitleSubtitleMolecule.kt @@ -32,6 +32,7 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize +import io.element.android.libraries.designsystem.icons.CompoundDrawables import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Text @@ -95,3 +96,14 @@ internal fun IconTitleSubtitleMoleculePreview() = ElementPreview { subTitle = "Subtitle", ) } + +@PreviewsDayNight +@Composable +internal fun IconTitleSubtitleMoleculeWithResIconPreview() = ElementPreview { + IconTitleSubtitleMolecule( + iconResourceId = CompoundDrawables.ic_compound_admin, + iconTint = Color.Black, + title = "Title", + subTitle = "Subtitle", + ) +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/PageTitle.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/PageTitle.kt index 9ff8ef38da..de1e25f5f3 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/PageTitle.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/PageTitle.kt @@ -52,9 +52,7 @@ fun PageTitle( callToAction: @Composable (() -> Unit)? = null, ) { Column( - modifier = modifier - .fillMaxWidth() - .padding(bottom = 40.dp), + modifier = modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, ) { BigIcon(style = iconStyle) diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt index 00fd9dc561..8d22fc174e 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/verification/SessionVerificationService.kt @@ -85,6 +85,9 @@ sealed interface SessionVerifiedStatus { /** Verified session status. */ data object Verified : SessionVerifiedStatus + + /** Returns whether the session is [Verified]. */ + fun isVerified(): Boolean = this is Verified } /** States produced by the [SessionVerificationService]. */ diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 0212a5293a..546acc6e84 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -40,6 +40,7 @@ import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryServic import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.awaitLoaded import io.element.android.libraries.matrix.api.sync.SyncService +import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.verification.SessionVerificationService @@ -84,8 +85,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -130,11 +130,6 @@ class RustMatrixClient( private val innerRoomListService = syncService.roomListService() private val sessionDispatcher = dispatchers.io.limitedParallelism(64) private val rustSyncService = RustSyncService(syncService, sessionCoroutineScope) - private val verificationService = RustSessionVerificationService( - client = client, - syncService = rustSyncService, - sessionCoroutineScope = sessionCoroutineScope, - ).apply { start() } private val pushersService = RustPushersService( client = client, dispatchers = dispatchers, @@ -230,6 +225,12 @@ class RustMatrixClient( ), ) + private val verificationService = RustSessionVerificationService( + client = client, + isSyncServiceReady = rustSyncService.syncState.map { it == SyncState.Running }, + sessionCoroutineScope = sessionCoroutineScope, + ) + private val eventFilters = TimelineConfig.excludedEvents .takeIf { it.isNotEmpty() } ?.let { listStateEventType -> @@ -274,11 +275,6 @@ class RustMatrixClient( .stateIn(sessionCoroutineScope, started = SharingStarted.Eagerly, initialValue = persistentListOf()) init { - roomListService.state.onEach { state -> - if (state == RoomListService.State.Running) { - setupVerificationControllerIfNeeded() - } - }.launchIn(sessionCoroutineScope) sessionCoroutineScope.launch { // Force a refresh of the profile getUserProfile() @@ -490,6 +486,7 @@ class RustMatrixClient( ignoreSdkError: Boolean, ): String? { var result: String? = null + syncService.stop() withContext(sessionDispatcher) { if (doRequest) { try { @@ -525,16 +522,6 @@ class RustMatrixClient( } } - private fun setupVerificationControllerIfNeeded() { - if (verificationService.verificationController == null) { - try { - verificationService.verificationController = client.getSessionVerificationController() - } catch (e: Throwable) { - Timber.e(e, "Could not start verification service. Will try again on the next sliding sync update.") - } - } - } - override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver private suspend fun File.getCacheSize( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt index 157e751d21..bb0821570b 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/verification/RustSessionVerificationService.kt @@ -16,92 +16,135 @@ package io.element.android.libraries.matrix.impl.verification -import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.data.tryOrNull -import io.element.android.libraries.matrix.api.sync.SyncState import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationFlowState -import io.element.android.libraries.matrix.impl.sync.RustSyncService import io.element.android.libraries.matrix.impl.util.cancelAndDestroy import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.Encryption import org.matrix.rustcomponents.sdk.RecoveryState import org.matrix.rustcomponents.sdk.RecoveryStateListener import org.matrix.rustcomponents.sdk.SessionVerificationController import org.matrix.rustcomponents.sdk.SessionVerificationControllerDelegate -import org.matrix.rustcomponents.sdk.SessionVerificationControllerInterface import org.matrix.rustcomponents.sdk.TaskHandle +import org.matrix.rustcomponents.sdk.VerificationState +import org.matrix.rustcomponents.sdk.VerificationStateListener import org.matrix.rustcomponents.sdk.use +import timber.log.Timber import org.matrix.rustcomponents.sdk.SessionVerificationData as RustSessionVerificationData class RustSessionVerificationService( client: Client, - private val syncService: RustSyncService, - private val sessionCoroutineScope: CoroutineScope, + isSyncServiceReady: Flow, + sessionCoroutineScope: CoroutineScope, ) : SessionVerificationService, SessionVerificationControllerDelegate { + private var verificationStateListenerTaskHandle: TaskHandle? = null private var recoveryStateListenerTaskHandle: TaskHandle? = null private val encryptionService: Encryption = client.encryption() - var verificationController: SessionVerificationControllerInterface? = null - set(value) { - field = value - _isReady.value = value != null - // If status was 'Unknown', move it to either 'Verified' or 'NotVerified' - if (value != null) { - value.setDelegate(this) - sessionCoroutineScope.launch { updateVerificationStatus(value.isVerified()) } - } - } + private lateinit var verificationController: SessionVerificationController private val _verificationFlowState = MutableStateFlow(VerificationFlowState.Initial) override val verificationFlowState = _verificationFlowState.asStateFlow() - private val _isReady = MutableStateFlow(false) - override val isReady = _isReady.asStateFlow() - private val _sessionVerifiedStatus = MutableStateFlow(SessionVerifiedStatus.Unknown) override val sessionVerifiedStatus: StateFlow = _sessionVerifiedStatus.asStateFlow() - override val canVerifySessionFlow = combine(sessionVerifiedStatus, syncService.syncState) { verificationStatus, syncState -> - syncState == SyncState.Running && verificationStatus == SessionVerifiedStatus.NotVerified + override val isReady = MutableStateFlow(false) + + override val canVerifySessionFlow = combine(sessionVerifiedStatus, isReady) { verificationStatus, isReady -> + isReady && verificationStatus == SessionVerifiedStatus.NotVerified } - fun start() { - recoveryStateListenerTaskHandle = encryptionService.recoveryStateListener(object : RecoveryStateListener { - override fun onUpdate(status: RecoveryState) { - sessionCoroutineScope.launch { - updateVerificationStatus(verificationController?.isVerified().orFalse()) + init { + isSyncServiceReady + .onEach { syncServiceReady -> + if (syncServiceReady) { + isReady.value = true + runCatching { + // If the controller was failed to initialize before, we try to get it again + if (!this::verificationController.isInitialized) { + verificationController = client.getSessionVerificationController() + } + } + .onFailure { + isReady.value = false + Timber.e(it, "Failed to get verification controller. Trying again in next sync.") + } + } else { + isReady.value = false } } - }) + .launchIn(sessionCoroutineScope) + + isReady.onEach { isReady -> + if (isReady) { + Timber.d("Starting verification service") + // Setup delegate + verificationController.setDelegate(this) + + // Immediate status update + updateVerificationStatus(encryptionService.verificationState()) + + // Listen for changes in verification status and update accordingly + verificationStateListenerTaskHandle?.cancelAndDestroy() + verificationStateListenerTaskHandle = encryptionService.verificationStateListener(object : VerificationStateListener { + override fun onUpdate(status: VerificationState) { + Timber.d("New verification state: $status") + updateVerificationStatus(status) + } + }) + + // In case we enter the recovery key instead we check changes in the recovery state, since the listener above won't be triggered + recoveryStateListenerTaskHandle?.cancelAndDestroy() + recoveryStateListenerTaskHandle = encryptionService.recoveryStateListener(object : RecoveryStateListener { + override fun onUpdate(status: RecoveryState) { + Timber.d("New recovery state: $status") + // We could check the `RecoveryState`, but it's easier to just use the verification state directly + updateVerificationStatus(encryptionService.verificationState()) + } + }) + } else { + Timber.d("Stopping verification service") + if (this::verificationController.isInitialized) { + verificationController.setDelegate(null) + } + } + } + .launchIn(sessionCoroutineScope) } override suspend fun requestVerification() = tryOrFail { - verificationController?.requestVerification() + verificationController.requestVerification() } - override suspend fun cancelVerification() = tryOrFail { verificationController?.cancelVerification() } + override suspend fun cancelVerification() = tryOrFail { verificationController.cancelVerification() } - override suspend fun approveVerification() = tryOrFail { verificationController?.approveVerification() } + override suspend fun approveVerification() = tryOrFail { verificationController.approveVerification() } - override suspend fun declineVerification() = tryOrFail { verificationController?.declineVerification() } + override suspend fun declineVerification() = tryOrFail { verificationController.declineVerification() } override suspend fun startVerification() = tryOrFail { - verificationController?.startSasVerification() + verificationController.startSasVerification() } private suspend fun tryOrFail(block: suspend () -> Unit) { runCatching { block() - }.onFailure { didFail() } + }.onFailure { + Timber.e(it, "Failed to verify session") + didFail() + } } // region Delegate implementation @@ -116,13 +159,14 @@ class RustSessionVerificationService( } override fun didFail() { + Timber.e("Session verification failed with an unknown error") _verificationFlowState.value = VerificationFlowState.Failed } override fun didFinish() { _verificationFlowState.value = VerificationFlowState.Finished // Ideally this should be `verificationController?.isVerified().orFalse()` but for some reason it always returns false - updateVerificationStatus(isVerified = true) + updateVerificationStatus(VerificationState.VERIFIED) } override fun didReceiveVerificationData(data: RustSessionVerificationData) { @@ -139,25 +183,26 @@ class RustSessionVerificationService( override suspend fun reset() { if (isReady.value) { // Cancel any pending verification attempt - tryOrNull { verificationController?.cancelVerification() } + tryOrNull { verificationController.cancelVerification() } } _verificationFlowState.value = VerificationFlowState.Initial } fun destroy() { + Timber.d("Destroying RustSessionVerificationService") recoveryStateListenerTaskHandle?.cancelAndDestroy() - verificationController?.setDelegate(null) - (verificationController as? SessionVerificationController)?.destroy() - verificationController = null + if (this::verificationController.isInitialized) { + verificationController.setDelegate(null) + (verificationController as? SessionVerificationController)?.destroy() + } } - private fun updateVerificationStatus(isVerified: Boolean) { - val newValue = when { - !isReady.value -> SessionVerifiedStatus.Unknown - !isVerified -> SessionVerifiedStatus.NotVerified - else -> SessionVerifiedStatus.Verified + private fun updateVerificationStatus(verificationState: VerificationState) { + _sessionVerifiedStatus.value = when (verificationState) { + VerificationState.UNKNOWN -> SessionVerifiedStatus.Unknown + VerificationState.VERIFIED -> SessionVerifiedStatus.Verified + VerificationState.UNVERIFIED -> SessionVerifiedStatus.NotVerified } - _sessionVerifiedStatus.value = newValue } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt index 4a7aa1c304..64c7c8ab97 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/verification/FakeSessionVerificationService.kt @@ -38,7 +38,11 @@ class FakeSessionVerificationService : SessionVerificationService { override val isReady: StateFlow = _isReady override suspend fun requestVerification() { - _verificationFlowState.value = VerificationFlowState.AcceptedVerificationRequest + if (!shouldFail) { + _verificationFlowState.value = VerificationFlowState.AcceptedVerificationRequest + } else { + _verificationFlowState.value = VerificationFlowState.Failed + } } override suspend fun cancelVerification() { diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 2f9812fc79..97ddec4b3b 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -254,6 +254,8 @@ "Failed selecting media, please try again." "Failed processing media to upload, please try again." "Failed uploading media, please try again." + "Failed loading" + "Room directory" "Failed processing media to upload, please try again." "Could not retrieve user details" "Block" diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt index 7bf3261371..264a754e73 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt @@ -152,7 +152,6 @@ class RoomListScreen( state = state, onRoomClicked = ::onRoomClicked, onSettingsClicked = {}, - onVerifyClicked = {}, onConfirmRecoveryKeyClicked = {}, onCreateRoomClicked = {}, onInvitesClicked = {}, diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index a8bf2184ef..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:455964d5b4d1652b5b9eeb8b7236f14c2c9490123399e8c65f1b9e920d20071d -size 21053 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_2,NEXUS_5,1.0,en].png deleted file mode 100644 index e6c83e61de..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Day-57_57_null_2,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:84d78e6672aaafd2c7974630e7d9391ee7e649c9a9de470627d1ed6e1241a1f4 -size 13366 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_0,NEXUS_5,1.0,en].png deleted file mode 100644 index 098d9fe800..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_0,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c90e7168839f33c8ea4ef79308cc2b1c7a1ad4ec07dbeedba14dd080a3a841d8 -size 20169 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_2,NEXUS_5,1.0,en].png deleted file mode 100644 index 302905149e..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.messages.impl.timeline.components.virtual_EncryptedHistoryBannerView_null_EncryptedHistoryBannerView-Night-57_58_null_2,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0628f8cd42815e725efc8f7bfe0bc790c2369f8d4cabfd31aabd494a469f7379 -size 12867 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png index d4df69f743..c54c15e9ca 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be4d708775d03680be450dfd5eebfeda24f1841eedced3e7de2ba036669ac479 -size 39086 +oid sha256:75fb611e02345fe1cf7947d1e160e309cf8520f0256ebd25b43bab8c3102f3f8 +size 37138 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png index 9d950f5916..90e78c16a5 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewDark_null_PreferencesRootViewDark--1_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:53660f4354d2a750ab539370151c9ee4ac49f9d06712f7646fdd487bf133753a -size 38766 +oid sha256:a7be4df5a4e391d2253f283acf0fb9362b965fa887235221b794915d74891899 +size 36783 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png index d8b913deea..4f2683cf78 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ae1828957e00adcbdbb772a0ebdc1fb6604afbe644cc5d8662da9fcd3973129 -size 41162 +oid sha256:67503a61f560ef79d7e981057094dccf46eda167ee84427c1aceb9f83edf0146 +size 39080 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png index 7f24f64da5..12e2374878 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.preferences.impl.root_PreferencesRootViewLight_null_PreferencesRootViewLight--0_0_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58e567815b4dc36abf8422b17f9902d8581dbec1a1ed216df2f120c6198b6fe5 -size 41124 +oid sha256:5cb3be70de8e3878bdd90db9945aed60fb2b38d8c66ea610806226c21b1f5a5a +size 39052 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-8_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-7_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-8_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Day-7_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-8_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-7_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-8_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBarWithIndicator_null_DefaultRoomListTopBarWithIndicator-Night-7_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-7_8_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-6_7_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-7_8_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Day-6_7_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-7_9_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-6_8_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-7_9_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_DefaultRoomListTopBar_null_DefaultRoomListTopBar-Night-6_8_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Day-5_6_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Day-5_6_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 1ff9a4e140..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Day-5_6_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f5fd867f51badedc8e9ded0900eb904ac11af348243573dcf34b8aaa3c1548b7 -size 26926 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Night-5_7_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Night-5_7_null,NEXUS_5,1.0,en].png deleted file mode 100644 index 604e02b79d..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RequestVerificationHeader_null_RequestVerificationHeader-Night-5_7_null,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:318838247c7d0cee133fd5c98bbbee6f2c5be09a95b6c2fd293c041e21480ab8 -size 26080 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-6_7_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Day-5_6_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-6_8_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomListContentView_null_RoomListContentView-Night-5_7_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Day-9_10_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Day-8_9_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Day-9_10_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Day-8_9_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Night-9_11_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Night-8_10_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Night-9_11_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryPlaceholderRow_null_RoomSummaryPlaceholderRow-Night-8_10_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_10,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_10,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_11,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_11,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_12,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_12,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_13,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_13,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_14,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_14,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_15,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_15,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_15,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_16,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_16,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_17,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_17,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_18,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_18,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_18,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_19,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_19,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_19,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_20,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_20,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_21,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_21,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_22,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_22,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_22,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_23,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_23,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_23,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_24,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_24,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_25,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_25,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_26,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_26,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_27,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_27,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_8,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_8,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-10_11_null_9,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Day-9_10_null_9,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_10,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_10,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_11,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_11,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_12,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_12,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_13,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_13,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_14,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_14,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_14,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_15,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_15,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_15,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_16,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_16,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_16,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_17,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_17,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_17,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_18,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_18,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_18,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_19,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_19,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_19,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_20,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_20,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_20,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_21,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_21,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_21,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_22,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_22,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_22,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_23,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_23,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_23,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_24,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_24,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_24,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_25,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_25,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_25,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_26,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_26,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_26,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_27,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_27,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_27,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_3,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_3,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_4,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_4,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_5,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_5,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_6,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_6,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_7,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_7,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_8,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_8,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-10_12_null_9,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.components_RoomSummaryRow_null_RoomSummaryRow-Night-9_11_null_9,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-11_12_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-10_11_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-11_12_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-10_11_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-11_12_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-10_11_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-11_12_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Day-10_11_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-11_13_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-10_12_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-11_13_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-10_12_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-11_13_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-10_12_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-11_13_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.filters_RoomListFiltersView_null_RoomListFiltersView-Night-10_12_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-12_13_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-11_12_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-12_13_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Day-11_12_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-12_14_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-11_13_null,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-12_14_null,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.migration_MigrationView_null_MigrationView-Night-11_13_null,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-13_14_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Day-12_13_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_0,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_0,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_0,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_1,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_1,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_1,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_2,NEXUS_5,1.0,en].png similarity index 100% rename from tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-13_15_null_2,NEXUS_5,1.0,en].png rename to tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl.search_RoomListSearchResultContent_null_RoomListSearchResultContent-Night-12_14_null_2,NEXUS_5,1.0,en].png diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png index 761cb8d3a8..1ff067e54b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_10,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8de26fbd49153871bdd18defc2297b2ab314f541fe598894a9c81fe633488db7 -size 51359 +oid sha256:0197c643bbbbc46dbb58ac8911b61003bb09fceb15f1997cba64bcb00aee90fe +size 162642 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png index 1ff067e54b..3057c59ef7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_11,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0197c643bbbbc46dbb58ac8911b61003bb09fceb15f1997cba64bcb00aee90fe -size 162642 +oid sha256:af42c9891a6670cdde07cf054e139ce1f83e877bb68f60463fcad6dd28d8e049 +size 6867 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png index 3057c59ef7..19b6010d17 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_12,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:af42c9891a6670cdde07cf054e139ce1f83e877bb68f60463fcad6dd28d8e049 -size 6867 +oid sha256:46e28da384551af27bf9c52a45c17b8441f8875494b3d3fd901ad66f5d7ff89b +size 74803 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_13,NEXUS_5,1.0,en].png deleted file mode 100644 index 19b6010d17..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_13,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:46e28da384551af27bf9c52a45c17b8441f8875494b3d3fd901ad66f5d7ff89b -size 74803 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png index a5a84223bb..872429b353 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ecdd0cf6f38c2be14eaad9152d7f0eac02682d12c10703abc605bcc73adbb92 -size 86084 +oid sha256:3f314f241b95aeaccd576c8235cfd907abaf5d796b5dc6f4e2acac8a4b9c7c2d +size 88678 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_8,NEXUS_5,1.0,en].png index 872429b353..6efd101dac 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f314f241b95aeaccd576c8235cfd907abaf5d796b5dc6f4e2acac8a4b9c7c2d -size 88678 +oid sha256:a0037f0401b53088f2a75af67f8e4df374866fbce80c052535af1d97354c9b22 +size 56605 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png index 6efd101dac..761cb8d3a8 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Day-3_4_null_9,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0037f0401b53088f2a75af67f8e4df374866fbce80c052535af1d97354c9b22 -size 56605 +oid sha256:8de26fbd49153871bdd18defc2297b2ab314f541fe598894a9c81fe633488db7 +size 51359 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png index 168ee31a4d..043a1223a4 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_10,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:35f35f058cff4435c278ba8cb9f60d68edabcc5da3ab58823abf99a082346978 -size 53292 +oid sha256:4b167704c2d05c857715aa11c3d7fb3abdf3b59ad7d6d2c479936d934a67f32d +size 186756 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png index 043a1223a4..08cfca5c0b 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_11,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b167704c2d05c857715aa11c3d7fb3abdf3b59ad7d6d2c479936d934a67f32d -size 186756 +oid sha256:6e95dac6e75d3f615ccf4d8e98f1780d8aeace1cddf0b33bba8b485860d3216b +size 6688 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png index 08cfca5c0b..52eccc7865 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_12,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e95dac6e75d3f615ccf4d8e98f1780d8aeace1cddf0b33bba8b485860d3216b -size 6688 +oid sha256:58ce650742396cd4addf9f545b2488bc2666e848b361a501d3ea2508c92c2a8a +size 76908 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_13,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_13,NEXUS_5,1.0,en].png deleted file mode 100644 index 52eccc7865..0000000000 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_13,NEXUS_5,1.0,en].png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:58ce650742396cd4addf9f545b2488bc2666e848b361a501d3ea2508c92c2a8a -size 76908 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png index 21f5c4f252..2728c83aa1 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:308e785ea0c43cafd2daea869ecad96cb2e4baeffd747148f1c2f853604603c8 -size 88246 +oid sha256:59c4e7f70dbef1f7c95edc705729dc37f7be3e96f48264e5b63c51f92c13aa22 +size 90762 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_8,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_8,NEXUS_5,1.0,en].png index 2728c83aa1..9b8391501a 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_8,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_8,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59c4e7f70dbef1f7c95edc705729dc37f7be3e96f48264e5b63c51f92c13aa22 -size 90762 +oid sha256:528d43fa1989f1368c33f4f447347caa2fefb92c3a0a1e48846974ad96f262de +size 58510 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png index 9b8391501a..168ee31a4d 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomlist.impl_RoomListView_null_RoomListView-Night-3_5_null_9,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:528d43fa1989f1368c33f4f447347caa2fefb92c3a0a1e48846974ad96f262de -size 58510 +oid sha256:35f35f058cff4435c278ba8cb9f60d68edabcc5da3ab58823abf99a082346978 +size 53292 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png index 25be545a89..87165509bc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e5c225258a6b257afcfc935971df619199a8985ad87203528d27a166a6fda2a -size 28334 +oid sha256:2ef711f98b345d4913e930a4ef2794d1d4ae2f19e29f842548664713dbc2f82c +size 27670 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en].png index abbb0fefb9..cdd4902766 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c13a37dfd42c7e3872cb7854b5f4b5b03e24e40f1751a8a3c430376cab8a0669 -size 27203 +oid sha256:97b2c76523b5475a45d7023960356feee4748ef3be6fa6a33b0f727b327dc667 +size 25541 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png index f239a76249..dddcf52c2f 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c4545536311f20615a2809a067af9eabf1a9398f39a9df819dd3c0a4c3de64bd -size 51321 +oid sha256:5f6269ea5f1be9794e768671ba27d44932ce8d7a2d2d599ad2a9837e6346d7ba +size 50761 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png index 4e7f01ae48..ff7200bbe7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26759996939952786a94b9d860e02c40154c0903a49afb8e7be05a20787f0fa4 -size 52615 +oid sha256:e1ba54ee6e97535ca0a350f687ea64e826c1c590e67fddf95ff5e6f85c9ca0ea +size 52342 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png index 22ffbb29ae..eeb7a029bb 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ce368edd4536137fb4545fb21892c51af43d7325f21b6e34e5ac1a72b818b34 -size 31575 +oid sha256:eb6e3df51c248b69357ec7dd3dd8c5ba8bb8c579c8f08e5279039c78d50c541e +size 31024 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png index 7dec5258da..771889d3c2 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4bff39ac46298be6b968326b64c632aa73b13a51f1efff512d5c6894c414a1b -size 20951 +oid sha256:aa8ed00e0184ac4636fbf26b42dd10893e1bc9aa64b6107922d7ad97e7304d80 +size 21927 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png index 7908dfeabd..e37ce30fa7 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0843965afef3d142709f377ab408866cacfb016f652107ee84dc2fd39770ff17 -size 35490 +oid sha256:ae000f0f2e0f81cf75588d800f3b623f875db1dee7d5459abebfb1cbb67d5da1 +size 34937 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en].png index 609952770e..87165509bc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Day-0_1_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cbaaf6ee91626a9e8db83ce42be14e1a02a8c841230bf7829fa74aff8cbdfab -size 32513 +oid sha256:2ef711f98b345d4913e930a4ef2794d1d4ae2f19e29f842548664713dbc2f82c +size 27670 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png index 0795fad021..e2a4d4b4b3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ef7b72a829b4add1f21b5f7fc06d6a260227b9c065c08ad770d70656b28f815 -size 26848 +oid sha256:f8cb1d19005b68d1f9f09240f58937bdf30efd00bf87758693791bda6627191f +size 25745 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en].png index 54d46147c0..74ea9fb0bc 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_1,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:383436d7acb3474d2d217bce7e566f9ca2957324fca95eb2ffb93fa1b2038082 -size 26117 +oid sha256:1141421ad8fc3ebc2e321a45604dd1d6dc4494a9ae7b860e7853e4a0cd610d5f +size 23697 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png index 128acd813b..a3bd57d7a0 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_2,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9fdcab5fa8620cb0ba0cc0cb822fe4a4807198dbbcd7de7dd7a230d2fe3030e0 -size 49141 +oid sha256:7a1b73e341ce8c0932f1253b9ee159a219e1b64abef54f14b286ac551b2542e4 +size 48479 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png index c8329b273e..1ccd2010c9 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_3,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:06b8e6bce1573d8e39a1bf5823945733152fde066a394a3e90f2bf8dc7929ea3 -size 50526 +oid sha256:f06386b912ef02aa34cd1806588c065e76ab1373892cd62ded705537dd593a81 +size 50027 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png index 2db49fef25..62977b86c3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_4,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:10c16c9a29f898a6a33f8bfa10df24d2da9adb93eeb764e2b744c6efe531890e -size 30007 +oid sha256:118b4d64a5977842c3d65d27bcf545cef8b5bf62f8417ab66934553fd3985b67 +size 29534 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png index 29ac2f3227..e00771d913 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_5,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4786a280d694ead76992dfa75f09bd2e20c292376509f86462a359d19be3e50 -size 19984 +oid sha256:35409dad83ef81e0aaa74a36b350e028d07a5d90cdcc75c29f9156fbdeb2e3c1 +size 20771 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png index b2be2a2397..507ff9cd8e 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_6,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59cabf858188557db3f2660f71cafc9b041977c656693dc5bc009da71a5c7648 -size 33457 +oid sha256:5da97854c7dd24f5f890ff1bcce8e8061892f2a66b919caf254c85ecf1831c38 +size 32717 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en].png index cb997ffa7d..e2a4d4b4b3 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.verifysession.impl_VerifySelfSessionView_null_VerifySelfSessionView-Night-0_2_null_7,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efcf672eba104371f27b43c9204d207f11f9ce42098da0e4dce3da4aa6639153 -size 30517 +oid sha256:f8cb1d19005b68d1f9f09240f58937bdf30efd00bf87758693791bda6627191f +size 25745 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Day_0_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Day_0_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..461a325d97 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Day_0_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2050a2e304b492d54d2cc20ee65f02f7ae0d380a33e207b41e2bb8a8cae4dac8 +size 10117 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Night_1_null,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Night_1_null,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..ae59789889 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[l.designsystem.atomic.molecules_IconTitleSubtitleMoleculeWithResIcon_null_IconTitleSubtitleMoleculeWithResIcon-Night_1_null,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfb15c08455c3b7c323ed81362d56beddf84a387ff06d30336dbfab75b4df8a9 +size 9732 diff --git a/tools/localazy/config.json b/tools/localazy/config.json index d63ede5638..566ea071e0 100644 --- a/tools/localazy/config.json +++ b/tools/localazy/config.json @@ -48,7 +48,8 @@ { "name" : ":features:verifysession:impl", "includeRegex" : [ - "screen_session_verification_.*" + "screen_session_verification_.*", + "screen_identity_.*" ] }, {