[Verify Session] Add missing 'start verification' screen. (#241)
* Add missing 'start verification' screen. * Fix retries sometimes not working because of `SessionVerificationController.setDelegate`. * Make the negative button invisible when not needed.
This commit is contained in:
parent
59218490ee
commit
1b9999425c
10 changed files with 38 additions and 17 deletions
|
|
@ -85,11 +85,14 @@ class VerifySelfSessionPresenter @Inject constructor(
|
||||||
StateMachineState.RequestingVerification,
|
StateMachineState.RequestingVerification,
|
||||||
StateMachineState.StartingSasVerification,
|
StateMachineState.StartingSasVerification,
|
||||||
StateMachineState.SasVerificationStarted,
|
StateMachineState.SasVerificationStarted,
|
||||||
StateMachineState.VerificationRequestAccepted,
|
|
||||||
StateMachineState.Canceling -> {
|
StateMachineState.Canceling -> {
|
||||||
VerifySelfSessionState.VerificationStep.AwaitingOtherDeviceResponse
|
VerifySelfSessionState.VerificationStep.AwaitingOtherDeviceResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateMachineState.VerificationRequestAccepted -> {
|
||||||
|
VerifySelfSessionState.VerificationStep.Ready
|
||||||
|
}
|
||||||
|
|
||||||
StateMachineState.Canceled -> {
|
StateMachineState.Canceled -> {
|
||||||
VerifySelfSessionState.VerificationStep.Canceled
|
VerifySelfSessionState.VerificationStep.Canceled
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ data class VerifySelfSessionState(
|
||||||
object Initial : VerificationStep
|
object Initial : VerificationStep
|
||||||
object Canceled : VerificationStep
|
object Canceled : VerificationStep
|
||||||
object AwaitingOtherDeviceResponse : VerificationStep
|
object AwaitingOtherDeviceResponse : VerificationStep
|
||||||
|
object Ready : VerificationStep
|
||||||
data class Verifying(val emojiList: List<VerificationEmoji>, val state: Async<Unit>) : VerificationStep
|
data class Verifying(val emojiList: List<VerificationEmoji>, val state: Async<Unit>) : VerificationStep
|
||||||
object Completed : VerificationStep
|
object Completed : VerificationStep
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ class VerifySelfSessionStateMachine(
|
||||||
// Observe the verification service state, translate it to state machine input events
|
// Observe the verification service state, translate it to state machine input events
|
||||||
sessionVerificationService.verificationFlowState.onEach { verificationAttemptState ->
|
sessionVerificationService.verificationFlowState.onEach { verificationAttemptState ->
|
||||||
when (verificationAttemptState) {
|
when (verificationAttemptState) {
|
||||||
|
VerificationFlowState.Initial -> stateMachine.restart()
|
||||||
VerificationFlowState.AcceptedVerificationRequest -> {
|
VerificationFlowState.AcceptedVerificationRequest -> {
|
||||||
stateMachine.process(Event.DidAcceptVerificationRequest)
|
stateMachine.process(Event.DidAcceptVerificationRequest)
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +103,6 @@ class VerifySelfSessionStateMachine(
|
||||||
VerificationFlowState.Failed -> {
|
VerificationFlowState.Failed -> {
|
||||||
stateMachine.process(Event.DidFail)
|
stateMachine.process(Event.DidFail)
|
||||||
}
|
}
|
||||||
else -> Unit
|
|
||||||
}
|
}
|
||||||
}.launchIn(coroutineScope)
|
}.launchIn(coroutineScope)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfS
|
||||||
aVerifySelfSessionState().copy(
|
aVerifySelfSessionState().copy(
|
||||||
verificationFlowStep = VerifySelfSessionState.VerificationStep.Canceled
|
verificationFlowStep = VerifySelfSessionState.VerificationStep.Canceled
|
||||||
),
|
),
|
||||||
|
aVerifySelfSessionState().copy(
|
||||||
|
verificationFlowStep = VerifySelfSessionState.VerificationStep.Ready
|
||||||
|
),
|
||||||
// Add other state here
|
// Add other state here
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,19 +106,19 @@ internal fun HeaderContent(verificationFlowStep: FlowStep, modifier: Modifier =
|
||||||
FlowStep.Initial -> R.drawable.ic_verification_devices
|
FlowStep.Initial -> R.drawable.ic_verification_devices
|
||||||
FlowStep.Canceled -> R.drawable.ic_verification_warning
|
FlowStep.Canceled -> R.drawable.ic_verification_warning
|
||||||
FlowStep.AwaitingOtherDeviceResponse -> R.drawable.ic_verification_waiting
|
FlowStep.AwaitingOtherDeviceResponse -> R.drawable.ic_verification_waiting
|
||||||
is FlowStep.Verifying, FlowStep.Completed -> R.drawable.ic_verification_emoji
|
FlowStep.Ready, is FlowStep.Verifying, FlowStep.Completed -> R.drawable.ic_verification_emoji
|
||||||
}
|
}
|
||||||
val titleTextId = when (verificationFlowStep) {
|
val titleTextId = when (verificationFlowStep) {
|
||||||
FlowStep.Initial -> StringR.string.verification_title_initial
|
FlowStep.Initial -> StringR.string.verification_title_initial
|
||||||
FlowStep.Canceled -> StringR.string.verification_title_canceled
|
FlowStep.Canceled -> StringR.string.verification_title_canceled
|
||||||
FlowStep.AwaitingOtherDeviceResponse -> StringR.string.verification_title_waiting
|
FlowStep.AwaitingOtherDeviceResponse -> StringR.string.verification_title_waiting
|
||||||
is FlowStep.Verifying, FlowStep.Completed -> StringR.string.verification_title_verifying
|
FlowStep.Ready, is FlowStep.Verifying, FlowStep.Completed -> StringR.string.verification_title_verifying
|
||||||
}
|
}
|
||||||
val subtitleTextId = when (verificationFlowStep) {
|
val subtitleTextId = when (verificationFlowStep) {
|
||||||
FlowStep.Initial -> StringR.string.verification_subtitle_initial
|
FlowStep.Initial -> StringR.string.verification_subtitle_initial
|
||||||
FlowStep.Canceled -> StringR.string.verification_subtitle_canceled
|
FlowStep.Canceled -> StringR.string.verification_subtitle_canceled
|
||||||
FlowStep.AwaitingOtherDeviceResponse -> StringR.string.verification_subtitle_waiting
|
FlowStep.AwaitingOtherDeviceResponse -> StringR.string.verification_subtitle_waiting
|
||||||
is FlowStep.Verifying, FlowStep.Completed -> StringR.string.verification_subtitle_verifying
|
FlowStep.Ready, is FlowStep.Verifying, FlowStep.Completed -> StringR.string.verification_subtitle_verifying
|
||||||
}
|
}
|
||||||
Column(modifier) {
|
Column(modifier) {
|
||||||
Spacer(Modifier.height(68.dp))
|
Spacer(Modifier.height(68.dp))
|
||||||
|
|
@ -167,7 +167,7 @@ internal fun Content(flowState: FlowStep, modifier: Modifier = Modifier) {
|
||||||
Column(modifier) {
|
Column(modifier) {
|
||||||
Spacer(Modifier.height(56.dp))
|
Spacer(Modifier.height(56.dp))
|
||||||
when (flowState) {
|
when (flowState) {
|
||||||
FlowStep.Initial, FlowStep.Canceled, FlowStep.Completed -> Unit
|
FlowStep.Initial, FlowStep.Ready, FlowStep.Canceled, FlowStep.Completed -> Unit
|
||||||
FlowStep.AwaitingOtherDeviceResponse -> ContentWaiting()
|
FlowStep.AwaitingOtherDeviceResponse -> ContentWaiting()
|
||||||
is FlowStep.Verifying -> ContentVerifying(flowState)
|
is FlowStep.Verifying -> ContentVerifying(flowState)
|
||||||
}
|
}
|
||||||
|
|
@ -219,6 +219,7 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit)
|
||||||
StringR.string.verification_positive_button_verifying_start
|
StringR.string.verification_positive_button_verifying_start
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FlowStep.Ready -> StringR.string.verification_positive_button_ready
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
val negativeButtonTitle = when (verificationViewState) {
|
val negativeButtonTitle = when (verificationViewState) {
|
||||||
|
|
@ -231,6 +232,7 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit)
|
||||||
|
|
||||||
val positiveButtonEvent = when (verificationViewState) {
|
val positiveButtonEvent = when (verificationViewState) {
|
||||||
FlowStep.Initial -> VerifySelfSessionViewEvents.RequestVerification
|
FlowStep.Initial -> VerifySelfSessionViewEvents.RequestVerification
|
||||||
|
FlowStep.Ready -> VerifySelfSessionViewEvents.StartSasVerification
|
||||||
is FlowStep.Verifying -> if (!isVerifying) VerifySelfSessionViewEvents.ConfirmVerification else null
|
is FlowStep.Verifying -> if (!isVerifying) VerifySelfSessionViewEvents.ConfirmVerification else null
|
||||||
FlowStep.Canceled -> VerifySelfSessionViewEvents.Restart
|
FlowStep.Canceled -> VerifySelfSessionViewEvents.Restart
|
||||||
else -> null
|
else -> null
|
||||||
|
|
@ -264,13 +266,15 @@ internal fun BottomMenu(screenState: VerifySelfSessionState, goBack: () -> Unit)
|
||||||
positiveButtonTitle?.let { Text(stringResource(it)) }
|
positiveButtonTitle?.let { Text(stringResource(it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
if (negativeButtonTitle != null) {
|
||||||
TextButton(
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
modifier = Modifier.fillMaxWidth(),
|
TextButton(
|
||||||
onClick = negativeButtonCallback,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
enabled = negativeButtonEnabled,
|
onClick = negativeButtonCallback,
|
||||||
) {
|
enabled = negativeButtonEnabled,
|
||||||
negativeButtonTitle?.let { Text(stringResource(it)) }
|
) {
|
||||||
|
Text(stringResource(negativeButtonTitle))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(40.dp))
|
Spacer(Modifier.height(40.dp))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,10 @@ class VerifySelfSessionPresenterTests {
|
||||||
eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
||||||
// Await for other device response:
|
// Await for other device response:
|
||||||
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse)
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse)
|
||||||
|
// Await for the state to be Ready
|
||||||
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.Ready)
|
||||||
|
// Await for other device response (again):
|
||||||
|
assertThat(awaitItem().verificationFlowStep).isEqualTo(VerificationStep.AwaitingOtherDeviceResponse)
|
||||||
// Finally, ChallengeReceived:
|
// Finally, ChallengeReceived:
|
||||||
val verifyingState = awaitItem()
|
val verifyingState = awaitItem()
|
||||||
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java)
|
assertThat(verifyingState.verificationFlowStep).isInstanceOf(VerificationStep.Verifying::class.java)
|
||||||
|
|
@ -233,8 +237,8 @@ class VerifySelfSessionPresenterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ReceiveTurbine<VerifySelfSessionState>.awaitChallengeReceivedState(): VerifySelfSessionState {
|
private suspend fun ReceiveTurbine<VerifySelfSessionState>.awaitChallengeReceivedState(): VerifySelfSessionState {
|
||||||
// Skip 'waiting for response' state
|
// Skip 'waiting for response', 'ready' and 'starting verification' state
|
||||||
skipItems(1)
|
skipItems(3)
|
||||||
// Received challenge
|
// Received challenge
|
||||||
return awaitItem()
|
return awaitItem()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ class RustSessionVerificationService @Inject constructor() : SessionVerification
|
||||||
_isReady.value = value != null
|
_isReady.value = value != null
|
||||||
// If status was 'Unknown', move it to either 'Verified' or 'NotVerified'
|
// If status was 'Unknown', move it to either 'Verified' or 'NotVerified'
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
value.setDelegate(this)
|
||||||
updateVerificationStatus(value.isVerified())
|
updateVerificationStatus(value.isVerified())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +53,6 @@ class RustSessionVerificationService @Inject constructor() : SessionVerification
|
||||||
override val sessionVerifiedStatus: StateFlow<SessionVerifiedStatus> = _sessionVerifiedStatus.asStateFlow()
|
override val sessionVerifiedStatus: StateFlow<SessionVerifiedStatus> = _sessionVerifiedStatus.asStateFlow()
|
||||||
|
|
||||||
override fun requestVerification() = tryOrFail {
|
override fun requestVerification() = tryOrFail {
|
||||||
verificationController?.setDelegate(this)
|
|
||||||
verificationController?.requestVerification()
|
verificationController?.requestVerification()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,7 +63,6 @@ class RustSessionVerificationService @Inject constructor() : SessionVerification
|
||||||
override fun declineVerification() = tryOrFail { verificationController?.declineVerification() }
|
override fun declineVerification() = tryOrFail { verificationController?.declineVerification() }
|
||||||
|
|
||||||
override fun startVerification() = tryOrFail {
|
override fun startVerification() = tryOrFail {
|
||||||
verificationController?.setDelegate(this)
|
|
||||||
verificationController?.startSasVerification()
|
verificationController?.startSasVerification()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
|
|
||||||
<string name="verification_positive_button_initial">I am ready</string>
|
<string name="verification_positive_button_initial">I am ready</string>
|
||||||
<string name="verification_positive_button_canceled">Retry verification</string>
|
<string name="verification_positive_button_canceled">Retry verification</string>
|
||||||
|
<string name="verification_positive_button_ready">Start</string>
|
||||||
<string name="verification_positive_button_verifying_start">They match</string>
|
<string name="verification_positive_button_verifying_start">They match</string>
|
||||||
<string name="verification_positive_button_verifying_ongoing">Waiting to match</string>
|
<string name="verification_positive_button_verifying_ongoing">Waiting to match</string>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:594ebca0307e0488bb6d22df074069181091a6310bb7fdb29a9109a10997319e
|
||||||
|
size 26874
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:25598da9a3d84cecb4204d140609f2de5b03facd547f7ef45c53ccead333ce05
|
||||||
|
size 26343
|
||||||
Loading…
Add table
Add a link
Reference in a new issue