diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-04 20:05:01 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-04 20:05:01 +0200 |
| commit | 8485283bbc30c886e28722516dc6f0b11c3bf82d (patch) | |
| tree | 1caf649b37b8ac693991f4bdf6d12247f9a0eefa /src/mainwindow.h | |
| parent | bd1b907ba22464bb869bcc10cc9327ed74c44791 (diff) | |
| download | qtmaildir-8485283bbc30c886e28722516dc6f0b11c3bf82d.tar.gz qtmaildir-8485283bbc30c886e28722516dc6f0b11c3bf82d.zip | |
fix(sync): count unsynced edits as net state, not as writes
Item 28, reported by the user: open a thread, let the automatic
mark-read remove `unread`, then press Ctrl+U to put it back. The
indicator read "2 unsynced change(s)" with the mail store exactly where
it started.
The counter incremented per confirmed write and never decremented, so
any add-then-remove of the same tag inflated it. Mark-read is simply the
path that fires without being asked, which is why it surfaced there.
The user's call was net state: an edit and its inverse are zero
outstanding changes, because what the indicator answers is whether
quitting now would strand work. A QHash keyed "<messageId>\n<tag>"
replaces the int, and a pair that reverts is erased rather than stored
with the new direction, so the map cannot grow without bound across a
long session of tagging and untagging.
Keyed per (message, tag) rather than per message: removing `unread` and
adding `flagged` on one message are independent changes and must not
cancel each other. A change carrying no message ids cannot be netted
against anything and is counted separately, since dropping it would
understate the indicator, which is the direction that costs work.
Both properties item 18 established still hold: a successful sync clears
everything, a failed one clears nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/mainwindow.h')
| -rw-r--r-- | src/mainwindow.h | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h index 2edeb79..cf9aca6 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -176,9 +176,17 @@ private: /// the one on screen. void markCurrentThreadRead(); - /// Redraws the unsynced-edits indicator from m_pendingEdits. + /// Redraws the unsynced-edits indicator from pendingEditCount(). void updatePendingIndicator(); + /// Records one confirmed (message, tag) change, cancelling it against an + /// opposite change already outstanding for the same pair. + void recordPendingEdit(const QString &messageId, const QString &tag, + bool added); + + /// Net changes the index holds that a sync has not carried over. + int pendingEditCount() const; + /// Shows or hides the "syncing" state: the progress bar and a disabled /// Sync button. /// @@ -318,7 +326,17 @@ private: /// /// A lower bound on what is outstanding, never a guarantee: the user's cron /// can run notmuch new without the application noticing. - int m_pendingEdits = 0; + /// + /// NET state rather than a tally of writes. Keyed "<messageId>\n<tag>", + /// value true for added and false for removed; a pair that reverts is + /// erased rather than stored, so an edit and its inverse leave nothing + /// behind and the map cannot grow without bound. + QHash<QString, bool> m_pendingTagEdits; + + /// Confirmed changes carrying no message ids, which cannot be netted + /// against anything. Counted separately rather than dropped: understating + /// the indicator is the direction that costs the user work. + int m_unnettablePendingEdits = 0; /// Marks the open thread read once it has been on screen long enough. /// |
