[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:
Jorge Martin Espinosa 2023-03-23 14:24:25 +01:00 committed by GitHub
parent 59218490ee
commit 1b9999425c
10 changed files with 38 additions and 17 deletions

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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)
} }

View file

@ -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
) )
} }

View file

@ -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))
} }

View file

@ -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()
} }

View file

@ -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()
} }

View file

@ -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>

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:594ebca0307e0488bb6d22df074069181091a6310bb7fdb29a9109a10997319e
size 26874

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:25598da9a3d84cecb4204d140609f2de5b03facd547f7ef45c53ccead333ce05
size 26343