diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-24 10:50:35 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-24 10:50:35 +0200 |
| commit | f814bb57c03e01c96ec97c2bfb2d314210a95f28 (patch) | |
| tree | 298d133b94c5fa0a3f99cf8041f6849b46cde3a1 /src | |
| parent | 22f01049b03f3a6bbe0455f96105a73d37abb3ee (diff) | |
| download | qtmaildir-f814bb57c03e01c96ec97c2bfb2d314210a95f28.tar.gz qtmaildir-f814bb57c03e01c96ec97c2bfb2d314210a95f28.zip | |
feat(messageview): give the notice bars a ground and a severity
The three out-of-band bars in the message pane were plain labels on the
pane's own background, so they read as part of the page they were trying to
interrupt. They now carry a severity, as the user asked for:
- yellow for a warning that explains a limitation and offers nothing to do
about it (the receive-only ribbon)
- blue for one offering an action (remote content blocked, stale thread),
with the button moved right of a stretch, where the eye ends up after
reading the sentence
Each severity carries its own light and dark set rather than one tint
dimmed, and the theme is read off QPalette::Base, the same surface
HtmlBuilder reads, so a bar and the message under it cannot disagree about
which way round the theme is. Every ground states its own text colour: the
palette's may be near-white, which is unreadable on a pale tint.
The blocked row had to become a widget on the way. It was a bare
QHBoxLayout, which has nothing to paint a ground on, and once wrapped, the
six sites that hid its label and button individually had to hide the
wrapper instead or an empty painted strip would have been left behind.
The test asserts on the stylesheet string rather than on pixels, per
CLAUDE.md on rendering probes: an unshown widget offscreen renders nothing,
so a pixel test would pass whatever the code does. It compares the COLOURS
the sheets name rather than the sheets themselves, since each names its own
widget and would differ by that alone.
Diffstat (limited to 'src')
| -rw-r--r-- | src/messageview.cpp | 77 | ||||
| -rw-r--r-- | src/messageview.h | 7 |
2 files changed, 69 insertions, 15 deletions
diff --git a/src/messageview.cpp b/src/messageview.cpp index aa887ae..22df6ce 100644 --- a/src/messageview.cpp +++ b/src/messageview.cpp @@ -370,10 +370,17 @@ MessageView::MessageView(QWidget *parent) connect(m_loadRemoteButton, &QPushButton::clicked, this, &MessageView::loadRemoteContent); - auto *blockedRow = new QHBoxLayout; + // A WIDGET rather than a bare layout, because a layout has nothing to + // paint a ground on and this bar now carries one. + m_blockedBar = new QWidget(this); + m_blockedBar->setObjectName(QStringLiteral("blockedContentBar")); + auto *blockedRow = new QHBoxLayout(m_blockedBar); blockedRow->addWidget(m_blockedLabel); - blockedRow->addWidget(m_loadRemoteButton); + // The stretch BEFORE the button, so the thing to act on sits at the right + // edge where the eye ends up after reading the sentence. blockedRow->addStretch(); + blockedRow->addWidget(m_loadRemoteButton); + m_blockedBar->hide(); // The stale-thread notice, deliberately the same shape as the row above: // a sentence and a button, above the message, leaving it readable. The @@ -410,10 +417,9 @@ MessageView::MessageView(QWidget *parent) emit staleThreadRecoveryRequested(threadId, messageId); }); auto *staleRow = new QHBoxLayout(m_staleBar); - staleRow->setContentsMargins(0, 0, 0, 0); staleRow->addWidget(m_staleLabel); - staleRow->addWidget(m_staleButton); staleRow->addStretch(); + staleRow->addWidget(m_staleButton); m_staleBar->hide(); // Receive-only ribbon (item 123). Hidden until a message from an account @@ -452,13 +458,15 @@ MessageView::MessageView(QWidget *parent) auto *layout = new QVBoxLayout(this); layout->addLayout(headerRow); - layout->addLayout(blockedRow); + layout->addWidget(m_blockedBar); layout->addWidget(m_receiveOnlyRibbon); layout->addWidget(m_staleBar); layout->addWidget(m_view, 1); layout->addWidget(m_attachmentBar); layout->addWidget(m_tagStrip); + applyNoticeBarStyles(); + clear(); } @@ -500,8 +508,7 @@ void MessageView::showPlaceholder( m_headerLabel->clear(); m_detailsButton->hide(); - m_blockedLabel->hide(); - m_loadRemoteButton->hide(); + m_blockedBar->hide(); rebuildAttachmentBar(); // Set before the document loads, not after: acceptNavigationRequest reads @@ -517,6 +524,48 @@ void MessageView::showPlaceholder( HtmlBuilder::brandPaletteFrom(palette()))); } +void MessageView::applyNoticeBarStyles() +{ + // QPalette::Base, the same surface HtmlBuilder reads, so a bar and the + // message under it never disagree about which way round the theme is. + const bool dark = palette().color(QPalette::Base).lightnessF() < 0.5; + + // Yellow for a warning, blue for an action, as the user asked. The dark + // values are not the light ones dimmed: the same nominal tint behaves + // differently against near-black, so each set carries its own ground, + // border and text, and every ground states its text colour rather than + // inheriting one that may be near-white on a pale tint. + const QString warningGround = dark ? QStringLiteral("#3a2f0b") + : QStringLiteral("#fdf6d8"); + const QString warningBorder = dark ? QStringLiteral("#6b5a15") + : QStringLiteral("#e3d08a"); + const QString warningText = dark ? QStringLiteral("#f0e2a8") + : QStringLiteral("#4a3c05"); + + const QString actionGround = dark ? QStringLiteral("#0e2740") + : QStringLiteral("#e3f0fb"); + const QString actionBorder = dark ? QStringLiteral("#1d4a70") + : QStringLiteral("#a8cbe8"); + const QString actionText = dark ? QStringLiteral("#cfe4f7") + : QStringLiteral("#0d3355"); + + const QString sheet = QStringLiteral( + "QWidget#%1 { background: %2; border: 1px solid %3; " + "border-radius: 4px; } QWidget#%1 QLabel { color: %4; }"); + + m_receiveOnlyRibbon->setStyleSheet( + QStringLiteral("QLabel#receiveOnlyRibbon { background: %1; " + "border: 1px solid %2; border-radius: 4px; " + "color: %3; padding: 6px 8px; }") + .arg(warningGround, warningBorder, warningText)); + + for (QWidget *bar : { m_blockedBar, m_staleBar }) { + bar->setStyleSheet( + sheet.arg(bar->objectName(), actionGround, actionBorder, + actionText)); + } +} + void MessageView::clear() { m_items.clear(); @@ -531,8 +580,7 @@ void MessageView::clear() setDocument(QString()); m_headerLabel->clear(); - m_blockedLabel->hide(); - m_loadRemoteButton->hide(); + m_blockedBar->hide(); // The stale notice describes the message that WAS rendered, so it goes with // it, for the same reason as the blocked-content bar above. Left behind, it @@ -604,8 +652,7 @@ void MessageView::showError(const QString &text, const QString &filePath) m_interceptor->resetForNewMessage(); m_headerLabel->setText(tr("<b>Cannot display message</b>")); - m_blockedLabel->hide(); - m_loadRemoteButton->hide(); + m_blockedBar->hide(); const QString html = QStringLiteral( "<html><body><p>%1</p><p><code>%2</code></p></body></html>") @@ -1073,8 +1120,9 @@ void MessageView::render() QTimer::singleShot(300, this, [this]() { const bool blocked = m_interceptor->blockedAnything() && !m_interceptor->allowRemote(); - m_blockedLabel->setVisible(blocked); - m_loadRemoteButton->setVisible(blocked); + // The BAR, not its children: the wrapper carries the ground, so + // hiding only the label and button would leave a painted empty strip. + m_blockedBar->setVisible(blocked); }); } @@ -1379,7 +1427,6 @@ void MessageView::loadRemoteContent() { // Applies to this thread only and is cleared by the next showThread(). m_interceptor->setAllowRemote(true); - m_blockedLabel->hide(); - m_loadRemoteButton->hide(); + m_blockedBar->hide(); render(); } diff --git a/src/messageview.h b/src/messageview.h index 044bded..29101d6 100644 --- a/src/messageview.h +++ b/src/messageview.h @@ -334,6 +334,12 @@ private: /// thread with fifteen of them. void rebuildAttachmentBar(); + /// Paints the three notice bars: yellow for a warning that + /// explains a limitation, blue for one offering an action. + /// Reads QPalette::Base, as HtmlBuilder does, so the bars and + /// the message agree about the theme. + void applyNoticeBarStyles(); + /// The list of attachments, with a save button each and a "save all". void showAttachmentDialog(); @@ -399,6 +405,7 @@ private: CidSchemeHandler *m_cidHandler = nullptr; QLabel *m_headerLabel = nullptr; + QWidget *m_blockedBar = nullptr; QLabel *m_blockedLabel = nullptr; QLabel *m_receiveOnlyRibbon = nullptr; QPushButton *m_loadRemoteButton = nullptr; |
