// 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(); } } }