Only offer to verify if a cross-signed device is available (#5433)

* Only offer to verify if a cross-signed device is available

* Fix tests

* use the right exception mapper

* adjust flag name and logic in ChooseSelfVerificationState

* add comment

* switch order of states to match previous logic
This commit is contained in:
Hubert Chathi
2025-10-06 06:40:52 -04:00
committed by GitHub
parent a9912e4a1e
commit 7c61c70b62
10 changed files with 47 additions and 14 deletions

View File

@@ -26,7 +26,7 @@ class ChooseSelfVerificationModePresenter(
) : Presenter<ChooseSelfVerificationModeState> {
@Composable
override fun present(): ChooseSelfVerificationModeState {
val isLastDevice by encryptionService.isLastDevice.collectAsState()
val hasDevicesToVerifyAgainst by encryptionService.hasDevicesToVerifyAgainst.collectAsState()
val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState()
val canEnterRecoveryKey by remember { derivedStateOf { recoveryState == RecoveryState.INCOMPLETE } }
@@ -39,7 +39,7 @@ class ChooseSelfVerificationModePresenter(
}
return ChooseSelfVerificationModeState(
isLastDevice = isLastDevice,
canUseAnotherDevice = hasDevicesToVerifyAgainst,
canEnterRecoveryKey = canEnterRecoveryKey,
directLogoutState = directLogoutState,
eventSink = ::eventHandler,

View File

@@ -10,7 +10,7 @@ package io.element.android.features.ftue.impl.sessionverification.choosemode
import io.element.android.features.logout.api.direct.DirectLogoutState
data class ChooseSelfVerificationModeState(
val isLastDevice: Boolean,
val canUseAnotherDevice: Boolean,
val canEnterRecoveryKey: Boolean,
val directLogoutState: DirectLogoutState,
val eventSink: (ChooseSelfVerificationModeEvent) -> Unit,

View File

@@ -13,18 +13,18 @@ import io.element.android.features.logout.api.direct.aDirectLogoutState
class ChooseSelfVerificationModeStateProvider :
PreviewParameterProvider<ChooseSelfVerificationModeState> {
override val values = sequenceOf(
aChooseSelfVerificationModeState(isLastDevice = true, canEnterRecoveryKey = true),
aChooseSelfVerificationModeState(isLastDevice = true, canEnterRecoveryKey = false),
aChooseSelfVerificationModeState(isLastDevice = false, canEnterRecoveryKey = true),
aChooseSelfVerificationModeState(isLastDevice = false, canEnterRecoveryKey = false),
aChooseSelfVerificationModeState(canUseAnotherDevice = false, canEnterRecoveryKey = true),
aChooseSelfVerificationModeState(canUseAnotherDevice = false, canEnterRecoveryKey = false),
aChooseSelfVerificationModeState(canUseAnotherDevice = true, canEnterRecoveryKey = true),
aChooseSelfVerificationModeState(canUseAnotherDevice = true, canEnterRecoveryKey = false),
)
}
fun aChooseSelfVerificationModeState(
isLastDevice: Boolean = false,
canUseAnotherDevice: Boolean = true,
canEnterRecoveryKey: Boolean = true,
) = ChooseSelfVerificationModeState(
isLastDevice = isLastDevice,
canUseAnotherDevice = canUseAnotherDevice,
canEnterRecoveryKey = canEnterRecoveryKey,
directLogoutState = aDirectLogoutState(),
eventSink = {},

View File

@@ -76,7 +76,7 @@ fun ChooseSelfVerificationModeView(
ButtonColumnMolecule(
modifier = Modifier.padding(bottom = 16.dp)
) {
if (state.isLastDevice.not()) {
if (state.canUseAnotherDevice) {
Button(
modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.screen_identity_use_another_device),

View File

@@ -24,15 +24,15 @@ class ChooseSessionVerificationModePresenterTest {
@Test
fun `initial state - is relayed from EncryptionService`() = runTest {
val encryptionService = FakeEncryptionService().apply {
// Is last device
emitIsLastDevice(true)
// Has device to verify against
emitHasDevicesToVerifyAgainst(false)
// Can enter recovery key
emitRecoveryState(RecoveryState.INCOMPLETE)
}
val presenter = createPresenter(encryptionService = encryptionService)
presenter.test {
awaitItem().run {
assertThat(isLastDevice).isTrue()
assertThat(canUseAnotherDevice).isFalse()
assertThat(canEnterRecoveryKey).isTrue()
assertThat(directLogoutState.logoutAction.isUninitialized()).isTrue()
}

View File

@@ -43,7 +43,7 @@ class ChooseSessionVerificationModeViewTest {
fun `clicking on use another device calls the callback`() {
ensureCalledOnce { callback ->
rule.setChooseSelfVerificationModeView(
aChooseSelfVerificationModeState(isLastDevice = false),
aChooseSelfVerificationModeState(canUseAnotherDevice = true),
onUseAnotherDevice = callback,
)
rule.clickOn(R.string.screen_identity_use_another_device)