From 080d3d9aaffa8848d6de8546511f096d8e7c30f5 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 17 Oct 2026 11:34:07 +0200 Subject: settings: pages edit a draft, and Save writes it The qtmaildir, Assistant and Ask presets pages wrote a field on Enter, and a switch or chip the moment it was clicked, so a half-finished change reached the file and a slip could not be taken back. They now edit a draft as fields are typed, and a Save and Discard pair in the page header (SaveBar, through Page.actions) writes or drops it. Save waits while a field holds a value that cannot be written, and a draft over a file that changed on disk meanwhile is refused at Save rather than written over it. A dot in the sidebar marks a page with unsaved edits; drafts survive moving between pages. The four Mail pages share one draft, since they are one file. Tool switches are staged too and renamed on Save; model Load, Prefer and Restart stay immediate, being actions rather than settings. Live editing needed two rules. A field is no longer bound to its value, which would reset the cursor and eat a typed trailing space; it follows the value only when the draft moves under it. And a Repeater's model is now the set of row keys (or a count), assigned only when that set changes: an array rebuilt from the draft on each keystroke recreates every row, including the one being typed in, which loses its focus. Git, autostart's rows, HyprSunset, HyprIdle and User keep their own buttons. Co-Authored-By: Claude Opus 5.5 --- desktop/modules/qtmaildir/Setting.qml | 50 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 21 deletions(-) (limited to 'desktop/modules/qtmaildir/Setting.qml') diff --git a/desktop/modules/qtmaildir/Setting.qml b/desktop/modules/qtmaildir/Setting.qml index 66d0a46..78103bf 100644 --- a/desktop/modules/qtmaildir/Setting.qml +++ b/desktop/modules/qtmaildir/Setting.qml @@ -12,10 +12,11 @@ import QtQuick import "../.." -// One labelled key of qtmaildir.conf: a text field that saves on Enter. -// Emptied, the key is unset and qtmaildir uses its default, which the -// placeholder names. kind "int" or "float" checks the number and its range -// before writing; a refused value shows why under the row. +// One labelled key of qtmaildir.conf: a text field that edits the draft as +// it is typed; the page's Save writes it. Emptied, the key is unset and +// qtmaildir uses its default, which the placeholder names. kind "int" or +// "float" checks the number and its range: a refused value stays out of the +// draft, shows why under the row, and holds Save back until it is fixed. Column { id: s property string section @@ -36,20 +37,31 @@ Column { readonly property string value: Qtm.get(s.section, s.key) ?? "" property string problem: "" - function commit(t) { + function apply(t) { t = t.trim(); - if (t === "") { s.problem = ""; Qtm.set(s.section, s.key, null); return; } - if (s.kind !== "text") { + let bad = ""; + if (t !== "" && s.kind !== "text") { const n = Number(t); - if (isNaN(n) || (s.kind === "int" && !Number.isInteger(n)) || n < s.min || n > s.max) { - s.problem = s.kind === "int" ? `a whole number from ${s.min} to ${s.max}` - : `a number from ${s.min} to ${s.max}`; - return; - } + if (isNaN(n) || (s.kind === "int" && !Number.isInteger(n)) || n < s.min || n > s.max) + bad = s.kind === "int" ? `a whole number from ${s.min} to ${s.max}` + : `a number from ${s.min} to ${s.max}`; } - s.problem = ""; - Qtm.set(s.section, s.key, t); + s.problem = bad; + Qtm.markInvalid(s.objectName, bad !== ""); + if (bad === "") Qtm.set(s.section, s.key, t === "" ? null : t); + } + + // The field is not bound to the value, which would reset the cursor and + // eat a typed trailing space; it follows the value only when the draft + // moves under it (Discard, a colour picked, a save of another page). + onValueChanged: if (ti.text.trim() !== s.value && s.problem === "") ti.text = s.value + Connections { + target: Qtm + function onInvalidChanged() { if (s.problem !== "" && !Qtm.invalid[s.objectName]) { s.problem = ""; ti.text = s.value; } } } + // A field that goes away cannot hold Save back; the draft keeps its last + // good value. + Component.onDestruction: Qtm.markInvalid(s.objectName, false) Item { width: s.width @@ -69,7 +81,7 @@ Column { visible: s.colour width: s.colour ? 34 : 0 colour: s.value - onPicked: hex => s.commit(hex) + onPicked: hex => s.apply(hex) } Rectangle { anchors { left: lbl.right; leftMargin: 8; right: pick.left; rightMargin: s.colour ? 8 : 0 @@ -84,12 +96,8 @@ Column { selectByMouse: true color: Theme.text font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } - text: s.value - onAccepted: if (text !== s.value) s.commit(text) - Keys.onEscapePressed: event => { - if (text !== s.value) text = s.value; - else event.accepted = false; - } + Component.onCompleted: text = s.value + onTextEdited: s.apply(text) Text { anchors.verticalCenter: parent.verticalCenter width: parent.width -- cgit v1.2.3