fix(qt): re-seed a line edit on the CHANGE, never on the focus loss

`QbzLineEdit` restored the owner's value with

    Binding { target: input; property: "text"; value: root.text
              when: !input.activeFocus }

and a Binding re-asserts whenever its condition flips, so BLURRING the
field wrote `root.text` back over whatever had been typed.

A SEARCH field never noticed: it fires `edited()` per keystroke, the
owner republishes, and `root.text` is already what the user typed. A
FORM field is the opposite — it reports on `committed()` and the owner
holds the value until Save — so `root.text` is still the stored value,
which for a password is the literal `""` that is deliberately never
prefilled. Every blur erased the field.

Measured in the media-server panel: username and password wiped each
other, so a Subsonic server could not be signed into by hand at all.
The stored state was in fact correct the whole time — `onCommitted`
fires on focus loss and captures the value before the Binding clears
the view — which is why this survived the Jellyfin round: the form
worked, it just did not look like it.

A republish IS a change to `root.text`; a focus loss is not. Reacting
to the change alone keeps the documented case (an external Reset
re-seeds an unfocused field) and drops the destructive one.

Verified in the window: password survives blurring into the username
box; the Tracks search keeps its query after a blur; the × still
collapses the expandable search with no stale query snapping back.

cc
This commit is contained in:
vicrodh committed 2026-08-20 15:27:22 -06:00
1 parent 4ba4d336d0
commit 1a2ebcf146
1 file changed
+25 -5
+25 -5
View File
@@ -230,11 +230,31 @@ Rectangle {
// frames between the × and the owner's republish, when
// `root.text` is still the query the user just cleared —
// see `_cleared`.
Binding {
target: input
property: "text"
value: root.text
when: !input.activeFocus && !root._cleared
//
// On the CHANGE, never on the focus loss. This was a
// `Binding { when: !input.activeFocus }`, which re-asserts
// whenever its condition flips — so blurring the field
// wrote `root.text` back over whatever had been typed. A
// SEARCH field never noticed: it fires `edited()` per
// keystroke, so the owner republishes and `root.text` is
// already what the user typed. A FORM field is the
// opposite — it reports on `committed()` and the owner
// holds the value until Save — so `root.text` is still the
// stored value (`""` for a password, which is never
// prefilled), and every blur ERASED the field. Measured in
// the media-server panel 2026-08-20: username and password
// wiped each other, so the form could not be filled by
// hand at all.
//
// A republish IS a change to `root.text`; a focus loss is
// not. Reacting to the change alone keeps the documented
// case and drops the destructive one.
Connections {
target: root
function onTextChanged() {
if (!input.activeFocus && !root._cleared)
input.text = root.text
}
}
}
Text {