Make sure we know the session verification state before showing the option to verify the session. #5521
This commit is contained in:
parent
32b1856dbd
commit
ff67c8beef
9 changed files with 228 additions and 60 deletions
|
|
@ -15,7 +15,9 @@ import androidx.compose.runtime.remember
|
|||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.features.logout.api.direct.DirectLogoutEvents
|
||||
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.encryption.EncryptionService
|
||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||
|
||||
|
|
@ -27,8 +29,33 @@ class ChooseSelfVerificationModePresenter(
|
|||
@Composable
|
||||
override fun present(): ChooseSelfVerificationModeState {
|
||||
val hasDevicesToVerifyAgainst by encryptionService.hasDevicesToVerifyAgainst.collectAsState()
|
||||
val recoveryState by encryptionService.recoveryStateStateFlow.collectAsState()
|
||||
val canEnterRecoveryKey by remember { derivedStateOf { recoveryState == RecoveryState.INCOMPLETE } }
|
||||
val canEnterRecoveryKey by encryptionService.recoveryStateStateFlow
|
||||
.mapState { recoveryState ->
|
||||
when (recoveryState) {
|
||||
RecoveryState.WAITING_FOR_SYNC,
|
||||
RecoveryState.UNKNOWN -> AsyncData.Loading()
|
||||
RecoveryState.INCOMPLETE -> AsyncData.Success(true)
|
||||
RecoveryState.ENABLED,
|
||||
RecoveryState.DISABLED -> AsyncData.Success(false)
|
||||
}
|
||||
}
|
||||
.collectAsState()
|
||||
val buttonsState by remember {
|
||||
derivedStateOf {
|
||||
val canUseAnotherDevice = hasDevicesToVerifyAgainst.dataOrNull()
|
||||
val canEnterRecoveryKey = canEnterRecoveryKey.dataOrNull()
|
||||
if (canUseAnotherDevice == null || canEnterRecoveryKey == null) {
|
||||
AsyncData.Loading()
|
||||
} else {
|
||||
AsyncData.Success(
|
||||
ChooseSelfVerificationModeState.ButtonsState(
|
||||
canUseAnotherDevice = canUseAnotherDevice,
|
||||
canEnterRecoveryKey = canEnterRecoveryKey,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val directLogoutState = directLogoutPresenter.present()
|
||||
|
||||
|
|
@ -39,8 +66,7 @@ class ChooseSelfVerificationModePresenter(
|
|||
}
|
||||
|
||||
return ChooseSelfVerificationModeState(
|
||||
canUseAnotherDevice = hasDevicesToVerifyAgainst,
|
||||
canEnterRecoveryKey = canEnterRecoveryKey,
|
||||
buttonsState = buttonsState,
|
||||
directLogoutState = directLogoutState,
|
||||
eventSink = ::eventHandler,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,10 +8,15 @@
|
|||
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
|
||||
|
||||
data class ChooseSelfVerificationModeState(
|
||||
val canUseAnotherDevice: Boolean,
|
||||
val canEnterRecoveryKey: Boolean,
|
||||
val buttonsState: AsyncData<ButtonsState>,
|
||||
val directLogoutState: DirectLogoutState,
|
||||
val eventSink: (ChooseSelfVerificationModeEvent) -> Unit,
|
||||
)
|
||||
) {
|
||||
data class ButtonsState(
|
||||
val canUseAnotherDevice: Boolean,
|
||||
val canEnterRecoveryKey: Boolean,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,23 +9,49 @@ 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
|
||||
|
||||
class ChooseSelfVerificationModeStateProvider :
|
||||
PreviewParameterProvider<ChooseSelfVerificationModeState> {
|
||||
override val values = sequenceOf(
|
||||
aChooseSelfVerificationModeState(canUseAnotherDevice = false, canEnterRecoveryKey = true),
|
||||
aChooseSelfVerificationModeState(canUseAnotherDevice = false, canEnterRecoveryKey = false),
|
||||
aChooseSelfVerificationModeState(canUseAnotherDevice = true, canEnterRecoveryKey = true),
|
||||
aChooseSelfVerificationModeState(canUseAnotherDevice = true, canEnterRecoveryKey = false),
|
||||
aChooseSelfVerificationModeState(
|
||||
buttonsState = AsyncData.Success(
|
||||
aButtonsState(canUseAnotherDevice = false, canEnterRecoveryKey = true),
|
||||
),
|
||||
),
|
||||
aChooseSelfVerificationModeState(
|
||||
buttonsState = AsyncData.Success(
|
||||
aButtonsState(canUseAnotherDevice = false, canEnterRecoveryKey = false),
|
||||
),
|
||||
),
|
||||
aChooseSelfVerificationModeState(
|
||||
buttonsState = AsyncData.Success(
|
||||
aButtonsState(canUseAnotherDevice = true, canEnterRecoveryKey = true),
|
||||
),
|
||||
),
|
||||
aChooseSelfVerificationModeState(
|
||||
buttonsState = AsyncData.Success(
|
||||
aButtonsState(canUseAnotherDevice = true, canEnterRecoveryKey = false),
|
||||
),
|
||||
),
|
||||
aChooseSelfVerificationModeState(
|
||||
buttonsState = AsyncData.Loading(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun aChooseSelfVerificationModeState(
|
||||
canUseAnotherDevice: Boolean = true,
|
||||
canEnterRecoveryKey: Boolean = true,
|
||||
buttonsState: AsyncData<ChooseSelfVerificationModeState.ButtonsState> = AsyncData.Success(aButtonsState()),
|
||||
) = ChooseSelfVerificationModeState(
|
||||
canUseAnotherDevice = canUseAnotherDevice,
|
||||
canEnterRecoveryKey = canEnterRecoveryKey,
|
||||
buttonsState = buttonsState,
|
||||
directLogoutState = aDirectLogoutState(),
|
||||
eventSink = {},
|
||||
)
|
||||
|
||||
fun aButtonsState(
|
||||
canUseAnotherDevice: Boolean = true,
|
||||
canEnterRecoveryKey: Boolean = true,
|
||||
) = ChooseSelfVerificationModeState.ButtonsState(
|
||||
canUseAnotherDevice = canUseAnotherDevice,
|
||||
canEnterRecoveryKey = canEnterRecoveryKey,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.unit.dp
|
|||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.ftue.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
|
|
@ -50,7 +51,6 @@ fun ChooseSelfVerificationModeView(
|
|||
BackHandler {
|
||||
activity?.finish()
|
||||
}
|
||||
|
||||
HeaderFooterPage(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
|
|
@ -73,29 +73,12 @@ fun ChooseSelfVerificationModeView(
|
|||
)
|
||||
},
|
||||
footer = {
|
||||
ButtonColumnMolecule(
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
) {
|
||||
if (state.canUseAnotherDevice) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_identity_use_another_device),
|
||||
onClick = onUseAnotherDevice,
|
||||
)
|
||||
}
|
||||
if (state.canEnterRecoveryKey) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_session_verification_enter_recovery_key),
|
||||
onClick = onUseRecoveryKey,
|
||||
)
|
||||
}
|
||||
OutlinedButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_identity_confirmation_cannot_confirm),
|
||||
onClick = onResetKey,
|
||||
)
|
||||
}
|
||||
ChooseSelfVerificationModeButtons(
|
||||
state = state,
|
||||
onUseAnotherDevice = onUseAnotherDevice,
|
||||
onUseRecoveryKey = onUseRecoveryKey,
|
||||
onResetKey = onResetKey,
|
||||
)
|
||||
}
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -113,6 +96,53 @@ fun ChooseSelfVerificationModeView(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChooseSelfVerificationModeButtons(
|
||||
state: ChooseSelfVerificationModeState,
|
||||
onUseAnotherDevice: () -> Unit,
|
||||
onUseRecoveryKey: () -> Unit,
|
||||
onResetKey: () -> Unit,
|
||||
) {
|
||||
ButtonColumnMolecule(
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
) {
|
||||
when (state.buttonsState) {
|
||||
AsyncData.Uninitialized,
|
||||
is AsyncData.Failure,
|
||||
is AsyncData.Loading -> {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = false,
|
||||
showProgress = true,
|
||||
text = stringResource(CommonStrings.common_loading),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
is AsyncData.Success -> {
|
||||
if (state.buttonsState.data.canUseAnotherDevice) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_identity_use_another_device),
|
||||
onClick = onUseAnotherDevice,
|
||||
)
|
||||
}
|
||||
if (state.buttonsState.data.canEnterRecoveryKey) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_session_verification_enter_recovery_key),
|
||||
onClick = onUseRecoveryKey,
|
||||
)
|
||||
}
|
||||
OutlinedButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_identity_confirmation_cannot_confirm),
|
||||
onClick = onResetKey,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun ChooseSelfVerificationModeViewPreview(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue