From d4c1bb61bbebdc1f6a5e30e59c9b31dad37fe1db Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 25 Sep 2026 15:48:00 +0200 Subject: [PATCH 1/9] Always open the sign out screen from the settings Remove the direct logout dialog from the settings and from the home screen, where it was never triggered. The sign out screen will later display the account information (#7765). The direct logout is still used in the FTUE session verification screen, so remove only the now unused `canDoDirectSignOut` field. Co-Authored-By: Claude Opus 5.5 (1M context) --- features/home/impl/build.gradle.kts | 2 - .../features/home/impl/HomeFlowNode.kt | 3 -- .../features/home/impl/HomePresenter.kt | 4 -- .../android/features/home/impl/HomeState.kt | 2 - .../home/impl/HomeStatePreviewParam.kt | 4 -- .../home/impl/DefaultHomeEntryPointTest.kt | 1 - .../features/home/impl/HomePresenterTest.kt | 2 - .../logout/api/direct/DirectLogoutState.kt | 1 - .../direct/DirectLogoutStatePreviewParam.kt | 2 - .../impl/direct/DirectLogoutPresenter.kt | 15 ------- .../impl/direct/DirectLogoutPresenterTest.kt | 44 ------------------- .../account/PreferencesAccountPresenter.kt | 5 --- .../impl/account/PreferencesAccountState.kt | 2 - .../PreferencesAccountStatePreviewParam.kt | 4 -- .../impl/root/PreferencesRootNode.kt | 13 +----- .../PreferencesAccountPresenterTest.kt | 3 -- 16 files changed, 1 insertion(+), 106 deletions(-) diff --git a/features/home/impl/build.gradle.kts b/features/home/impl/build.gradle.kts index c66a4fd0e6..5a9bb700f2 100644 --- a/features/home/impl/build.gradle.kts +++ b/features/home/impl/build.gradle.kts @@ -53,7 +53,6 @@ dependencies { implementation(projects.features.announcement.api) implementation(projects.features.invite.api) implementation(projects.features.networkmonitor.api) - implementation(projects.features.logout.api) implementation(projects.features.leaveroom.api) implementation(projects.features.rageshake.api) implementation(projects.services.analytics.api) @@ -67,7 +66,6 @@ dependencies { testCommonDependencies(libs, true) testImplementation(projects.features.announcement.test) testImplementation(projects.features.invite.test) - testImplementation(projects.features.logout.test) testImplementation(projects.features.networkmonitor.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.featureflag.test) diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt index 20f27f67bd..74dd6e441d 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeFlowNode.kt @@ -40,7 +40,6 @@ import io.element.android.features.invite.api.InviteData import io.element.android.features.invite.api.acceptdecline.AcceptDeclineInviteView import io.element.android.features.invite.api.declineandblock.DeclineInviteAndBlockEntryPoint import io.element.android.features.leaveroom.api.LeaveRoomRenderer -import io.element.android.features.logout.api.direct.DirectLogoutView import io.element.android.features.reportroom.api.ReportRoomEntryPoint import io.element.android.features.rolesandpermissions.api.ChangeRoomMemberRolesEntryPoint import io.element.android.features.rolesandpermissions.api.ChangeRoomMemberRolesListType @@ -83,7 +82,6 @@ class HomeFlowNode( private val inviteFriendsUseCase: InviteFriendsUseCase, private val analyticsService: AnalyticsService, private val acceptDeclineInviteView: AcceptDeclineInviteView, - private val directLogoutView: DirectLogoutView, private val reportRoomEntryPoint: ReportRoomEntryPoint, private val declineInviteAndBlockUserEntryPoint: DeclineInviteAndBlockEntryPoint, private val changeRoomMemberRolesEntryPoint: ChangeRoomMemberRolesEntryPoint, @@ -248,7 +246,6 @@ class HomeFlowNode( ) } ) - directLogoutView.Render(state.directLogoutState) } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomePresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomePresenter.kt index 1e49b1aa70..f0bcedbb43 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomePresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomePresenter.kt @@ -21,7 +21,6 @@ import androidx.compose.runtime.setValue import dev.zacsweers.metro.Inject import io.element.android.features.home.impl.roomlist.RoomListState import io.element.android.features.home.impl.spaces.HomeSpacesState -import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.features.rageshake.api.RageshakeFeatureAvailability import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher @@ -42,7 +41,6 @@ class HomePresenter( private val indicatorService: IndicatorService, private val roomListPresenter: Presenter, private val homeSpacesPresenter: Presenter, - private val logoutPresenter: Presenter, private val rageshakeFeatureAvailability: RageshakeFeatureAvailability, private val sessionStore: SessionStore, ) : Presenter { @@ -75,7 +73,6 @@ class HomePresenter( } // Avatar indicator val showAvatarIndicator by indicatorService.showRoomListTopBarIndicator() - val directLogoutState = logoutPresenter.present() fun handleEvent(event: HomeEvent) { when (event) { @@ -98,7 +95,6 @@ class HomePresenter( homeSpacesState = homeSpacesState, snackbarMessage = snackbarMessage, canReportBug = canReportBug, - directLogoutState = directLogoutState, eventSink = ::handleEvent, ) } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt index ae59ef8eb9..462084aefb 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt @@ -11,7 +11,6 @@ package io.element.android.features.home.impl import io.element.android.features.home.impl.roomlist.RoomListState import io.element.android.features.home.impl.spacefilters.SpaceFiltersState import io.element.android.features.home.impl.spaces.HomeSpacesState -import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList @@ -29,7 +28,6 @@ data class HomeState( val homeSpacesState: HomeSpacesState, val snackbarMessage: SnackbarMessage?, val canReportBug: Boolean, - val directLogoutState: DirectLogoutState, val eventSink: (HomeEvent) -> Unit, ) { val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStatePreviewParam.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStatePreviewParam.kt index 14ab6dc7f6..f39942275a 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStatePreviewParam.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeStatePreviewParam.kt @@ -16,8 +16,6 @@ import io.element.android.features.home.impl.roomlist.aRoomsContentState import io.element.android.features.home.impl.roomlist.generateRoomListRoomSummaryList import io.element.android.features.home.impl.spaces.HomeSpacesState import io.element.android.features.home.impl.spaces.aHomeSpacesState -import io.element.android.features.logout.api.direct.DirectLogoutState -import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.user.MatrixUser @@ -63,7 +61,6 @@ internal fun aHomeState( roomListState: RoomListState = aRoomListState(), homeSpacesState: HomeSpacesState = aHomeSpacesState(), canReportBug: Boolean = true, - directLogoutState: DirectLogoutState = aDirectLogoutState(), eventSink: (HomeEvent) -> Unit = {} ) = HomeState( currentUserAndNeighbors = currentUserAndNeighbors.toImmutableList(), @@ -71,7 +68,6 @@ internal fun aHomeState( hasNetworkConnection = hasNetworkConnection, snackbarMessage = snackbarMessage, canReportBug = canReportBug, - directLogoutState = directLogoutState, currentHomeNavigationBarItem = currentHomeNavigationBarItem, roomListState = roomListState, homeSpacesState = homeSpacesState, diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt index c0cb5f7c01..cf9336b6ea 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/DefaultHomeEntryPointTest.kt @@ -36,7 +36,6 @@ class DefaultHomeEntryPointTest : RobolectricTest() { inviteFriendsUseCase = { lambdaError() }, analyticsService = FakeAnalyticsService(), acceptDeclineInviteView = { _, _, _, _ -> lambdaError() }, - directLogoutView = { _ -> lambdaError() }, reportRoomEntryPoint = { _, _, _ -> lambdaError() }, declineInviteAndBlockUserEntryPoint = FakeDeclineInviteAndBlockEntryPoint(), changeRoomMemberRolesEntryPoint = { _, _, _, _ -> lambdaError() }, diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt index 58ad4eb100..a5553352db 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/HomePresenterTest.kt @@ -12,7 +12,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.home.impl.roomlist.aRoomListState import io.element.android.features.home.impl.spaces.HomeSpacesState import io.element.android.features.home.impl.spaces.aHomeSpacesState -import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.features.rageshake.api.RageshakeFeatureAvailability import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher @@ -162,7 +161,6 @@ internal fun createHomePresenter( indicatorService = indicatorService, roomListPresenter = { aRoomListState() }, homeSpacesPresenter = homeSpacesPresenter, - logoutPresenter = { aDirectLogoutState() }, rageshakeFeatureAvailability = rageshakeFeatureAvailability, sessionStore = sessionStore, ) diff --git a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutState.kt b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutState.kt index 75c3392ac1..62b4d36bd1 100644 --- a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutState.kt +++ b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutState.kt @@ -11,7 +11,6 @@ package io.element.android.features.logout.api.direct import io.element.android.libraries.architecture.AsyncAction data class DirectLogoutState( - val canDoDirectSignOut: Boolean, val logoutAction: AsyncAction, val eventSink: (DirectLogoutEvent) -> Unit, ) diff --git a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutStatePreviewParam.kt b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutStatePreviewParam.kt index 936f7d2a58..ca1d9fbd0b 100644 --- a/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutStatePreviewParam.kt +++ b/features/logout/api/src/main/kotlin/io/element/android/features/logout/api/direct/DirectLogoutStatePreviewParam.kt @@ -23,11 +23,9 @@ open class DirectLogoutStatePreviewParam : PreviewParameterProvider = AsyncAction.Uninitialized, eventSink: (DirectLogoutEvent) -> Unit = {}, ) = DirectLogoutState( - canDoDirectSignOut = canDoDirectSignOut, logoutAction = logoutAction, eventSink = eventSink, ) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenter.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenter.kt index 79798dd2ab..0b18856ff4 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenter.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenter.kt @@ -10,28 +10,22 @@ package io.element.android.features.logout.impl.direct import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import dev.zacsweers.metro.Inject import io.element.android.features.logout.api.direct.DirectLogoutEvent import io.element.android.features.logout.api.direct.DirectLogoutState -import io.element.android.features.logout.impl.tools.isBackingUp import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.matrix.api.MatrixClient -import io.element.android.libraries.matrix.api.encryption.BackupUploadState -import io.element.android.libraries.matrix.api.encryption.EncryptionService import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @Inject class DirectLogoutPresenter( private val matrixClient: MatrixClient, - private val encryptionService: EncryptionService, ) : Presenter { @Composable override fun present(): DirectLogoutState { @@ -41,13 +35,6 @@ class DirectLogoutPresenter( mutableStateOf(AsyncAction.Uninitialized) } - val backupUploadState: BackupUploadState by remember { - encryptionService.waitForBackupUploadSteadyState() - } - .collectAsState(initial = BackupUploadState.Unknown) - - val isLastDevice by encryptionService.isLastDevice.collectAsState() - fun handleEvent(event: DirectLogoutEvent) { when (event) { is DirectLogoutEvent.Logout -> { @@ -64,8 +51,6 @@ class DirectLogoutPresenter( } return DirectLogoutState( - canDoDirectSignOut = !isLastDevice && - !backupUploadState.isBackingUp(), logoutAction = logoutAction.value, eventSink = ::handleEvent, ) diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenterTest.kt index d11c31cf1b..ff0420e04d 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenterTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/direct/DirectLogoutPresenterTest.kt @@ -16,13 +16,9 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.logout.api.direct.DirectLogoutEvent import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.MatrixClient -import io.element.android.libraries.matrix.api.encryption.BackupUploadState -import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.tests.testutils.WarmUpRule -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -38,44 +34,6 @@ class DirectLogoutPresenterTest { presenter.present() }.test { val initialState = awaitFirstItem() - assertThat(initialState.canDoDirectSignOut).isTrue() - assertThat(initialState.logoutAction).isEqualTo(AsyncAction.Uninitialized) - } - } - - @Test - fun `present - initial state - last session`() = runTest { - val presenter = createDirectLogoutPresenter( - encryptionService = FakeEncryptionService().apply { - emitIsLastDevice(true) - } - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - val initialState = awaitFirstItem() - assertThat(initialState.canDoDirectSignOut).isFalse() - assertThat(initialState.logoutAction).isEqualTo(AsyncAction.Uninitialized) - } - } - - @Test - fun `present - initial state - backing up`() = runTest { - val encryptionService = FakeEncryptionService() - encryptionService.givenWaitForBackupUploadSteadyStateFlow( - flow { - emit(BackupUploadState.Waiting) - } - ) - val presenter = createDirectLogoutPresenter( - encryptionService = encryptionService - ) - moleculeFlow(RecompositionMode.Immediate) { - presenter.present() - }.test { - skipItems(1) - val initialState = awaitFirstItem() - assertThat(initialState.canDoDirectSignOut).isFalse() assertThat(initialState.logoutAction).isEqualTo(AsyncAction.Uninitialized) } } @@ -180,9 +138,7 @@ class DirectLogoutPresenterTest { private fun createDirectLogoutPresenter( matrixClient: MatrixClient = FakeMatrixClient(), - encryptionService: EncryptionService = FakeEncryptionService(), ): DirectLogoutPresenter = DirectLogoutPresenter( matrixClient = matrixClient, - encryptionService = encryptionService, ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt index ad9686be9c..4e04cd0ab6 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenter.kt @@ -17,7 +17,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import dev.zacsweers.metro.Inject import io.element.android.features.enterprise.api.SessionEnterpriseService -import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.features.rageshake.api.RageshakeFeatureAvailability import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher @@ -34,7 +33,6 @@ class PreferencesAccountPresenter( private val sessionVerificationService: SessionVerificationService, private val snackbarDispatcher: SnackbarDispatcher, private val indicatorService: IndicatorService, - private val directLogoutPresenter: Presenter, private val rageshakeFeatureAvailability: RageshakeFeatureAvailability, private val featureFlagService: FeatureFlagService, private val sessionEnterpriseService: SessionEnterpriseService, @@ -65,8 +63,6 @@ class PreferencesAccountPresenter( canDeactivateAccount = matrixClient.canDeactivateAccount() } - val directLogoutState = directLogoutPresenter.present() - val accountManagementUrl by produceState(initialValue = null) { value = matrixClient.getAccountManagementUrl(null) .getOrNull() @@ -83,7 +79,6 @@ class PreferencesAccountPresenter( canReportBug = canReportBug, showLinkNewDevice = showLinkNewDevice, canDeactivateAccount = canDeactivateAccount, - directLogoutState = directLogoutState, snackbarMessage = snackbarMessage, ) } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountState.kt index 00abbf2ad4..eaf65328f0 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountState.kt @@ -7,7 +7,6 @@ package io.element.android.features.preferences.impl.account -import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.user.MatrixUser @@ -19,6 +18,5 @@ data class PreferencesAccountState( val canReportBug: Boolean, val showLinkNewDevice: Boolean, val canDeactivateAccount: Boolean, - val directLogoutState: DirectLogoutState, val snackbarMessage: SnackbarMessage?, ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountStatePreviewParam.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountStatePreviewParam.kt index 0cf42104ef..2308b75d43 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountStatePreviewParam.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountStatePreviewParam.kt @@ -8,8 +8,6 @@ package io.element.android.features.preferences.impl.account import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.features.logout.api.direct.DirectLogoutState -import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser @@ -56,7 +54,6 @@ fun aPreferencesAccountState( canReportBug: Boolean = false, showLinkNewDevice: Boolean = false, canDeactivateAccount: Boolean = false, - directLogoutState: DirectLogoutState = aDirectLogoutState(), snackbarMessage: SnackbarMessage? = null, ) = PreferencesAccountState( myUser = myUser, @@ -66,6 +63,5 @@ fun aPreferencesAccountState( canReportBug = canReportBug, showLinkNewDevice = showLinkNewDevice, canDeactivateAccount = canDeactivateAccount, - directLogoutState = directLogoutState, snackbarMessage = snackbarMessage, ) 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 57ed6294fa..c4416ad61e 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 @@ -19,8 +19,6 @@ import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode import io.element.android.compound.theme.ElementTheme -import io.element.android.features.logout.api.direct.DirectLogoutEvent -import io.element.android.features.logout.api.direct.DirectLogoutView import io.element.android.features.preferences.impl.account.PreferencesAccountCallback import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab import io.element.android.libraries.architecture.callback @@ -34,7 +32,6 @@ class PreferencesRootNode( @Assisted plugins: List, private val presenter: PreferencesRootPresenter, private val emojiPickerRenderer: EmojiPickerRenderer, - private val directLogoutView: DirectLogoutView, ) : Node(buildContext, plugins = plugins) { interface Callback : PreferencesAccountCallback, Plugin { fun navigateToAddAccount() @@ -89,16 +86,8 @@ class PreferencesRootNode( onManageAccountClick = { onManageAccountClick(activity, it, isDark) }, onOpenNotificationSettings = callback::navigateToNotificationSettings, onEditProfileClick = callback::navigateToUserProfile, - onSignOutClick = { - if (state.preferencesAccountState.directLogoutState.canDoDirectSignOut) { - state.preferencesAccountState.directLogoutState.eventSink(DirectLogoutEvent.Logout(ignoreSdkError = false)) - } else { - callback.startSignOutFlow() - } - }, + onSignOutClick = callback::startSignOutFlow, onDeactivateClick = callback::startAccountDeactivationFlow ) - - directLogoutView.Render(state = state.preferencesAccountState.directLogoutState) } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenterTest.kt index cd1bd186f4..dce2d78a0d 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/account/PreferencesAccountPresenterTest.kt @@ -10,7 +10,6 @@ package io.element.android.features.preferences.impl.account import com.google.common.truth.Truth.assertThat import io.element.android.features.enterprise.api.SessionEnterpriseService import io.element.android.features.enterprise.test.FakeSessionEnterpriseService -import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.features.rageshake.api.RageshakeFeatureAvailability import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.featureflag.api.FeatureFlagService @@ -65,7 +64,6 @@ class PreferencesAccountPresenterTest { assertThat(initialState.showSecureBackupBadge).isFalse() assertThat(initialState.accountManagementUrl).isNull() assertThat(initialState.showLinkNewDevice).isFalse() - assertThat(initialState.directLogoutState).isEqualTo(aDirectLogoutState()) assertThat(initialState.snackbarMessage).isNull() val loadedState = consumeItemsUntilPredicate { it.accountManagementUrl != null }.last() assertThat(loadedState.showSecureBackup).isFalse() @@ -169,7 +167,6 @@ class PreferencesAccountPresenterTest { sessionVerificationService = sessionVerificationService, snackbarDispatcher = SnackbarDispatcher(), indicatorService = indicatorService, - directLogoutPresenter = { aDirectLogoutState() }, rageshakeFeatureAvailability = rageshakeFeatureAvailability, featureFlagService = featureFlagService, sessionEnterpriseService = sessionEnterpriseService, From 3de59bbd88ffdd9f9d1a8596f46f00bd1edade97 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 25 Sep 2026 16:19:29 +0200 Subject: [PATCH 2/9] Logout screen: add Cancel button and update icon. --- .../android/features/logout/impl/LogoutView.kt | 12 ++++++++++-- .../features/logout/impl/LogoutViewTest.kt | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt index 90a502fc16..cdfca04036 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt @@ -32,6 +32,7 @@ import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.LinearProgressIndicator import io.element.android.libraries.designsystem.theme.components.OutlinedButton import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.BackupUploadState @@ -54,7 +55,7 @@ fun LogoutView( onBackClick = onBackClick, title = title(state), subTitle = subtitle(state), - iconStyle = BigIcon.Style.Default(CompoundIcons.KeySolid()), + iconStyle = BigIcon.Style.Default(CompoundIcons.Mobile()), modifier = modifier, buttons = { Buttons( @@ -62,7 +63,8 @@ fun LogoutView( onChangeRecoveryKeyClick = onChangeRecoveryKeyClick, onLogoutClick = { eventSink(LogoutEvent.Logout(ignoreSdkError = false)) - } + }, + onCancelClick = onBackClick, ) }, ) { @@ -116,6 +118,7 @@ private fun ColumnScope.Buttons( state: LogoutState, onLogoutClick: () -> Unit, onChangeRecoveryKeyClick: () -> Unit, + onCancelClick: () -> Unit, ) { val logoutAction = state.logoutAction if (state.isLastDevice) { @@ -139,6 +142,11 @@ private fun ColumnScope.Buttons( .testTag(TestTags.signOut), onClick = onLogoutClick, ) + TextButton( + text = stringResource(id = CommonStrings.action_cancel), + modifier = Modifier.fillMaxWidth(), + onClick = onCancelClick, + ) } @Composable diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt index f69ec8f0ca..c1a480b0ed 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt @@ -88,10 +88,24 @@ class LogoutViewTest : RobolectricTest() { eventSink = eventsRecorder ), ) - clickOn(CommonStrings.action_cancel) + clickOn(CommonStrings.action_cancel, inDialog = true) eventsRecorder.assertSingle(LogoutEvent.CloseDialogs) } + @Test + fun `clicking on cancel invoke back callback`() = runAndroidComposeUiTest { + val eventsRecorder = EventsRecorder(expectEvents = false) + ensureCalledOnce { callback -> + setLogoutView( + aLogoutState( + eventSink = eventsRecorder + ), + onBackClick = callback, + ) + clickOn(CommonStrings.action_cancel) + } + } + @Test fun `last session setting button invoke onChangeRecoveryKeyClicked`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder(expectEvents = false) From e1ec0b3c55da02072afb481e88f12bae338f0418 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 28 Sep 2026 09:15:48 +0200 Subject: [PATCH 3/9] Logout screen: add account info. --- features/logout/impl/build.gradle.kts | 1 + .../features/logout/impl/LogoutPresenter.kt | 2 + .../features/logout/impl/LogoutState.kt | 2 + .../logout/impl/LogoutStatePreviewParam.kt | 5 + .../features/logout/impl/LogoutView.kt | 14 +- .../logout/impl/LogoutPresenterTest.kt | 11 +- .../features/logout/impl/LogoutViewTest.kt | 17 ++ .../components/avatar/AvatarSize.kt | 1 + .../components/accountinfo/AccountInfoCard.kt | 193 ++++++++++++++++++ .../accountinfo/AccountInfoCardState.kt | 33 +++ .../AccountInfoCardStatePreviewParam.kt | 41 ++++ 11 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt create mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardState.kt create mode 100644 libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardStatePreviewParam.kt diff --git a/features/logout/impl/build.gradle.kts b/features/logout/impl/build.gradle.kts index d5356ced63..bc6646a68f 100644 --- a/features/logout/impl/build.gradle.kts +++ b/features/logout/impl/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(projects.libraries.architecture) implementation(projects.libraries.featureflag.api) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) implementation(projects.libraries.designsystem) implementation(projects.libraries.testtags) implementation(projects.libraries.uiStrings) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutPresenter.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutPresenter.kt index 4ad8a6c78e..a3cd2f6429 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutPresenter.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutPresenter.kt @@ -41,6 +41,7 @@ class LogoutPresenter( @Composable override fun present(): LogoutState { val localCoroutineScope = rememberCoroutineScope() + val currentUser by matrixClient.userProfile.collectAsState() val logoutAction: MutableState> = remember { mutableStateOf(AsyncAction.Uninitialized) } @@ -90,6 +91,7 @@ class LogoutPresenter( } return LogoutState( + currentUser = currentUser, isLastDevice = isLastDevice, backupState = backupState, doesBackupExistOnServer = doesBackupExistOnServerAction.value.dataOrNull().orTrue(), diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutState.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutState.kt index 6233c1cb23..dfab1906fb 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutState.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutState.kt @@ -12,8 +12,10 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.BackupUploadState import io.element.android.libraries.matrix.api.encryption.RecoveryState +import io.element.android.libraries.matrix.api.user.MatrixUser data class LogoutState( + val currentUser: MatrixUser, val isLastDevice: Boolean, val backupState: BackupState, val doesBackupExistOnServer: Boolean, diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt index e2d948a7f3..f30a9e7d77 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt @@ -14,11 +14,14 @@ import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.BackupUploadState import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.encryption.SteadyStateException +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUser open class LogoutStatePreviewParam : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aLogoutState(), + aLogoutState(currentUser = aMatrixUser(id = "@alice:server.org", displayName = null)), aLogoutState(isLastDevice = true), aLogoutState(isLastDevice = false, backupUploadState = BackupUploadState.Uploading(66, 200)), aLogoutState(isLastDevice = true, backupUploadState = BackupUploadState.Done), @@ -43,6 +46,7 @@ open class LogoutStatePreviewParam : PreviewParameterProvider { } fun aLogoutState( + currentUser: MatrixUser = aMatrixUser(), isLastDevice: Boolean = false, backupState: BackupState = BackupState.ENABLED, doesBackupExistOnServer: Boolean = true, @@ -52,6 +56,7 @@ fun aLogoutState( logoutAction: AsyncAction = AsyncAction.Uninitialized, eventSink: (LogoutEvent) -> Unit = {}, ) = LogoutState( + currentUser = currentUser, isLastDevice = isLastDevice, backupState = backupState, doesBackupExistOnServer = doesBackupExistOnServer, diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt index cdfca04036..2e604af7ca 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt @@ -11,7 +11,9 @@ package io.element.android.features.logout.impl import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -38,6 +40,9 @@ import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.BackupUploadState import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.encryption.SteadyStateException +import io.element.android.libraries.matrix.ui.components.accountinfo.AccountInfoCard +import io.element.android.libraries.matrix.ui.components.accountinfo.AccountInfoCardMode +import io.element.android.libraries.matrix.ui.components.accountinfo.AccountInfoCardState import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings @@ -157,9 +162,16 @@ private fun Content( Column( modifier = modifier .fillMaxWidth() - .padding(top = 60.dp, start = 20.dp, end = 20.dp), + .padding(top = 8.dp, start = 16.dp, end = 16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { + AccountInfoCard( + AccountInfoCardState( + matrixUser = state.currentUser, + mode = AccountInfoCardMode.Simple, + ) + ) + Spacer(modifier = Modifier.height(16.dp)) when (state.backupUploadState) { is BackupUploadState.Uploading -> { LinearProgressIndicator( diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt index 5b14bc5cc3..f22eef1bc3 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPresenterTest.kt @@ -20,7 +20,9 @@ import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.BackupUploadState 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.user.MatrixUser import io.element.android.libraries.matrix.test.AN_EXCEPTION +import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.workmanager.api.WorkManagerRequestType @@ -39,11 +41,18 @@ class LogoutPresenterTest { @Test fun `present - initial state`() = runTest { - val presenter = createLogoutPresenter() + val presenter = createLogoutPresenter( + matrixClient = FakeMatrixClient( + sessionId = A_SESSION_ID, + userDisplayName = "Alice", + userAvatarUrl = "mxc://avatar", + ), + ) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { val initialState = awaitFirstItem() + assertThat(initialState.currentUser).isEqualTo(MatrixUser(A_SESSION_ID, "Alice", "mxc://avatar")) assertThat(initialState.isLastDevice).isFalse() assertThat(initialState.backupState).isEqualTo(BackupState.UNKNOWN) assertThat(initialState.doesBackupExistOnServer).isTrue() diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt index c1a480b0ed..4ec9bb4811 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutViewTest.kt @@ -13,8 +13,11 @@ package io.element.android.features.logout.impl import androidx.activity.ComponentActivity import androidx.compose.ui.test.AndroidComposeUiTest import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.v2.runAndroidComposeUiTest import io.element.android.libraries.architecture.AsyncAction +import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.tests.testutils.EnsureNeverCalled @@ -25,8 +28,22 @@ import io.element.android.tests.testutils.pressBack import io.element.android.tests.testutils.pressTag import io.element.android.tests.testutils.robolectric.RobolectricTest import org.junit.Test +import org.robolectric.annotation.Config class LogoutViewTest : RobolectricTest() { + @Test + @Config(qualifiers = "h1024dp") + fun `the current user is displayed`() = runAndroidComposeUiTest { + setLogoutView( + aLogoutState( + currentUser = aMatrixUser(id = "@alice:server.org", displayName = "Alice"), + eventSink = EventsRecorder(expectEvents = false), + ), + ) + onNodeWithText("Alice").assertIsDisplayed() + onNodeWithText("@alice:server.org").assertIsDisplayed() + } + @Test fun `clicking on logout sends a LogoutEvent`() = runAndroidComposeUiTest { val eventsRecorder = EventsRecorder() diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt index e4c8ebc641..bbf6d94d9b 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/avatar/AvatarSize.kt @@ -31,6 +31,7 @@ enum class AvatarSize(val dp: Dp) { UserHeader(96.dp), UserListItem(36.dp), + AccountInfoUser(36.dp), SelectedUser(52.dp), SelectedRoom(56.dp), diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt new file mode 100644 index 0000000000..6931598190 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.ui.components.accountinfo + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +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.libraries.designsystem.atomic.atoms.RoundedIconAtom +import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize +import io.element.android.libraries.designsystem.atomic.molecules.TextWithLabelMolecule +import io.element.android.libraries.designsystem.components.avatar.Avatar +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.avatar.AvatarType +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.HorizontalDivider +import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.model.getAvatarData +import io.element.android.libraries.matrix.ui.model.getBestName +import io.element.android.libraries.ui.strings.CommonStrings + +/** + * Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=5873-996 + */ +@Composable +fun AccountInfoCard( + state: AccountInfoCardState, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxWidth() + .border(1.dp, ElementTheme.colors.borderDisabled, RoundedCornerShape(8.dp)) + .padding(20.dp), + ) { + when (state.mode) { + AccountInfoCardMode.Simple -> Unit + is AccountInfoCardMode.DeviceVerification -> Unit + is AccountInfoCardMode.UserVerification -> { + Text( + // TODO + text = "User requesting verification:", + style = ElementTheme.typography.fontBodySmRegular, + color = ElementTheme.colors.textSecondary, + ) + Spacer(modifier = Modifier.height(8.dp)) + } + } + AccountInfoCardUser( + matrixUser = state.matrixUser, + ) + when (state.mode) { + AccountInfoCardMode.Simple -> Unit + is AccountInfoCardMode.DeviceVerification -> { + AccountInfoSeparator() + DeviceInfoRow(state.mode) + } + is AccountInfoCardMode.UserVerification -> { + AccountInfoSeparator() + AccountInfoCardUser( + matrixUser = state.mode.otherUser, + ) + } + } + } +} + +@Composable +private fun AccountInfoSeparator() { + HorizontalDivider( + modifier = Modifier.padding(vertical = 20.dp), + color = ElementTheme.colors.separatorPrimary, + ) +} + +@Composable +private fun DeviceInfoRow( + mode: AccountInfoCardMode.DeviceVerification, +) { + Column( + modifier = Modifier + .fillMaxWidth() + .semantics(mergeDescendants = true) {}, + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + RoundedIconAtom( + modifier = Modifier, + size = RoundedIconAtomSize.Big, + resourceId = CompoundDrawables.ic_compound_devices + ) + Text( + text = mode.deviceName ?: mode.deviceId.value, + style = ElementTheme.typography.fontBodyMdMedium, + color = ElementTheme.colors.textPrimary, + ) + } + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + TextWithLabelMolecule( + // TODO i18n + label = "Signed in", + text = mode.signInFormattedTimestamp, + modifier = Modifier.weight(1f), + ) + TextWithLabelMolecule( + label = stringResource(CommonStrings.common_device_id), + text = mode.deviceId.value, + modifier = Modifier.weight(1f), + spellText = true, + ) + } + } +} + +@Composable +private fun AccountInfoCardUser(matrixUser: MatrixUser) { + val subtext = if (matrixUser.displayName.isNullOrEmpty()) null else matrixUser.userId.value + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + Avatar( + avatarData = matrixUser.getAvatarData(AvatarSize.AccountInfoUser), + avatarType = AvatarType.User, + ) + Spacer(modifier = Modifier.width(12.dp)) + Column( + modifier = Modifier.weight(1f), + ) { + // Name + Text( + modifier = Modifier.clipToBounds(), + text = matrixUser.getBestName(), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = ElementTheme.colors.textPrimary, + style = ElementTheme.typography.fontBodyLgMedium, + ) + // Id + subtext?.let { + Text( + text = subtext, + color = ElementTheme.colors.textSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = ElementTheme.typography.fontBodyMdRegular, + ) + } + } + + } +} + +@PreviewsDayNight +@Composable +internal fun AccountInfoCardPreview( + @PreviewParameter(AccountInfoCardStatePreviewParam::class) state: AccountInfoCardState +) = ElementPreview { + // Add some padding to view the border + Box(modifier = Modifier.padding(16.dp)) { + AccountInfoCard(state) + } +} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardState.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardState.kt new file mode 100644 index 0000000000..68b66d72ee --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardState.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.ui.components.accountinfo + +import androidx.compose.runtime.Immutable +import io.element.android.libraries.matrix.api.core.DeviceId +import io.element.android.libraries.matrix.api.user.MatrixUser + +data class AccountInfoCardState( + val matrixUser: MatrixUser, + val mode: AccountInfoCardMode, +) + +@Immutable +sealed interface AccountInfoCardMode { + data object Simple : AccountInfoCardMode + + data class UserVerification( + val otherUser: MatrixUser, + ) : AccountInfoCardMode + + // TODO Replace SessionDetailsView with this component + data class DeviceVerification( + val deviceName: String?, + val deviceId: DeviceId, + val signInFormattedTimestamp: String, + ) : AccountInfoCardMode +} diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardStatePreviewParam.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardStatePreviewParam.kt new file mode 100644 index 0000000000..d383648154 --- /dev/null +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCardStatePreviewParam.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.matrix.ui.components.accountinfo + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import io.element.android.libraries.matrix.api.core.DeviceId +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUser + +open class AccountInfoCardStatePreviewParam : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + anAccountInfoCardState(), + anAccountInfoCardState(aMatrixUser(displayName = null)), + anAccountInfoCardState( + mode = AccountInfoCardMode.UserVerification( + otherUser = aMatrixUser(displayName = "Other User"), + ) + ), + anAccountInfoCardState( + mode = AccountInfoCardMode.DeviceVerification( + deviceName = "My Device", + deviceId = DeviceId("DEVICEID"), + signInFormattedTimestamp = "2024-06-01 12:00:00", + ) + ), + ) +} + +private fun anAccountInfoCardState( + matrixUser: MatrixUser = aMatrixUser(), + mode: AccountInfoCardMode = AccountInfoCardMode.Simple, +) = AccountInfoCardState( + matrixUser = matrixUser, + mode = mode, +) From 672b6eaf813d3c0681aa5bda480601e3448f6482 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 28 Sep 2026 15:47:54 +0200 Subject: [PATCH 4/9] Remove blank line --- .../matrix/ui/components/accountinfo/AccountInfoCard.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt index 6931598190..ab0b172cc5 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/accountinfo/AccountInfoCard.kt @@ -177,7 +177,6 @@ private fun AccountInfoCardUser(matrixUser: MatrixUser) { ) } } - } } From 26ea6be44ca976b7ffcfc6be5b88807c9bfb152b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 28 Sep 2026 17:31:42 +0200 Subject: [PATCH 5/9] Logout: do not double render the progress state and disable the cancel button during the process. --- .../io/element/android/features/logout/impl/LogoutView.kt | 6 ++++++ .../logout/impl/direct/DefaultDirectLogoutView.kt | 1 + .../android/features/logout/impl/ui/LogoutActionDialog.kt | 8 ++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt index 2e604af7ca..32a83b823e 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt @@ -47,6 +47,9 @@ import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.testTag import io.element.android.libraries.ui.strings.CommonStrings +/** + * Ref: https://www.figma.com/design/kEAcfun9iSpszeUDvdKZ6b/ER-351--Multi-account-in-EX?node-id=442-34581 + */ @Composable fun LogoutView( state: LogoutState, @@ -78,6 +81,8 @@ fun LogoutView( LogoutActionDialog( state.logoutAction, + // Do not show the progress dialog, the progress is rendered in the button. + showProgressDialog = false, onConfirmClick = { eventSink(LogoutEvent.Logout(ignoreSdkError = false)) }, @@ -149,6 +154,7 @@ private fun ColumnScope.Buttons( ) TextButton( text = stringResource(id = CommonStrings.action_cancel), + enabled = logoutAction !is AsyncAction.Loading, modifier = Modifier.fillMaxWidth(), onClick = onCancelClick, ) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt index 901e4e9654..454a7a25fb 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/direct/DefaultDirectLogoutView.kt @@ -27,6 +27,7 @@ class DefaultDirectLogoutView : DirectLogoutView { val eventSink = state.eventSink LogoutActionDialog( state.logoutAction, + showProgressDialog = true, onConfirmClick = { eventSink(DirectLogoutEvent.Logout(ignoreSdkError = false)) }, diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt index 0222a991db..ca9e6d9a16 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/ui/LogoutActionDialog.kt @@ -19,6 +19,7 @@ import io.element.android.libraries.ui.strings.CommonStrings @Composable fun LogoutActionDialog( state: AsyncAction, + showProgressDialog: Boolean, onConfirmClick: () -> Unit, onForceLogoutClick: () -> Unit, onDismissDialog: () -> Unit, @@ -31,8 +32,11 @@ fun LogoutActionDialog( onSubmitClick = onConfirmClick, onDismiss = onDismissDialog ) - is AsyncAction.Loading -> - ProgressDialog(text = stringResource(id = R.string.screen_signout_in_progress_dialog_content)) + is AsyncAction.Loading -> { + if (showProgressDialog) { + ProgressDialog(text = stringResource(id = R.string.screen_signout_in_progress_dialog_content)) + } + } is AsyncAction.Failure -> RetryDialog( title = stringResource(id = CommonStrings.dialog_title_error), From 83c3b646c2ef16da3621321e956352ea8395fdce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 28 Sep 2026 17:35:37 +0200 Subject: [PATCH 6/9] Make the content of LogoutView scrollable --- .../kotlin/io/element/android/features/logout/impl/LogoutView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt index 32a83b823e..4093be223d 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutView.kt @@ -65,6 +65,7 @@ fun LogoutView( subTitle = subtitle(state), iconStyle = BigIcon.Style.Default(CompoundIcons.Mobile()), modifier = modifier, + isScrollable = true, buttons = { Buttons( state = state, From 1e6bb0a168dca57697f17f13127b6bf5c24ce759 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 29 Sep 2026 09:32:18 +0200 Subject: [PATCH 7/9] Fix Maestro tests --- .maestro/tests/account/logout.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.maestro/tests/account/logout.yaml b/.maestro/tests/account/logout.yaml index 83f834da04..270020c82c 100644 --- a/.maestro/tests/account/logout.yaml +++ b/.maestro/tests/account/logout.yaml @@ -2,17 +2,25 @@ appId: ${MAESTRO_APP_ID} --- - tapOn: id: "home_screen-settings" -- tapOn: - id: "settings-user_profile" -- assertVisible: "Your account" - tapOn: "Remove this device" - takeScreenshot: build/maestro/900-SignOutScreen - back - tapOn: "Remove this device" +# Ensure pressing back cancels +- back +- tapOn: "Remove this device" # Ensure cancel cancels +- tapOn: "Cancel" +- tapOn: "Remove this device" +- tapOn: + text: "Remove this device" + index: 1 +# Cancel the dialog cancels the logout - tapOn: id: "dialog-negative" -- tapOn: "Remove this device" +- tapOn: + text: "Remove this device" + index: 1 - tapOn: id: "dialog-positive" - runFlow: ../assertions/assertInitDisplayed.yaml From 1664e0e15d361cdcc3af66f1080722adfe9205c2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 29 Sep 2026 17:31:18 +0200 Subject: [PATCH 8/9] Reorder states: new state at the end --- .../android/features/logout/impl/LogoutStatePreviewParam.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt index f30a9e7d77..9db884330b 100644 --- a/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt +++ b/features/logout/impl/src/main/kotlin/io/element/android/features/logout/impl/LogoutStatePreviewParam.kt @@ -21,7 +21,6 @@ open class LogoutStatePreviewParam : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( aLogoutState(), - aLogoutState(currentUser = aMatrixUser(id = "@alice:server.org", displayName = null)), aLogoutState(isLastDevice = true), aLogoutState(isLastDevice = false, backupUploadState = BackupUploadState.Uploading(66, 200)), aLogoutState(isLastDevice = true, backupUploadState = BackupUploadState.Done), @@ -42,6 +41,7 @@ open class LogoutStatePreviewParam : PreviewParameterProvider { backupUploadState = BackupUploadState.Waiting, waitingForALongTime = true, ), + aLogoutState(currentUser = aMatrixUser(id = "@alice:server.org", displayName = null)), ) } From 46ba7729f4dc47057d7e465952cdc77297ae331b Mon Sep 17 00:00:00 2001 From: ElementBot Date: Tue, 29 Sep 2026 14:19:38 +0000 Subject: [PATCH 9/9] Update screenshots --- .../images/features.logout.impl_LogoutView_Day_0_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_10_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_11_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_12_en.png | 3 +++ .../images/features.logout.impl_LogoutView_Day_1_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_2_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_3_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_4_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_5_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_6_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_7_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_8_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Day_9_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_0_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_10_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_11_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_12_en.png | 3 +++ .../images/features.logout.impl_LogoutView_Night_1_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_2_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_3_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_4_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_5_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_6_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_7_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_8_en.png | 4 ++-- .../images/features.logout.impl_LogoutView_Night_9_en.png | 4 ++-- ...rix.ui.components.accountinfo_AccountInfoCard_Day_0_en.png | 3 +++ ...rix.ui.components.accountinfo_AccountInfoCard_Day_1_en.png | 3 +++ ...rix.ui.components.accountinfo_AccountInfoCard_Day_2_en.png | 3 +++ ...rix.ui.components.accountinfo_AccountInfoCard_Day_3_en.png | 3 +++ ...x.ui.components.accountinfo_AccountInfoCard_Night_0_en.png | 3 +++ ...x.ui.components.accountinfo_AccountInfoCard_Night_1_en.png | 3 +++ ...x.ui.components.accountinfo_AccountInfoCard_Night_2_en.png | 3 +++ ...x.ui.components.accountinfo_AccountInfoCard_Night_3_en.png | 3 +++ 34 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_12_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_12_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_2_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_3_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_1_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_2_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_3_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_0_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_0_en.png index 69c57875c1..8f4e2b4c1c 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44eae581d98f2dbb2a6d84b4f921b170ade4185be87bf3bc893a0bb29fcf5f09 -size 15528 +oid sha256:1e17f781dae39f5f5b013943b9b487fb3be5b21d490c5fb96028e6fb5d682141 +size 23288 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png index da7923cf50..88d6dd4b37 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1c09cbb0217a1fb844828590e7827c27a2e9a99ecf5aed225f4d1bd0e413c8d -size 29343 +oid sha256:325477f895a8c99bd020abb1169c7236c72f716f6a0cfa017c17ee04bd6af95f +size 36633 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png index 68b16e509f..b36442ffdc 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ee66772b20b9c1cacf1f9387c173f8170d0c132d6caddfbd389d254b2ae7aa5 -size 33977 +oid sha256:b99a0ee27a3f6f7a954625943b124451ad817425093e9f7e842082298ad19a1a +size 41351 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_12_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_12_en.png new file mode 100644 index 0000000000..ac8112489d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_12_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb9457326b991e445f5abeb6ce23f4620a9ac62d6bf919a838b6f2864b27a96b +size 22796 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png index 56510ac1e2..a8e3378c65 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3eed90dbcc789f3db882d61a31924668a42cf78e00cd634192a5bfb831f67190 -size 53659 +oid sha256:d15e0d6f7bc3dbf133b89587d61221deaee93065dab1f04eb825a50ea76f7afc +size 58418 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png index 3bc29fbe6e..5525fbc5ad 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:228a9ed83c86a160fe494254ec654fc0bf1d6923e78f5de2b4057d386e25b333 -size 30750 +oid sha256:ef2738c74013f4c0aa3835f9372410de51e5646deb478edb518733e34eb45419 +size 38204 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png index 56510ac1e2..a8e3378c65 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3eed90dbcc789f3db882d61a31924668a42cf78e00cd634192a5bfb831f67190 -size 53659 +oid sha256:d15e0d6f7bc3dbf133b89587d61221deaee93065dab1f04eb825a50ea76f7afc +size 58418 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_4_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_4_en.png index 19ae842b7a..4e3a60b547 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:edf7aeb5f361d1299f0c1f6466de64cea36289c3268398b2a52dac2da057497c -size 33064 +oid sha256:b837a5c050e22298a90a281402a929cd19138cc0253b775d644cf7f6ffa42e78 +size 34025 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_5_en.png index 208b57113f..30e5972cf9 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1e489a5935471f6f607e9ed7e1f18ec0bf57d8664904323fef0a4453a179a0ce -size 20387 +oid sha256:07f4562818f73384486d27207fee92b948c3d91379f8ae83526c6f014d6fbdfc +size 23635 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_6_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_6_en.png index 344f09d582..cb3793d04d 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27186c887a4403c8e175ba40059e18635db2e2ffac8da6804b6d52a6e2d12726 -size 28110 +oid sha256:3bd7cfe56e444eb6404f18360f40102efcd151051ec8fc475569278ea851c2b6 +size 29050 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png index bdad7df7bc..db43d58156 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64c4173147686886d5021cdaf6480644a5a520f81392ca84aa7ab5d705211bc7 -size 38682 +oid sha256:46122301e6f4c886045e8be69182297dd41e567713f9522ee4222d493204e7c8 +size 46289 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png index f52aac7f1c..3089d813a8 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6c73dd018eb82fe9e54ffbe38dcc491938da69791f4ff32081b2dac7549a4b2 -size 47958 +oid sha256:4bfd98771ca84e02a54510f934f0d368a456e00e85a5f58ca93b618383b7d8d7 +size 54782 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png index f52aac7f1c..3089d813a8 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Day_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6c73dd018eb82fe9e54ffbe38dcc491938da69791f4ff32081b2dac7549a4b2 -size 47958 +oid sha256:4bfd98771ca84e02a54510f934f0d368a456e00e85a5f58ca93b618383b7d8d7 +size 54782 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_0_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_0_en.png index ecf38c9b24..46638c106a 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_0_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_0_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c4499b08be7d79d0cad438c4699c055bac12f6922551a19f3cfe18568c3d065 -size 14827 +oid sha256:d0478eaa2dce7809435ec4c1e0d1f3cc70b4d515409b4ad4c9a29d5d82bf62fa +size 22658 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png index 4d2c26d91d..c6c2bed7ec 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_10_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b0e1f00b98e463a97c9334da018ba944414526f771aa4ceaea18ab192a36863 -size 28080 +oid sha256:10222d4eb6b76925590d0910e15ee711da8089404f7bee285f0c3eb864662264 +size 35550 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png index a650636f24..19bacd5b43 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_11_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87e337a40741a5c7bdcb2015b8f82282ae69e1eff98e30641a02314660ecbd73 -size 32583 +oid sha256:efdbf580fd5a8eab0606a5223255132f6f109baa0233f7d1794dd7c72a1c9770 +size 40170 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_12_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_12_en.png new file mode 100644 index 0000000000..71067cadbe --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_12_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:86675c500add0bfa1e0934a89e08d63c651f3b4d1618a56273dceeab5e6f90e8 +size 22032 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png index 62596baf31..a872ba68dc 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_1_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66a0dc249d2df7e52a6a5f7cb3f1a94be011164eaf23d365f548b99f093d3d14 -size 51681 +oid sha256:99b00a68566e255c32551776bd0d973d0a263487d9efd1673d2a0343efff7c2d +size 56364 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png index f97ba2a853..a7ac05d24c 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_2_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:aba88e94521e05328079fb2ac0b06fd97987f81694b3378f02c19a20bfae2572 -size 29636 +oid sha256:a5cff92d97cd7b098d408397cc7ae41579fc227c96fc82e13f885a1bd815fdbd +size 37119 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png index 62596baf31..a872ba68dc 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_3_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66a0dc249d2df7e52a6a5f7cb3f1a94be011164eaf23d365f548b99f093d3d14 -size 51681 +oid sha256:99b00a68566e255c32551776bd0d973d0a263487d9efd1673d2a0343efff7c2d +size 56364 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_4_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_4_en.png index 5a3527f7e9..c9bddd0204 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_4_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_4_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f66b1cb00a31cd7925f4c505b0aeda77ee8aa8b473f1b576c97d3dc0bf3bf547 -size 30984 +oid sha256:00a4053efae3a0a5e575d7261110f9e45b957609217dafa527f4689d37aa5cf2 +size 31861 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_5_en.png index 71158fba7f..a698364606 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_5_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_5_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:702604dea65bb5f398728254f624e0486fdd152adcc336736f6256df9f7a63c4 -size 19617 +oid sha256:272c9302500693f2de77995f66df4fd1f59b59da9a13ba8b6f26b59fdf5e969e +size 22888 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_6_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_6_en.png index d368f54758..c093c81f1e 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_6_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_6_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fff0f77b004d6a5d4fa8c28c0fe72221449e20c0b501ed4b82e48c04596485a7 -size 26294 +oid sha256:2fb71ef151d5da4bb0ae4ccc0ddd08c1d423708b6cc4fdcdc3d7e5c1f2c69a06 +size 27257 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png index 17526d949c..69f867eb94 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_7_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd6d4b2d03d0e86a22c48f89f05c83b0e7622f4b6fc2a946ace1ef33e66b2e9a -size 37183 +oid sha256:1352f9f09c05070fa2ea6f728916dfc47c6679ec805c8e5fc6a3cb497c8d3967 +size 44945 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png index bf33b63f8a..f9db4ef9af 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_8_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8f9a50b522d34a29ec48fcef545a0880ff0f43d464f1874c3486adb9c79e202 -size 46251 +oid sha256:5038b48d5f2aec502adf2f053adb18e1d9acd1a1fad471eceaf0ce1ea6679416 +size 53350 diff --git a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png index bf33b63f8a..f9db4ef9af 100644 --- a/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png +++ b/tests/uitests/src/test/snapshots/images/features.logout.impl_LogoutView_Night_9_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d8f9a50b522d34a29ec48fcef545a0880ff0f43d464f1874c3486adb9c79e202 -size 46251 +oid sha256:5038b48d5f2aec502adf2f053adb18e1d9acd1a1fad471eceaf0ce1ea6679416 +size 53350 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_0_en.png new file mode 100644 index 0000000000..21f523a482 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edfdf1cbf1190c68bce3b77d32325105e7564f6dfbd0bea6ddc737b668f780b5 +size 10579 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_1_en.png new file mode 100644 index 0000000000..f01248d6c0 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:344913f57b4c0ff9f738c0545a491bd6bd1521bcfe3bf59a238ca8a28d67850d +size 8947 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_2_en.png new file mode 100644 index 0000000000..a209b2a775 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:164bc673bc7ea750329b4e3660f639e2ef37a5eb2bd0739359405d55d88a2bac +size 21871 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_3_en.png new file mode 100644 index 0000000000..707cf6cd0f --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Day_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:087cb3e50dc482a46a18c10f6bfea45e815a867f5422e6092ea66aaccc2736be +size 21497 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_0_en.png new file mode 100644 index 0000000000..69d467c730 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44c4aabd8644d45a4364a9156d0d9bd3e6a10830bbbc3611ae356324b41e3202 +size 10195 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_1_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_1_en.png new file mode 100644 index 0000000000..a945f669a7 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_1_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6171540623e4a76987b4d1d4e0085fea34977e9b662ef450bc754dd443164e7a +size 8810 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_2_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_2_en.png new file mode 100644 index 0000000000..6e6745377d --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_2_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3e08ffd8241960a40e6986378028777cd98d7f86350658e0706199d191c5f21 +size 21424 diff --git a/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_3_en.png b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_3_en.png new file mode 100644 index 0000000000..9e014c83f2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.matrix.ui.components.accountinfo_AccountInfoCard_Night_3_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da063790dbc384a82b35c16887fbb389d99e823728320d7df32315746c392eeb +size 20790