diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-11 19:02:59 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-11 19:02:59 +0200 |
| commit | 72812c0ac053a1a841f3864c9e4cce5cb6dab04a (patch) | |
| tree | 26285a20ab686b1f4bb1e51e0dfbfa16e4307d1b /src/mainwindow.h | |
| parent | ddce3f3b198b733bd1815cd11c083f0d5ae0beb7 (diff) | |
| download | qtmaildir-72812c0ac053a1a841f3864c9e4cce5cb6dab04a.tar.gz qtmaildir-72812c0ac053a1a841f3864c9e4cce5cb6dab04a.zip | |
feat(placeholder): count sent mail and drafts on the blank pane
Item 67. The pane counted unread, flagged and inbox from three fixed
tag: queries. Sent and drafts cannot join that list as tags: tag:draft
counts 0 against a real database and no draft-ish tag exists in it at
all, so a tag-based line would be a permanent zero that reads as working
code. Both are composed from each account's folder keys instead, the
same way the Sent view already composes its query.
The drafts key was parsed and documented as unused in v1. Composing
drafts is still v2; counting them is not, so Account::draftsQuery() and
Config::allDraftsQuery() now mirror the sent pair. The shared body moved
into folderQuery() and joinAccountQueries(), so the load-bearing quoting
(a provider nests both folders under a bracketed parent, and [ and ] are
Xapian syntax) and the bare-"or" guard exist once rather than once per
folder type.
The fixed array is gone rather than extended. It held queries and labels
in two lists indexed in parallel, which is a hazard that grows with the
list: an entry inserted in one and not the other prints a real number
against the wrong name and looks entirely plausible. placeholderLines()
carries each query beside the callable that labels it, so the two cannot
drift, and the count reply stays paired by position as the worker
requires.
A line is omitted when no account configures that folder rather than
shown as 0, following item 63: a missing folder is a real configuration,
and "0 sent" claims the user has sent nothing.
Measured against the real config: 4 sent terms over 601 threads, 5
drafts terms over 3, the extra drafts term coming from the one account
that configures drafts and no sent, which is what proves the two are
collected independently.
Four tests here and four in test_config, mutation-checked at three
points: dropping the drafts line, an off-by-one in the label pairing,
and removing the -1 guard for an uncountable query. Each mutation fails
a test.
Diffstat (limited to 'src/mainwindow.h')
| -rw-r--r-- | src/mainwindow.h | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h index 6e90ba1..0912520 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -165,6 +165,25 @@ public: return !m_recoverThreadId.isEmpty(); } + /// The placeholder's queries, in the order requestCounts() asks for them. + /// + /// A test seam. The worker's reply is paired with these POSITIONALLY, so a + /// test standing in for it has to know the order, and that order now + /// depends on config rather than on a fixed list. + QStringList placeholderQueriesForTesting() const + { + return placeholderQueries(); + } + + /// The helper lines as the pane would render them. + QList<HtmlBuilder::PlaceholderHelper> placeholderHelpersForTesting() const + { + return placeholderHelpers(); + } + + /// The generation the next counts reply must carry to be accepted. + quint64 countsGenerationForTesting() const { return m_countsGeneration; } + protected: void closeEvent(QCloseEvent *event) override; @@ -310,6 +329,30 @@ private: /// The helper lines, built from the last counts received. Rendered with /// whatever the previous answer was until the new one lands, so the pane /// never flashes empty while the worker replies. + /// One placeholder line: the query it counts, and how to label the answer. + /// + /// The label is a callable rather than a string because the count is not + /// known until the worker replies, and `tr("%n ...")` has to be given the + /// number to pick its plural form. + /// + /// Query and label travel together deliberately. The version this replaced + /// held them in two arrays indexed in parallel, where inserting an entry in + /// one and not the other put a real number against the wrong name. + struct PlaceholderLine { + QString query; + std::function<QString(int)> label; + }; + + /// The placeholder's lines, in render order. + /// + /// Built per call rather than cached: the sent and drafts lines come from + /// config, and a cache would be a second source of truth for the pairing + /// the counts reply depends on. + QList<PlaceholderLine> placeholderLines() const; + + /// Just the queries, in the order requestCounts() asks for them. + QStringList placeholderQueries() const; + QList<HtmlBuilder::PlaceholderHelper> placeholderHelpers() const; void showWarnings(); @@ -552,7 +595,7 @@ private: /// Indeterminate, shown only while a sync runs. See setSyncBusy(). QProgressBar *m_syncProgress = nullptr; - /// The last counts the worker answered, one per kPlaceholderQueries entry. + /// The last counts the worker answered, one per placeholderLines() entry. /// Empty until the first reply, which renders the pane without its helper /// lines rather than with three zeroes that would be a lie. QVector<int> m_placeholderCounts; |
