diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-07 17:51:52 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-07 17:51:52 +0200 |
| commit | 334b510e2673a6ab3875ffa7a4c5b3b2dd09a369 (patch) | |
| tree | 59b38af32af41d629a0c02ecd8e0fcfcddbb60e6 /src/messageview.h | |
| parent | 6003bab2d4c491a857b7a728f2f23c719723ef1a (diff) | |
| download | qtmaildir-334b510e2673a6ab3875ffa7a4c5b3b2dd09a369.tar.gz qtmaildir-334b510e2673a6ab3875ffa7a4c5b3b2dd09a369.zip | |
feat(ui): fill the blank message pane with a branded placeholder
An empty right pane said nothing, and multi-select made it a routine
sight. It now carries the wordmark, thread counts that run their query
when clicked, and a sync line that appears only when something needs
attention.
Rendered into the existing web view as a third document shape, so there
is one document path and one set of security rules. The brand palette is
a deliberate exception to deriving colours from the desktop theme, since
a logo is brand rather than chrome; the theme still picks which of the
two sets is used.
Counts refresh when the pane is about to show rather than in the
background: one goes stale the moment a tag is edited, and refreshing one
nobody is looking at is work for nothing. A generation counter discards a
superseded reply, and a late answer cannot repaint over an opened thread.
The helper lines are real links because JavaScript is off in this
profile. The handler is gated on the placeholder actually being
displayed, so the same URL inside a message body is dropped: a stranger's
mail must not drive the thread list, even to run a harmless query.
Three defects found while building, all silent:
- Every CSS percentage was invalid. QString::arg does not collapse "%%"
into "%", so the document carried "50%%" and the browser dropped each
declaration holding one, disabling the mask, the glow and both radial
gradients while still rendering something plausible. Substitution is by
named token now, which cannot collide with a percent sign.
- A geometry probe endorsed the layout while that was live, because it
measured only properties without percentages.
- The font test passed against a build with one face missing, since the
other satisfied both of its checks on its own.
The mockup's light values needed correcting against a real pane: the grid
vanished at a 2% luminance step on white, and the glow subtracts light
there rather than adding it, washing the pane. Strength only, not hue.
Diffstat (limited to 'src/messageview.h')
| -rw-r--r-- | src/messageview.h | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/messageview.h b/src/messageview.h index c55f5c5..135c85d 100644 --- a/src/messageview.h +++ b/src/messageview.h @@ -59,6 +59,22 @@ public: void showError(const QString &text, const QString &filePath); void clear(); + /// Shows the branded pane used when no thread is displayed. + /// + /// Separate from clear(), which still exists and still blanks: clear() + /// drops the previous thread's state, and a caller that wants the + /// placeholder asks for it afterwards. Keeping them apart is what stops + /// the pane flashing a logo between selecting a thread and rendering it, + /// which the item lists as a constraint. + /// + /// helpers are already-translated lines; an empty query makes one plain + /// text rather than a link. + void showPlaceholder(const QList<HtmlBuilder::PlaceholderHelper> &helpers); + + /// True while the placeholder is what the view is showing. Lets the window + /// re-render it with fresh counts without guessing what is on screen. + bool showingPlaceholder() const { return m_showingPlaceholder; } + /// Supplies the tag strip's colours. Not owned; must outlive the view. void setTagColors(const TagColors *colours); @@ -98,6 +114,17 @@ public slots: signals: void statusMessage(const QString &text); + /// A helper line on the placeholder was clicked. The window runs the query; + /// the view has no business driving the query bar itself. + /// + /// **Gated on the placeholder being what is displayed.** A message body is + /// attacker-controlled HTML and can carry a qtmaildir-query: link as easily + /// as any other; without the gate, clicking one would let a stranger's mail + /// drive the thread list. The consequence is mild (a query runs, nothing is + /// mutated or sent), but "a link in a message does something inside the + /// app" is a boundary worth keeping shut rather than arguing about. + void queryRequested(const QString &query); + protected: /// Turns Ctrl+wheel over the body into zoom, and Ctrl+middle-click into a /// reset. Both events are delivered to the web view's internal QQuickWidget @@ -147,6 +174,9 @@ private: QList<ThreadRenderItem> m_items; bool m_preferHtml = true; + /// Gates queryRequested(), so a link in a message body cannot run a query. + bool m_showingPlaceholder = false; + QWebEngineProfile *m_profile = nullptr; QWebEngineView *m_view = nullptr; RequestInterceptor *m_interceptor = nullptr; |
