[Client] Active pill for alts table, dismissed pill for report queue

This commit is contained in:
Lukas Brübach 2026-10-13 22:55:41 +02:00
parent 2de068270d
commit e105ba4f1b
5 changed files with 31 additions and 10 deletions

View file

@ -15,9 +15,14 @@ constexpr int PILL_PAD_Y = 4;
constexpr int ICON_TEXT_GAP = 4; constexpr int ICON_TEXT_GAP = 4;
} // namespace } // namespace
AltTableDelegate::AltTableDelegate(int viaColumn, int warnsColumn, int bansColumn, int sharedColumn, QObject *parent) AltTableDelegate::AltTableDelegate(int viaColumn,
int warnsColumn,
int bansColumn,
int sharedColumn,
int activeColumn,
QObject *parent)
: QStyledItemDelegate(parent), viaColumn(viaColumn), warnsColumn(warnsColumn), bansColumn(bansColumn), : QStyledItemDelegate(parent), viaColumn(viaColumn), warnsColumn(warnsColumn), bansColumn(bansColumn),
sharedColumn(sharedColumn) sharedColumn(sharedColumn), activeColumn(activeColumn)
{ {
} }
@ -116,13 +121,21 @@ void AltTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
} }
} }
if (index.column() == activeColumn) {
const QVariant activeData = index.data(Qt::UserRole);
const bool active =
activeData.isValid() ? activeData.toBool() : text.compare(QStringLiteral("yes"), Qt::CaseInsensitive) == 0;
paintPill(active ? QPalette::Highlight : QPalette::PlaceholderText, emphasisRole, QIcon(), text);
return;
}
QStyledItemDelegate::paint(painter, opt, index); QStyledItemDelegate::paint(painter, opt, index);
} }
QSize AltTableDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const QSize AltTableDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{ {
const QSize hint = QStyledItemDelegate::sizeHint(option, index); const QSize hint = QStyledItemDelegate::sizeHint(option, index);
if (index.column() == viaColumn) { if (index.column() == viaColumn || index.column() == activeColumn) {
return hint + QSize(PILL_PAD_X + 2 * ICON_TEXT_GAP, PILL_PAD_Y); return hint + QSize(PILL_PAD_X + 2 * ICON_TEXT_GAP, PILL_PAD_Y);
} }
if (index.column() == warnsColumn || index.column() == bansColumn) { if (index.column() == warnsColumn || index.column() == bansColumn) {

View file

@ -9,7 +9,9 @@
* renders as a palette-tinted pill per match type (email / client id / IP), * renders as a palette-tinted pill per match type (email / client id / IP),
* with the style's warning icon once an IP is shared by more than the VPN * with the style's warning icon once an IP is shared by more than the VPN
* threshold. Warn/ban counts gain the style's warning/critical icons when * threshold. Warn/ban counts gain the style's warning/critical icons when
* nonzero. Selected rows and unknown content fall back to default painting. * nonzero. The active column renders as a palette-tinted pill (Highlight
* when active, PlaceholderText when inactive, from Qt::UserRole). Selected
* rows and unknown content fall back to default painting.
*/ */
class AltTableDelegate : public QStyledItemDelegate class AltTableDelegate : public QStyledItemDelegate
{ {
@ -19,6 +21,7 @@ public:
int warnsColumn, int warnsColumn,
int bansColumn, int bansColumn,
int sharedColumn, int sharedColumn,
int activeColumn,
QObject *parent = nullptr); QObject *parent = nullptr);
void setVpnThreshold(int threshold); void setVpnThreshold(int threshold);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
@ -29,6 +32,7 @@ private:
int warnsColumn; int warnsColumn;
int bansColumn; int bansColumn;
int sharedColumn; int sharedColumn;
int activeColumn;
int vpnThreshold = 10; int vpnThreshold = 10;
}; };

View file

@ -30,7 +30,7 @@ void ReportStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
tintRole = QPalette::Highlight; tintRole = QPalette::Highlight;
} else if (status == QStringLiteral("assigned")) { } else if (status == QStringLiteral("assigned")) {
tintRole = QPalette::Link; tintRole = QPalette::Link;
} else if (status == QStringLiteral("resolved")) { } else if (status == QStringLiteral("resolved") || status == QStringLiteral("dismissed")) {
tintRole = QPalette::PlaceholderText; tintRole = QPalette::PlaceholderText;
} }

