AccountDeactivationEvents -> AccountDeactivationEvent

This commit is contained in:
Benoit Marty
2026-08-25 09:52:00 +02:00
parent dff9af9ce0
commit e1e2718c54
7 changed files with 47 additions and 47 deletions
@@ -8,9 +8,9 @@
package io.element.android.features.logout.impl
sealed interface AccountDeactivationEvents {
data class SetEraseData(val eraseData: Boolean) : AccountDeactivationEvents
data class SetPassword(val password: String) : AccountDeactivationEvents
data class DeactivateAccount(val isRetry: Boolean) : AccountDeactivationEvents
data object CloseDialogs : AccountDeactivationEvents
sealed interface AccountDeactivationEvent {
data class SetEraseData(val eraseData: Boolean) : AccountDeactivationEvent
data class SetPassword(val password: String) : AccountDeactivationEvent
data class DeactivateAccount(val isRetry: Boolean) : AccountDeactivationEvent
data object CloseDialogs : AccountDeactivationEvent
}
@@ -34,19 +34,19 @@ class AccountDeactivationPresenter(
val formState = remember { mutableStateOf(DeactivateFormState.Default) }
fun handleEvent(event: AccountDeactivationEvents) {
fun handleEvent(event: AccountDeactivationEvent) {
when (event) {
is AccountDeactivationEvents.SetEraseData -> {
is AccountDeactivationEvent.SetEraseData -> {
updateFormState(formState) {
copy(eraseData = event.eraseData)
}
}
is AccountDeactivationEvents.SetPassword -> {
is AccountDeactivationEvent.SetPassword -> {
updateFormState(formState) {
copy(password = event.password)
}
}
is AccountDeactivationEvents.DeactivateAccount ->
is AccountDeactivationEvent.DeactivateAccount ->
if (action.value.isConfirming() || event.isRetry) {
localCoroutineScope.deactivateAccount(
formState = formState.value,
@@ -55,7 +55,7 @@ class AccountDeactivationPresenter(
} else {
action.value = AsyncAction.ConfirmingNoParams
}
AccountDeactivationEvents.CloseDialogs -> {
AccountDeactivationEvent.CloseDialogs -> {
action.value = AsyncAction.Uninitialized
}
}
@@ -15,7 +15,7 @@ import kotlinx.parcelize.Parcelize
data class AccountDeactivationState(
val deactivateFormState: DeactivateFormState,
val accountDeactivationAction: AsyncAction<Unit>,
val eventSink: (AccountDeactivationEvents) -> Unit,
val eventSink: (AccountDeactivationEvent) -> Unit,
) {
val submitEnabled: Boolean
get() = accountDeactivationAction is AsyncAction.Uninitialized &&
@@ -45,7 +45,7 @@ internal fun aDeactivateFormState(
internal fun anAccountDeactivationState(
deactivateFormState: DeactivateFormState = aDeactivateFormState(),
accountDeactivationAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
eventSink: (AccountDeactivationEvents) -> Unit = {},
eventSink: (AccountDeactivationEvent) -> Unit = {},
) = AccountDeactivationState(
deactivateFormState = deactivateFormState,
accountDeactivationAction = accountDeactivationAction,
@@ -102,14 +102,14 @@ fun AccountDeactivationView(
Content(
state = state,
onSubmitClick = {
eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
}
)
Spacer(modifier = Modifier.height(32.dp))
Buttons(
state = state,
onSubmitClick = {
eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
}
)
}
@@ -117,13 +117,13 @@ fun AccountDeactivationView(
AccountDeactivationActionDialog(
state.accountDeactivationAction,
onConfirmClick = {
eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
},
onRetryClick = {
eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = true))
eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = true))
},
onDismissDialog = {
eventSink(AccountDeactivationEvents.CloseDialogs)
eventSink(AccountDeactivationEvent.CloseDialogs)
},
)
}
@@ -239,7 +239,7 @@ private fun Content(
headline = stringResource(R.string.screen_deactivate_account_delete_all_messages),
value = eraseData,
onChange = {
eventSink(AccountDeactivationEvents.SetEraseData(it))
eventSink(AccountDeactivationEvent.SetEraseData(it))
},
enabled = !isLoading,
)
@@ -275,7 +275,7 @@ private fun Content(
onValueChange = {
val sanitized = it.sanitize()
passwordFieldState = sanitized
eventSink(AccountDeactivationEvents.SetPassword(sanitized))
eventSink(AccountDeactivationEvent.SetPassword(sanitized))
},
placeholder = stringResource(CommonStrings.common_password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
@@ -47,11 +47,11 @@ class AccountDeactivationPresenterTest {
}.test {
val initialState = awaitItem()
assertThat(initialState.deactivateFormState).isEqualTo(DeactivateFormState.Default)
initialState.eventSink(AccountDeactivationEvents.SetEraseData(true))
initialState.eventSink(AccountDeactivationEvent.SetEraseData(true))
val updatedState = awaitItem()
assertThat(updatedState.deactivateFormState).isEqualTo(DeactivateFormState.Default.copy(eraseData = true))
assertThat(updatedState.submitEnabled).isFalse()
updatedState.eventSink(AccountDeactivationEvents.SetPassword("password"))
updatedState.eventSink(AccountDeactivationEvent.SetPassword("password"))
val updatedState2 = awaitItem()
assertThat(updatedState2.deactivateFormState).isEqualTo(DeactivateFormState(password = "password", eraseData = true))
assertThat(updatedState2.submitEnabled).isTrue()
@@ -71,12 +71,12 @@ class AccountDeactivationPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(AccountDeactivationEvents.SetPassword("password"))
initialState.eventSink(AccountDeactivationEvent.SetPassword("password"))
skipItems(1)
initialState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
initialState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState = awaitItem()
assertThat(updatedState.accountDeactivationAction).isEqualTo(AsyncAction.ConfirmingNoParams)
updatedState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
updatedState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState2 = awaitItem()
assertThat(updatedState2.accountDeactivationAction).isEqualTo(AsyncAction.Loading)
val finalState = awaitItem()
@@ -98,20 +98,20 @@ class AccountDeactivationPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(AccountDeactivationEvents.SetPassword("password"))
initialState.eventSink(AccountDeactivationEvents.SetEraseData(true))
initialState.eventSink(AccountDeactivationEvent.SetPassword("password"))
initialState.eventSink(AccountDeactivationEvent.SetEraseData(true))
skipItems(2)
initialState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
initialState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState = awaitItem()
assertThat(updatedState.accountDeactivationAction).isEqualTo(AsyncAction.ConfirmingNoParams)
updatedState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
updatedState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState2 = awaitItem()
assertThat(updatedState2.accountDeactivationAction).isEqualTo(AsyncAction.Loading)
val finalState = awaitItem()
assertThat(finalState.accountDeactivationAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION))
recorder.assertions().isCalledOnce().with(value("password"), value(true))
// Retry
finalState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = true))
finalState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = true))
val finalState2 = awaitItem()
assertThat(finalState2.accountDeactivationAction).isEqualTo(AsyncAction.Loading)
assertThat(awaitItem().accountDeactivationAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION))
@@ -131,20 +131,20 @@ class AccountDeactivationPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(AccountDeactivationEvents.SetPassword("password"))
initialState.eventSink(AccountDeactivationEvents.SetEraseData(true))
initialState.eventSink(AccountDeactivationEvent.SetPassword("password"))
initialState.eventSink(AccountDeactivationEvent.SetEraseData(true))
skipItems(2)
initialState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
initialState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState = awaitItem()
assertThat(updatedState.accountDeactivationAction).isEqualTo(AsyncAction.ConfirmingNoParams)
updatedState.eventSink(AccountDeactivationEvents.DeactivateAccount(isRetry = false))
updatedState.eventSink(AccountDeactivationEvent.DeactivateAccount(isRetry = false))
val updatedState2 = awaitItem()
assertThat(updatedState2.accountDeactivationAction).isEqualTo(AsyncAction.Loading)
val finalState = awaitItem()
assertThat(finalState.accountDeactivationAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION))
recorder.assertions().isCalledOnce().with(value("password"), value(true))
// Cancel
finalState.eventSink(AccountDeactivationEvents.CloseDialogs)
finalState.eventSink(AccountDeactivationEvent.CloseDialogs)
val finalState2 = awaitItem()
assertThat(finalState2.accountDeactivationAction).isEqualTo(AsyncAction.Uninitialized)
}
@@ -35,7 +35,7 @@ import org.robolectric.annotation.Config
class AccountDeactivationViewTest : RobolectricTest() {
@Test
fun `clicking on back invokes the expected callback`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>(expectEvents = false)
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>(expectEvents = false)
ensureCalledOnce {
setAccountDeactivationView(
state = anAccountDeactivationState(eventSink = eventsRecorder),
@@ -48,7 +48,7 @@ class AccountDeactivationViewTest : RobolectricTest() {
@Config(qualifiers = "h1024dp")
@Test
fun `clicking on Deactivate emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
deactivateFormState = aDeactivateFormState(
@@ -58,12 +58,12 @@ class AccountDeactivationViewTest : RobolectricTest() {
),
)
clickOn(CommonStrings.action_delete)
eventsRecorder.assertSingle(AccountDeactivationEvents.DeactivateAccount(false))
eventsRecorder.assertSingle(AccountDeactivationEvent.DeactivateAccount(false))
}
@Test
fun `clicking on Deactivate on the confirmation dialog emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
deactivateFormState = aDeactivateFormState(
@@ -74,12 +74,12 @@ class AccountDeactivationViewTest : RobolectricTest() {
),
)
pressTag(TestTags.dialogPositive.value)
eventsRecorder.assertSingle(AccountDeactivationEvents.DeactivateAccount(false))
eventsRecorder.assertSingle(AccountDeactivationEvent.DeactivateAccount(false))
}
@Test
fun `clicking on retry on the confirmation dialog emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
deactivateFormState = aDeactivateFormState(
@@ -90,24 +90,24 @@ class AccountDeactivationViewTest : RobolectricTest() {
),
)
clickOn(CommonStrings.action_retry)
eventsRecorder.assertSingle(AccountDeactivationEvents.DeactivateAccount(true))
eventsRecorder.assertSingle(AccountDeactivationEvent.DeactivateAccount(true))
}
@Test
fun `switching on the erase all switch emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
eventSink = eventsRecorder,
),
)
clickOn(R.string.screen_deactivate_account_delete_all_messages)
eventsRecorder.assertSingle(AccountDeactivationEvents.SetEraseData(true))
eventsRecorder.assertSingle(AccountDeactivationEvent.SetEraseData(true))
}
@Test
fun `switching off the erase all switch emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
deactivateFormState = aDeactivateFormState(
@@ -117,13 +117,13 @@ class AccountDeactivationViewTest : RobolectricTest() {
),
)
clickOn(R.string.screen_deactivate_account_delete_all_messages)
eventsRecorder.assertSingle(AccountDeactivationEvents.SetEraseData(false))
eventsRecorder.assertSingle(AccountDeactivationEvent.SetEraseData(false))
}
@Config(qualifiers = "h1024dp")
@Test
fun `typing text in the password field emits the expected Event`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AccountDeactivationEvents>()
val eventsRecorder = EventsRecorder<AccountDeactivationEvent>()
setAccountDeactivationView(
state = anAccountDeactivationState(
deactivateFormState = aDeactivateFormState(
@@ -133,7 +133,7 @@ class AccountDeactivationViewTest : RobolectricTest() {
),
)
onNodeWithTag(TestTags.loginPassword.value).performTextInput("A")
eventsRecorder.assertSingle(AccountDeactivationEvents.SetPassword("A$A_PASSWORD"))
eventsRecorder.assertSingle(AccountDeactivationEvent.SetPassword("A$A_PASSWORD"))
}
}