Make Home light ordering explicit and durable
This commit is contained in:
@@ -9,93 +9,61 @@ Rectangle {
|
||||
required property string sourceName
|
||||
required property int index
|
||||
required property bool featured
|
||||
required property bool canMoveEarlier
|
||||
required property bool canMoveLater
|
||||
|
||||
signal aliasCommitted(string id, string alias)
|
||||
signal removeRequested(string id)
|
||||
signal moveRequested(string id, int targetIndex)
|
||||
|
||||
readonly property bool dragging: dragHandler.active
|
||||
|
||||
implicitHeight: 108
|
||||
radius: Theme.cardRadius
|
||||
color: root.dragging
|
||||
? Theme.mix(Theme.bgDark, Theme.accent, 0.09)
|
||||
: Theme.alpha(Theme.bgDark, 0.7)
|
||||
border.width: root.dragging ? 2 : 1
|
||||
border.color: root.dragging
|
||||
? Theme.alpha(Theme.accent, 0.82)
|
||||
: Theme.alpha(Theme.fg, 0.07)
|
||||
z: root.dragging ? 10 : 0
|
||||
|
||||
transform: Translate {
|
||||
x: root.dragging ? dragHandler.translation.x : 0
|
||||
y: root.dragging ? dragHandler.translation.y : 0
|
||||
}
|
||||
color: Theme.alpha(Theme.bgDark, 0.7)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.07)
|
||||
|
||||
PrismEdge {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
inset: root.radius
|
||||
opacity: root.dragging ? 0.82 : 0.2
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: dragHandle
|
||||
Column {
|
||||
id: reorderControls
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 11
|
||||
anchors.leftMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 30
|
||||
height: 42
|
||||
radius: 9
|
||||
activeFocusOnTab: true
|
||||
color: root.dragging || activeFocus
|
||||
? Theme.alpha(Theme.accent, 0.14)
|
||||
: (handleMouse.containsMouse ? Theme.alpha(Theme.fg, 0.09) : Theme.alpha(Theme.fg, 0.045))
|
||||
border.width: activeFocus ? 2 : 1
|
||||
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.06)
|
||||
spacing: 4
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "⠿"
|
||||
color: root.dragging ? Theme.accent : Theme.fgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: 16
|
||||
SettingsButton {
|
||||
width: 30
|
||||
height: 29
|
||||
text: "↑"
|
||||
enabled: root.canMoveEarlier
|
||||
activeFocusOnTab: enabled
|
||||
onClicked: root.moveRequested(root.favorite.id, root.index - 1)
|
||||
Keys.onReturnPressed: if (enabled) root.moveRequested(root.favorite.id, root.index - 1)
|
||||
Keys.onSpacePressed: if (enabled) root.moveRequested(root.favorite.id, root.index - 1)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: handleMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.SizeAllCursor
|
||||
}
|
||||
|
||||
DragHandler {
|
||||
id: dragHandler
|
||||
target: null
|
||||
onActiveChanged: {
|
||||
if (!active)
|
||||
root.commitDrag();
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Left || event.key === Qt.Key_Up) {
|
||||
root.moveRequested(root.favorite.id, Math.max(0, root.index - 1));
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Right || event.key === Qt.Key_Down) {
|
||||
const grid = root.GridView.view;
|
||||
const lastIndex = grid ? grid.count - 1 : root.index;
|
||||
root.moveRequested(root.favorite.id, Math.min(lastIndex, root.index + 1));
|
||||
event.accepted = true;
|
||||
}
|
||||
SettingsButton {
|
||||
width: 30
|
||||
height: 29
|
||||
text: "↓"
|
||||
enabled: root.canMoveLater
|
||||
activeFocusOnTab: enabled
|
||||
onClicked: root.moveRequested(root.favorite.id, root.index + 1)
|
||||
Keys.onReturnPressed: if (enabled) root.moveRequested(root.favorite.id, root.index + 1)
|
||||
Keys.onSpacePressed: if (enabled) root.moveRequested(root.favorite.id, root.index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: aliasFrame
|
||||
anchors.left: dragHandle.right
|
||||
anchors.left: reorderControls.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.right: removeButton.left
|
||||
anchors.rightMargin: 12
|
||||
@@ -188,16 +156,4 @@ Rectangle {
|
||||
Keys.onReturnPressed: root.removeRequested(root.favorite.id)
|
||||
Keys.onSpacePressed: root.removeRequested(root.favorite.id)
|
||||
}
|
||||
|
||||
function commitDrag(): void {
|
||||
const grid = root.GridView.view;
|
||||
if (!grid || grid.count <= 0)
|
||||
return;
|
||||
const centerX = root.x + dragHandler.translation.x + root.width / 2;
|
||||
const centerY = root.y + dragHandler.translation.y + root.height / 2;
|
||||
const modelCount = grid.count;
|
||||
const column = Math.max(0, Math.min(1, Math.floor(centerX / grid.cellWidth)));
|
||||
const row = Math.max(0, Math.floor(centerY / grid.cellHeight));
|
||||
root.moveRequested(root.favorite.id, Math.min(modelCount - 1, row * 2 + column));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ SettingsPage {
|
||||
})
|
||||
sourceName: modelData.sourceName
|
||||
featured: index < 4
|
||||
canMoveEarlier: index > 0
|
||||
canMoveLater: index < favoritesGrid.count - 1
|
||||
onAliasCommitted: (id, alias) => HomePreferences.setAlias(id, alias)
|
||||
onMoveRequested: (id, targetIndex) => HomePreferences.move(id, targetIndex)
|
||||
onRemoveRequested: id => HomePreferences.remove(id)
|
||||
|
||||
@@ -111,7 +111,15 @@ fi
|
||||
assert_contains 'signal aliasCommitted(string id, string alias)' "$favorite_card"
|
||||
assert_contains 'signal removeRequested(string id)' "$favorite_card"
|
||||
assert_contains 'signal moveRequested(string id, int targetIndex)' "$favorite_card"
|
||||
assert_contains 'DragHandler {' "$favorite_card"
|
||||
assert_contains 'text: "↑"' "$favorite_card"
|
||||
assert_contains 'text: "↓"' "$favorite_card"
|
||||
assert_contains 'enabled: root.canMoveEarlier' "$favorite_card"
|
||||
assert_contains 'enabled: root.canMoveLater' "$favorite_card"
|
||||
if rg -Fq 'DragHandler {' "$favorite_card"; then
|
||||
fail 'Home light cards still expose the broken drag affordance'
|
||||
fi
|
||||
assert_contains 'canMoveEarlier: index > 0' "$home_page"
|
||||
assert_contains 'canMoveLater: index < favoritesGrid.count - 1' "$home_page"
|
||||
assert_contains 'onEditingFinished:' "$favorite_card"
|
||||
assert_contains 'text: "Control Center"' "$favorite_card"
|
||||
assert_contains 'activeFocusOnTab: true' "$favorite_card"
|
||||
|
||||
@@ -96,6 +96,8 @@ assert_reset_persists_without_debounce() {
|
||||
initial_ids=' ["light.kitchen","light.hall","light.desk"]'
|
||||
expected='{"initialized":true,"favorites":[{"id":"light.desk","alias":""},{"id":"light.kitchen","alias":"Island"}],"saveError":""}'
|
||||
expected_file='{"initialized":true,"favorites":[{"id":"light.desk","alias":""},{"id":"light.kitchen","alias":"Island"}]}'
|
||||
reordered_expected='{"initialized":true,"favorites":[{"id":"light.desk","alias":""},{"id":"light.kitchen","alias":"Island"},{"id":"light.hall","alias":""}],"saveError":""}'
|
||||
reordered_file='{"initialized":true,"favorites":[{"id":"light.desk","alias":""},{"id":"light.kitchen","alias":"Island"},{"id":"light.hall","alias":""}]}'
|
||||
empty_expected='{"initialized":true,"favorites":[],"saveError":""}'
|
||||
empty_file='{"initialized":true,"favorites":[]}'
|
||||
reset_expected='{"initialized":false,"favorites":[],"saveError":""}'
|
||||
@@ -106,6 +108,12 @@ start_harness
|
||||
qs_for_harness ipc call home-pref-test initialize "$initial_ids" >/dev/null
|
||||
qs_for_harness ipc call home-pref-test alias light.kitchen ' Island ' >/dev/null
|
||||
qs_for_harness ipc call home-pref-test move light.desk 0 >/dev/null
|
||||
wait_for_status "$reordered_expected"
|
||||
wait_for_file_content "$reordered_file"
|
||||
stop_harness
|
||||
start_harness
|
||||
wait_for_status "$reordered_expected"
|
||||
|
||||
qs_for_harness ipc call home-pref-test remove light.hall >/dev/null
|
||||
wait_for_status "$expected"
|
||||
wait_for_file_content "$expected_file"
|
||||
|
||||
Reference in New Issue
Block a user