feat: Add cancel button to swipe-to-delete confirmation

After swiping a draft to delete, the red confirmation background now
shows both a "Delete" button (left) and a "Cancel" button (right).
Tapping Cancel resets the swipe state, allowing users to dismiss
the delete action without deleting the draft.

https://claude.ai/code/session_01ULVR1fKwka5TgfgSucPE4r
This commit is contained in:
Claude
2026-03-13 23:19:47 +00:00
parent 64118058f2
commit bcb5be76c7
@@ -27,9 +27,11 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -110,10 +112,16 @@ fun SwipeToDeleteWithConfirmation(
state = dismissState, state = dismissState,
modifier = modifier, modifier = modifier,
backgroundContent = { backgroundContent = {
ConfirmDeleteBackground(dismissState) { ConfirmDeleteBackground(
onDelete() dismissState = dismissState,
scope.launch { dismissState.reset() } onConfirmDelete = {
} onDelete()
scope.launch { dismissState.reset() }
},
onCancel = {
scope.launch { dismissState.reset() }
},
)
}, },
enableDismissFromEndToStart = true, enableDismissFromEndToStart = true,
content = content, content = content,
@@ -165,6 +173,7 @@ fun DismissBackground(dismissState: SwipeToDismissBoxState) {
fun ConfirmDeleteBackground( fun ConfirmDeleteBackground(
dismissState: SwipeToDismissBoxState, dismissState: SwipeToDismissBoxState,
onConfirmDelete: () -> Unit, onConfirmDelete: () -> Unit,
onCancel: () -> Unit,
) { ) {
val settled = dismissState.currentValue == Settled && dismissState.targetValue == Settled val settled = dismissState.currentValue == Settled && dismissState.targetValue == Settled
@@ -189,23 +198,51 @@ fun ConfirmDeleteBackground(
Modifier Modifier
.fillMaxSize() .fillMaxSize()
.background(color) .background(color)
.clickable(enabled = !settled) { onConfirmDelete() }
.padding(20.dp, 8.dp), .padding(20.dp, 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
) { ) {
Icon( Row(
Icons.Default.Delete, modifier =
contentDescription = stringRes(id = R.string.request_deletion), Modifier
) .weight(1f)
Text( .fillMaxHeight()
text = stringRes(id = R.string.request_deletion), .clickable(enabled = !settled) { onConfirmDelete() },
color = Color.White, verticalAlignment = Alignment.CenterVertically,
style = MaterialTheme.typography.titleMedium, horizontalArrangement = Arrangement.Center,
) ) {
Icon( Icon(
Icons.Default.Delete, Icons.Default.Delete,
contentDescription = stringRes(id = R.string.request_deletion), contentDescription = stringRes(id = R.string.request_deletion),
) tint = Color.White,
)
Spacer(modifier = Modifier.padding(horizontal = 4.dp))
Text(
text = stringRes(id = R.string.request_deletion),
color = Color.White,
style = MaterialTheme.typography.titleMedium,
)
}
Row(
modifier =
Modifier
.weight(1f)
.fillMaxHeight()
.clickable(enabled = !settled) { onCancel() },
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Icon(
Icons.Default.Close,
contentDescription = stringRes(id = R.string.cancel),
tint = Color.White,
)
Spacer(modifier = Modifier.padding(horizontal = 4.dp))
Text(
text = stringRes(id = R.string.cancel),
color = Color.White,
style = MaterialTheme.typography.titleMedium,
)
}
} }
} }