No forgetting, deleting or clearing on a single press, anywhere
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -30,13 +30,54 @@ Rectangle {
|
||||
readonly property bool isDefault: root.theme.id === (root.theme.scheme === "light"
|
||||
? ThemeCatalog.defaultLight : ThemeCatalog.defaultDark)
|
||||
|
||||
// Delete arms in place rather than through ConfirmAction. The ✕ badge is a
|
||||
// 22px corner of a card whose whole body is the apply target roughly ten
|
||||
// pixels away -- there is nowhere in that caption to put a Keep beside a
|
||||
// Delete it without the pair becoming the card. So the badge itself is the
|
||||
// two presses: the first turns it into a labelled danger pill and reddens
|
||||
// the card's border, the second deletes. The token is ShellState's, the
|
||||
// same one ConfirmAction uses, so one confirm is armed app-wide.
|
||||
readonly property string removeActionId: "theme-card-delete:" + root.theme.id
|
||||
readonly property bool removeArmed: ShellState.armedConfirm === root.removeActionId
|
||||
|
||||
function pressRemove(): void {
|
||||
if (!root.removeArmed) {
|
||||
ShellState.armedConfirm = root.removeActionId;
|
||||
return;
|
||||
}
|
||||
root.disarmRemove();
|
||||
root.removed();
|
||||
}
|
||||
|
||||
function disarmRemove(): void {
|
||||
if (root.removeArmed)
|
||||
ShellState.armedConfirm = "";
|
||||
}
|
||||
|
||||
// Armed, the card body is the way out: a press anywhere on it takes the
|
||||
// arming back instead of applying the theme, because the miss this guards
|
||||
// against is a press landing next to the badge rather than on it.
|
||||
function press(): void {
|
||||
if (root.removeArmed) {
|
||||
root.disarmRemove();
|
||||
return;
|
||||
}
|
||||
root.chosen();
|
||||
}
|
||||
|
||||
// A card that scrolls away, or a gallery that rebuilds, must not leave the
|
||||
// token claiming a theme nothing is showing.
|
||||
Component.onDestruction: root.disarmRemove()
|
||||
|
||||
implicitHeight: preview.height + caption.height + 4
|
||||
radius: Theme.cardRadius + 2
|
||||
color: Theme.alpha(Theme.fg, 0.04)
|
||||
border.width: 2
|
||||
border.color: root.activeFocus
|
||||
? Theme.accentSecondary
|
||||
: (root.active ? Theme.accent : Theme.alpha(Theme.fg, 0.12))
|
||||
border.color: root.removeArmed
|
||||
? Theme.danger
|
||||
: (root.activeFocus
|
||||
? Theme.accentSecondary
|
||||
: (root.active ? Theme.accent : Theme.alpha(Theme.fg, 0.12)))
|
||||
clip: true
|
||||
activeFocusOnTab: true
|
||||
|
||||
@@ -44,11 +85,13 @@ Rectangle {
|
||||
Accessible.name: root.theme.name
|
||||
Accessible.description: (root.theme.scheme === "light" ? "Light theme" : "Dark theme")
|
||||
+ (root.active ? ", selected" : "")
|
||||
+ (root.removeArmed ? ", delete is armed — press this card to keep it" : "")
|
||||
Accessible.focusable: true
|
||||
Accessible.focused: root.activeFocus
|
||||
|
||||
Keys.onReturnPressed: root.chosen()
|
||||
Keys.onSpacePressed: root.chosen()
|
||||
Keys.onReturnPressed: root.press()
|
||||
Keys.onSpacePressed: root.press()
|
||||
Keys.onEscapePressed: root.disarmRemove()
|
||||
|
||||
Rectangle {
|
||||
id: preview
|
||||
@@ -148,36 +191,52 @@ Rectangle {
|
||||
// Only saved themes can be removed, and the affordance is a
|
||||
// separate focus stop so Tab never lands on "delete" when the
|
||||
// person meant "select".
|
||||
//
|
||||
// At rest the badge is neutral: danger marks the press that
|
||||
// confirms, never the one that initiates, which is SettingsButton's
|
||||
// contract and holds here too. Armed, it stops being a glyph and
|
||||
// becomes a labelled pill wide enough to read.
|
||||
Rectangle {
|
||||
id: remove
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !root.shipped
|
||||
width: 22
|
||||
width: root.removeArmed ? removeLabel.implicitWidth + 16 : 22
|
||||
height: 22
|
||||
radius: 7
|
||||
color: removeHover.hovered
|
||||
? Theme.alpha(Theme.danger, 0.22)
|
||||
: Theme.alpha(Theme.fg, 0.07)
|
||||
border.width: remove.activeFocus ? 2 : 1
|
||||
border.color: remove.activeFocus
|
||||
color: root.removeArmed
|
||||
? Theme.alpha(Theme.danger, 0.3)
|
||||
: (removeHover.hovered
|
||||
? Theme.alpha(Theme.fg, 0.14)
|
||||
: Theme.alpha(Theme.fg, 0.07))
|
||||
border.width: root.removeArmed || remove.activeFocus ? 2 : 1
|
||||
border.color: root.removeArmed || remove.activeFocus
|
||||
? Theme.danger : Theme.alpha(Theme.fg, 0.08)
|
||||
activeFocusOnTab: visible
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: "Delete " + root.theme.name
|
||||
Accessible.name: root.removeArmed
|
||||
? "Delete " + root.theme.name + ", press again to confirm"
|
||||
: "Delete " + root.theme.name
|
||||
Accessible.description: root.removeArmed
|
||||
? "This theme's palette, terminal colours and effects go with it"
|
||||
: ""
|
||||
Accessible.focusable: true
|
||||
Accessible.focused: remove.activeFocus
|
||||
|
||||
Keys.onReturnPressed: root.removed()
|
||||
Keys.onSpacePressed: root.removed()
|
||||
Keys.onReturnPressed: root.pressRemove()
|
||||
Keys.onSpacePressed: root.pressRemove()
|
||||
Keys.onEscapePressed: root.disarmRemove()
|
||||
|
||||
Text {
|
||||
id: removeLabel
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: "✕"
|
||||
color: Theme.danger
|
||||
text: root.removeArmed ? "Delete it" : "✕"
|
||||
color: root.removeArmed ? Theme.danger : Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: root.removeArmed ? Font.DemiBold : Font.Normal
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
@@ -190,7 +249,7 @@ Rectangle {
|
||||
// on its way out.
|
||||
TapHandler {
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
onTapped: root.removed()
|
||||
onTapped: root.pressRemove()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,6 +261,6 @@ Rectangle {
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
onTapped: root.chosen()
|
||||
onTapped: root.press()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user