Merge pull request #3829 from element-hq/feature/bma/verificationIteration
Verification UI / UX iteration
This commit is contained in:
commit
f77ac55ec5
17 changed files with 98 additions and 130 deletions
|
|
@ -80,14 +80,14 @@ fun IncomingVerificationView(
|
||||||
@Composable
|
@Composable
|
||||||
private fun IncomingVerificationHeader(step: Step) {
|
private fun IncomingVerificationHeader(step: Step) {
|
||||||
val iconStyle = when (step) {
|
val iconStyle = when (step) {
|
||||||
Step.Canceled,
|
Step.Canceled -> BigIcon.Style.AlertSolid
|
||||||
is Step.Initial -> BigIcon.Style.Default(CompoundIcons.LockSolid())
|
is Step.Initial -> BigIcon.Style.Default(CompoundIcons.LockSolid())
|
||||||
is Step.Verifying -> BigIcon.Style.Default(CompoundIcons.Reaction())
|
is Step.Verifying -> BigIcon.Style.Default(CompoundIcons.Reaction())
|
||||||
Step.Completed -> BigIcon.Style.SuccessSolid
|
Step.Completed -> BigIcon.Style.SuccessSolid
|
||||||
Step.Failure -> BigIcon.Style.AlertSolid
|
Step.Failure -> BigIcon.Style.AlertSolid
|
||||||
}
|
}
|
||||||
val titleTextId = when (step) {
|
val titleTextId = when (step) {
|
||||||
Step.Canceled -> CommonStrings.common_verification_cancelled
|
Step.Canceled -> R.string.screen_session_verification_request_failure_title
|
||||||
is Step.Initial -> R.string.screen_session_verification_request_title
|
is Step.Initial -> R.string.screen_session_verification_request_title
|
||||||
is Step.Verifying -> when (step.data) {
|
is Step.Verifying -> when (step.data) {
|
||||||
is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_title
|
is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_title
|
||||||
|
|
@ -97,7 +97,7 @@ private fun IncomingVerificationHeader(step: Step) {
|
||||||
Step.Failure -> R.string.screen_session_verification_request_failure_title
|
Step.Failure -> R.string.screen_session_verification_request_failure_title
|
||||||
}
|
}
|
||||||
val subtitleTextId = when (step) {
|
val subtitleTextId = when (step) {
|
||||||
Step.Canceled -> R.string.screen_session_verification_cancelled_subtitle
|
Step.Canceled -> R.string.screen_session_verification_request_failure_subtitle
|
||||||
is Step.Initial -> R.string.screen_session_verification_request_subtitle
|
is Step.Initial -> R.string.screen_session_verification_request_subtitle
|
||||||
is Step.Verifying -> when (step.data) {
|
is Step.Verifying -> when (step.data) {
|
||||||
is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_subtitle
|
is SessionVerificationData.Decimals -> R.string.screen_session_verification_compare_numbers_subtitle
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ class VerifySelfSessionPresenter @AssistedInject constructor(
|
||||||
fun handleEvents(event: VerifySelfSessionViewEvents) {
|
fun handleEvents(event: VerifySelfSessionViewEvents) {
|
||||||
Timber.d("Verification user action: ${event::class.simpleName}")
|
Timber.d("Verification user action: ${event::class.simpleName}")
|
||||||
when (event) {
|
when (event) {
|
||||||
|
VerifySelfSessionViewEvents.UseAnotherDevice -> stateAndDispatch.dispatchAction(StateMachineEvent.UseAnotherDevice)
|
||||||
VerifySelfSessionViewEvents.RequestVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.RequestVerification)
|
VerifySelfSessionViewEvents.RequestVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.RequestVerification)
|
||||||
VerifySelfSessionViewEvents.StartSasVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.StartSasVerification)
|
VerifySelfSessionViewEvents.StartSasVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.StartSasVerification)
|
||||||
VerifySelfSessionViewEvents.ConfirmVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.AcceptChallenge)
|
VerifySelfSessionViewEvents.ConfirmVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.AcceptChallenge)
|
||||||
|
|
@ -134,6 +135,9 @@ class VerifySelfSessionPresenter @AssistedInject constructor(
|
||||||
isLastDevice = encryptionService.isLastDevice.value
|
isLastDevice = encryptionService.isLastDevice.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
VerifySelfSessionStateMachine.State.UseAnotherDevice -> {
|
||||||
|
VerifySelfSessionState.Step.UseAnotherDevice
|
||||||
|
}
|
||||||
StateMachineState.RequestingVerification,
|
StateMachineState.RequestingVerification,
|
||||||
StateMachineState.StartingSasVerification,
|
StateMachineState.StartingSasVerification,
|
||||||
StateMachineState.SasVerificationStarted,
|
StateMachineState.SasVerificationStarted,
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ data class VerifySelfSessionState(
|
||||||
|
|
||||||
// FIXME canEnterRecoveryKey value is never read.
|
// FIXME canEnterRecoveryKey value is never read.
|
||||||
data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : Step
|
data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : Step
|
||||||
|
data object UseAnotherDevice : Step
|
||||||
data object Canceled : Step
|
data object Canceled : Step
|
||||||
data object AwaitingOtherDeviceResponse : Step
|
data object AwaitingOtherDeviceResponse : Step
|
||||||
data object Ready : Step
|
data object Ready : Step
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,14 @@ class VerifySelfSessionStateMachine @Inject constructor(
|
||||||
init {
|
init {
|
||||||
spec {
|
spec {
|
||||||
inState<State.Initial> {
|
inState<State.Initial> {
|
||||||
|
on { _: Event.UseAnotherDevice, state ->
|
||||||
|
state.override { State.UseAnotherDevice.andLogStateChange() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inState<State.UseAnotherDevice> {
|
||||||
on { _: Event.RequestVerification, state ->
|
on { _: Event.RequestVerification, state ->
|
||||||
state.override { State.RequestingVerification.andLogStateChange() }
|
state.override { State.RequestingVerification.andLogStateChange() }
|
||||||
}
|
}
|
||||||
on { _: Event.StartSasVerification, state ->
|
|
||||||
state.override { State.StartingSasVerification.andLogStateChange() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
inState<State.RequestingVerification> {
|
inState<State.RequestingVerification> {
|
||||||
onEnterEffect {
|
onEnterEffect {
|
||||||
|
|
@ -64,9 +66,6 @@ class VerifySelfSessionStateMachine @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inState<State.Canceled> {
|
inState<State.Canceled> {
|
||||||
on { _: Event.RequestVerification, state ->
|
|
||||||
state.override { State.RequestingVerification.andLogStateChange() }
|
|
||||||
}
|
|
||||||
on { _: Event.Reset, state ->
|
on { _: Event.Reset, state ->
|
||||||
state.override { State.Initial.andLogStateChange() }
|
state.override { State.Initial.andLogStateChange() }
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +118,7 @@ class VerifySelfSessionStateMachine @Inject constructor(
|
||||||
on { _: Event.Cancel, state: MachineState<State> ->
|
on { _: Event.Cancel, state: MachineState<State> ->
|
||||||
when (state.snapshot) {
|
when (state.snapshot) {
|
||||||
State.Initial, State.Completed, State.Canceled -> state.noChange()
|
State.Initial, State.Completed, State.Canceled -> state.noChange()
|
||||||
|
State.UseAnotherDevice -> state.override { State.Initial.andLogStateChange() }
|
||||||
// For some reason `cancelVerification` is not calling its delegate `didCancel` method so we don't pass from
|
// For some reason `cancelVerification` is not calling its delegate `didCancel` method so we don't pass from
|
||||||
// `Canceling` state to `Canceled` automatically anymore
|
// `Canceling` state to `Canceled` automatically anymore
|
||||||
else -> {
|
else -> {
|
||||||
|
|
@ -144,6 +144,9 @@ class VerifySelfSessionStateMachine @Inject constructor(
|
||||||
/** The initial state, before verification started. */
|
/** The initial state, before verification started. */
|
||||||
data object Initial : State
|
data object Initial : State
|
||||||
|
|
||||||
|
/** Let the user know that they need to get ready on their other session. */
|
||||||
|
data object UseAnotherDevice : State
|
||||||
|
|
||||||
/** Waiting for verification acceptance. */
|
/** Waiting for verification acceptance. */
|
||||||
data object RequestingVerification : State
|
data object RequestingVerification : State
|
||||||
|
|
||||||
|
|
@ -175,6 +178,9 @@ class VerifySelfSessionStateMachine @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface Event {
|
sealed interface Event {
|
||||||
|
/** User wants to use another session. */
|
||||||
|
data object UseAnotherDevice : Event
|
||||||
|
|
||||||
/** Request verification. */
|
/** Request verification. */
|
||||||
data object RequestVerification : Event
|
data object RequestVerification : Event
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfS
|
||||||
aVerifySelfSessionState(
|
aVerifySelfSessionState(
|
||||||
step = Step.Skipped
|
step = Step.Skipped
|
||||||
),
|
),
|
||||||
|
aVerifySelfSessionState(
|
||||||
|
step = Step.UseAnotherDevice
|
||||||
|
),
|
||||||
// Add other state here
|
// Add other state here
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,9 @@ fun VerifySelfSessionView(
|
||||||
fun cancelOrResetFlow() {
|
fun cancelOrResetFlow() {
|
||||||
when (step) {
|
when (step) {
|
||||||
is Step.Canceled -> state.eventSink(VerifySelfSessionViewEvents.Reset)
|
is Step.Canceled -> state.eventSink(VerifySelfSessionViewEvents.Reset)
|
||||||
is Step.AwaitingOtherDeviceResponse, Step.Ready -> state.eventSink(VerifySelfSessionViewEvents.Cancel)
|
is Step.AwaitingOtherDeviceResponse,
|
||||||
|
Step.UseAnotherDevice,
|
||||||
|
Step.Ready -> state.eventSink(VerifySelfSessionViewEvents.Cancel)
|
||||||
is Step.Verifying -> {
|
is Step.Verifying -> {
|
||||||
if (!step.state.isLoading()) {
|
if (!step.state.isLoading()) {
|
||||||
state.eventSink(VerifySelfSessionViewEvents.DeclineVerification)
|
state.eventSink(VerifySelfSessionViewEvents.DeclineVerification)
|
||||||
|
|
@ -159,7 +161,9 @@ fun VerifySelfSessionView(
|
||||||
private fun VerifySelfSessionHeader(step: Step) {
|
private fun VerifySelfSessionHeader(step: Step) {
|
||||||
val iconStyle = when (step) {
|
val iconStyle = when (step) {
|
||||||
Step.Loading -> error("Should not happen")
|
Step.Loading -> error("Should not happen")
|
||||||
is Step.Initial, Step.AwaitingOtherDeviceResponse -> BigIcon.Style.Default(CompoundIcons.LockSolid())
|
is Step.Initial -> BigIcon.Style.Default(CompoundIcons.LockSolid())
|
||||||
|
Step.UseAnotherDevice -> BigIcon.Style.Default(CompoundIcons.Devices())
|
||||||
|
Step.AwaitingOtherDeviceResponse -> BigIcon.Style.Default(CompoundIcons.Devices())
|
||||||
Step.Canceled -> BigIcon.Style.AlertSolid
|
Step.Canceled -> BigIcon.Style.AlertSolid
|
||||||
Step.Ready, is Step.Verifying -> BigIcon.Style.Default(CompoundIcons.Reaction())
|
Step.Ready, is Step.Verifying -> BigIcon.Style.Default(CompoundIcons.Reaction())
|
||||||
Step.Completed -> BigIcon.Style.SuccessSolid
|
Step.Completed -> BigIcon.Style.SuccessSolid
|
||||||
|
|
@ -167,8 +171,10 @@ private fun VerifySelfSessionHeader(step: Step) {
|
||||||
}
|
}
|
||||||
val titleTextId = when (step) {
|
val titleTextId = when (step) {
|
||||||
Step.Loading -> error("Should not happen")
|
Step.Loading -> error("Should not happen")
|
||||||
is Step.Initial, Step.AwaitingOtherDeviceResponse -> R.string.screen_identity_confirmation_title
|
is Step.Initial -> R.string.screen_identity_confirmation_title
|
||||||
Step.Canceled -> CommonStrings.common_verification_cancelled
|
Step.UseAnotherDevice -> R.string.screen_session_verification_use_another_device_title
|
||||||
|
Step.AwaitingOtherDeviceResponse -> R.string.screen_session_verification_waiting_another_device_title
|
||||||
|
Step.Canceled -> CommonStrings.common_verification_failed
|
||||||
Step.Ready -> R.string.screen_session_verification_compare_emojis_title
|
Step.Ready -> R.string.screen_session_verification_compare_emojis_title
|
||||||
Step.Completed -> R.string.screen_identity_confirmed_title
|
Step.Completed -> R.string.screen_identity_confirmed_title
|
||||||
is Step.Verifying -> when (step.data) {
|
is Step.Verifying -> when (step.data) {
|
||||||
|
|
@ -179,8 +185,10 @@ private fun VerifySelfSessionHeader(step: Step) {
|
||||||
}
|
}
|
||||||
val subtitleTextId = when (step) {
|
val subtitleTextId = when (step) {
|
||||||
Step.Loading -> error("Should not happen")
|
Step.Loading -> error("Should not happen")
|
||||||
is Step.Initial, Step.AwaitingOtherDeviceResponse -> R.string.screen_identity_confirmation_subtitle
|
is Step.Initial -> R.string.screen_identity_confirmation_subtitle
|
||||||
Step.Canceled -> R.string.screen_session_verification_cancelled_subtitle
|
Step.UseAnotherDevice -> R.string.screen_session_verification_use_another_device_subtitle
|
||||||
|
Step.AwaitingOtherDeviceResponse -> R.string.screen_session_verification_waiting_another_device_subtitle
|
||||||
|
Step.Canceled -> R.string.screen_session_verification_failed_subtitle
|
||||||
Step.Ready -> R.string.screen_session_verification_ready_subtitle
|
Step.Ready -> R.string.screen_session_verification_ready_subtitle
|
||||||
Step.Completed -> R.string.screen_identity_confirmed_subtitle
|
Step.Completed -> R.string.screen_identity_confirmed_subtitle
|
||||||
is Step.Verifying -> when (step.data) {
|
is Step.Verifying -> when (step.data) {
|
||||||
|
|
@ -252,7 +260,7 @@ private fun VerifySelfSessionBottomMenu(
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.screen_identity_use_another_device),
|
text = stringResource(R.string.screen_identity_use_another_device),
|
||||||
onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) },
|
onClick = { eventSink(VerifySelfSessionViewEvents.UseAnotherDevice) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
|
|
@ -267,18 +275,26 @@ private fun VerifySelfSessionBottomMenu(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is Step.UseAnotherDevice -> {
|
||||||
|
VerificationBottomMenu {
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
text = stringResource(CommonStrings.action_start_verification),
|
||||||
|
onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) },
|
||||||
|
)
|
||||||
|
// Placeholder so the 1st button keeps its vertical position
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
is Step.Canceled -> {
|
is Step.Canceled -> {
|
||||||
VerificationBottomMenu {
|
VerificationBottomMenu {
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.screen_session_verification_positive_button_canceled),
|
text = stringResource(CommonStrings.action_done),
|
||||||
onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) },
|
|
||||||
)
|
|
||||||
TextButton(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = stringResource(CommonStrings.action_cancel),
|
|
||||||
onClick = onCancelClick,
|
onClick = onCancelClick,
|
||||||
)
|
)
|
||||||
|
// Placeholder so the 1st button keeps its vertical position
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is Step.Ready -> {
|
is Step.Ready -> {
|
||||||
|
|
@ -302,6 +318,7 @@ private fun VerifySelfSessionBottomMenu(
|
||||||
text = stringResource(R.string.screen_identity_waiting_on_other_device),
|
text = stringResource(R.string.screen_identity_waiting_on_other_device),
|
||||||
onClick = {},
|
onClick = {},
|
||||||
showProgress = true,
|
showProgress = true,
|
||||||
|
enabled = false,
|
||||||
)
|
)
|
||||||
// Placeholder so the 1st button keeps its vertical position
|
// Placeholder so the 1st button keeps its vertical position
|
||||||
Spacer(modifier = Modifier.height(40.dp))
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.verifysession.impl.outgoing
|
package io.element.android.features.verifysession.impl.outgoing
|
||||||
|
|
||||||
sealed interface VerifySelfSessionViewEvents {
|
sealed interface VerifySelfSessionViewEvents {
|
||||||
|
data object UseAnotherDevice : VerifySelfSessionViewEvents
|
||||||
data object RequestVerification : VerifySelfSessionViewEvents
|
data object RequestVerification : VerifySelfSessionViewEvents
|
||||||
data object StartSasVerification : VerifySelfSessionViewEvents
|
data object StartSasVerification : VerifySelfSessionViewEvents
|
||||||
data object ConfirmVerification : VerifySelfSessionViewEvents
|
data object ConfirmVerification : VerifySelfSessionViewEvents
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@
|
||||||
<string name="screen_session_verification_request_title">"Verification requested"</string>
|
<string name="screen_session_verification_request_title">"Verification requested"</string>
|
||||||
<string name="screen_session_verification_they_dont_match">"They don’t match"</string>
|
<string name="screen_session_verification_they_dont_match">"They don’t match"</string>
|
||||||
<string name="screen_session_verification_they_match">"They match"</string>
|
<string name="screen_session_verification_they_match">"They match"</string>
|
||||||
|
<string name="screen_session_verification_use_another_device_subtitle">"Make sure you have the app open in the other device before starting verification from here."</string>
|
||||||
|
<string name="screen_session_verification_use_another_device_title">"Open the app on another verified device"</string>
|
||||||
|
<string name="screen_session_verification_waiting_another_device_subtitle">"You should see a popup on the other device. Start the verification from there now."</string>
|
||||||
|
<string name="screen_session_verification_waiting_another_device_title">"Start verification on the other device"</string>
|
||||||
<string name="screen_session_verification_waiting_to_accept_subtitle">"Accept the request to start the verification process in your other session to continue."</string>
|
<string name="screen_session_verification_waiting_to_accept_subtitle">"Accept the request to start the verification process in your other session to continue."</string>
|
||||||
<string name="screen_session_verification_waiting_to_accept_title">"Waiting to accept request"</string>
|
<string name="screen_session_verification_waiting_to_accept_title">"Waiting to accept request"</string>
|
||||||
<string name="screen_signout_in_progress_dialog_content">"Signing out…"</string>
|
<string name="screen_signout_in_progress_dialog_content">"Signing out…"</string>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.features.verifysession.impl.outgoing
|
package io.element.android.features.verifysession.impl.outgoing
|
||||||
|
|
||||||
import app.cash.molecule.RecompositionMode
|
|
||||||
import app.cash.molecule.moleculeFlow
|
|
||||||
import app.cash.turbine.ReceiveTurbine
|
import app.cash.turbine.ReceiveTurbine
|
||||||
import app.cash.turbine.test
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.logout.api.LogoutUseCase
|
import io.element.android.features.logout.api.LogoutUseCase
|
||||||
import io.element.android.features.logout.test.FakeLogoutUseCase
|
import io.element.android.features.logout.test.FakeLogoutUseCase
|
||||||
|
|
@ -33,6 +30,7 @@ import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.lambda.lambdaError
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
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
|
||||||
|
import io.element.android.tests.testutils.test
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -48,9 +46,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
val presenter = createVerifySelfSessionPresenter(
|
val presenter = createVerifySelfSessionPresenter(
|
||||||
service = unverifiedSessionService(),
|
service = unverifiedSessionService(),
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
awaitItem().run {
|
awaitItem().run {
|
||||||
assertThat(step).isEqualTo(Step.Initial(false))
|
assertThat(step).isEqualTo(Step.Initial(false))
|
||||||
assertThat(displaySkipButton).isTrue()
|
assertThat(displaySkipButton).isTrue()
|
||||||
|
|
@ -65,9 +61,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
service = unverifiedSessionService(),
|
service = unverifiedSessionService(),
|
||||||
buildMeta = buildMeta,
|
buildMeta = buildMeta,
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().displaySkipButton).isFalse()
|
assertThat(awaitItem().displaySkipButton).isFalse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +77,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
emitRecoveryState(RecoveryState.INCOMPLETE)
|
emitRecoveryState(RecoveryState.INCOMPLETE)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Initial(true))
|
assertThat(awaitItem().step).isEqualTo(Step.Initial(true))
|
||||||
resetLambda.assertions().isCalledOnce().with(value(true))
|
resetLambda.assertions().isCalledOnce().with(value(true))
|
||||||
}
|
}
|
||||||
|
|
@ -100,9 +92,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
emitRecoveryState(RecoveryState.INCOMPLETE)
|
emitRecoveryState(RecoveryState.INCOMPLETE)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Initial(canEnterRecoveryKey = true, isLastDevice = true))
|
assertThat(awaitItem().step).isEqualTo(Step.Initial(canEnterRecoveryKey = true, isLastDevice = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,43 +104,17 @@ class VerifySelfSessionPresenterTest {
|
||||||
startVerificationLambda = { },
|
startVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
requestVerificationAndAwaitVerifyingState(service)
|
requestVerificationAndAwaitVerifyingState(service)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `present - Handles startSasVerification`() = runTest {
|
|
||||||
val service = unverifiedSessionService(
|
|
||||||
startVerificationLambda = { },
|
|
||||||
)
|
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val initialState = awaitItem()
|
|
||||||
assertThat(initialState.step).isEqualTo(Step.Initial(false))
|
|
||||||
initialState.eventSink(VerifySelfSessionViewEvents.StartSasVerification)
|
|
||||||
// Await for other device response:
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.AwaitingOtherDeviceResponse)
|
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidStartSasVerification)
|
|
||||||
// ChallengeReceived:
|
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidReceiveVerificationData(SessionVerificationData.Emojis(emptyList())))
|
|
||||||
val verifyingState = awaitItem()
|
|
||||||
assertThat(verifyingState.step).isInstanceOf(Step.Verifying::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - Cancellation on initial state does nothing`() = runTest {
|
fun `present - Cancellation on initial state does nothing`() = runTest {
|
||||||
val presenter = createVerifySelfSessionPresenter(
|
val presenter = createVerifySelfSessionPresenter(
|
||||||
service = unverifiedSessionService(),
|
service = unverifiedSessionService(),
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.step).isEqualTo(Step.Initial(false))
|
assertThat(initialState.step).isEqualTo(Step.Initial(false))
|
||||||
val eventSink = initialState.eventSink
|
val eventSink = initialState.eventSink
|
||||||
|
|
@ -167,9 +131,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
approveVerificationLambda = { },
|
approveVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
val state = requestVerificationAndAwaitVerifyingState(service)
|
||||||
state.eventSink(VerifySelfSessionViewEvents.ConfirmVerification)
|
state.eventSink(VerifySelfSessionViewEvents.ConfirmVerification)
|
||||||
// Cancelling
|
// Cancelling
|
||||||
|
|
@ -186,9 +148,8 @@ class VerifySelfSessionPresenterTest {
|
||||||
requestVerificationLambda = { },
|
requestVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
awaitItem().eventSink(VerifySelfSessionViewEvents.UseAnotherDevice)
|
||||||
}.test {
|
|
||||||
awaitItem().eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
awaitItem().eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidFail)
|
service.emitVerificationFlowState(VerificationFlowState.DidFail)
|
||||||
assertThat(awaitItem().step).isInstanceOf(Step.AwaitingOtherDeviceResponse::class.java)
|
assertThat(awaitItem().step).isInstanceOf(Step.AwaitingOtherDeviceResponse::class.java)
|
||||||
|
|
@ -204,9 +165,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
cancelVerificationLambda = { },
|
cancelVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
val state = requestVerificationAndAwaitVerifyingState(service)
|
||||||
state.eventSink(VerifySelfSessionViewEvents.Cancel)
|
state.eventSink(VerifySelfSessionViewEvents.Cancel)
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Canceled)
|
assertThat(awaitItem().step).isEqualTo(Step.Canceled)
|
||||||
|
|
@ -220,35 +179,13 @@ class VerifySelfSessionPresenterTest {
|
||||||
startVerificationLambda = { },
|
startVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
requestVerificationAndAwaitVerifyingState(service)
|
requestVerificationAndAwaitVerifyingState(service)
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidReceiveVerificationData(SessionVerificationData.Emojis(emptyList())))
|
service.emitVerificationFlowState(VerificationFlowState.DidReceiveVerificationData(SessionVerificationData.Emojis(emptyList())))
|
||||||
ensureAllEventsConsumed()
|
ensureAllEventsConsumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `present - Restart after cancellation returns to requesting verification`() = runTest {
|
|
||||||
val service = unverifiedSessionService(
|
|
||||||
requestVerificationLambda = { },
|
|
||||||
startVerificationLambda = { },
|
|
||||||
)
|
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidCancel)
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Canceled)
|
|
||||||
state.eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
|
||||||
// Went back to requesting verification
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.AwaitingOtherDeviceResponse)
|
|
||||||
cancelAndIgnoreRemainingEvents()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - Go back after cancellation returns to initial state`() = runTest {
|
fun `present - Go back after cancellation returns to initial state`() = runTest {
|
||||||
val service = unverifiedSessionService(
|
val service = unverifiedSessionService(
|
||||||
|
|
@ -256,9 +193,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
startVerificationLambda = { },
|
startVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
val state = requestVerificationAndAwaitVerifyingState(service)
|
||||||
service.emitVerificationFlowState(VerificationFlowState.DidCancel)
|
service.emitVerificationFlowState(VerificationFlowState.DidCancel)
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Canceled)
|
assertThat(awaitItem().step).isEqualTo(Step.Canceled)
|
||||||
|
|
@ -280,9 +215,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
approveVerificationLambda = { },
|
approveVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(
|
val state = requestVerificationAndAwaitVerifyingState(
|
||||||
service,
|
service,
|
||||||
SessionVerificationData.Emojis(emojis)
|
SessionVerificationData.Emojis(emojis)
|
||||||
|
|
@ -307,9 +240,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
declineVerificationLambda = { },
|
declineVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
val state = requestVerificationAndAwaitVerifyingState(service)
|
||||||
state.eventSink(VerifySelfSessionViewEvents.DeclineVerification)
|
state.eventSink(VerifySelfSessionViewEvents.DeclineVerification)
|
||||||
assertThat(awaitItem().step).isEqualTo(
|
assertThat(awaitItem().step).isEqualTo(
|
||||||
|
|
@ -330,9 +261,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
startVerificationLambda = { },
|
startVerificationLambda = { },
|
||||||
)
|
)
|
||||||
val presenter = createVerifySelfSessionPresenter(service)
|
val presenter = createVerifySelfSessionPresenter(service)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
val state = requestVerificationAndAwaitVerifyingState(service)
|
val state = requestVerificationAndAwaitVerifyingState(service)
|
||||||
state.eventSink(VerifySelfSessionViewEvents.SkipVerification)
|
state.eventSink(VerifySelfSessionViewEvents.SkipVerification)
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Skipped)
|
assertThat(awaitItem().step).isEqualTo(Step.Skipped)
|
||||||
|
|
@ -352,9 +281,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
service = service,
|
service = service,
|
||||||
showDeviceVerifiedScreen = true,
|
showDeviceVerifiedScreen = true,
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Completed)
|
assertThat(awaitItem().step).isEqualTo(Step.Completed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -372,9 +299,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
service = service,
|
service = service,
|
||||||
showDeviceVerifiedScreen = false,
|
showDeviceVerifiedScreen = false,
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
assertThat(awaitItem().step).isEqualTo(Step.Skipped)
|
assertThat(awaitItem().step).isEqualTo(Step.Skipped)
|
||||||
}
|
}
|
||||||
|
|
@ -394,9 +319,7 @@ class VerifySelfSessionPresenterTest {
|
||||||
service,
|
service,
|
||||||
logoutUseCase = FakeLogoutUseCase(signOutLambda)
|
logoutUseCase = FakeLogoutUseCase(signOutLambda)
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
presenter.test {
|
||||||
presenter.present()
|
|
||||||
}.test {
|
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val initialItem = awaitItem()
|
val initialItem = awaitItem()
|
||||||
initialItem.eventSink(VerifySelfSessionViewEvents.SignOut)
|
initialItem.eventSink(VerifySelfSessionViewEvents.SignOut)
|
||||||
|
|
@ -414,6 +337,9 @@ class VerifySelfSessionPresenterTest {
|
||||||
): VerifySelfSessionState {
|
): VerifySelfSessionState {
|
||||||
var state = awaitItem()
|
var state = awaitItem()
|
||||||
assertThat(state.step).isEqualTo(Step.Initial(false))
|
assertThat(state.step).isEqualTo(Step.Initial(false))
|
||||||
|
state.eventSink(VerifySelfSessionViewEvents.UseAnotherDevice)
|
||||||
|
state = awaitItem()
|
||||||
|
assertThat(state.step).isEqualTo(Step.UseAnotherDevice)
|
||||||
state.eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
state.eventSink(VerifySelfSessionViewEvents.RequestVerification)
|
||||||
// Await for other device response:
|
// Await for other device response:
|
||||||
fakeService.emitVerificationFlowState(VerificationFlowState.DidAcceptVerificationRequest)
|
fakeService.emitVerificationFlowState(VerificationFlowState.DidAcceptVerificationRequest)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:bee1454db757b0897ae2113d3a11ed9adef0eb6bc52f3775edac56ed8533a88f
|
oid sha256:d3340a2d29e6c1d86f5ec5664179cae9501fcc95381311174d7d6b45b15af326
|
||||||
size 24076
|
size 24123
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:59a23ec5e3086349d3382f006cf1bcb4121183c83ea8c749aa95e3160561aef1
|
oid sha256:c6c7e8cdf40bdf018931635565ac649fed518140a047a71cf70cf63e9edf54d3
|
||||||
size 23524
|
size 23932
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:18dadaebe7a32aacde31afa0352a343913955b099ca4a07851e3ffe75e88b4d6
|
||||||
|
size 31012
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:2cc647747c41f4c2cf96a3425e8b279b39fd4e09e1441e5b5afcd260f79afaa1
|
oid sha256:71b9f32b26b391ff3bf231ca9f364a157f535c1e6ff52ee3e3ead3630bb1b239
|
||||||
size 22714
|
size 30007
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a7fe45575eb8423161d355d9b99ecff4acc0f708e5b106d9d38aa2657942d736
|
oid sha256:000374157cb5fbf6670b4af041fc385538df78bf4aecaf83ea24d39dfec84f23
|
||||||
size 28219
|
size 24278
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:4dd274f8c2ade6213a13a47400ec3a571844eafcc82b292b1c813bd9aa098236
|
||||||
|
size 30241
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:786a63d0d824657270b44428a1a251d0d521e6a97a4239516ae5f2eff06fdc3b
|
oid sha256:994b39ba25e011cce97504a1f3d4ed0c420b7bce87daafae77ba481cc629cdae
|
||||||
size 22125
|
size 29051
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c29d3f5bbff739d23800345feb42e73fe9374c5cb5db27690278fb22c5546fe3
|
oid sha256:3a3f08002e805fe5f7a4c96aa4b73c2fcd6e8b79e6a9e82bcc7bd3df50d8c22d
|
||||||
size 27754
|
size 24015
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue