fix(qt): move the cortinilla debounce from QML into Rust
The 220ms debounce wrapped the WHOLE searchLive invokable in QML, so live()
- which opens the dropdown and raises the skeleton - only ran 220ms after
the LAST keystroke. Continuous typing therefore showed nothing at all. The
reference opens the panel and raises the skeleton on the FIRST keystroke of
2+ characters and debounces only the LOAD.
live() is now two halves. The synchronous half runs on the first poll of the
spawned task, i.e. at the keystroke: gates, selection reset, open, query,
version bump, loading flag. Then it sleeps 220ms and re-checks the version,
so a superseded task exits without touching the network. This is the shape
the immersive arm already uses (imm_live), which is the precedent in both
respects: raise synchronously, debounce the load.
cortinillaLoading gets exactly one owner in the synchronous half and is
written once more at the publish - never in both halves for the same
keystroke.
Two consequences ride along:
- dismiss() becomes a real cancellation point. It only flipped the open
flag, so an in-flight load survived Esc, published into a closed
dropdown and rewrote LAST_CORT. It now bumps the version too. This
matters more now that the version bumps per keystroke.
- the idle-close timer restarts on the QUERY rather than the payload. A
burst of typing publishes one payload but many queries, and the
reference restarts per keystroke.
HeaderBar.qml's header claimed the cortinilla and live-search were "out of
scope" in the file that wires the whole input path. Corrected here, beside
the code that falsifies it, rather than in a later docs sweep.
Contract: qbz-nix-docs/qt-frontend/2026-08-03-cortinilla-parity, commit C3
(H1/H2/H3/H8, D-BUG-8, R7-4).
Gate: build clean, 256/256 tests, both QML audits OK, offscreen smoke
0 complaints + home published.
cc
This commit is contained in:
3 files changed
+52
-18
No files matched your search
@@ -61,8 +61,11 @@ Item {
|
||||
}
|
||||
Connections {
|
||||
target: QbzSearch
|
||||
// Activity restarts the countdown (keystroke or arrow move).
|
||||
function onCortinillaJsonChanged() { if (root.visible && !root.panelHovered) idleClose.restart() }
|
||||
// Activity restarts the countdown (keystroke or arrow move). The
|
||||
// keystroke probe is the QUERY, not the payload: the reference
|
||||
// restarts per keystroke, and now that the debounce lives in Rust a
|
||||
// burst of typing publishes one payload but many queries.
|
||||
function onCortinillaQueryChanged() { if (root.visible && !root.panelHovered) idleClose.restart() }
|
||||
function onCortinillaSelectedIndexChanged() { if (root.visible && !root.panelHovered) idleClose.restart() }
|
||||
// Keyboard scroll-into-view: the controller publishes the selected
|
||||
// row's content-space top-y; nudge the Flickable so it is visible.
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
//
|
||||
// The search field gives up 60px whenever the nav is in the header, and
|
||||
// re-centers with a 220ms animation (HeaderBar.slint:569).
|
||||
// Center: the search field, absolutely centered on the window (VISUAL
|
||||
// replica — the cortinilla/live-search is out of scope; POC-NOTE).
|
||||
// Center: the search field, absolutely centered on the window. It owns the
|
||||
// live-search input path: the >= 2-char gate and the dismiss below it, the
|
||||
// arrow/Enter/Escape rules, the ↵ affordance and clearSearch(). The 220ms
|
||||
// debounce is NOT here — it lives in Rust (search_qt::live), so the panel
|
||||
// opens on the first keystroke instead of 220ms after the last one. The
|
||||
// dropdown itself is shell/Cortinilla.qml.
|
||||
// Right: the tri-state offline status badge with its flyout (recovery
|
||||
// "Sign in" wired to QbzSession.recoveryLogin) and the app menu (user block
|
||||
// + Keyboard Shortcuts + Documentation + Log Out + Close. Still missing vs
|
||||
@@ -665,24 +669,21 @@ Rectangle {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: text === "" && !activeFocus ? Text.AlignHCenter : Text.AlignLeft
|
||||
clip: true
|
||||
// No QML debounce: the 220ms CORTINILLA_DEBOUNCE lives in Rust
|
||||
// now (search_qt::live). Debouncing the whole invokable here
|
||||
// meant the panel and its skeleton only appeared 220ms after the
|
||||
// LAST keystroke, so continuous typing showed nothing at all;
|
||||
// the reference opens on the FIRST keystroke >= 2 chars and
|
||||
// debounces only the LOAD. Rust's version guard is what discards
|
||||
// the superseded loads.
|
||||
onTextEdited: {
|
||||
if (text.trim().length < 2) {
|
||||
liveDebounce.stop()
|
||||
QbzSearch.cortinillaDismiss()
|
||||
} else {
|
||||
liveDebounce.restart()
|
||||
QbzSearch.searchLive(text)
|
||||
}
|
||||
}
|
||||
|
||||
// 220ms live debounce (CORTINILLA_DEBOUNCE — one load per pause,
|
||||
// not one per keystroke).
|
||||
Timer {
|
||||
id: liveDebounce
|
||||
interval: 220
|
||||
repeat: false
|
||||
onTriggered: QbzSearch.searchLive(searchInput.text)
|
||||
}
|
||||
|
||||
// The Enter rule (HeaderBar.slint on-enter): cortinilla open +
|
||||
// a keyboard selection -> activate the row; open + none -> full
|
||||
// search; closed -> plain submit (also Search > All).
|
||||
|
||||
Reference in new issue
Block a user