summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-24 10:50:35 +0200
committerDanilo M. <danix@danix.xyz>2026-08-24 10:50:35 +0200
commitf814bb57c03e01c96ec97c2bfb2d314210a95f28 (patch)
tree298d133b94c5fa0a3f99cf8041f6849b46cde3a1 /tests
parent22f01049b03f3a6bbe0455f96105a73d37abb3ee (diff)
downloadqtmaildir-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 'tests')
-rw-r--r--tests/test_messageview.cpp76
1 files changed, 76 insertions, 0 deletions
diff --git a/tests/test_messageview.cpp b/tests/test_messageview.cpp
index c0c9bc2..f9268ef 100644
--- a/tests/test_messageview.cpp
+++ b/tests/test_messageview.cpp
@@ -16,9 +16,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QPushButton>
+#include <QRegularExpression>
#include <QSet>
#include <QSignalSpy>
#include <QWebEnginePage>
@@ -66,6 +68,7 @@ private slots:
void aPlainLinkOpensExternally();
void aTargetBlankLinkOpensExternally();
void theLinkMenuDropsTheOpenInWindowActions();
+ void theNoticeBarsCarryTheirSeverityAndFollowTheTheme();
private:
QWebEngineView *webViewOf(MessageView *view) const
@@ -1165,5 +1168,78 @@ void TestMessageView::theLinkMenuDropsTheOpenInWindowActions()
}
}
+void TestMessageView::theNoticeBarsCarryTheirSeverityAndFollowTheTheme()
+{
+ // The bars are the pane's only out-of-band messages, and they read as part
+ // of the page until they carry a ground of their own. Two severities: a
+ // warning that explains a limitation and offers nothing to do about it,
+ // and an action the user can take.
+ MessageView view;
+
+ auto *warning =
+ view.findChild<QWidget *>(QStringLiteral("receiveOnlyRibbon"));
+ auto *blocked =
+ view.findChild<QWidget *>(QStringLiteral("blockedContentBar"));
+ auto *stale = view.findChild<QWidget *>(QStringLiteral("staleThreadBar"));
+ QVERIFY2(warning && blocked && stale, "a notice bar is missing");
+
+ // Asserting on the stylesheet STRING rather than on a rendered pixel, for
+ // the reason CLAUDE.md records about rendering probes: an unshown widget
+ // under the offscreen platform renders nothing, so a pixel test here would
+ // pass whatever the code does.
+ const QString warningSheet = warning->styleSheet();
+ const QString blockedSheet = blocked->styleSheet();
+ const QString staleSheet = stale->styleSheet();
+
+ for (const QString &sheet : { warningSheet, blockedSheet, staleSheet }) {
+ QVERIFY2(sheet.contains(QStringLiteral("background")),
+ qPrintable(QStringLiteral("a bar paints no ground: %1")
+ .arg(sheet)));
+ }
+
+ // The two severities must not look alike, which is the whole point: a
+ // warning and an action reading identically is the state being fixed.
+ QVERIFY2(warningSheet != blockedSheet,
+ "the warning and the action bar share one appearance");
+
+ // Both action bars are the same severity and must agree on their COLOURS.
+ // Not on the whole sheet: each names its own widget, so the strings differ
+ // by that alone. Compare what carries the severity instead.
+ const QRegularExpression hex(QStringLiteral("#[0-9a-fA-F]{6}"));
+ const auto coloursOf = [&hex](const QString &sheet) {
+ QStringList found;
+ auto it = hex.globalMatch(sheet);
+ while (it.hasNext())
+ found << it.next().captured(0).toLower();
+ return found;
+ };
+ QVERIFY2(!coloursOf(blockedSheet).isEmpty(),
+ "the action bar names no colours at all");
+ QCOMPARE(coloursOf(blockedSheet), coloursOf(staleSheet));
+
+ // And the warning genuinely differs in colour, not merely in widget name.
+ QVERIFY2(coloursOf(warningSheet) != coloursOf(blockedSheet),
+ "the warning and the action bar use the same colours");
+
+ // The action bars put their button on the RIGHT. addStretch() at the end
+ // of the row left-aligns it, which is what both did.
+ for (QWidget *bar : { blocked, stale }) {
+ auto *row = qobject_cast<QHBoxLayout *>(bar->layout());
+ QVERIFY2(row, "an action bar has no horizontal row");
+ int lastWidget = -1;
+ int lastStretch = -1;
+ for (int i = 0; i < row->count(); ++i) {
+ if (row->itemAt(i)->widget())
+ lastWidget = i;
+ else if (row->itemAt(i)->spacerItem())
+ lastStretch = i;
+ }
+ QVERIFY2(lastStretch >= 0 && lastWidget >= 0,
+ "an action bar has no stretch, so nothing is aligned");
+ QVERIFY2(lastStretch < lastWidget,
+ "the stretch comes after the button, left-aligning it");
+ }
+}
+
QTEST_MAIN(TestMessageView)
#include "test_messageview.moc"