feat: Wino-style compact mail view with display modes + hover actions
- CompactMailDelegate: 3 display modes (Compact/Medium/Spacious) like WinUI original * Compact: 64px, minimal, no preview * Medium: 96px, with preview, detailed categories * Spacious: 120px, full padding, preview visible - Hover actions: Reply (↩), Forward (↪), Mark unread (✎) on right side - Unread dot indicator (top-right, blue) like WinUI - User-configurable display mode via combo box in filter bar - MainMainWindow handlers for reply/forward/mark-unread from compact view - Signals: replyRequested, forwardRequested, markUnreadRequested
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "CompactMailDelegate.h"
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QCursor>
|
||||
|
||||
CompactMailDelegate::CompactMailDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
@@ -11,11 +13,28 @@ void CompactMailDelegate::setConfig(const Config& config)
|
||||
m_config = config;
|
||||
}
|
||||
|
||||
void CompactMailDelegate::setDisplayMode(DisplayMode mode)
|
||||
{
|
||||
m_config.displayMode = mode;
|
||||
m_config.cardHeight = cardHeightForMode(mode);
|
||||
m_config.showPreviewText = (mode != Compact);
|
||||
}
|
||||
|
||||
QSize CompactMailDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(index);
|
||||
return QSize(0, m_config.cardHeight); // width will be determined by view
|
||||
return QSize(0, m_config.cardHeight);
|
||||
}
|
||||
|
||||
int CompactMailDelegate::cardHeightForMode(DisplayMode mode) const
|
||||
{
|
||||
switch (mode) {
|
||||
case Compact: return 64;
|
||||
case Medium: return 96;
|
||||
case Spacious: return 120;
|
||||
}
|
||||
return 76;
|
||||
}
|
||||
|
||||
void CompactMailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
@@ -24,6 +43,8 @@ void CompactMailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
||||
|
||||
bool hovered = (option.state & QStyle::State_MouseOver);
|
||||
m_hovered = hovered;
|
||||
drawCard(painter, option, index);
|
||||
|
||||
painter->restore();
|
||||
@@ -35,9 +56,9 @@ bool CompactMailDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QPoint pos = mouseEvent->pos();
|
||||
|
||||
// Check if click is on an action button
|
||||
// Check action buttons
|
||||
for (const ActionButton &btn : m_lastButtons) {
|
||||
if (btn.rect.contains(pos)) {
|
||||
if (btn.visible && btn.rect.contains(pos)) {
|
||||
int mailId = index.data(EmailListModel::IdRole).toInt();
|
||||
switch (btn.type) {
|
||||
case ActionFlag:
|
||||
@@ -57,21 +78,60 @@ bool CompactMailDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
}
|
||||
}
|
||||
|
||||
// Click on card body (not buttons) - select mail
|
||||
// Check hover actions (reply, forward, mark unread)
|
||||
if (m_config.hoverActionsEnabled && m_hovered) {
|
||||
int mailId = index.data(EmailListModel::IdRole).toInt();
|
||||
QRect cardRect = m_lastCardRect;
|
||||
int actionAreaX = cardRect.left() + (m_config.showAvatar ? m_config.avatarSize + 10 : 0);
|
||||
int actionAreaWidth = 100; // area for hover actions on the right
|
||||
QRect hoverActionRect(cardRect.right() - actionAreaWidth, cardRect.top(), actionAreaWidth, cardRect.height());
|
||||
|
||||
if (hoverActionRect.contains(pos)) {
|
||||
// Determine which hover action based on vertical position
|
||||
int third = cardRect.height() / 3;
|
||||
int relativeY = pos.y() - cardRect.top();
|
||||
if (relativeY < third) {
|
||||
emit replyRequested(mailId);
|
||||
} else if (relativeY < 2 * third) {
|
||||
emit forwardRequested(mailId);
|
||||
} else {
|
||||
emit markUnreadRequested(mailId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Click on card body - select mail
|
||||
int mailId = index.data(EmailListModel::IdRole).toInt();
|
||||
emit mailClicked(mailId);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::Enter) {
|
||||
m_hovered = true;
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
m_hovered = false;
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QRect cardRect = option.rect.adjusted(4, 2, -4, -2); // margins
|
||||
QRect cardRect = option.rect.adjusted(4, 2, -4, -2);
|
||||
m_lastCardRect = cardRect;
|
||||
|
||||
bool isSelected = option.state & QStyle::State_Selected;
|
||||
bool isHovered = option.state & QStyle::State_MouseOver;
|
||||
bool isUnread = !index.data(EmailListModel::ReadRole).toBool();
|
||||
bool isFlagged = index.data(EmailListModel::FlaggedRole).toBool();
|
||||
bool hasAttachments = !index.data(EmailListModel::AttachmentsRole).value<QVector<QString>>().isEmpty();
|
||||
|
||||
// Data from model
|
||||
QString sender = index.data(EmailListModel::SenderRole).toString();
|
||||
QString subject = index.data(EmailListModel::SubjectRole).toString();
|
||||
QString previewText = index.data(EmailListModel::SubjectRole).toString(); // Using subject as preview for now
|
||||
QDateTime date = index.data(EmailListModel::DateRole).toDateTime();
|
||||
|
||||
// Background
|
||||
QColor bgColor;
|
||||
@@ -86,18 +146,13 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
|
||||
}
|
||||
|
||||
painter->setBrush(bgColor);
|
||||
painter->setPen(QColor(0xe8, 0xe8, 0xed)); // separator color
|
||||
painter->setPen(QColor(0xe8, 0xe8, 0xed));
|
||||
painter->drawRoundedRect(cardRect, 8, 8);
|
||||
|
||||
// Inner padding
|
||||
QRect contentRect = cardRect.adjusted(12, 8, -12, -8);
|
||||
|
||||
// Data from model
|
||||
QString sender = index.data(EmailListModel::SenderRole).toString();
|
||||
QString subject = index.data(EmailListModel::SubjectRole).toString();
|
||||
QDateTime date = index.data(EmailListModel::DateRole).toDateTime();
|
||||
bool hasAttachments = !index.data(EmailListModel::AttachmentsRole).value<QVector<QString>>().isEmpty();
|
||||
bool flagged = index.data(EmailListModel::FlaggedRole).toBool();
|
||||
// Inner padding based on display mode
|
||||
int hPadding = (m_config.displayMode == Spacious) ? 16 : 12;
|
||||
int vPadding = (m_config.displayMode == Spacious) ? 12 : 8;
|
||||
QRect contentRect = cardRect.adjusted(hPadding, vPadding, -hPadding, -vPadding);
|
||||
|
||||
int x = contentRect.left();
|
||||
int y = contentRect.top();
|
||||
@@ -121,11 +176,24 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
|
||||
subjectFont.setPointSizeF(12);
|
||||
subjectFont.setWeight(QFont::Normal);
|
||||
|
||||
QFont previewFont = QApplication::font();
|
||||
previewFont.setPointSizeF(11);
|
||||
|
||||
QFont dateFont = QApplication::font();
|
||||
dateFont.setPointSizeF(11);
|
||||
|
||||
QFont actionFont = QApplication::font();
|
||||
actionFont.setPointSizeF(11);
|
||||
// Unread dot (top-right like WinUI)
|
||||
if (isUnread && m_config.showAvatar) {
|
||||
drawUnreadDot(painter, cardRect);
|
||||
}
|
||||
|
||||
// Flag indicator
|
||||
if (isFlagged && m_config.showAvatar) {
|
||||
QRect flagRect(x - m_config.avatarSize - 10 + m_config.avatarSize - 8, y, 12, 12);
|
||||
painter->setBrush(m_config.flagColor);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawEllipse(flagRect);
|
||||
}
|
||||
|
||||
// Line 1: Sender (left) + Date (right)
|
||||
int line1Y = y + 2;
|
||||
@@ -141,15 +209,18 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
|
||||
|
||||
// Draw sender
|
||||
painter->setFont(senderFont);
|
||||
painter->setPen(isUnread ? m_config.textPrimaryColor : m_config.textPrimaryColor);
|
||||
QColor senderColor = isUnread ? m_config.accentColor : m_config.textPrimaryColor;
|
||||
if (isSelected) senderColor = Qt::white;
|
||||
painter->setPen(senderColor);
|
||||
painter->drawText(QRect(x, line1Y, senderMaxWidth, senderFM.height()), Qt::AlignLeft | Qt::AlignVCenter, elidedSender);
|
||||
|
||||
// Draw date
|
||||
painter->setFont(dateFont);
|
||||
painter->setPen(m_config.textSecondaryColor);
|
||||
QColor dateColor = isSelected ? Qt::white : m_config.textSecondaryColor;
|
||||
painter->setPen(dateColor);
|
||||
painter->drawText(QRect(x + senderMaxWidth + 8, line1Y, dateWidth, dateFM.height()), Qt::AlignRight | Qt::AlignVCenter, dateStr);
|
||||
|
||||
// Line 2: Attachment icon + Subject
|
||||
// Line 2: Subject + Attachment icon
|
||||
int line2Y = line1Y + senderFM.height() + 2;
|
||||
QString subjectPrefix = "";
|
||||
int prefixWidth = 0;
|
||||
@@ -164,10 +235,27 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
|
||||
QString elidedSubject = elideText(painter, subject, subjectMaxWidth, subjectFont);
|
||||
|
||||
painter->setFont(subjectFont);
|
||||
painter->setPen(isUnread ? m_config.textPrimaryColor : m_config.textSecondaryColor);
|
||||
QColor subjectColor = isUnread ? m_config.textPrimaryColor : m_config.textSecondaryColor;
|
||||
if (isSelected) subjectColor = Qt::white;
|
||||
painter->setPen(subjectColor);
|
||||
painter->drawText(QRect(x, line2Y, prefixWidth, subjectFont.pointSizeF()), Qt::AlignLeft | Qt::AlignVCenter, subjectPrefix);
|
||||
painter->drawText(QRect(x + prefixWidth, line2Y, subjectMaxWidth, subjectFont.pointSizeF()), Qt::AlignLeft | Qt::AlignVCenter, elidedSubject);
|
||||
|
||||
// Line 3: Preview text (Medium/Spacious only)
|
||||
if (m_config.showPreviewText && m_config.displayMode != Compact) {
|
||||
int line3Y = line2Y + subjectFont.pointSizeF() + 4;
|
||||
int previewMaxWidth = availableWidth;
|
||||
QString elidedPreview = elideText(painter, previewText, previewMaxWidth, previewFont);
|
||||
|
||||
painter->setFont(previewFont);
|
||||
QColor previewColor = isSelected ? Qt::white : m_config.textSecondaryColor;
|
||||
painter->setPen(previewColor);
|
||||
painter->drawText(QRect(x, line3Y, previewMaxWidth, previewFont.pointSizeF()), Qt::AlignLeft | Qt::AlignVCenter, elidedPreview);
|
||||
}
|
||||
|
||||
// Categories (if enabled and present) - simplified for now
|
||||
// TODO: Add category support from model
|
||||
|
||||
// Action buttons (bottom)
|
||||
int buttonAreaY = cardRect.bottom() - 28;
|
||||
QRect buttonAreaRect(contentRect.left(), buttonAreaY, contentRect.width(), 24);
|
||||
@@ -177,12 +265,9 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
|
||||
|
||||
drawActionButtons(painter, buttonAreaRect, index, m_lastButtons);
|
||||
|
||||
// Flag indicator (small dot on top-right of avatar area if flagged)
|
||||
if (flagged && m_config.showAvatar) {
|
||||
QRect flagRect(x - m_config.avatarSize - 10 + m_config.avatarSize - 8, y, 12, 12);
|
||||
painter->setBrush(m_config.flagColor);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawEllipse(flagRect);
|
||||
// Hover actions (right side)
|
||||
if (m_config.hoverActionsEnabled && isHovered) {
|
||||
drawHoverActions(painter, cardRect, index, isHovered);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +281,6 @@ void CompactMailDelegate::drawAvatar(QPainter *painter, const QRect &rect, const
|
||||
// Initial
|
||||
QString initial;
|
||||
if (!sender.isEmpty()) {
|
||||
// Extract first letter of first name or email
|
||||
QString clean = sender;
|
||||
int lt = clean.indexOf('<');
|
||||
if (lt > 0) clean = clean.left(lt).trimmed();
|
||||
@@ -217,15 +301,57 @@ void CompactMailDelegate::drawAvatar(QPainter *painter, const QRect &rect, const
|
||||
painter->drawText(rect, Qt::AlignCenter, initial);
|
||||
}
|
||||
|
||||
void CompactMailDelegate::drawUnreadDot(QPainter *painter, const QRect &cardRect) const
|
||||
{
|
||||
// Draw unread indicator dot at top-right of card (like WinUI)
|
||||
int dotSize = 8;
|
||||
QRect dotRect(cardRect.right() - 12 - dotSize, cardRect.top() + 12, dotSize, dotSize);
|
||||
painter->setBrush(m_config.unreadDotColor);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawEllipse(dotRect);
|
||||
}
|
||||
|
||||
void CompactMailDelegate::drawHoverActions(QPainter *painter, const QRect &cardRect, const QModelIndex &index, bool hovered) const
|
||||
{
|
||||
if (!hovered) return;
|
||||
|
||||
Q_UNUSED(index);
|
||||
|
||||
// Draw 3 hover action icons on the right side
|
||||
int actionSize = 28;
|
||||
int spacing = 4;
|
||||
int totalHeight = 3 * actionSize + 2 * spacing;
|
||||
int startY = cardRect.center().y() - totalHeight / 2;
|
||||
int actionX = cardRect.right() - 12 - actionSize;
|
||||
|
||||
QFont font = QApplication::font();
|
||||
font.setPointSizeF(14);
|
||||
painter->setFont(font);
|
||||
|
||||
QString actions[3] = {"↩", "↪", "✎"}; // Reply, Forward, Mark unread
|
||||
QColor actionColor = m_config.accentColor;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QRect actionRect(actionX, startY + i * (actionSize + spacing), actionSize, actionSize);
|
||||
|
||||
// Background on hover
|
||||
painter->setBrush(QColor(0x00, 0x71, 0xe3, 0x15));
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->drawRoundedRect(actionRect, 6, 6);
|
||||
|
||||
// Icon
|
||||
painter->setPen(actionColor);
|
||||
painter->drawText(actionRect, Qt::AlignCenter, actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
QColor CompactMailDelegate::avatarColorForSender(const QString &sender) const
|
||||
{
|
||||
// Hash-based color from sender email/name
|
||||
uint hash = 0;
|
||||
for (QChar c : sender) {
|
||||
hash = hash * 31 + c.unicode();
|
||||
}
|
||||
|
||||
// Predefined pleasant colors (macOS Mail style)
|
||||
static const QColor colors[] = {
|
||||
QColor(0xff, 0x3b, 0x30), // red
|
||||
QColor(0xff, 0x95, 0x00), // orange
|
||||
@@ -242,30 +368,6 @@ QColor CompactMailDelegate::avatarColorForSender(const QString &sender) const
|
||||
return colors[hash % 10];
|
||||
}
|
||||
|
||||
CompactMailDelegate::ActionButton CompactMailDelegate::makeButton(ActionButtonType type, const QRect &rect) const
|
||||
{
|
||||
QString icon, tooltip;
|
||||
switch (type) {
|
||||
case ActionFlag:
|
||||
icon = "★";
|
||||
tooltip = "Marcar para seguimiento";
|
||||
break;
|
||||
case ActionDelete:
|
||||
icon = "🗑";
|
||||
tooltip = "Borrar";
|
||||
break;
|
||||
case ActionCategory:
|
||||
icon = "🏷";
|
||||
tooltip = "Categoría";
|
||||
break;
|
||||
case ActionMore:
|
||||
icon = "⋯";
|
||||
tooltip = "Más opciones";
|
||||
break;
|
||||
}
|
||||
return {type, icon, tooltip, rect};
|
||||
}
|
||||
|
||||
QVector<CompactMailDelegate::ActionButton> CompactMailDelegate::layoutActionButtons(const QRect &areaRect) const
|
||||
{
|
||||
QVector<ActionButton> buttons;
|
||||
@@ -275,10 +377,12 @@ QVector<CompactMailDelegate::ActionButton> CompactMailDelegate::layoutActionButt
|
||||
int startX = areaRect.left() + (areaRect.width() - totalWidth) / 2;
|
||||
int y = areaRect.top() + (areaRect.height() - buttonSize) / 2;
|
||||
|
||||
QString icons[] = {"★", "🗑", "🏷", "⋯"};
|
||||
|
||||
for (int i = 0; i < m_config.actionOrder.size(); ++i) {
|
||||
ActionButtonType type = m_config.actionOrder[i];
|
||||
QRect btnRect(startX + i * (buttonSize + spacing), y, buttonSize, buttonSize);
|
||||
buttons.append(makeButton(type, btnRect));
|
||||
buttons.append({type, icons[type], "", btnRect, true});
|
||||
}
|
||||
|
||||
return buttons;
|
||||
@@ -294,6 +398,8 @@ void CompactMailDelegate::drawActionButtons(QPainter *painter, const QRect &area
|
||||
painter->setFont(font);
|
||||
|
||||
for (const ActionButton &btn : buttons) {
|
||||
if (!btn.visible) continue;
|
||||
|
||||
// Icon
|
||||
painter->setPen(m_config.textSecondaryColor);
|
||||
painter->drawText(btn.rect, Qt::AlignCenter, btn.icon);
|
||||
@@ -320,7 +426,7 @@ QString CompactMailDelegate::formatDateRelative(const QDateTime &date) const
|
||||
QDate today = QDate::currentDate();
|
||||
if (d == today) return date.toString("HH:mm");
|
||||
if (d == today.addDays(-1)) return "Ayer";
|
||||
if (d > today.addDays(-7)) return d.toString("ddd"); // "lun", "mar"...
|
||||
if (d > today.addDays(-7)) return d.toString("ddd");
|
||||
if (d.year() == today.year()) return d.toString("dd/MM");
|
||||
return d.toString("dd/MM/yy");
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ class CompactMailDelegate : public QStyledItemDelegate
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DisplayMode {
|
||||
Compact = 0, // 64px - minimal, no preview
|
||||
Medium = 1, // 96px - with preview, detailed categories
|
||||
Spacious = 2 // Auto - full padding, preview visible
|
||||
};
|
||||
|
||||
enum ActionButtonType {
|
||||
ActionFlag = 0,
|
||||
ActionDelete = 1,
|
||||
@@ -33,17 +39,22 @@ public:
|
||||
QString icon;
|
||||
QString tooltip;
|
||||
QRect rect;
|
||||
bool visible = true;
|
||||
};
|
||||
|
||||
struct Config {
|
||||
DisplayMode displayMode = Compact;
|
||||
bool showAvatar = true;
|
||||
int avatarSize = 36;
|
||||
int cardHeight = 76;
|
||||
int cardHeight = 76; // Compact default
|
||||
int thresholdWidth = 420;
|
||||
QVector<ActionButtonType> actionOrder = {ActionFlag, ActionDelete, ActionCategory, ActionMore};
|
||||
bool showAttachmentIcon = true;
|
||||
bool showDateRelative = true;
|
||||
QColor unreadBgColor = QColor(0xe3, 0xf2, 0xfd); // light blue
|
||||
bool showPreviewText = false; // only in Medium/Spacious
|
||||
bool showCategories = true;
|
||||
bool hoverActionsEnabled = true;
|
||||
QColor unreadBgColor = QColor(0xe3, 0xf2, 0xfd);
|
||||
QColor readBgColor = QColor(0xff, 0xff, 0xff);
|
||||
QColor hoverBgColor = QColor(0xf0, 0xf0, 0xf5);
|
||||
QColor selectedBgColor = QColor(0xd6, 0xe8, 0xf7);
|
||||
@@ -51,6 +62,7 @@ public:
|
||||
QColor textSecondaryColor = QColor(0x86, 0x86, 0x8b);
|
||||
QColor accentColor = QColor(0x00, 0x71, 0xe3);
|
||||
QColor flagColor = QColor(0xff, 0x3b, 0x30);
|
||||
QColor unreadDotColor = QColor(0x00, 0x71, 0xe3);
|
||||
};
|
||||
|
||||
explicit CompactMailDelegate(QObject *parent = nullptr);
|
||||
@@ -58,6 +70,7 @@ public:
|
||||
|
||||
void setConfig(const Config& config);
|
||||
Config config() const { return m_config; }
|
||||
void setDisplayMode(DisplayMode mode);
|
||||
|
||||
// QStyledItemDelegate interface
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
@@ -68,20 +81,27 @@ signals:
|
||||
void flagRequested(int mailId);
|
||||
void deleteRequested(int mailId);
|
||||
void categoryRequested(int mailId);
|
||||
void moreRequested(int mailId, const QPoint& globalPos); // for context menu
|
||||
void moreRequested(int mailId, const QPoint& globalPos);
|
||||
void mailClicked(int mailId);
|
||||
void replyRequested(int mailId);
|
||||
void forwardRequested(int mailId);
|
||||
void markUnreadRequested(int mailId);
|
||||
|
||||
private:
|
||||
void drawCard(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
void drawAvatar(QPainter *painter, const QRect &rect, const QString &sender) const;
|
||||
void drawUnreadDot(QPainter *painter, const QRect &cardRect) const;
|
||||
void drawHoverActions(QPainter *painter, const QRect &cardRect, const QModelIndex &index, bool hovered) const;
|
||||
QColor avatarColorForSender(const QString &sender) const;
|
||||
void drawActionButtons(QPainter *painter, const QRect &cardRect, const QModelIndex &index, const QVector<ActionButton>& buttons) const;
|
||||
QVector<ActionButton> layoutActionButtons(const QRect &cardRect) const;
|
||||
ActionButton makeButton(ActionButtonType type, const QRect &rect) const;
|
||||
QString formatDateRelative(const QDateTime &date) const;
|
||||
QString elideText(QPainter *painter, const QString &text, int maxWidth, const QFont &font) const;
|
||||
int cardHeightForMode(DisplayMode mode) const;
|
||||
|
||||
Config m_config;
|
||||
mutable QVector<ActionButton> m_lastButtons; // for hit testing
|
||||
mutable QVector<ActionButton> m_lastButtons;
|
||||
mutable QModelIndex m_lastIndex;
|
||||
mutable QRect m_lastCardRect;
|
||||
mutable bool m_hovered = false;
|
||||
};
|
||||
@@ -70,6 +70,22 @@ void MailListView::setupUI()
|
||||
|
||||
filterLayout->addStretch();
|
||||
|
||||
// Display mode combo (Compact/Medium/Spacious)
|
||||
m_displayModeCombo = new QComboBox();
|
||||
m_displayModeCombo->addItem("Compacto");
|
||||
m_displayModeCombo->addItem("Medio");
|
||||
m_displayModeCombo->addItem("Espacioso");
|
||||
m_displayModeCombo->setFixedWidth(120);
|
||||
m_displayModeCombo->setStyleSheet(
|
||||
"QComboBox { border: 1px solid #d1d1d6; border-radius: 4px; padding: 4px 8px; "
|
||||
"background: white; min-height: 20px; }"
|
||||
"QComboBox:hover { border-color: #bdbdbd; }"
|
||||
"QComboBox:focus { border-color: #1976D2; }"
|
||||
);
|
||||
connect(m_displayModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &MailListView::onDisplayModeChanged);
|
||||
filterLayout->addWidget(m_displayModeCombo);
|
||||
|
||||
// Group by combo
|
||||
m_groupByCombo = new QComboBox();
|
||||
m_groupByCombo->addItem("Sin agrupación");
|
||||
@@ -282,4 +298,26 @@ void MailListView::onCompactMoreRequested(int mailId, const QPoint &globalPos)
|
||||
void MailListView::onCompactMailClicked(int mailId)
|
||||
{
|
||||
emit emailSelected(mailId);
|
||||
}
|
||||
|
||||
void MailListView::onCompactReplyRequested(int mailId)
|
||||
{
|
||||
emit replyRequested(mailId);
|
||||
}
|
||||
|
||||
void MailListView::onCompactForwardRequested(int mailId)
|
||||
{
|
||||
emit forwardRequested(mailId);
|
||||
}
|
||||
|
||||
void MailListView::onCompactMarkUnreadRequested(int mailId)
|
||||
{
|
||||
emit markUnreadRequested(mailId);
|
||||
}
|
||||
|
||||
void MailListView::onDisplayModeChanged(int index)
|
||||
{
|
||||
CompactMailDelegate::DisplayMode mode = static_cast<CompactMailDelegate::DisplayMode>(index);
|
||||
m_compactDelegate->setDisplayMode(mode);
|
||||
m_listView->update();
|
||||
}
|
||||
@@ -38,6 +38,9 @@ signals:
|
||||
void deleteRequested(int mailId);
|
||||
void categoryRequested(int mailId);
|
||||
void moreRequested(int mailId, const QPoint& globalPos);
|
||||
void replyRequested(int mailId);
|
||||
void forwardRequested(int mailId);
|
||||
void markUnreadRequested(int mailId);
|
||||
|
||||
private slots:
|
||||
void onRowSelected(const QModelIndex &index);
|
||||
@@ -49,6 +52,10 @@ private slots:
|
||||
void onCompactCategoryRequested(int mailId);
|
||||
void onCompactMoreRequested(int mailId, const QPoint& globalPos);
|
||||
void onCompactMailClicked(int mailId);
|
||||
void onCompactReplyRequested(int mailId);
|
||||
void onCompactForwardRequested(int mailId);
|
||||
void onCompactMarkUnreadRequested(int mailId);
|
||||
void onDisplayModeChanged(int index);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
@@ -70,7 +77,8 @@ private:
|
||||
QCheckBox *m_flaggedOnlyCheck;
|
||||
QCheckBox *m_hasAttachmentsCheck;
|
||||
QComboBox *m_groupByCombo;
|
||||
QComboBox *m_displayModeCombo;
|
||||
CompactMailDelegate *m_compactDelegate = nullptr;
|
||||
bool m_compactMode = false;
|
||||
int m_compactThreshold = 420;
|
||||
int m_compactThreshold = 500;
|
||||
};
|
||||
@@ -261,6 +261,9 @@ void MainMainWindow::setupMailPage()
|
||||
connect(m_mailListView, &MailListView::deleteRequested, this, &MainMainWindow::onDeleteRequested);
|
||||
connect(m_mailListView, &MailListView::categoryRequested, this, &MainMainWindow::onCategoryRequested);
|
||||
connect(m_mailListView, &MailListView::moreRequested, this, &MainMainWindow::onMoreRequested);
|
||||
connect(m_mailListView, &MailListView::replyRequested, this, &MainMainWindow::onReplyRequested);
|
||||
connect(m_mailListView, &MailListView::forwardRequested, this, &MainMainWindow::onForwardRequested);
|
||||
connect(m_mailListView, &MailListView::markUnreadRequested, this, &MainMainWindow::onMarkUnreadRequested);
|
||||
m_folderSplitter->addWidget(m_mailListView);
|
||||
|
||||
// Viewer stack: placeholder, reader, compose
|
||||
@@ -525,6 +528,30 @@ void MainMainWindow::onMoreRequested(int mailId, const QPoint &globalPos)
|
||||
menu.exec(globalPos);
|
||||
}
|
||||
|
||||
void MainMainWindow::onReplyRequested(int mailId)
|
||||
{
|
||||
onReaderReplyRequested(mailId);
|
||||
}
|
||||
|
||||
void MainMainWindow::onForwardRequested(int mailId)
|
||||
{
|
||||
onReaderForwardRequested(mailId);
|
||||
}
|
||||
|
||||
void MainMainWindow::onMarkUnreadRequested(int mailId)
|
||||
{
|
||||
auto item = MailItemDao::findById(mailId);
|
||||
if (item.has_value()) {
|
||||
item->setRead(false);
|
||||
MailItemDao::update(*item);
|
||||
m_emailModel->refresh();
|
||||
if (m_currentMailId == mailId) {
|
||||
m_emailViewer->setMailItem(&*item);
|
||||
}
|
||||
statusBar()->showMessage(tr("Marcado como no leído"), 2000);
|
||||
}
|
||||
}
|
||||
|
||||
void MainMainWindow::onNewMessage()
|
||||
{ // Show compose view in the viewer stack
|
||||
m_embeddedComposeView->initializeComposition();
|
||||
|
||||
@@ -79,6 +79,9 @@ private slots:
|
||||
void onDeleteRequested(int mailId);
|
||||
void onCategoryRequested(int mailId);
|
||||
void onMoreRequested(int mailId, const QPoint &globalPos);
|
||||
void onReplyRequested(int mailId);
|
||||
void onForwardRequested(int mailId);
|
||||
void onMarkUnreadRequested(int mailId);
|
||||
|
||||
// Slots for embedded compose view
|
||||
void onEmbeddedSendRequested(const QString &to, const QString &cc, const QString &bcc,
|
||||
|
||||
Reference in New Issue
Block a user