aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules/qtmaildir/Setting.qml
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-17 11:08:49 +0200
committerDanilo M. <danix@danix.xyz>2026-10-17 11:08:49 +0200
commitc6fc5bbef45bcfa4f8d5e50ca7401aa1f5b6bc7d (patch)
tree775fa89b284c68d30205c58d83fae55336676f60 /desktop/modules/qtmaildir/Setting.qml
parent8e9d8b9ac1b593032dea9eca312fa1495c0c8858 (diff)
downloadquickshell-c6fc5bbef45bcfa4f8d5e50ca7401aa1f5b6bc7d.tar.gz
quickshell-c6fc5bbef45bcfa4f8d5e50ca7401aa1f5b6bc7d.zip
settings: qtmaildir's config, in four Mail pages
qtmaildir is configured through qtmaildir.conf alone, which it reads at startup and never writes. Four settings pages under a new Mail group edit it: Mail ([general], [sync], [completion]), Compose, Accounts (a card per account, add and remove) and Tags & shortcuts ([tagcolors] and [keys]). Fields save on Enter and unset when emptied, with qtmaildir's defaults as placeholders and numbers range-checked; the pages say when qtmaildir is running and a change waits for its restart. Ini.js edits the file line by line so its comments survive. Headers are only whole [name] lines: a section is never cut at the next "[", since values such as [Gmail]/Bozze hold brackets, the trap AGENTS.md records. The shortcut actions are copied from qtmaildir's KeyMap::knownActions() rather than exported by it, since a CLI flag there would have meant translations and a changelog entry; the field also takes free text, and the copy is marked as a ponytail ceiling. The settings sidebar now clips, which a list long enough to scroll showed it did not: entries drew over the search box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/qtmaildir/Setting.qml')
-rw-r--r--desktop/modules/qtmaildir/Setting.qml104
1 files changed, 104 insertions, 0 deletions
diff --git a/desktop/modules/qtmaildir/Setting.qml b/desktop/modules/qtmaildir/Setting.qml
new file mode 100644
index 0000000..59e9c1b
--- /dev/null
+++ b/desktop/modules/qtmaildir/Setting.qml
@@ -0,0 +1,104 @@
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+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.
+Column {
+ id: s
+ property string section
+ property string key
+ property string label
+ property string placeholder: ""
+ property string hint: ""
+ property string kind: "text"
+ property real min: -Infinity
+ property real max: Infinity
+ // What a search hit scrolls to.
+ objectName: section + "/" + key
+ width: parent ? parent.width : 0
+ spacing: 2
+
+ readonly property string value: Qtm.get(s.section, s.key) ?? ""
+ property string problem: ""
+
+ function commit(t) {
+ t = t.trim();
+ if (t === "") { s.problem = ""; Qtm.set(s.section, s.key, null); return; }
+ if (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;
+ }
+ }
+ s.problem = "";
+ Qtm.set(s.section, s.key, t);
+ }
+
+ Item {
+ width: s.width
+ height: 34
+ Text {
+ id: lbl
+ anchors { left: parent.left; verticalCenter: parent.verticalCenter }
+ width: 160
+ elide: Text.ElideRight
+ text: s.label
+ color: Theme.subtext
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
+ }
+ Rectangle {
+ anchors { left: lbl.right; leftMargin: 8; right: parent.right; top: parent.top; bottom: parent.bottom }
+ radius: 8
+ color: Theme.surface
+ TextInput {
+ id: ti
+ anchors { fill: parent; leftMargin: 10; rightMargin: 10 }
+ verticalAlignment: TextInput.AlignVCenter
+ clip: true
+ 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;
+ }
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ width: parent.width
+ elide: Text.ElideRight
+ visible: parent.text === ""
+ text: s.placeholder
+ color: Theme.overlay
+ font: parent.font
+ }
+ }
+ }
+ }
+
+ Text {
+ x: 168
+ width: s.width - x
+ visible: s.problem !== "" || s.hint !== ""
+ wrapMode: Text.Wrap
+ text: s.problem !== "" ? "Must be " + s.problem + "." : s.hint
+ color: s.problem !== "" ? Theme.red : Theme.overlay
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
+ }
+}