I have a list of items, each item has a "Delete" button. Pressing the button should show a dialog asking the user to confirm the deletion, and include the name of the item being deleted.
Currently, I have this, which works:
In the viewmodel
// The dialog's state. Either hidden or visible. If visible it needs to display
// text specific to the item associated with the button the user pressed.
sealed interface ConfirmDeleteItemDialogState {
data object Hidden : ConfirmDeleteItemDialogState
data class Visible(val item: Item): ConfirmDeleteItemDialogState
}
// ...
class MyViewModel(/* ... */) : ViewModel() {
// ...
val confirmDeleteItemDialogState: StateFlow<ConfirmDeleteItemDialogState>
field = MutableStateFlow<ConfirmDeleteItemDialogState(ConfirmDeleteItemDialogState.Hidden)
// ...
// Called when the user clicks the button in a list entry to delete an item.
fun showConfirmDeleteItemDialog(item: item) {
confirmDeleteItemDialogState.update {
ConfirmDeleteItemDialogState.Visible(item)
}
}
fun hideConfirmDeleteItemDialog() {
confirmDeleteItemDialogState.update {
ConfirmDeleteItemDialogState.Hidden
}
}
// Called when the user clicks the "OK" button in the confirmation dialog.
fun deleteItem(item: Item) {
hideConfirmDeleteDialog()
// ... code that does the deletion here
}
// ...
}The Screen Composable
@Composable
fun ItemListScreen(
viewModel: MyViewModel
) {
// ...
val confirmDeleteItemDialogState by viewModel.confirmDeleteItemDialogState
.collectAsStateWithLifecycle(ConfirmDeleteItemDialogState.Hidden)
// ...
AppTheme {
// ...
// Show the "Delete item X?" dialog. The dialog's title needs to include the
// value of the `name` property from the given `item`.
if (confirmDeleteItemDialogState is ConfirmDeleteItemDialogState.Visible) {
val item = confirmDeleteItemDialogState.item
MyAlertDialog(
onDismissRequest = { viewModel.hideConfirmDeleteItemDialog() },
onConfirmation = { viewModel.deleteItem(item) },
dialogTitle = stringResource(R.id.confirm_delete_item, item.name)
// ...
)
)
}
}The dialog
Note how the state parameter is assigned a constant and never changed, because the presence of the dialog is determined by the if statement in ItemListScreen.
@Composable
private fun MyAlertDialog(
onDismissRequest: () -> Unit,
onConfirmation: () -> Unit,
dialogTitle: String,
dialogText: String,
) {
UnstyledScrim()
UnstyledDialog(
state = rememberDialogState(initiallyVisible = true),
onDismiss = onDismissRequest,
) {
// ...
}
}
Alternate.
The Screen Composable
The dialog