From 1c68c391cd10b5726d082d487b97e7decb823512 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 17 Oct 2026 10:06:12 +0200 Subject: desktop: settings search finds rows, and a hit reveals its row Search used to stop at the page: clicking a result opened it at the top and left the setting to be found by eye. Now each settings module keeps its rows as searchItems, {text, key}, reread on every window open since the page itself is not loaded until shown: git runs gitcfg list, and autostart watches its file. A row hit opens the page, and Page.reveal() finds the row whose objectName is the key, waiting up to 3s for the page's own data, scrolls to it and flashes it in the accent. The reveal lives in Page, so a page only names its rows. Git's long keyword list was a stand-in for exactly this and is cut to "gitconfig". The autostart page takes its path from the module now that both read the file. Also corrects the AGENTS note on missed hot reloads: it blamed sed -i replacing the file, but the Edit tool writes a new inode too and usually reloads. The cause is unknown; the note now says how to detect it and that a process that stops watching needs a restart. Co-Authored-By: Claude Opus 5.5 --- desktop/Page.qml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'desktop/Page.qml') diff --git a/desktop/Page.qml b/desktop/Page.qml index 8365c51..357c3a7 100644 --- a/desktop/Page.qml +++ b/desktop/Page.qml @@ -80,7 +80,47 @@ Item { color: Qt.alpha(Theme.text, 0.12) } + // Scrolls to the content row whose objectName is key and flashes it, for + // a settings search hit. Rows usually arrive after the page loads its + // data, so it looks for up to 3s before giving up. + function reveal(key) { + finder.key = key; + finder.tries = 0; + finder.restart(); + } + + function findNamed(item, key) { + if (item.objectName === key) return item; + for (let i = 0; i < item.children.length; i++) { + const f = page.findNamed(item.children[i], key); + if (f) return f; + } + return null; + } + + Timer { + id: finder + property string key: "" + property int tries: 0 + interval: 100 + repeat: true + onTriggered: { + const it = page.findNamed(holder, key); + if (!it) { if (++tries > 30) stop(); return; } + stop(); + const p = it.mapToItem(holder, 0, 0); + const flick = scroll.contentItem; + flick.contentY = Math.max(0, Math.min(p.y - 40, flick.contentHeight - flick.height)); + flash.x = p.x - 4; + flash.y = p.y - 2; + flash.width = it.width + 8; + flash.height = it.height + 4; + flashAnim.restart(); + } + } + ScrollView { + id: scroll anchors { top: rule.bottom; left: parent.left; right: parent.right; bottom: parent.bottom } anchors.topMargin: 12 clip: true @@ -92,4 +132,24 @@ Item { implicitHeight: childrenRect.height } } + + // The reveal highlight, over the row and in holder's coordinates. + // Declared out here, not in the ScrollView, which sizes from a single + // child; parent puts it in holder all the same. + Rectangle { + id: flash + parent: holder + z: 10 + radius: 8 + opacity: 0 + color: Qt.alpha(Theme.accent, 0.28) + border.width: 1 + border.color: Theme.accent + SequentialAnimation { + id: flashAnim + NumberAnimation { target: flash; property: "opacity"; to: 1; duration: 120 } + PauseAnimation { duration: 1400 } + NumberAnimation { target: flash; property: "opacity"; to: 0; duration: 600 } + } + } } -- cgit v1.2.3