Browse Source

Add a way to sign out when the user is asked to verify the session.

pull/3359/head
Benoit Marty 3 weeks ago
parent
commit
f4beddef99
  1. 2
      features/verifysession/impl/build.gradle.kts
  2. 7
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt
  3. 17
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt
  4. 2
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt
  5. 7
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateProvider.kt
  6. 49
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt
  7. 1
      features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt
  8. 1
      features/verifysession/impl/src/main/res/values/localazy.xml
  9. 31
      features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt
  10. 18
      features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt
  11. 1
      tools/localazy/config.json

2
features/verifysession/impl/build.gradle.kts

@ -43,6 +43,7 @@ dependencies {
implementation(projects.libraries.designsystem) implementation(projects.libraries.designsystem)
implementation(projects.libraries.preferences.api) implementation(projects.libraries.preferences.api)
implementation(projects.libraries.uiStrings) implementation(projects.libraries.uiStrings)
implementation(projects.features.logout.api)
api(libs.statemachine) api(libs.statemachine)
api(projects.features.verifysession.api) api(projects.features.verifysession.api)
@ -52,6 +53,7 @@ dependencies {
testImplementation(libs.test.robolectric) testImplementation(libs.test.robolectric)
testImplementation(libs.test.truth) testImplementation(libs.test.truth)
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.features.logout.test)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.preferences.test) testImplementation(projects.libraries.preferences.test)
testImplementation(projects.tests.testutils) testImplementation(projects.tests.testutils)

7
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionNode.kt

@ -16,8 +16,10 @@
package io.element.android.features.verifysession.impl package io.element.android.features.verifysession.impl
import android.app.Activity
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.Plugin
@ -25,6 +27,8 @@ import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.logout.api.util.onSuccessLogout
import io.element.android.features.verifysession.api.VerifySessionEntryPoint import io.element.android.features.verifysession.api.VerifySessionEntryPoint
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
@ -39,12 +43,15 @@ class VerifySelfSessionNode @AssistedInject constructor(
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val state = presenter.present() val state = presenter.present()
val activity = LocalContext.current as Activity
val isDark = ElementTheme.isLightTheme.not()
VerifySelfSessionView( VerifySelfSessionView(
state = state, state = state,
modifier = modifier, modifier = modifier,
onEnterRecoveryKey = callback::onEnterRecoveryKey, onEnterRecoveryKey = callback::onEnterRecoveryKey,
onResetKey = callback::onResetKey, onResetKey = callback::onResetKey,
onFinish = callback::onDone, onFinish = callback::onDone,
onSuccessLogout = { onSuccessLogout(activity, isDark, it) },
) )
} }
} }

17
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenter.kt

