From 87e1deaccf49f394a18de4535dc99f6aca9ff56c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Oct 2026 09:56:57 +0200 Subject: [PATCH] Show account info on the identity confirmation screen Render an AccountInfoCard with the current user on the "Confirm your digital identity" screen, so the user knows which account needs to be verified. Closes #7898 Co-Authored-By: Claude Opus 5.5 (1M context) --- features/ftue/impl/build.gradle.kts | 1 + .../ChooseSelfVerificationModePresenter.kt | 4 ++ .../ChooseSelfVerificationModeState.kt | 2 + ...seSelfVerificationModeStatePreviewParam.kt | 4 ++ .../ChooseSelfVerificationModeView.kt | 40 +++++++++++++------ ...oseSessionVerificationModePresenterTest.kt | 28 +++++++++++++ 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/features/ftue/impl/build.gradle.kts b/features/ftue/impl/build.gradle.kts index f6d1970a5a..1ef41bcae2 100644 --- a/features/ftue/impl/build.gradle.kts +++ b/features/ftue/impl/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { implementation(projects.libraries.core) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) implementation(projects.libraries.designsystem) implementation(projects.libraries.preferences.api) implementation(projects.libraries.uiCommon) diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModePresenter.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModePresenter.kt index f19c323d52..7fd2770fb3 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModePresenter.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModePresenter.kt @@ -20,16 +20,19 @@ import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.mapState +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState @Inject class ChooseSelfVerificationModePresenter( + private val matrixClient: MatrixClient, private val encryptionService: EncryptionService, private val directLogoutPresenter: Presenter, ) : Presenter { @Composable override fun present(): ChooseSelfVerificationModeState { + val currentUser by matrixClient.userProfile.collectAsState() val hasDevicesToVerifyAgainst by encryptionService.hasDevicesToVerifyAgainst.collectAsState() val canUseRecoveryKey by produceState>(AsyncData.Uninitialized) { encryptionService.recoveryStateStateFlow @@ -72,6 +75,7 @@ class ChooseSelfVerificationModePresenter( } return ChooseSelfVerificationModeState( + currentUser = currentUser, buttonsState = buttonsState, directLogoutState = directLogoutState, eventSink = ::handleEvent, diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeState.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeState.kt index 0512636fca..98dbc340e4 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeState.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeState.kt @@ -10,8 +10,10 @@ package io.element.android.features.ftue.impl.sessionverification.choosemode import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.user.MatrixUser data class ChooseSelfVerificationModeState( + val currentUser: MatrixUser, val buttonsState: AsyncData, val directLogoutState: DirectLogoutState, val eventSink: (ChooseSelfVerificationModeEvent) -> Unit, diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeStatePreviewParam.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeStatePreviewParam.kt index 1af6786289..d12a3003ae 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeStatePreviewParam.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeStatePreviewParam.kt @@ -11,6 +11,8 @@ package io.element.android.features.ftue.impl.sessionverification.choosemode import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.libraries.architecture.AsyncData +import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.matrix.ui.components.aMatrixUser class ChooseSelfVerificationModeStatePreviewParam : PreviewParameterProvider { @@ -43,7 +45,9 @@ class ChooseSelfVerificationModeStatePreviewParam : fun aChooseSelfVerificationModeState( buttonsState: AsyncData = AsyncData.Success(aButtonsState()), + currentUser: MatrixUser = aMatrixUser(), ) = ChooseSelfVerificationModeState( + currentUser = currentUser, buttonsState = buttonsState, directLogoutState = aDirectLogoutState(), eventSink = {}, diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt index f6f1094d1b..63d653410f 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSelfVerificationModeView.kt @@ -12,6 +12,7 @@ import androidx.activity.compose.BackHandler import androidx.activity.compose.LocalActivity import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -39,6 +40,9 @@ 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.components.TopAppBar +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.ui.strings.CommonStrings @Composable @@ -75,6 +79,7 @@ fun ChooseSelfVerificationModeView( subTitle = stringResource(id = R.string.screen_identity_confirmation_subtitle) ) }, + isScrollable = true, footer = { ChooseSelfVerificationModeButtons( state = state, @@ -84,20 +89,31 @@ fun ChooseSelfVerificationModeView( ) } ) { - Row( + Column( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center, + verticalArrangement = Arrangement.spacedBy(24.dp), ) { - Text( - modifier = Modifier - .clickable(onClick = onLearnMore) - .padding(vertical = 4.dp, horizontal = 16.dp) - .semantics { - // Note: there is no Role.Link, so we use Role.Button for better accessibility support - role = Role.Button - }, - text = stringResource(CommonStrings.action_learn_more), - style = ElementTheme.typography.fontBodyLgMedium + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + Text( + modifier = Modifier + .clickable(onClick = onLearnMore) + .padding(vertical = 4.dp, horizontal = 16.dp) + .semantics { + // Note: there is no Role.Link, so we use Role.Button for better accessibility support + role = Role.Button + }, + text = stringResource(CommonStrings.action_learn_more), + style = ElementTheme.typography.fontBodyLgMedium + ) + } + AccountInfoCard( + state = AccountInfoCardState( + matrixUser = state.currentUser, + mode = AccountInfoCardMode.Simple, + ), ) } } diff --git a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModePresenterTest.kt b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModePresenterTest.kt index 8ceb683993..78f257daf0 100644 --- a/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModePresenterTest.kt +++ b/features/ftue/impl/src/test/kotlin/io/element/android/features/ftue/impl/sessionverification/choosemode/ChooseSessionVerificationModePresenterTest.kt @@ -14,7 +14,13 @@ import io.element.android.features.logout.api.direct.DirectLogoutState import io.element.android.features.logout.api.direct.aDirectLogoutState import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.MatrixClient 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_AVATAR_URL +import io.element.android.libraries.matrix.test.A_SESSION_ID +import io.element.android.libraries.matrix.test.A_USER_NAME +import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value @@ -34,6 +40,26 @@ class ChooseSessionVerificationModePresenterTest { } } + @Test + fun `present - current user is exposed`() = runTest { + val presenter = createPresenter( + matrixClient = FakeMatrixClient( + sessionId = A_SESSION_ID, + userDisplayName = A_USER_NAME, + userAvatarUrl = AN_AVATAR_URL, + ), + ) + presenter.test { + assertThat(awaitItem().currentUser).isEqualTo( + MatrixUser( + userId = A_SESSION_ID, + displayName = A_USER_NAME, + avatarUrl = AN_AVATAR_URL, + ) + ) + } + } + @Test fun `present - state is relayed from EncryptionService, order 1`() = runTest { val encryptionService = FakeEncryptionService() @@ -126,9 +152,11 @@ class ChooseSessionVerificationModePresenterTest { } private fun createPresenter( + matrixClient: MatrixClient = FakeMatrixClient(), encryptionService: FakeEncryptionService = FakeEncryptionService(), directLogoutPresenter: Presenter = Presenter { aDirectLogoutState() } ) = ChooseSelfVerificationModePresenter( + matrixClient = matrixClient, encryptionService = encryptionService, directLogoutPresenter = directLogoutPresenter, )