Remove confirmExitAction and use AsyncAction.ConfirmingCancellation instead.

This commit is contained in:
Benoit Marty 2025-12-03 14:46:58 +01:00 committed by Benoit Marty
parent eeef1b11ea
commit 278231f3d2
6 changed files with 43 additions and 37 deletions

View file

@ -73,8 +73,7 @@ class ChangeRoomPermissionsPresenter(
private var initialPermissions by mutableStateOf<RoomPowerLevelsValues?>(null) private var initialPermissions by mutableStateOf<RoomPowerLevelsValues?>(null)
private var currentPermissions by mutableStateOf<RoomPowerLevelsValues?>(null) private var currentPermissions by mutableStateOf<RoomPowerLevelsValues?>(null)
private var saveAction by mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) private var saveAction by mutableStateOf<AsyncAction<Boolean>>(AsyncAction.Uninitialized)
private var confirmExitAction by mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
@Composable @Composable
override fun present(): ChangeRoomPermissionsState { override fun present(): ChangeRoomPermissionsState {
@ -109,15 +108,14 @@ class ChangeRoomPermissionsPresenter(
} }
is ChangeRoomPermissionsEvent.Save -> coroutineScope.save() is ChangeRoomPermissionsEvent.Save -> coroutineScope.save()
is ChangeRoomPermissionsEvent.Exit -> { is ChangeRoomPermissionsEvent.Exit -> {
confirmExitAction = if (!hasChanges || confirmExitAction.isConfirming()) { saveAction = if (!hasChanges || saveAction == AsyncAction.ConfirmingCancellation) {
AsyncAction.Success(Unit) AsyncAction.Success(false)
} else { } else {
AsyncAction.ConfirmingNoParams AsyncAction.ConfirmingCancellation
} }
} }
is ChangeRoomPermissionsEvent.ResetPendingActions -> { is ChangeRoomPermissionsEvent.ResetPendingActions -> {
saveAction = AsyncAction.Uninitialized saveAction = AsyncAction.Uninitialized
confirmExitAction = AsyncAction.Uninitialized
} }
} }
} }
@ -126,7 +124,6 @@ class ChangeRoomPermissionsPresenter(
itemsBySection = itemsBySection, itemsBySection = itemsBySection,
hasChanges = hasChanges, hasChanges = hasChanges,
saveAction = saveAction, saveAction = saveAction,
confirmExitAction = confirmExitAction,
eventSink = ::handleEvent, eventSink = ::handleEvent,
) )
} }
@ -147,7 +144,7 @@ class ChangeRoomPermissionsPresenter(
.onSuccess { .onSuccess {
analyticsService.trackPermissionChangeAnalytics(initialPermissions, updatedRoomPowerLevels) analyticsService.trackPermissionChangeAnalytics(initialPermissions, updatedRoomPowerLevels)
initialPermissions = currentPermissions initialPermissions = currentPermissions
saveAction = AsyncAction.Success(Unit) saveAction = AsyncAction.Success(true)
} }
.onFailure { .onFailure {
saveAction = AsyncAction.Failure(it) saveAction = AsyncAction.Failure(it)

View file

@ -23,8 +23,7 @@ data class ChangeRoomPermissionsState(
val currentPermissions: RoomPowerLevelsValues?, val currentPermissions: RoomPowerLevelsValues?,
val itemsBySection: ImmutableMap<RoomPermissionsSection, ImmutableList<RoomPermissionType>>, val itemsBySection: ImmutableMap<RoomPermissionsSection, ImmutableList<RoomPermissionType>>,
val hasChanges: Boolean, val hasChanges: Boolean,
val saveAction: AsyncAction<Unit>, val saveAction: AsyncAction<Boolean>,
val confirmExitAction: AsyncAction<Unit>,
val eventSink: (ChangeRoomPermissionsEvent) -> Unit, val eventSink: (ChangeRoomPermissionsEvent) -> Unit,
) { ) {
fun selectedRoleForType(type: RoomPermissionType): SelectableRole? { fun selectedRoleForType(type: RoomPermissionType): SelectableRole? {

View file

@ -25,7 +25,7 @@ class ChangeRoomPermissionsStateProvider : PreviewParameterProvider<ChangeRoomPe
hasChanges = true, hasChanges = true,
saveAction = AsyncAction.Failure(IllegalStateException("Failed to save changes")) saveAction = AsyncAction.Failure(IllegalStateException("Failed to save changes"))
), ),
aChangeRoomPermissionsState(hasChanges = true, confirmExitAction = AsyncAction.ConfirmingNoParams), aChangeRoomPermissionsState(hasChanges = true, saveAction = AsyncAction.ConfirmingCancellation),
) )
} }
@ -33,15 +33,13 @@ internal fun aChangeRoomPermissionsState(
currentPermissions: RoomPowerLevelsValues = previewPermissions(), currentPermissions: RoomPowerLevelsValues = previewPermissions(),
itemsBySection: Map<RoomPermissionsSection, ImmutableList<RoomPermissionType>> = ChangeRoomPermissionsPresenter.buildItems(false), itemsBySection: Map<RoomPermissionsSection, ImmutableList<RoomPermissionType>> = ChangeRoomPermissionsPresenter.buildItems(false),
hasChanges: Boolean = false, hasChanges: Boolean = false,
saveAction: AsyncAction<Unit> = AsyncAction.Uninitialized, saveAction: AsyncAction<Boolean> = AsyncAction.Uninitialized,
confirmExitAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
eventSink: (ChangeRoomPermissionsEvent) -> Unit = {}, eventSink: (ChangeRoomPermissionsEvent) -> Unit = {},
) = ChangeRoomPermissionsState( ) = ChangeRoomPermissionsState(
currentPermissions = currentPermissions, currentPermissions = currentPermissions,
itemsBySection = itemsBySection.toImmutableMap(), itemsBySection = itemsBySection.toImmutableMap(),
hasChanges = hasChanges, hasChanges = hasChanges,
saveAction = saveAction, saveAction = saveAction,
confirmExitAction = confirmExitAction,
eventSink = eventSink, eventSink = eventSink,
) )