@ -20,14 +20,19 @@ package io.element.android.features.verifysession.impl
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import com.freeletics.flowredux.compose.rememberStateAndDispatch import com.freeletics.flowredux.compose.rememberStateAndDispatch
import io.element.android.features.logout.api.LogoutUseCase
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState import io.element.android.libraries.matrix.api.encryption.RecoveryState
@ -49,6 +54,7 @@ class VerifySelfSessionPresenter @Inject constructor(
private val stateMachine: VerifySelfSessionStateMachine, private val stateMachine: VerifySelfSessionStateMachine,
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
private val sessionPreferencesStore: SessionPreferencesStore, private val sessionPreferencesStore: SessionPreferencesStore,
private val logoutUseCase: LogoutUseCase,
) : Presenter<VerifySelfSessionState> { ) : Presenter<VerifySelfSessionState> {
@Composable @Composable
override fun present(): VerifySelfSessionState { override fun present(): VerifySelfSessionState {
@ -61,6 +67,9 @@ class VerifySelfSessionPresenter @Inject constructor(
val stateAndDispatch = stateMachine.rememberStateAndDispatch() val stateAndDispatch = stateMachine.rememberStateAndDispatch()
val skipVerification by sessionPreferencesStore.isSessionVerificationSkipped().collectAsState(initial = false) val skipVerification by sessionPreferencesStore.isSessionVerificationSkipped().collectAsState(initial = false)
val needsVerification by sessionVerificationService.needsSessionVerification.collectAsState(initial = true) val needsVerification by sessionVerificationService.needsSessionVerification.collectAsState(initial = true)
val signOutAction = remember {
mutableStateOf<AsyncAction<String?>>(AsyncAction.Uninitialized)
}
val verificationFlowStep by remember { val verificationFlowStep by remember {
derivedStateOf { derivedStateOf {
when { when {
@ -85,6 +94,7 @@ class VerifySelfSessionPresenter @Inject constructor(
VerifySelfSessionViewEvents.DeclineVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.DeclineChallenge) VerifySelfSessionViewEvents.DeclineVerification -> stateAndDispatch.dispatchAction(StateMachineEvent.DeclineChallenge)
VerifySelfSessionViewEvents.Cancel -> stateAndDispatch.dispatchAction(StateMachineEvent.Cancel) VerifySelfSessionViewEvents.Cancel -> stateAndDispatch.dispatchAction(StateMachineEvent.Cancel)
VerifySelfSessionViewEvents.Reset -> stateAndDispatch.dispatchAction(StateMachineEvent.Reset) VerifySelfSessionViewEvents.Reset -> stateAndDispatch.dispatchAction(StateMachineEvent.Reset)
VerifySelfSessionViewEvents.SignOut -> coroutineScope.signOut(signOutAction)
VerifySelfSessionViewEvents.SkipVerification -> coroutineScope.launch { VerifySelfSessionViewEvents.SkipVerification -> coroutineScope.launch {
sessionPreferencesStore.setSkipSessionVerification(true) sessionPreferencesStore.setSkipSessionVerification(true)
} }
@ -92,6 +102,7 @@ class VerifySelfSessionPresenter @Inject constructor(
} }
return VerifySelfSessionState( return VerifySelfSessionState(
verificationFlowStep = verificationFlowStep, verificationFlowStep = verificationFlowStep,
signOutAction = signOutAction.value,
displaySkipButton = buildMeta.isDebuggable, displaySkipButton = buildMeta.isDebuggable,
eventSink = ::handleEvents, eventSink = ::handleEvents,
) )
@ -160,4 +171,10 @@ class VerifySelfSessionPresenter @Inject constructor(
} }
}.launchIn(this) }.launchIn(this)
} }
private fun CoroutineScope.signOut(signOutAction: MutableState<AsyncAction<String?>>) = launch {
suspend {
logoutUseCase.logout(ignoreSdkError = true)
}.runCatchingUpdatingState(signOutAction)
}
} }

2
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionState.kt

@ -18,12 +18,14 @@ package io.element.android.features.verifysession.impl
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.SessionVerificationData
@Immutable @Immutable
data class VerifySelfSessionState( data class VerifySelfSessionState(
val verificationFlowStep: VerificationStep, val verificationFlowStep: VerificationStep,
val signOutAction: AsyncAction<String?>,
val displaySkipButton: Boolean, val displaySkipButton: Boolean,
val eventSink: (VerifySelfSessionViewEvents) -> Unit, val eventSink: (VerifySelfSessionViewEvents) -> Unit,
) { ) {

7
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionStateProvider.kt

@ -18,6 +18,7 @@ package io.element.android.features.verifysession.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.verification.SessionVerificationData import io.element.android.libraries.matrix.api.verification.SessionVerificationData
import io.element.android.libraries.matrix.api.verification.VerificationEmoji import io.element.android.libraries.matrix.api.verification.VerificationEmoji
@ -54,6 +55,10 @@ open class VerifySelfSessionStateProvider : PreviewParameterProvider<VerifySelfS
verificationFlowStep = VerificationStep.Completed, verificationFlowStep = VerificationStep.Completed,
displaySkipButton = true, displaySkipButton = true,
), ),
aVerifySelfSessionState(
signOutAction = AsyncAction.Loading,
displaySkipButton = true,
),
// Add other state here // Add other state here
) )
} }
@ -72,12 +77,14 @@ private fun aDecimalsSessionVerificationData(
internal fun aVerifySelfSessionState( internal fun aVerifySelfSessionState(
verificationFlowStep: VerificationStep = VerificationStep.Initial(canEnterRecoveryKey = false), verificationFlowStep: VerificationStep = VerificationStep.Initial(canEnterRecoveryKey = false),
signOutAction: AsyncAction<String?> = AsyncAction.Uninitialized,
displaySkipButton: Boolean = false, displaySkipButton: Boolean = false,
eventSink: (VerifySelfSessionViewEvents) -> Unit = {}, eventSink: (VerifySelfSessionViewEvents) -> Unit = {},
) = VerifySelfSessionState( ) = VerifySelfSessionState(
verificationFlowStep = verificationFlowStep, verificationFlowStep = verificationFlowStep,
displaySkipButton = displaySkipButton, displaySkipButton = displaySkipButton,
eventSink = eventSink, eventSink = eventSink,
signOutAction = signOutAction,
) )
private fun aVerificationEmojiList() = listOf( private fun aVerificationEmojiList() = listOf(

49
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionView.kt

@ -37,6 +37,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -46,11 +47,13 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.verifysession.impl.emoji.toEmojiResource import io.element.android.features.verifysession.impl.emoji.toEmojiResource
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.components.BigIcon import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.PageTitle import io.element.android.libraries.designsystem.components.PageTitle
import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
@ -70,11 +73,13 @@ fun VerifySelfSessionView(
onEnterRecoveryKey: () -> Unit, onEnterRecoveryKey: () -> Unit,
onResetKey: () -> Unit, onResetKey: () -> Unit,
onFinish: () -> Unit, onFinish: () -> Unit,
onSuccessLogout: (String?) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
fun resetFlow() { fun resetFlow() {
state.eventSink(VerifySelfSessionViewEvents.Reset) state.eventSink(VerifySelfSessionViewEvents.Reset)
} }
val latestOnFinish by rememberUpdatedState(newValue = onFinish) val latestOnFinish by rememberUpdatedState(newValue = onFinish)
LaunchedEffect(state.verificationFlowStep, latestOnFinish) { LaunchedEffect(state.verificationFlowStep, latestOnFinish) {
if (state.verificationFlowStep is FlowStep.Skipped) { if (state.verificationFlowStep is FlowStep.Skipped) {
@ -97,17 +102,23 @@ fun VerifySelfSessionView(
HeaderFooterPage( HeaderFooterPage(
modifier = modifier, modifier = modifier,
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
actions = { actions = {
if (state.displaySkipButton && state.verificationFlowStep != FlowStep.Completed) { if (state.verificationFlowStep != FlowStep.Completed) {
TextButton( if (state.displaySkipButton && LocalInspectionMode.current.not()) {
text = stringResource(CommonStrings.action_skip), TextButton(
onClick = { state.eventSink(VerifySelfSessionViewEvents.SkipVerification) } text = stringResource(CommonStrings.action_skip),
) onClick = { state.eventSink(VerifySelfSessionViewEvents.SkipVerification) }
} )
} }
) TextButton(
text = stringResource(CommonStrings.action_signout),
onClick = { state.eventSink(VerifySelfSessionViewEvents.SignOut) }
)
}
}
)
}, },
header = { header = {
HeaderContent(verificationFlowStep = verificationFlowStep) HeaderContent(verificationFlowStep = verificationFlowStep)
@ -124,6 +135,21 @@ fun VerifySelfSessionView(
) { ) {
Content(flowState = verificationFlowStep) Content(flowState = verificationFlowStep)
} }
when (state.signOutAction) {
AsyncAction.Loading -> {
ProgressDialog(text = stringResource(id = R.string.screen_signout_in_progress_dialog_content))
}
is AsyncAction.Success -> {
val latestOnSuccessLogout by rememberUpdatedState(onSuccessLogout)
LaunchedEffect(state) {
latestOnSuccessLogout(state.signOutAction.data)
}
}
AsyncAction.Confirming,
is AsyncAction.Failure,
AsyncAction.Uninitialized -> Unit
}
} }
@Composable @Composable
@ -367,5 +393,6 @@ internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionSta
onEnterRecoveryKey = {}, onEnterRecoveryKey = {},
onResetKey = {}, onResetKey = {},
onFinish = {}, onFinish = {},
onSuccessLogout = {},
) )
} }

1
features/verifysession/impl/src/main/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewEvents.kt

@ -23,5 +23,6 @@ sealed interface VerifySelfSessionViewEvents {
data object DeclineVerification : VerifySelfSessionViewEvents data object DeclineVerification : VerifySelfSessionViewEvents
data object Cancel : VerifySelfSessionViewEvents data object Cancel : VerifySelfSessionViewEvents
data object Reset : VerifySelfSessionViewEvents data object Reset : VerifySelfSessionViewEvents
data object SignOut : VerifySelfSessionViewEvents
data object SkipVerification : VerifySelfSessionViewEvents data object SkipVerification : VerifySelfSessionViewEvents
} }

1
features/verifysession/impl/src/main/res/values/localazy.xml

@ -28,4 +28,5 @@
<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_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>
</resources> </resources>

31
features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionPresenterTest.kt

@ -21,6 +21,8 @@ import app.cash.molecule.moleculeFlow
import app.cash.turbine.ReceiveTurbine import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test 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.test.FakeLogoutUseCase
import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep import io.element.android.features.verifysession.impl.VerifySelfSessionState.VerificationStep
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
@ -36,6 +38,8 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
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
@ -309,6 +313,31 @@ class VerifySelfSessionPresenterTest {
} }
} }
@Test
fun `present - When user request to sign out, the sign out use case is invoked`() = runTest {
val service = FakeSessionVerificationService().apply {
givenNeedsSessionVerification(false)
givenVerifiedStatus(SessionVerifiedStatus.Verified)
givenVerificationFlowState(VerificationFlowState.Finished)
}
val signOutLambda = lambdaRecorder<Boolean, String?> { "aUrl" }
val presenter = createVerifySelfSessionPresenter(
service,
logoutUseCase = FakeLogoutUseCase(signOutLambda)
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
skipItems(1)
val initialItem = awaitItem()
initialItem.eventSink(VerifySelfSessionViewEvents.SignOut)
val finalItem = awaitItem()
assertThat(finalItem.signOutAction.isSuccess()).isTrue()
assertThat(finalItem.signOutAction.dataOrNull()).isEqualTo("aUrl")
signOutLambda.assertions().isCalledOnce().with(value(true))
}
}
private suspend fun ReceiveTurbine<VerifySelfSessionState>.requestVerificationAndAwaitVerifyingState( private suspend fun ReceiveTurbine<VerifySelfSessionState>.requestVerificationAndAwaitVerifyingState(
fakeService: FakeSessionVerificationService, fakeService: FakeSessionVerificationService,
sessionVerificationData: SessionVerificationData = SessionVerificationData.Emojis(emptyList()), sessionVerificationData: SessionVerificationData = SessionVerificationData.Emojis(emptyList()),
@ -344,6 +373,7 @@ class VerifySelfSessionPresenterTest {
encryptionService: EncryptionService = FakeEncryptionService(), encryptionService: EncryptionService = FakeEncryptionService(),
buildMeta: BuildMeta = aBuildMeta(), buildMeta: BuildMeta = aBuildMeta(),
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(), sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
logoutUseCase: LogoutUseCase = FakeLogoutUseCase(),
): VerifySelfSessionPresenter { ): VerifySelfSessionPresenter {
return VerifySelfSessionPresenter( return VerifySelfSessionPresenter(
sessionVerificationService = service, sessionVerificationService = service,
@ -351,6 +381,7 @@ class VerifySelfSessionPresenterTest {
stateMachine = VerifySelfSessionStateMachine(service, encryptionService), stateMachine = VerifySelfSessionStateMachine(service, encryptionService),
buildMeta = buildMeta, buildMeta = buildMeta,
sessionPreferencesStore = sessionPreferencesStore, sessionPreferencesStore = sessionPreferencesStore,
logoutUseCase = logoutUseCase,
) )
} }
} }

