82 lines
2.6 KiB
QML
82 lines
2.6 KiB
QML
// The two-stage destructive confirm, as one component instead of twenty
|
|
// hand-rolled copies. The first press arms ("Verb…", normal tone -- danger
|
|
// never initiates, per SettingsButton's own contract); armed, the row shows
|
|
// Cancel ("Keep") beside the confirming press ("Verb it", danger tone).
|
|
//
|
|
// One armed confirm exists app-wide: the token lives on ShellState, so arming
|
|
// this one disarms whichever other row was armed, on any page. Consumers give
|
|
// a unique actionId, the verb pair, and handle onConfirmed; the component owns
|
|
// the state, the copy shape, and the keyboard path (via SettingsButton).
|
|
//
|
|
// ConfirmAction {
|
|
// actionId: "forget-network:" + ssid
|
|
// armText: "Forget…" // default: verb + ellipsis
|
|
// confirmText: "Forget it"
|
|
// cancelText: "Keep" // the house cancel word
|
|
// enabled: !Service.busy
|
|
// onConfirmed: Service.forget(ssid)
|
|
// }
|
|
//
|
|
// The armed state is readable (`armed`) so a row can swap its detail line for
|
|
// the consequence-naming sentence while armed -- naming what is lost is the
|
|
// caller's half of the contract; this component only guarantees the two
|
|
// presses happen and the wrong button cannot be the easy one.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
Row {
|
|
id: root
|
|
|
|
property string actionId: ""
|
|
property string armText: "Remove…"
|
|
property string confirmText: "Remove it"
|
|
property string cancelText: "Keep"
|
|
property bool enabled: true
|
|
signal confirmed
|
|
signal armedChanged2
|
|
|
|
readonly property bool armed: root.actionId !== ""
|
|
&& ShellState.armedConfirm === root.actionId
|
|
|
|
spacing: 7
|
|
|
|
function disarm(): void {
|
|
if (root.armed)
|
|
ShellState.armedConfirm = "";
|
|
}
|
|
|
|
// Leaving the page, or the row vanishing under the armed state, must not
|
|
// leave a stale token claiming some other future row's identity. Rows more
|
|
// often hide than unload (an override pill, a conditional card), so the
|
|
// visibility guard matters as much as the destruction one.
|
|
Component.onDestruction: root.disarm()
|
|
onVisibleChanged: if (!root.visible) root.disarm()
|
|
|
|
SettingsButton {
|
|
visible: !root.armed
|
|
enabled: root.enabled
|
|
text: root.armText
|
|
onClicked: ShellState.armedConfirm = root.actionId
|
|
}
|
|
|
|
SettingsButton {
|
|
visible: root.armed
|
|
enabled: root.enabled
|
|
text: root.cancelText
|
|
onClicked: root.disarm()
|
|
}
|
|
|
|
SettingsButton {
|
|
visible: root.armed
|
|
enabled: root.enabled
|
|
tone: "danger"
|
|
text: root.confirmText
|
|
onClicked: {
|
|
root.disarm();
|
|
root.confirmed();
|
|
}
|
|
}
|
|
}
|