diff options
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 87 |
1 files changed, 87 insertions, 0 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 4aeff26..755caa5 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 @@ -232,6 +232,9 @@ taking that too literally. | 159 | The Drafts view lists threads, so a draft is unreachable by double-click | defect | S | **done** 2026-08-25, unreleased. Reverses item 138's own decision, confirmed with the user. `generatorIsFlat()` in `config.cpp` is now the single closed set of flat generators, replacing three hardcoded comparisons against `"sent"`: the built-in filter, the reader that reapplies the mode, and the writer that skips storing what the generator implies. Those three had to agree and nothing made them; a `drafts` entry saved and reloaded would otherwise have come back THREADED while the button was flat. `builtinFilter()` sets `flat` once from the helper rather than in a branch, so the set cannot drift from the labels | +| 160 | The composer never says a draft was autosaved | feedback | S | open, 2026-08-25, from the notes. Autosave works (`m_autosaveTimer`, `saveDraftNow()`) and is SILENT on success: the only feedback is `m_banner`, which appears on FAILURE. The user asks for a status bar reporting "last autosave 20s ago" progressing to "Draft autosaved", plus an eye-catching "unsaved content" cue whenever `m_dirty` is true. Both states already exist as data; nothing displays them | +| 161 | The composer has no menu bar | discoverability | S | open, 2026-08-25, from the notes. Save draft on `Ctrl+S` is asked for and does not exist at all: `saveDraftNow()` is reachable only from the timer, Send and `closeEvent`. The composer's actions are ad-hoc `QAction`s parented to the window (Send, Close, and the formatting toolbar's), none registered in `KeyMap`, so item 132's menu-reachability rule does not currently reach them. Depends on 160 for what "saved" then reports | + Sizes are rough: XS under an hour, S a sitting, M a session. --- @@ -1333,3 +1336,87 @@ half of the fork above, and it would look exactly like this. The 70-second duration recorded above fits a `QTRY_*` waiting for a file that is never going to appear, which is consistent with a wrong destination rather than a slow one. + +## 160. The composer never says a draft was autosaved + +**Observed (user, 2026-08-25):** "we should add a status bar to the compose +window, to report every time a draft is autosaved. With a timer like 'last +autosave 20s ago' progressing into 'Draft autosaved' and next to it a visually +highlighted notification 'unsaved content' (blinking, color yellow, something +eye catching) whenever there's new content since the last autosave." + +**Cause (verified in code):** autosave is built and works. `m_autosaveTimer` +is a single-shot timer restarted on every edit (`composewindow.cpp:960-963`), +so it fires once the user pauses rather than once per character, and +`saveDraftNow()` writes the Maildir file. It reports **nothing on success**. + +The only feedback that exists is `m_banner`, and it is deliberately a FAILURE +channel: the comment at `composewindow.cpp:1026` records the reasoning, "a +PERSISTENT banner, not a modal and not a status-bar line that fades", because +a failed save must survive until it is dealt with. Success is the opposite +case and wants the fading line that comment rejected for failure. + +**Both states already exist as data**, which is what makes this small: + +- `m_dirty` is true exactly when there is content newer than the last save. +- `m_savedFingerprint` and the `draftSaved` signal mark a successful write. + +Nothing displays either. There is no `QStatusBar` on the composer at all. + +**Approach.** A `QStatusBar` on the composer, with the age line as a permanent +widget and the unsaved cue beside it. The age needs a second timer of its own, +since "20s ago" changes with no edit to drive it; a one-second tick is wasteful +for a label that reads in tens of seconds, so tick slower and accept the +granularity. + +**Constraints.** + +- **Do not reuse `m_banner`.** Its persistence is load-bearing for the quit + path's honesty, and a success message that shares it would either fade the + failure away or make success sticky. +- The "blinking" the note asks for should be treated as "eye-catching", not + literally: a blinking widget is an accessibility problem and Qt has no + blink facility to reach for. A yellow ground matching item 151's warning + severity is the established vocabulary here. +- `saveDraftNow()` returns false on failure and the banner takes over, so the + status line must not claim a save the write did not make. + +## 161. The composer has no menu bar + +**Observed (user, 2026-08-25):** "the compose window should have a menu bar on +top", with "save draft (ctrl+s)" and "duplicate the other actions like we do +on the main window". + +**Cause (verified in code):** the composer has no `QMenuBar`, and **Save draft +does not exist as an action at all.** `saveDraftNow()` is reachable only from +the autosave timer, from the send path, and from `closeEvent`; there is no way +for the user to ask for a save, and no `Ctrl+S` anywhere in the composer or in +`KeyMap`. + +The actions the composer does have are ad-hoc `QAction`s parented to the +window: `m_sendAction` and a Close action (`composewindow.cpp:583-608`), plus +the formatting toolbar's own. **None is registered in `KeyMap`**, which is +deliberate and documented for `Ctrl+W` in item 148: they are WindowShortcuts +dispatched to the active composer only, so they never touch the main window's +namespace. A consequence worth stating before this item is built: +`everyActionIsReachableFromAMenu()` walks the MAIN window's menu bar, so it +does not currently constrain these, and adding a composer menu bar does not +automatically bring them under item 132's rules. + +**Approach.** A `QMenuBar` on the composer, with Save draft (`Ctrl+S`) as the +new action and the existing ones gathered under it rather than duplicated. + +**Constraints.** + +- **"Duplicate the other actions" means the main window's MESSAGE actions, and + most of them are meaningless here.** A composer has no thread, no selection + and no tag surface. Ask which the user actually wants before building a menu + that offers Archive or Mark all read over a message being written. +- Keep the composer's actions out of `KeyMap`, per item 148's reasoning. A + composer menu bar is not a reason to move them. +- Save draft must go through `saveDraftNow()`, which already handles the + failure banner and emits `draftSaved` for the indexing item 158 added. A + second write path would reintroduce the ghost-file problem that fixed. +- **Depends on item 160** for what a manual save then reports: with no status + line, a successful `Ctrl+S` would be as silent as an autosave is now. + |
