Merge pull request #5845 from element-hq/feature/bma/unsavedChangeDialog
Update unsaved change dialog
This commit is contained in:
commit
b20ccf8b63
59 changed files with 537 additions and 468 deletions
|
|
@ -73,8 +73,7 @@ class ChangeRoomPermissionsPresenter(
|
|||
|
||||
private var initialPermissions by mutableStateOf<RoomPowerLevelsValues?>(null)
|
||||
private var currentPermissions by mutableStateOf<RoomPowerLevelsValues?>(null)
|
||||
private var saveAction by mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
private var confirmExitAction by mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized)
|
||||
private var saveAction by mutableStateOf<AsyncAction<Boolean>>(AsyncAction.Uninitialized)
|
||||
|
||||
@Composable
|
||||
override fun present(): ChangeRoomPermissionsState {
|
||||
|
|
@ -109,15 +108,14 @@ class ChangeRoomPermissionsPresenter(
|
|||
}
|
||||
is ChangeRoomPermissionsEvent.Save -> coroutineScope.save()
|
||||
is ChangeRoomPermissionsEvent.Exit -> {
|
||||
confirmExitAction = if (!hasChanges || confirmExitAction.isConfirming()) {
|
||||
AsyncAction.Success(Unit)
|
||||
saveAction = if (!hasChanges || saveAction == AsyncAction.ConfirmingCancellation) {
|
||||
AsyncAction.Success(false)
|
||||
} else {
|
||||
AsyncAction.ConfirmingNoParams
|
||||
AsyncAction.ConfirmingCancellation
|
||||
}
|
||||
}
|
||||
is ChangeRoomPermissionsEvent.ResetPendingActions -> {
|
||||
saveAction = AsyncAction.Uninitialized
|
||||
confirmExitAction = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +124,6 @@ class ChangeRoomPermissionsPresenter(
|
|||
itemsBySection = itemsBySection,
|
||||
hasChanges = hasChanges,
|
||||
saveAction = saveAction,
|
||||
confirmExitAction = confirmExitAction,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
|
@ -147,7 +144,7 @@ class ChangeRoomPermissionsPresenter(
|
|||
.onSuccess {
|
||||
analyticsService.trackPermissionChangeAnalytics(initialPermissions, updatedRoomPowerLevels)
|
||||
initialPermissions = currentPermissions
|
||||
saveAction = AsyncAction.Success(Unit)
|
||||
saveAction = AsyncAction.Success(true)
|
||||
}
|
||||
.onFailure {
|
||||
saveAction = AsyncAction.Failure(it)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ data class ChangeRoomPermissionsState(
|
|||
val currentPermissions: RoomPowerLevelsValues?,
|
||||
val itemsBySection: ImmutableMap<RoomPermissionsSection, ImmutableList<RoomPermissionType>>,
|
||||
val hasChanges: Boolean,
|
||||
val saveAction: AsyncAction<Unit>,
|
||||
val confirmExitAction: AsyncAction<Unit>,
|
||||
val saveAction: AsyncAction<Boolean>,
|
||||
val eventSink: (ChangeRoomPermissionsEvent) -> Unit,
|
||||
) {
|
||||
fun selectedRoleForType(type: RoomPermissionType): SelectableRole? {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ChangeRoomPermissionsStateProvider : PreviewParameterProvider<ChangeRoomPe
|
|||
hasChanges = true,
|
||||
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(),
|
||||
itemsBySection: Map<RoomPermissionsSection, ImmutableList<RoomPermissionType>> = ChangeRoomPermissionsPresenter.buildItems(false),
|
||||
hasChanges: Boolean = false,
|
||||
saveAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
confirmExitAction: AsyncAction<Unit> = AsyncAction.Uninitialized,
|
||||
saveAction: AsyncAction<Boolean> = AsyncAction.Uninitialized,
|
||||
eventSink: (ChangeRoomPermissionsEvent) -> Unit = {},
|
||||
) = ChangeRoomPermissionsState(
|
||||
currentPermissions = currentPermissions,
|
||||
itemsBySection = itemsBySection.toImmutableMap(),
|
||||
hasChanges = hasChanges,
|
||||
saveAction = saveAction,
|
||||
confirmExitAction = confirmExitAction,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
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.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.SaveChangesDialog
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceDropdown
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
|
@ -91,24 +92,19 @@ fun ChangeRoomPermissionsView(
|
|||
|
||||
AsyncActionView(
|
||||
async = state.saveAction,
|
||||
onSuccess = { onComplete(true) },
|
||||
onErrorDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) }
|
||||
)
|
||||
|
||||
AsyncActionView(
|
||||
async = state.confirmExitAction,
|
||||
onSuccess = { onComplete(false) },
|
||||
confirmationDialog = {
|
||||
ConfirmationDialog(
|
||||
title = stringResource(R.string.screen_room_change_role_unsaved_changes_title),
|
||||
content = stringResource(R.string.screen_room_change_role_unsaved_changes_description),
|
||||
submitText = stringResource(CommonStrings.action_save),
|
||||
cancelText = stringResource(CommonStrings.action_discard),
|
||||
onSubmitClick = { state.eventSink(ChangeRoomPermissionsEvent.Save) },
|
||||
onDismiss = { state.eventSink(ChangeRoomPermissionsEvent.Exit) }
|
||||
)
|
||||
onSuccess = { onComplete(it) },
|
||||
confirmationDialog = { confirming ->
|
||||
when (confirming) {
|
||||
is AsyncAction.ConfirmingCancellation -> {
|
||||
SaveChangesDialog(
|
||||
onSaveClick = { state.eventSink(ChangeRoomPermissionsEvent.Save) },
|
||||
onDiscardClick = { state.eventSink(ChangeRoomPermissionsEvent.Exit) },
|
||||
onDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) },
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onErrorDismiss = {},
|
||||
onErrorDismiss = { state.eventSink(ChangeRoomPermissionsEvent.ResetPendingActions) }
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,8 +172,9 @@ fun ChangeRolesView(
|
|||
when (confirming) {
|
||||
is AsyncAction.ConfirmingCancellation -> {
|
||||
SaveChangesDialog(
|
||||
onSubmitClick = { state.eventSink(ChangeRolesEvent.Exit) },
|
||||
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) }
|
||||
onSaveClick = { state.eventSink(ChangeRolesEvent.Save) },
|
||||
onDiscardClick = { state.eventSink(ChangeRolesEvent.Exit) },
|
||||
onDismiss = { state.eventSink(ChangeRolesEvent.CloseDialog) },
|
||||
)
|
||||
}
|
||||
is ConfirmingModifyingOwners -> {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ class ChangeRoomPermissionsPresenterTest {
|
|||
assertThat(this.itemsBySection).isNotEmpty()
|
||||
assertThat(this.hasChanges).isFalse()
|
||||
assertThat(this.saveAction).isEqualTo(AsyncAction.Uninitialized)
|
||||
assertThat(this.confirmExitAction).isEqualTo(AsyncAction.Uninitialized)
|
||||
}
|
||||
|
||||
// Updated state, permissions loaded
|
||||
|
|
@ -162,7 +161,7 @@ class ChangeRoomPermissionsPresenterTest {
|
|||
assertThat(awaitItem().hasChanges).isFalse()
|
||||
awaitItem().run {
|
||||
assertThat(currentPermissions?.roomName).isEqualTo(Moderator.powerLevel)
|
||||
assertThat(saveAction).isEqualTo(AsyncAction.Success(Unit))
|
||||
assertThat(saveAction).isEqualTo(AsyncAction.Success(true))
|
||||
}
|
||||
assertThat(analyticsService.capturedEvents).containsExactlyElementsIn(
|
||||
listOf(
|
||||
|
|
@ -243,10 +242,10 @@ class ChangeRoomPermissionsPresenterTest {
|
|||
assertThat(awaitItem().hasChanges).isTrue()
|
||||
|
||||
state.eventSink(ChangeRoomPermissionsEvent.Exit)
|
||||
assertThat(awaitItem().confirmExitAction).isEqualTo(AsyncAction.ConfirmingNoParams)
|
||||
assertThat(awaitItem().saveAction).isEqualTo(AsyncAction.ConfirmingCancellation)
|
||||
|
||||
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)
|
||||
|
||||
assertThat(awaitItem().confirmExitAction).isEqualTo(AsyncAction.Success(Unit))
|
||||
assertThat(awaitItem().saveAction).isEqualTo(AsyncAction.Success(false))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.clickOnFirst
|
||||
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
||||
import io.element.android.tests.testutils.pressBack
|
||||
import io.element.android.tests.testutils.pressBackKey
|
||||
|
|
@ -76,7 +75,7 @@ class ChangeRoomPermissionsViewTest {
|
|||
rule.setChangeRoomPermissionsRule(
|
||||
state = aChangeRoomPermissionsState(
|
||||
hasChanges = true,
|
||||
confirmExitAction = AsyncAction.ConfirmingNoParams,
|
||||
saveAction = AsyncAction.ConfirmingCancellation,
|
||||
eventSink = recorder,
|
||||
),
|
||||
)
|
||||
|
|
@ -90,11 +89,11 @@ class ChangeRoomPermissionsViewTest {
|
|||
rule.setChangeRoomPermissionsRule(
|
||||
state = aChangeRoomPermissionsState(
|
||||
hasChanges = true,
|
||||
confirmExitAction = AsyncAction.ConfirmingNoParams,
|
||||
saveAction = AsyncAction.ConfirmingCancellation,
|
||||
eventSink = recorder,
|
||||
),
|
||||
)
|
||||
rule.clickOnFirst(CommonStrings.action_save)
|
||||
rule.clickOn(CommonStrings.action_save, inDialog = true)
|
||||
recorder.assertSingle(ChangeRoomPermissionsEvent.Save)
|
||||
}
|
||||
|
||||
|
|
@ -136,9 +135,23 @@ class ChangeRoomPermissionsViewTest {
|
|||
rule.setChangeRoomPermissionsRule(
|
||||
state = aChangeRoomPermissionsState(
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class ChangeRolesViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `exit confirmation dialog - submit exits the screen`() {
|
||||
fun `exit confirmation dialog - discard exits the screen`() {
|
||||
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
||||
rule.setChangeRolesContent(
|
||||
state = aChangeRolesState(
|
||||
|
|
@ -128,12 +128,12 @@ class ChangeRolesViewTest {
|
|||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_ok)
|
||||
rule.clickOn(CommonStrings.action_discard)
|
||||
eventsRecorder.assertSingle(ChangeRolesEvent.Exit)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exit confirmation dialog - cancel removes the dialog`() {
|
||||
fun `exit confirmation dialog - save emits the save event`() {
|
||||
val eventsRecorder = EventsRecorder<ChangeRolesEvent>()
|
||||
rule.setChangeRolesContent(
|
||||
state = aChangeRolesState(
|
||||
|
|
@ -142,8 +142,8 @@ class ChangeRolesViewTest {
|
|||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_cancel)
|
||||
eventsRecorder.assertSingle(ChangeRolesEvent.CloseDialog)
|
||||
rule.clickOn(CommonStrings.action_save)
|
||||
eventsRecorder.assertSingle(ChangeRolesEvent.Save)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue