diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/EventMoveHost.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/EventMoveHost.kt index 97347c9..98de947 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/EventMoveHost.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/EventMoveHost.kt @@ -32,6 +32,9 @@ import java.util.Locale /** How long the confirmation chip stays up, matching a short snackbar. */ private const val CHIP_MILLIS = 4_000L +/** What the chip currently reads, kept past the outcome it was built from. */ +private data class ChipContent(val message: String, val undo: MoveUndo?) + /** The FAB's own band at the bottom end, which the chip must not run into. */ private val FAB_BAND = 88.dp @@ -75,13 +78,16 @@ fun EventMoveHost(viewModel: RescheduleViewModel, modifier: Modifier = Modifier) } // Held past the outcome being consumed so the chip has something to draw - // while it slides back out. - var shownMessage by remember { mutableStateOf("") } - var shownUndo by remember { mutableStateOf(null) } + // while it springs back out. Updated *in composition* rather than from an + // effect: an effect lands a frame late, so the chip would open carrying the + // previous message and grow into this one while it was still animating in. + val shown = remember { mutableStateOf(ChipContent("", null)) } + if (message != null && (shown.value.message != message || shown.value.undo != moved?.undo)) { + shown.value = ChipContent(message, moved?.undo) + } + val content = shown.value LaunchedEffect(outcome) { - val text = message ?: return@LaunchedEffect - shownMessage = text - shownUndo = moved?.undo + if (outcome == null) return@LaunchedEffect delay(CHIP_MILLIS) viewModel.consumeOutcome() } @@ -101,11 +107,11 @@ fun EventMoveHost(viewModel: RescheduleViewModel, modifier: Modifier = Modifier) ) { SnackChip( visible = outcome != null, - message = shownMessage, + message = content.message, maxWidth = chipMaxWidth, actionLabel = stringResource(R.string.event_move_undo) - .takeIf { shownUndo != null }, - onAction = shownUndo?.let { undo -> { viewModel.undo(undo) } }, + .takeIf { content.undo != null }, + onAction = content.undo?.let { undo -> { viewModel.undo(undo) } }, ) } } diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/RescheduleViewModel.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/RescheduleViewModel.kt index ba5868d..95af55b 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/RescheduleViewModel.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/RescheduleViewModel.kt @@ -226,11 +226,15 @@ class RescheduleViewModel @Inject constructor( _scopePrompt.value = null } - /** Put a completed move back where it came from. */ + /** + * Put a completed move back where it came from. The outcome deliberately + * stands until the inverse write reports back: clearing it first would drop + * the confirmation chip and open a second one a moment later, rather than + * letting the one chip change what it says. + */ fun undo(undo: MoveUndo) { if (busy) return busy = true - _outcome.value = null viewModelScope.launch { _outcome.value = try { repository.updateEvent(undo.eventId, undo.moved, undo.restored) diff --git a/floret-kit b/floret-kit index fd86bc4..71a4f37 160000 --- a/floret-kit +++ b/floret-kit @@ -1 +1 @@ -Subproject commit fd86bc4a24675f4fc807d411db6991f2b3ecb7a3 +Subproject commit 71a4f371b6dba4f32fc68bac254226c45696c283