Spring the confirmation chip, and build it a frame earlier (#68)
The chip springs open from its corner on the expressive fast specs instead of sliding in clipped, and its text is resolved in composition rather than from an effect — a frame late meant it opened carrying the previous message and grew into the new one mid-animation. Undo now leaves the outcome standing until its write reports back, so the one chip changes what it says instead of closing and reopening.
This commit is contained in:
@@ -32,6 +32,9 @@ import java.util.Locale
|
|||||||
/** How long the confirmation chip stays up, matching a short snackbar. */
|
/** How long the confirmation chip stays up, matching a short snackbar. */
|
||||||
private const val CHIP_MILLIS = 4_000L
|
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. */
|
/** The FAB's own band at the bottom end, which the chip must not run into. */
|
||||||
private val FAB_BAND = 88.dp
|
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
|
// Held past the outcome being consumed so the chip has something to draw
|
||||||
// while it slides back out.
|
// while it springs back out. Updated *in composition* rather than from an
|
||||||
var shownMessage by remember { mutableStateOf("") }
|
// effect: an effect lands a frame late, so the chip would open carrying the
|
||||||
var shownUndo by remember { mutableStateOf<MoveUndo?>(null) }
|
// 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) {
|
LaunchedEffect(outcome) {
|
||||||
val text = message ?: return@LaunchedEffect
|
if (outcome == null) return@LaunchedEffect
|
||||||
shownMessage = text
|
|
||||||
shownUndo = moved?.undo
|
|
||||||
delay(CHIP_MILLIS)
|
delay(CHIP_MILLIS)
|
||||||
viewModel.consumeOutcome()
|
viewModel.consumeOutcome()
|
||||||
}
|
}
|
||||||
@@ -101,11 +107,11 @@ fun EventMoveHost(viewModel: RescheduleViewModel, modifier: Modifier = Modifier)
|
|||||||
) {
|
) {
|
||||||
SnackChip(
|
SnackChip(
|
||||||
visible = outcome != null,
|
visible = outcome != null,
|
||||||
message = shownMessage,
|
message = content.message,
|
||||||
maxWidth = chipMaxWidth,
|
maxWidth = chipMaxWidth,
|
||||||
actionLabel = stringResource(R.string.event_move_undo)
|
actionLabel = stringResource(R.string.event_move_undo)
|
||||||
.takeIf { shownUndo != null },
|
.takeIf { content.undo != null },
|
||||||
onAction = shownUndo?.let { undo -> { viewModel.undo(undo) } },
|
onAction = content.undo?.let { undo -> { viewModel.undo(undo) } },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,11 +226,15 @@ class RescheduleViewModel @Inject constructor(
|
|||||||
_scopePrompt.value = null
|
_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) {
|
fun undo(undo: MoveUndo) {
|
||||||
if (busy) return
|
if (busy) return
|
||||||
busy = true
|
busy = true
|
||||||
_outcome.value = null
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_outcome.value = try {
|
_outcome.value = try {
|
||||||
repository.updateEvent(undo.eventId, undo.moved, undo.restored)
|
repository.updateEvent(undo.eventId, undo.moved, undo.restored)
|
||||||
|
|||||||
Submodule floret-kit updated: fd86bc4a24...71a4f371b6
Reference in New Issue
Block a user