feat(android): typed-confirm on AdminUsers delete (audit v3 §4.20)
Delete-user was a plain Delete/Cancel AlertDialog — too permissive for an irreversible action. Now mirrors Flutter's TypedConfirmSheet: an OutlinedTextField where the admin must type "DELETE" before the Delete button enables (case-insensitive). The button stays disabled and muted until the word matches. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -512,18 +512,41 @@ private fun DeleteConfirmDialog(
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
) {
|
||||
var typed by remember { mutableStateOf("") }
|
||||
val confirmed = typed.trim().equals(DELETE_CONFIRM_WORD, ignoreCase = true)
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text("Delete user?") },
|
||||
text = {
|
||||
Text("Delete @${user.username}? This removes the account and all their data.")
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Text(
|
||||
"Delete @${user.username}? This removes the account and all " +
|
||||
"their data. Type $DELETE_CONFIRM_WORD to confirm.",
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = typed,
|
||||
onValueChange = { typed = it },
|
||||
label = { Text("Type $DELETE_CONFIRM_WORD") },
|
||||
singleLine = true,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onConfirm) {
|
||||
Text("Delete", color = MaterialTheme.colorScheme.error)
|
||||
TextButton(onClick = onConfirm, enabled = confirmed) {
|
||||
Text(
|
||||
"Delete",
|
||||
color = if (confirmed) {
|
||||
MaterialTheme.colorScheme.error
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel") } },
|
||||
)
|
||||
}
|
||||
|
||||
private const val DELETE_CONFIRM_WORD = "DELETE"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user