aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-03 16:33:13 +0200
committerDanilo M. <danix@danix.xyz>2026-08-03 16:33:13 +0200
commitea90e69d5e974960c653e65a5bb9ca1359f2d52c (patch)
tree87410a035212f0e8e5997722662803c17a3320d8 /docs
parentec390fb46e1a36d8406dde487228bbb0f348a20a (diff)
parent2c33529fb665cb54c31e54230fcb7b2491cf8565 (diff)
downloadqtmaildir-ea90e69d5e974960c653e65a5bb9ca1359f2d52c.tar.gz
qtmaildir-ea90e69d5e974960c653e65a5bb9ca1359f2d52c.zip
Merge branch 'feature/ui-state-persistence'
Persistence cluster from the post-0.1.0 usability backlog: window, splitter and column geometry survive restart, the message pane owns its zoom and remembers it, and the startup query is chosen by name instead of by alphabetical accident. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md69
1 files changed, 67 insertions, 2 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 915c8cb..02bf7c4 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -34,10 +34,10 @@ taking that too literally.
| # | Item | Cluster | Size | Status |
|---|------|---------|------|--------|
-| 1 | Splitter/column widths do not survive restart | persistence | S | open |
+| 1 | Splitter/column widths do not survive restart | persistence | S | **done** |
| 2 | No way to see full message details (From/To/Cc/Subject) | information | M | open |
| 3 | Too few clickable affordances, shortcuts are the only route | discoverability | M | **done** |
-| 4 | Message-pane font size does not survive restart | persistence | S | open |
+| 4 | Message-pane font size does not survive restart | persistence | S | **done** |
| 5 | Thread list is cramped, poor readability | presentation | S | open |
| 6 | Opened message stays unread | behavior | S | open |
| 7 | HTML view should be default for HTML messages | behavior | XS | **verify first, may already be done** |
@@ -89,6 +89,24 @@ as well. Establish it once, in whichever lands first.
confirm both held. Then delete the state file and confirm the app still starts
with the 1200x800 default rather than a zero-size window.
+### Outcome (done)
+
+Built as described. `MainWindow::uiStatePath()` establishes the state file the
+plan calls for, so items 4 and 10 inherit it. Two things worth recording:
+
+- **`QStandardPaths::StateLocation` is the wrong enum here.** It appends both
+ the organization and the application name, and this app sets both to
+ `qtmaildir`, so it yields `~/.local/state/qtmaildir/qtmaildir/`. The path is
+ built from `GenericStateLocation` plus an explicit `/qtmaildir`, the same
+ shape as `Config::defaultPath()`. A test pins the component count.
+- **`restoreUiState()` runs after `buildMenus()`, not at the end of
+ `buildUi()`** as the plan proposed. `QMainWindow::restoreState()` matches
+ toolbars by object name, so a toolbar that does not exist yet has its
+ position silently dropped.
+
+Every restore is guarded on a non-empty blob, so absent state leaves the
+`buildUi()` defaults rather than producing a zero-size window.
+
## 2. No way to see full message details
**Observed:** From, To, Cc, Subject and the rest are not visible for the
@@ -243,6 +261,38 @@ already exists.
- Route the actions through item 3's `QAction` conversion so they appear in the
View menu, which also makes the reset discoverable.
+### Outcome (done)
+
+Built as described, and both of the plan's stated risks turned out not to
+exist. Probed rather than assumed:
+
+- **The application `QAction` wins over Chromium's native zoom key.** The plan
+ called this "the one real risk in the item". It is not one: the action fires
+ and the web view's own handling never runs, so the tracked factor cannot
+ diverge from what is on screen.
+- **Zoom survives `setHtml()`.** The plan expected the view might reset it on
+ navigation and asked for a reapply per render. Not needed; the web view keeps
+ the factor, so it is the single source of truth and there is no second copy.
+- **Do not test key reachability with synthetic input.** A probe using
+ `QTest::keyClick()` reported `Ctrl++` as a dead binding, and a test was
+ written asserting it. Both were wrong: `Ctrl++` is exactly what the `+` key
+ emits on an Italian layout, confirmed against the real keyboard, and it is
+ the shipped default. Whether a symbol needs Shift is a property of the
+ layout, not of Qt, and `keyClick()` reproduces neither. The test now only
+ checks that every default parses.
+- `Ctrl+=` is a second binding for reset, skipped when `[keys]` gives `Ctrl+=`
+ to something else. Ctrl+wheel zooms and Ctrl+middle-click resets, both
+ filtered by ancestry from an application-level filter: the events land on an
+ internal `QQuickWidget` the web view creates lazily, so a filter installed on
+ the view itself never sees them.
+
+**A pre-existing bug surfaced while adding the config key.** `[general]`
+entries were read as `general/<key>`, which matches nothing: QSettings' INI
+backend treats a section literally named `[general]` as its own fallback
+section and strips the prefix. `notmuch_config` had therefore never worked.
+Both keys are now read without the prefix; the file format the user writes is
+unchanged. Regression test in `test_config`.
+
## 5. Thread list is cramped
**Observed:** rows are tightly packed, everything is uniform, the UI reads as
@@ -342,6 +392,21 @@ stays blocked and per-render.
Do not build a full account sidebar for this. Persisting the selection may
resolve the complaint entirely, and it is a fraction of the work. Reassess after.
+### Partly done
+
+**The startup query is now chosen by name**, not by sort order. `[queries]` is
+read through `childKeys()`, which sorts alphabetically, so the old
+`savedQueries().first()` opened whichever entry happened to sort first, which
+is why the app came up on Inbox. `[general] startup_query` names the entry,
+defaults to `Unread`, and falls back to the first saved query when the name
+matches nothing. Only a name the user wrote is worth a warning: the built-in
+default naming a query they never created is not something they got wrong.
+
+Neither half of item 10 proper is done: the account selection still resets on
+restart, and reaching an account's inbox is still two steps. Persisting the
+selection remains the next cheap step, and the reassessment the item calls for
+should happen after that rather than now.
+
## 11. Icon, `.desktop` file, SlackBuild
Packaging, independent of everything above, and can proceed in parallel.