aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-26 16:03:49 +0200
committerDanilo M. <danix@danix.xyz>2026-08-26 16:03:49 +0200
commitbd90331cba3633754482fc13b99ae39a3b5f79a2 (patch)
treed850c76f382aa94db5139edceb72c18bc08851ec /src
parentef4d48c56c39f19efc751488cc2df6ee5af24a7f (diff)
downloadqtmaildir-bd90331cba3633754482fc13b99ae39a3b5f79a2.tar.gz
qtmaildir-bd90331cba3633754482fc13b99ae39a3b5f79a2.zip
feat: draw a sender's avatar on every card
Diffstat (limited to 'src')
-rw-r--r--src/carddelegate.cpp33
-rw-r--r--src/carddelegate.h28
2 files changed, 61 insertions, 0 deletions
diff --git a/src/carddelegate.cpp b/src/carddelegate.cpp
index 6541932..89c3ed0 100644
--- a/src/carddelegate.cpp
+++ b/src/carddelegate.cpp
@@ -18,6 +18,8 @@
#include "carddelegate.h"
+#include "avatar.h"
+#include "businesssenders.h"
#include "cardlayout.h"
#include "marks.h"
#include "tagchip.h"
@@ -160,6 +162,21 @@ QSize CardDelegate::sizeHint(const QStyleOptionViewItem &option,
return QSize(option.rect.width(), CardLayout::heightFor(option.font));
}
+QPixmap CardDelegate::avatarFor(const QString &senderAddress,
+ const QString &senderName,
+ const QString &accountAddress,
+ const QString &accountLabel,
+ bool isBusinessSender, int side,
+ const QFont &font)
+{
+ const bool haveSender = !senderAddress.trimmed().isEmpty();
+ const QString seed = haveSender ? senderAddress : accountAddress;
+ const QString initials =
+ Avatar::initialsFor(senderName, senderAddress, accountLabel);
+ const Avatar::Fill fill = Avatar::fillFor(senderName, isBusinessSender);
+ return Avatar::pixmapFor(seed, initials, fill, side, font);
+}
+
void CardDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
@@ -232,6 +249,22 @@ void CardDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
painter->fillRect(spine, spineColour);
}
+ // The sender's squircle, in the layout's reserved gutter. Drawn before the
+ // text so a wide avatar can never overprint the sender line.
+ if (!card.avatarRect.isEmpty()) {
+ const QString senderAddress =
+ index.data(ThreadListModel::SenderAddressRole).toString();
+ const QString senderName =
+ index.data(ThreadListModel::SenderNameRole).toString();
+ painter->drawPixmap(
+ card.avatarRect,
+ avatarFor(senderAddress, senderName, m_accountAddress,
+ m_accountLabel,
+ BusinessSenders::contains(m_businessSenders,
+ senderAddress),
+ card.avatarRect.width(), option.font));
+ }
+
// Selection outranks the model's foreground, and the order matters: a read
// card carries a dimmed colour blended against the UNSELECTED background,
// so over the highlight it lands grey-on-highlight and close to unreadable.
diff --git a/src/carddelegate.h b/src/carddelegate.h
index 5a0830c..18c735f 100644
--- a/src/carddelegate.h
+++ b/src/carddelegate.h
@@ -18,6 +18,7 @@
#pragma once
+#include "businesssenders.h"
#include "tagchip.h"
/// Paints a whole card: three lines, all of it, including the tag chips.
@@ -109,4 +110,31 @@ public:
/// survived exactly that kind of test.
static QSize chipSize(const QFontMetrics &metrics, const QString &text,
bool own);
+
+ /// The squircle for one row, resolved from what the model supplies.
+ ///
+ /// Falls back to the ACCOUNT when the row has no sender address, so every
+ /// card carries an avatar rather than a hole: the seed becomes the
+ /// account's own address and the letters come from its label.
+ static QPixmap avatarFor(const QString &senderAddress,
+ const QString &senderName,
+ const QString &accountAddress,
+ const QString &accountLabel,
+ bool isBusinessSender, int side,
+ const QFont &font);
+
+ void setAccountAddress(const QString &address)
+ {
+ m_accountAddress = address;
+ }
+ void setAccountLabel(const QString &label) { m_accountLabel = label; }
+ void setBusinessSenders(const BusinessSenders::List &list)
+ {
+ m_businessSenders = list;
+ }
+
+private:
+ QString m_accountAddress;
+ QString m_accountLabel;
+ BusinessSenders::List m_businessSenders;
};