mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 06:55:41 +00:00
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) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ dependencies {
|
|||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.architecture)
|
implementation(projects.libraries.architecture)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
|
implementation(projects.libraries.matrixui)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.preferences.api)
|
implementation(projects.libraries.preferences.api)
|
||||||
implementation(projects.libraries.uiCommon)
|
implementation(projects.libraries.uiCommon)
|
||||||
|
|||||||
+4
@@ -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.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.coroutine.mapState
|
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.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
class ChooseSelfVerificationModePresenter(
|
class ChooseSelfVerificationModePresenter(
|
||||||
|
private val matrixClient: MatrixClient,
|
||||||
private val encryptionService: EncryptionService,
|
private val encryptionService: EncryptionService,
|
||||||
private val directLogoutPresenter: Presenter<DirectLogoutState>,
|
private val directLogoutPresenter: Presenter<DirectLogoutState>,
|
||||||
) : Presenter<ChooseSelfVerificationModeState> {
|
) : Presenter<ChooseSelfVerificationModeState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ChooseSelfVerificationModeState {
|
override fun present(): ChooseSelfVerificationModeState {
|
||||||
|
val currentUser by matrixClient.userProfile.collectAsState()
|
||||||
val hasDevicesToVerifyAgainst by encryptionService.hasDevicesToVerifyAgainst.collectAsState()
|
val hasDevicesToVerifyAgainst by encryptionService.hasDevicesToVerifyAgainst.collectAsState()
|
||||||
val canUseRecoveryKey by produceState<AsyncData<Boolean>>(AsyncData.Uninitialized) {
|
val canUseRecoveryKey by produceState<AsyncData<Boolean>>(AsyncData.Uninitialized) {
|
||||||
encryptionService.recoveryStateStateFlow
|
encryptionService.recoveryStateStateFlow
|
||||||
@@ -72,6 +75,7 @@ class ChooseSelfVerificationModePresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ChooseSelfVerificationModeState(
|
return ChooseSelfVerificationModeState(
|
||||||
|
currentUser = currentUser,
|
||||||
buttonsState = buttonsState,
|
buttonsState = buttonsState,
|
||||||
directLogoutState = directLogoutState,
|
directLogoutState = directLogoutState,
|
||||||
eventSink = ::handleEvent,
|
eventSink = ::handleEvent,
|
||||||
|
|||||||
+2
@@ -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.features.logout.api.direct.DirectLogoutState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
||||||
data class ChooseSelfVerificationModeState(
|
data class ChooseSelfVerificationModeState(
|
||||||
|
val currentUser: MatrixUser,
|
||||||
val buttonsState: AsyncData<ButtonsState>,
|
val buttonsState: AsyncData<ButtonsState>,
|
||||||
val directLogoutState: DirectLogoutState,
|
val directLogoutState: DirectLogoutState,
|
||||||
val eventSink: (ChooseSelfVerificationModeEvent) -> Unit,
|
val eventSink: (ChooseSelfVerificationModeEvent) -> Unit,
|
||||||
|
|||||||
+4
@@ -11,6 +11,8 @@ package io.element.android.features.ftue.impl.sessionverification.choosemode
|
|||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.logout.api.direct.aDirectLogoutState
|
import io.element.android.features.logout.api.direct.aDirectLogoutState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
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 :
|
class ChooseSelfVerificationModeStatePreviewParam :
|
||||||
PreviewParameterProvider<ChooseSelfVerificationModeState> {
|
PreviewParameterProvider<ChooseSelfVerificationModeState> {
|
||||||
@@ -43,7 +45,9 @@ class ChooseSelfVerificationModeStatePreviewParam :
|
|||||||
|
|
||||||
fun aChooseSelfVerificationModeState(
|
fun aChooseSelfVerificationModeState(
|
||||||
buttonsState: AsyncData<ChooseSelfVerificationModeState.ButtonsState> = AsyncData.Success(aButtonsState()),
|
buttonsState: AsyncData<ChooseSelfVerificationModeState.ButtonsState> = AsyncData.Success(aButtonsState()),
|
||||||
|
currentUser: MatrixUser = aMatrixUser(),
|
||||||
) = ChooseSelfVerificationModeState(
|
) = ChooseSelfVerificationModeState(
|
||||||
|
currentUser = currentUser,
|
||||||
buttonsState = buttonsState,
|
buttonsState = buttonsState,
|
||||||
directLogoutState = aDirectLogoutState(),
|
directLogoutState = aDirectLogoutState(),
|
||||||
eventSink = {},
|
eventSink = {},
|
||||||
|
|||||||
+28
-12
@@ -12,6 +12,7 @@ import androidx.activity.compose.BackHandler
|
|||||||
import androidx.activity.compose.LocalActivity
|
import androidx.activity.compose.LocalActivity
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
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.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
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
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -75,6 +79,7 @@ fun ChooseSelfVerificationModeView(
|
|||||||
subTitle = stringResource(id = R.string.screen_identity_confirmation_subtitle)
|
subTitle = stringResource(id = R.string.screen_identity_confirmation_subtitle)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
isScrollable = true,
|
||||||
footer = {
|
footer = {
|
||||||
ChooseSelfVerificationModeButtons(
|
ChooseSelfVerificationModeButtons(
|
||||||
state = state,
|
state = state,
|
||||||
@@ -84,20 +89,31 @@ fun ChooseSelfVerificationModeView(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Row(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.clickable(onClick = onLearnMore)
|
horizontalArrangement = Arrangement.Center,
|
||||||
.padding(vertical = 4.dp, horizontal = 16.dp)
|
) {
|
||||||
.semantics {
|
Text(
|
||||||
// Note: there is no Role.Link, so we use Role.Button for better accessibility support
|
modifier = Modifier
|
||||||
role = Role.Button
|
.clickable(onClick = onLearnMore)
|
||||||
},
|
.padding(vertical = 4.dp, horizontal = 16.dp)
|
||||||
text = stringResource(CommonStrings.action_learn_more),
|
.semantics {
|
||||||
style = ElementTheme.typography.fontBodyLgMedium
|
// 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,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
@@ -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.features.logout.api.direct.aDirectLogoutState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
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.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.libraries.matrix.test.encryption.FakeEncryptionService
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
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
|
@Test
|
||||||
fun `present - state is relayed from EncryptionService, order 1`() = runTest {
|
fun `present - state is relayed from EncryptionService, order 1`() = runTest {
|
||||||
val encryptionService = FakeEncryptionService()
|
val encryptionService = FakeEncryptionService()
|
||||||
@@ -126,9 +152,11 @@ class ChooseSessionVerificationModePresenterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createPresenter(
|
private fun createPresenter(
|
||||||
|
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||||
encryptionService: FakeEncryptionService = FakeEncryptionService(),
|
encryptionService: FakeEncryptionService = FakeEncryptionService(),
|
||||||
directLogoutPresenter: Presenter<DirectLogoutState> = Presenter<DirectLogoutState> { aDirectLogoutState() }
|
directLogoutPresenter: Presenter<DirectLogoutState> = Presenter<DirectLogoutState> { aDirectLogoutState() }
|
||||||
) = ChooseSelfVerificationModePresenter(
|
) = ChooseSelfVerificationModePresenter(
|
||||||
|
matrixClient = matrixClient,
|
||||||
encryptionService = encryptionService,
|
encryptionService = encryptionService,
|
||||||
directLogoutPresenter = directLogoutPresenter,
|
directLogoutPresenter = directLogoutPresenter,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user