View file

@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.rolesandpermissions.impl.R import io.element.android.features.rolesandpermissions.impl.R
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.designsystem.components.async.AsyncActionView import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.SaveChangesDialog import io.element.android.libraries.designsystem.components.dialogs.SaveChangesDialog
@ -91,21 +92,19 @@ fun ChangeRoomPermissionsView(
AsyncActionView( AsyncActionView(
async = state.saveAction, async = state.saveAction,
onSuccess = { onComplete(true) }, onSuccess = { onComplete(it) },
onErrorDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) } confirmationDialog = { confirming ->
) when (confirming) {
is AsyncAction.ConfirmingCancellation -> {
AsyncActionView( SaveChangesDialog(
async = state.confirmExitAction, onSaveClick = { state.eventSink(ChangeRoomPermissionsEvent.Save) },
onSuccess = { onComplete(false) }, onDiscardClick = { state.eventSink(ChangeRoomPermissionsEvent.Exit) },
confirmationDialog = { onDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) },
SaveChangesDialog( )
onSaveClick = { state.eventSink(ChangeRoomPermissionsEvent.Save) }, }
onDiscardClick = { state.eventSink(ChangeRoomPermissionsEvent.Exit) }, }
onDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) },
)
}, },
onErrorDismiss = {}, onErrorDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) }
) )
} }

View file