View file

@ -6,9 +6,9 @@
/** /**
* Status pill for the report queue table. Paints the status text on a * Status pill for the report queue table. Paints the status text on a
* translucent badge tinted with a palette role per status, so the colors * translucent badge tinted with a palette role per status (open, assigned,
* always follow the active theme. Falls back to default painting for * resolved, dismissed), so the colors always follow the active theme.
* selected rows and unknown statuses. * Falls back to default painting for selected rows and unknown statuses.
*/ */
class ReportStatusDelegate : public QStyledItemDelegate class ReportStatusDelegate : public QStyledItemDelegate
{ {

View file

@ -154,12 +154,14 @@ TabAlts::TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
altsTable = new QTableWidget(0, COL_ALTS_COUNT); altsTable = new QTableWidget(0, COL_ALTS_COUNT);
configureAltTable(altsTable); configureAltTable(altsTable);
altsDelegate = new AltTableDelegate(COL_ALTS_VIA, COL_ALTS_WARNS, COL_ALTS_BANS, COL_ALTS_SHARED, altsTable); altsDelegate =
new AltTableDelegate(COL_ALTS_VIA, COL_ALTS_WARNS, COL_ALTS_BANS, COL_ALTS_SHARED, COL_ALTS_ACTIVE, altsTable);
altsDelegate->setVpnThreshold(vpnSpin->value()); altsDelegate->setVpnThreshold(vpnSpin->value());
connect(vpnSpin, &QSpinBox::valueChanged, altsDelegate, &AltTableDelegate::setVpnThreshold); connect(vpnSpin, &QSpinBox::valueChanged, altsDelegate, &AltTableDelegate::setVpnThreshold);
altsTable->setItemDelegateForColumn(COL_ALTS_VIA, altsDelegate); altsTable->setItemDelegateForColumn(COL_ALTS_VIA, altsDelegate);
altsTable->setItemDelegateForColumn(COL_ALTS_WARNS, altsDelegate); altsTable->setItemDelegateForColumn(COL_ALTS_WARNS, altsDelegate);
altsTable->setItemDelegateForColumn(COL_ALTS_BANS, altsDelegate); altsTable->setItemDelegateForColumn(COL_ALTS_BANS, altsDelegate);
altsTable->setItemDelegateForColumn(COL_ALTS_ACTIVE, altsDelegate);
connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) { connect(altsTable, &QTableWidget::activated, this, [this](const QModelIndex &index) {
if (!index.isValid()) { if (!index.isValid()) {
return; return;
@ -456,7 +458,9 @@ void TabAlts::renderTable()
altsTable->setItem(row, COL_ALTS_LAST_LOGIN, new QTableWidgetItem(formatEpoch(alt.last_login()))); altsTable->setItem(row, COL_ALTS_LAST_LOGIN, new QTableWidgetItem(formatEpoch(alt.last_login())));
altsTable->setItem(row, COL_ALTS_WARNS, new QTableWidgetItem(QString::number(alt.warn_count()))); altsTable->setItem(row, COL_ALTS_WARNS, new QTableWidgetItem(QString::number(alt.warn_count())));
altsTable->setItem(row, COL_ALTS_BANS, new QTableWidgetItem(QString::number(alt.ban_count()))); altsTable->setItem(row, COL_ALTS_BANS, new QTableWidgetItem(QString::number(alt.ban_count())));
altsTable->setItem(row, COL_ALTS_ACTIVE, new QTableWidgetItem(alt.is_active() ? tr("yes") : tr("no"))); auto *activeItem = new QTableWidgetItem(alt.is_active() ? tr("yes") : tr("no"));
activeItem->setData(Qt::UserRole, alt.is_active());
altsTable->setItem(row, COL_ALTS_ACTIVE, activeItem);
if (QString::fromStdString(alt.match_reason()).startsWith(QStringLiteral("ip:")) && alt.has_shared_count() && if (QString::fromStdString(alt.match_reason()).startsWith(QStringLiteral("ip:")) && alt.has_shared_count() &&
alt.shared_count() > 1) { alt.shared_count() > 1) {
for (int col = 0; col < COL_ALTS_COUNT; ++col) { for (int col = 0; col < COL_ALTS_COUNT; ++col) {