18
features/verifysession/impl/src/test/kotlin/io/element/android/features/verifysession/impl/VerifySelfSessionViewTest.kt

@ -20,6 +20,7 @@ import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EnsureNeverCalled
@ -27,6 +28,7 @@ import io.element.android.tests.testutils.EnsureNeverCalledWithParam
import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.EventsRecorder
import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.ensureCalledOnce import io.element.android.tests.testutils.ensureCalledOnce
import io.element.android.tests.testutils.ensureCalledOnceWithParam
import io.element.android.tests.testutils.pressBackKey import io.element.android.tests.testutils.pressBackKey
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -213,11 +215,26 @@ class VerifySelfSessionViewTest {
} }
} }
@Test
fun `on success logout - onFinished callback is called immediately`() {
val aUrl = "aUrl"
ensureCalledOnceWithParam<String?>(aUrl) { callback ->
rule.setVerifySelfSessionView(
aVerifySelfSessionState(
signOutAction = AsyncAction.Success(aUrl),
eventSink = EnsureNeverCalledWithParam(),
),
onSuccessLogout = callback,
)
}
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setVerifySelfSessionView( private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setVerifySelfSessionView(
state: VerifySelfSessionState, state: VerifySelfSessionState,
onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(), onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(),
onFinished: () -> Unit = EnsureNeverCalled(), onFinished: () -> Unit = EnsureNeverCalled(),
onResetKey: () -> Unit = EnsureNeverCalled(), onResetKey: () -> Unit = EnsureNeverCalled(),
onSuccessLogout: (String?) -> Unit = EnsureNeverCalledWithParam(),
) { ) {
setContent { setContent {
VerifySelfSessionView( VerifySelfSessionView(
@ -225,6 +242,7 @@ class VerifySelfSessionViewTest {
onEnterRecoveryKey = onEnterRecoveryKey, onEnterRecoveryKey = onEnterRecoveryKey,
onFinish = onFinished, onFinish = onFinished,
onResetKey = onResetKey, onResetKey = onResetKey,
onSuccessLogout = onSuccessLogout,
) )
} }
} }

1
tools/localazy/config.json

@ -55,6 +55,7 @@
"name" : ":features:verifysession:impl", "name" : ":features:verifysession:impl",
"includeRegex" : [ "includeRegex" : [
"screen_session_verification_.*", "screen_session_verification_.*",
"screen_signout_in_progress_dialog_content",
"screen_identity_.*" "screen_identity_.*"
] ]
}, },

Loading…
Cancel
Save