@ -39,7 +39,6 @@ class ChangeRoomPermissionsPresenterTest {
assertThat(this.itemsBySection).isNotEmpty() assertThat(this.itemsBySection).isNotEmpty()
assertThat(this.hasChanges).isFalse() assertThat(this.hasChanges).isFalse()
assertThat(this.saveAction).isEqualTo(AsyncAction.Uninitialized) assertThat(this.saveAction).isEqualTo(AsyncAction.Uninitialized)
assertThat(this.confirmExitAction).isEqualTo(AsyncAction.Uninitialized)
} }
// Updated state, permissions loaded // Updated state, permissions loaded
@ -162,7 +161,7 @@ class ChangeRoomPermissionsPresenterTest {
assertThat(awaitItem().hasChanges).isFalse() assertThat(awaitItem().hasChanges).isFalse()
awaitItem().run { awaitItem().run {
assertThat(currentPermissions?.roomName).isEqualTo(Moderator.powerLevel) assertThat(currentPermissions?.roomName).isEqualTo(Moderator.powerLevel)
assertThat(saveAction).isEqualTo(AsyncAction.Success(Unit)) assertThat(saveAction).isEqualTo(AsyncAction.Success(true))
} }
assertThat(analyticsService.capturedEvents).containsExactlyElementsIn( assertThat(analyticsService.capturedEvents).containsExactlyElementsIn(
listOf( listOf(
@ -243,10 +242,10 @@ class ChangeRoomPermissionsPresenterTest {
assertThat(awaitItem().hasChanges).isTrue() assertThat(awaitItem().hasChanges).isTrue()
state.eventSink(ChangeRoomPermissionsEvent.Exit) state.eventSink(ChangeRoomPermissionsEvent.Exit)
assertThat(awaitItem().confirmExitAction).isEqualTo(AsyncAction.ConfirmingNoParams) assertThat(awaitItem().saveAction).isEqualTo(AsyncAction.ConfirmingCancellation)
state.eventSink(ChangeRoomPermissionsEvent.Exit) state.eventSink(ChangeRoomPermissionsEvent.Exit)
assertThat(awaitItem().confirmExitAction).isEqualTo(AsyncAction.Success(Unit)) assertThat(awaitItem().saveAction).isEqualTo(AsyncAction.Success(false))
} }
} }
@ -260,7 +259,7 @@ class ChangeRoomPermissionsPresenterTest {
state.eventSink(ChangeRoomPermissionsEvent.Exit) state.eventSink(ChangeRoomPermissionsEvent.Exit)
assertThat(awaitItem().confirmExitAction).isEqualTo(AsyncAction.Success(Unit)) assertThat(awaitItem().saveAction).isEqualTo(AsyncAction.Success(false))
} }
} }

View file

@ -76,7 +76,7 @@ class ChangeRoomPermissionsViewTest {
rule.setChangeRoomPermissionsRule( rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState( state = aChangeRoomPermissionsState(
hasChanges = true, hasChanges = true,
confirmExitAction = AsyncAction.ConfirmingNoParams, saveAction = AsyncAction.ConfirmingCancellation,
eventSink = recorder, eventSink = recorder,
), ),
) )
@ -90,7 +90,7 @@ class ChangeRoomPermissionsViewTest {
rule.setChangeRoomPermissionsRule( rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState( state = aChangeRoomPermissionsState(
hasChanges = true, hasChanges = true,
confirmExitAction = AsyncAction.ConfirmingNoParams, saveAction = AsyncAction.ConfirmingCancellation,
eventSink = recorder, eventSink = recorder,
), ),
) )
@ -136,9 +136,23 @@ class ChangeRoomPermissionsViewTest {
rule.setChangeRoomPermissionsRule( rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState( state = aChangeRoomPermissionsState(
hasChanges = true, hasChanges = true,
saveAction = AsyncAction.Success(Unit), saveAction = AsyncAction.Success(true),
), ),
onComplete = callback onComplete = callback,
)
rule.clickOn(CommonStrings.action_save)
}
}
@Test
fun `a cancellation exits the screen`() {
ensureCalledOnceWithParam(false) { callback ->
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
hasChanges = true,
saveAction = AsyncAction.Success(false),
),
onComplete = callback,
) )
rule.clickOn(CommonStrings.action_save) rule.clickOn(CommonStrings.action_save)
} }