diff --git a/icons.qrc b/icons.qrc
index aff78ee..3b053b1 100644
--- a/icons.qrc
+++ b/icons.qrc
@@ -12,6 +12,7 @@
resources/icons/SVG/Linear/Arrows Action/Reply.svg
resources/icons/SVG/Linear/Arrows Action/Forward.svg
resources/icons/SVG/Linear/Essentional, UI/Trash Bin Minimalistic.svg
+ resources/icons/SVG/Linear/Arrows Action/Square Top Down.svg
resources/icons/SVG/Linear/Design, Tools/Filters.svg
resources/icons/SVG/Linear/Time/Stopwatch Play.svg
resources/icons/SVG/Linear/Files/File Text.svg
diff --git a/src/services/mailservice.cpp b/src/services/mailservice.cpp
index e508cb7..80a04e7 100644
--- a/src/services/mailservice.cpp
+++ b/src/services/mailservice.cpp
@@ -353,6 +353,39 @@ void MailService::sendMail(const MailItem &mail, const QString &accountId,
watcher->setFuture(future);
}
+void MailService::scheduleSend(const MailItem &mail, const QString &accountId,
+ const QStringList &attachmentPaths, const QDateTime &when)
+{
+ QDateTime now = QDateTime::currentDateTime();
+ if (!when.isValid() || when <= now) {
+ // Send immediately
+ sendMail(mail, accountId, attachmentPaths);
+ return;
+ }
+
+ m_pendingMail = mail;
+ m_pendingAccountId = accountId;
+ m_pendingAttachments = attachmentPaths;
+
+ int ms = qMax(1000, int(now.msecsTo(when)));
+ m_sendTimer.stop();
+ // Re-arm the single-shot timer with the delay until `when`.
+ m_sendTimer.disconnect(this);
+ connect(&m_sendTimer, &QTimer::timeout, this, [this]() {
+ MailItem mail = m_pendingMail;
+ QString accountId = m_pendingAccountId;
+ QStringList attachments = m_pendingAttachments;
+ m_pendingMail = MailItem();
+ m_pendingAccountId.clear();
+ m_pendingAttachments.clear();
+ sendMail(mail, accountId, attachments);
+ });
+ m_sendTimer.start(ms);
+
+ emit statusMessage(
+ tr("Envío programado para %1").arg(when.toString("dd/MM/yyyy HH:mm")));
+}
+
void MailService::fetchMails(const QString &accountId, const QString &folderId)
{
// Determine provider type from account
diff --git a/src/services/mailservice.h b/src/services/mailservice.h
index c2a1b3d..0bb39a7 100644
--- a/src/services/mailservice.h
+++ b/src/services/mailservice.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "core/mailitem.h"
#include "core/emailcomposerbridge.h"
#include "core/synchronizerprovider.h"
@@ -24,6 +25,9 @@ public:
void sendMail(const MailItem &mail, const QString &accountId);
void sendMail(const MailItem &mail, const QString &accountId,
const QStringList &attachmentPaths);
+ /// Schedule a mail to be sent at `when`. Emits mailSent(mailItemId) when sent.
+ void scheduleSend(const MailItem &mail, const QString &accountId,
+ const QStringList &attachmentPaths, const QDateTime &when);
void fetchMails(const QString &accountId, const QString &folderId);
void moveMail(const QString &mailItemId, const QString &targetFolderId);
void deleteMail(const QString &mailItemId);
@@ -50,6 +54,10 @@ private:
const QString &folderId);
EmailComposerBridge *m_composer;
AccountService *m_accountService;
+ QTimer m_sendTimer{this}; // one-shot timer driving scheduled sends
+ MailItem m_pendingMail;
+ QString m_pendingAccountId;
+ QStringList m_pendingAttachments;
};
#endif // MAILSERVICE_H
diff --git a/src/ui/composeview.cpp b/src/ui/composeview.cpp
index 84253da..41a5c40 100644
--- a/src/ui/composeview.cpp
+++ b/src/ui/composeview.cpp
@@ -292,7 +292,7 @@ void ComposeView::setupUI() {
ccLayout->addWidget(m_ccField, 1);
m_hideCcButton = new QPushButton("");
- m_hideCcButton->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Linear/Essentional, UI/Close Square.svg")));
+ m_hideCcButton->setIcon(QIcon(QStringLiteral(":/icons/close.svg")));
m_hideCcButton->setFixedSize(20, 20);
m_hideCcButton->setToolTip(tr("Hide Cc"));
m_hideCcButton->setStyleSheet(
@@ -319,7 +319,7 @@ void ComposeView::setupUI() {
m_hideBccButton = new QPushButton("");
m_hideBccButton->setFixedSize(20, 20);
- m_hideBccButton->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Linear/Essentional, UI/Close Square.svg")));
+ m_hideBccButton->setIcon(QIcon(QStringLiteral(":/icons/close.svg")));
m_hideBccButton->setToolTip(tr("Hide Bcc"));
m_hideBccButton->setStyleSheet(
"QPushButton { background: transparent; border: none; color: blue; font-weight: bold; }"
@@ -348,7 +348,7 @@ void ComposeView::setupUI() {
// Detach button placed to the right of the subject line
m_detachButton = new QPushButton("");//("↥ Detach");
- m_detachButton->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Linear/Arrows Action/Square Top Down.svg")));
+ m_detachButton->setIcon(QIcon(QStringLiteral(":/icons/detach.svg")));
m_detachButton->setToolTip(tr("Open compose window in a separate window"));
m_detachButton->setStyleSheet(
"QPushButton { background: transparent; border: 1px solid #d1d1d6; border-radius: 4px; padding: 6px 12px; color: #555; font-size: 12px; }"
@@ -421,7 +421,7 @@ void ComposeView::setupUI() {
// Attachments and Templates buttons (right-aligned)
QHBoxLayout *buttonRow = new QHBoxLayout();
m_attachButton = new QToolButton();
- m_attachButton->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Outline/Messages, Conversation/Paperclip.svg")));
+ m_attachButton->setIcon(QIcon(QStringLiteral(":/icons/attachment.svg")));
m_attachButton->setToolTip(tr("Add attachment"));
m_attachButton->setIconSize(QSize(20,20));
m_attachButton->setStyleSheet("QToolButton { border: none; padding: 5px; } QToolButton:hover { background: #e0e0e0; border-radius: 3px; }");
@@ -429,7 +429,7 @@ void ComposeView::setupUI() {
buttonRow->addWidget(m_attachButton);
m_templateButton = new QToolButton();
- m_templateButton->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Outline/Files/File Text.svg"))); // Assuming you have a template icon
+ m_templateButton->setIcon(QIcon(QStringLiteral(":/icons/file-text.svg"))); // Assuming you have a template icon
m_templateButton->setToolTip(tr("Email templates"));
m_templateButton->setIconSize(QSize(20,20));
m_templateButton->setStyleSheet("QToolButton { border: none; padding: 5px; } QToolButton:hover { background: #e0e0e0; border-radius: 3px; }");
@@ -459,7 +459,7 @@ void ComposeView::setupUI() {
m_sendSplit = new QToolButton();
m_sendSplit->setText(tr("Send"));
- m_sendSplit->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Bold Duotone/Messages, Conversation/Plain.svg")));
+ m_sendSplit->setIcon(QIcon(QStringLiteral(":/icons/send.svg")));
m_templateButton->setIconSize(QSize(20,20));
//m_sendSplit->setToolButtonStyle(Qt::ToolButtonTextOnly);
m_sendSplit->setPopupMode(QToolButton::MenuButtonPopup);
diff --git a/src/ui/delegates/CompactMailDelegate.cpp b/src/ui/delegates/CompactMailDelegate.cpp
index a532d40..a5c5c99 100644
--- a/src/ui/delegates/CompactMailDelegate.cpp
+++ b/src/ui/delegates/CompactMailDelegate.cpp
@@ -1,4 +1,5 @@
#include "CompactMailDelegate.h"
+#include "db/dao/categorydao.h"
#include
#include
#include
@@ -269,8 +270,38 @@ void CompactMailDelegate::drawCard(QPainter *painter, const QStyleOptionViewItem
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
+ // Category badges (if any)
+ int mailId = index.data(EmailListModel::IdRole).toInt();
+ QVector catIds = CategoryDao::categoriesForMail(mailId);
+ if (!catIds.isEmpty() && catIds.size() <= 3 && m_config.displayMode != Compact) {
+ int catY = line2Y + subjectFont.pointSizeF() + (m_config.showPreviewText && m_config.displayMode != Compact
+ ? previewFont.pointSizeF() + 8 : 6);
+ int cx = contentRect.left() + (m_config.showAvatar ? m_config.avatarSize + 10 : 0);
+ QFont catFont = subjectFont;
+ catFont.setPointSizeF(qMax(6.5, subjectFont.pointSizeF() - 3.0));
+ catFont.setBold(true);
+ painter->setFont(catFont);
+ int maxCatWidth = availableWidth;
+ for (qint64 cid : catIds) {
+ auto cat = CategoryDao::findById(cid);
+ if (!cat.has_value()) continue;
+ QString label = " " + cat->name + " ";
+ QColor catColor = cat->color.isValid() ? cat->color : QColor(0x00, 0x71, 0xe3);
+ QFontMetrics fm(catFont);
+ int w = fm.horizontalAdvance(label) + 8;
+ if (maxCatWidth < w) break;
+ QRect chip(cx, catY, w, fm.height() + 4);
+ painter->setRenderHint(QPainter::Antialiasing);
+ QColor fill = catColor; fill.setAlpha(45);
+ painter->setPen(catColor);
+ painter->setBrush(fill);
+ painter->drawRoundedRect(chip, 4, 4);
+ painter->setPen(catColor);
+ painter->drawText(chip.adjusted(4, 2, -2, 0), Qt::AlignLeft | Qt::AlignVCenter, label.trimmed());
+ cx += w + 6;
+ maxCatWidth -= w + 6;
+ }
+ }
// Action buttons (bottom)
int buttonAreaY = cardRect.bottom() - 28;
diff --git a/src/ui/maillistview.h b/src/ui/maillistview.h
index 1e4f136..25794bb 100644
--- a/src/ui/maillistview.h
+++ b/src/ui/maillistview.h
@@ -27,6 +27,8 @@ public:
~MailListView() override;
void setModel(EmailListModel *model);
+ /// Currently selected mail ids (multi-selection or current row).
+ QVector selectedMailIds() const { return m_selectedMailIds; }
QTreeView* treeView() const { return m_treeView; }
QListView* listView() const { return m_listView; }
diff --git a/src/ui/mainmainwindow.cpp b/src/ui/mainmainwindow.cpp
index af07dce..d0e1ee1 100644
--- a/src/ui/mainmainwindow.cpp
+++ b/src/ui/mainmainwindow.cpp
@@ -108,10 +108,6 @@ void MainMainWindow::setupUI()
// Page 1: Compose
m_composeView = new ComposeView();
connect(m_composeView, &ComposeView::sendRequested, [this](const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QDateTime &scheduleTime, const QString &fromAddr, const QStringList &attachmentPaths) {
- if (scheduleTime.isValid()) {
- statusBar()->showMessage(tr("Scheduled sending is not available yet"), 5000);
- return;
- }
if (fromAddr.isEmpty()) {
statusBar()->showMessage(tr("Select an account before sending"), 5000);
return;
@@ -124,8 +120,13 @@ void MainMainWindow::setupUI()
mail.setSubject(subject);
mail.setBodyHtml(body);
mail.setDate(QDateTime::currentDateTimeUtc());
- m_mailService->sendMail(mail, fromAddr, attachmentPaths);
- statusBar()->showMessage(tr("Sending message…"), 5000);
+ if (scheduleTime.isValid()) {
+ m_mailService->scheduleSend(mail, fromAddr, attachmentPaths, scheduleTime);
+ statusBar()->showMessage(tr("Envío programado"), 5000);
+ } else {
+ m_mailService->sendMail(mail, fromAddr, attachmentPaths);
+ statusBar()->showMessage(tr("Sending message…"), 5000);
+ }
switchToPage(PageMail);
});
connect(m_composeView, &ComposeView::discardRequested, [this]() {
@@ -305,6 +306,7 @@ void MainMainWindow::setupMailPage()
connect(m_emailViewer, &ReaderView::forwardRequested, this, &MainMainWindow::onReaderForwardRequested);
connect(m_emailViewer, &ReaderView::deleteRequested, this, &MainMainWindow::onReaderDeleteRequested);
connect(m_emailViewer, &ReaderView::markUnreadRequested, this, &MainMainWindow::onMarkUnreadRequested);
+ connect(m_emailViewer, &ReaderView::markSpamRequested, this, &MainMainWindow::onMarkSpamRequested);
connect(m_emailViewer, &ReaderView::detachRequested, this, [this]() {
if (m_currentMailId >= 0) {
openMailInIndependentWindow(m_currentMailId);
@@ -685,6 +687,39 @@ void MainMainWindow::onMarkUnreadRequested(int mailId)
}
}
+void MainMainWindow::onMarkSpamRequested(int mailId)
+{
+ std::optional optMail = MailItemDao::findById(mailId);
+ if (!optMail) return;
+ std::optional curFolder = FolderDao::findById(optMail->folderId());
+ if (!curFolder) return;
+ int accountId = curFolder->accountId();
+
+ // Find a Spam/Junk folder for this account.
+ QVector folders = FolderDao::findByAccountId(accountId);
+ int spamFolderId = -1;
+ for (const Folder &f : folders) {
+ QString n = f.name().toLower();
+ if (n == "spam" || n == "junk" || n.contains("spam") || n.contains("junk")) {
+ spamFolderId = f.id();
+ break;
+ }
+ }
+
+ if (spamFolderId < 0) {
+ QMessageBox::information(this, tr("Marcar como spam"),
+ tr("No hay una carpeta de Spam en esta cuenta. Mueve el correo manualmente con «Mover a...»."));
+ return;
+ }
+
+ m_mailService->moveMail(QString::number(mailId), QString::number(spamFolderId));
+ if (m_currentMailId == mailId) m_currentMailId = -1;
+ m_emailModel->refresh();
+ m_mailListView->treeView()->clearSelection();
+ m_viewerStack->setCurrentIndex(0);
+ statusBar()->showMessage(tr("Marcado como spam y movido a la carpeta de spam"), 3000);
+}
+
void MainMainWindow::onNewMessage()
{ // Show compose view in the viewer stack
m_embeddedComposeView->initializeComposition();
@@ -784,10 +819,21 @@ void MainMainWindow::onRunRulesOnFolder()
void MainMainWindow::onRunRulesOnSelected()
{
- // Get selected mail IDs
- QMessageBox::information(this, tr("Ejecutar reglas"), tr("Ejecutando reglas en correos seleccionados..."));
- // TODO: Get selected mail IDs from MailListView
- statusBar()->showMessage(tr("Reglas ejecutadas"), 3000);
+ QVector ids = m_mailListView->selectedMailIds();
+ if (ids.isEmpty() && m_currentMailId >= 0) {
+ ids.append(m_currentMailId);
+ }
+ if (ids.isEmpty()) {
+ statusBar()->showMessage(tr("Selecciona al menos un correo"), 3000);
+ return;
+ }
+
+ QVector mailIds;
+ for (int id : ids) mailIds.append(id);
+ int processed = RulesEngine::runRulesOnMails(mailIds);
+ statusBar()->showMessage(tr("Reglas ejecutadas en %1 correos").arg(processed), 3000);
+ m_emailModel->refresh();
+ m_categoryTree->refresh();
}
void MainMainWindow::showRulesManager()
@@ -1197,10 +1243,6 @@ void MainMainWindow::onEmbeddedSendRequested(const QString &to, const QString &c
const QString &fromAddress,
const QStringList &attachmentPaths)
{
- if (scheduleTime.isValid()) {
- statusBar()->showMessage(tr("Scheduled sending is not available yet"), 5000);
- return;
- }
if (fromAddress.isEmpty()) {
statusBar()->showMessage(tr("Select an account before sending"), 5000);
return;
@@ -1213,8 +1255,13 @@ void MainMainWindow::onEmbeddedSendRequested(const QString &to, const QString &c
mail.setSubject(subject);
mail.setBodyHtml(body);
mail.setDate(QDateTime::currentDateTimeUtc());
- m_mailService->sendMail(mail, fromAddress, attachmentPaths);
- statusBar()->showMessage(tr("Sending message…"), 5000);
+ if (scheduleTime.isValid()) {
+ m_mailService->scheduleSend(mail, fromAddress, attachmentPaths, scheduleTime);
+ statusBar()->showMessage(tr("Envío programado"), 5000);
+ } else {
+ m_mailService->sendMail(mail, fromAddress, attachmentPaths);
+ statusBar()->showMessage(tr("Sending message…"), 5000);
+ }
m_viewerStack->setCurrentIndex(0); // placeholder
m_embeddedComposeView->initializeComposition();
}
diff --git a/src/ui/mainmainwindow.h b/src/ui/mainmainwindow.h
index 569f4f1..0ac5727 100644
--- a/src/ui/mainmainwindow.h
+++ b/src/ui/mainmainwindow.h
@@ -86,6 +86,7 @@ private slots:
void onBatchDeleteRequested(const QVector &mailIds);
void onBatchMarkUnreadRequested(const QVector &mailIds);
void onBatchFlagRequested(const QVector &mailIds, bool flagged);
+ void onMarkSpamRequested(int mailId);
void onMarkUnreadRequested(int mailId);
// Online search
void onOnlineSearchRequested(const QString& query);
diff --git a/src/ui/readerview.cpp b/src/ui/readerview.cpp
index 1f48a13..cf2710b 100644
--- a/src/ui/readerview.cpp
+++ b/src/ui/readerview.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -370,8 +371,7 @@ void ReaderView::setupUI() {
});
moreMenu->addAction("Marcar como spam", [this]() {
if (m_currentMailId < 0) return;
- QMessageBox::information(this, tr("Marcar como spam"),
- tr("Función: mover a carpeta «Spam». Disponible en una próxima versión."));
+ emit markSpamRequested(m_currentMailId);
});
m_moreButton->setMenu(moreMenu);
m_moreButton->setStyleSheet(
@@ -729,8 +729,23 @@ void ReaderView::showAttachmentContextMenu(const QPoint &pos, const QString &pat
menu.addSeparator();
QAction *deleteAct = menu.addAction("Eliminar adjunto", [this, name]() {
- // TODO: Implement attachment deletion from stored mail
- QMessageBox::information(this, "No implementado", "Eliminar adjuntos del almacenamiento local aún no está implementado.");
+ if (m_currentMailId < 0) return;
+ QVector all = MailItemDao::attachmentsForMail(m_currentMailId);
+ QVector remaining;
+ // Delete the matching stored file and keep the others.
+ for (const StoredAttachmentRecord &a : all) {
+ if (a.fileName == name) {
+ if (!a.storedPath.isEmpty())
+ QFile::remove(a.storedPath);
+ } else {
+ remaining.append(a);
+ }
+ }
+ if (MailItemDao::replaceAttachments(m_currentMailId, remaining)) {
+ QMessageBox::information(this, "Adjunto", tr("Adjunto «%1» eliminado.").arg(name));
+ } else {
+ QMessageBox::warning(this, "Adjunto", tr("No se pudo eliminar el adjunto."));
+ }
});
deleteAct->setIcon(QIcon::fromTheme("edit-delete", QApplication::style()->standardIcon(QStyle::SP_TrashIcon)));
@@ -776,8 +791,10 @@ void ReaderView::setMailItem(const MailItem* item) {
// From
m_fromLabel->setText("De: " + formatAddress(sender));
- // To - MailItem doesn't have recipients easily accessible, skip for now
- m_toLabel->setText("Para: —"); // TODO: fetch from MailItem or DB
+ // To - prefer recipient()/to(), fallback to placeholder
+ QString toText = item->recipient();
+ if (toText.isEmpty()) toText = item->to();
+ m_toLabel->setText("Para: " + (toText.isEmpty() ? QString("—") : formatAddress(toText)));
// Date
m_dateLabel->setText("Fecha: " + formatDate(item->date()));
diff --git a/src/ui/readerview.h b/src/ui/readerview.h
index 19d0665..441e810 100644
--- a/src/ui/readerview.h
+++ b/src/ui/readerview.h
@@ -30,6 +30,7 @@ signals:
void deleteRequested(int mailId);
void detachRequested();
void markUnreadRequested(int mailId);
+ void markSpamRequested(int mailId);
void openAttachmentRequested(const QString &path);
private slots:
diff --git a/src/ui/richtexteditor.cpp b/src/ui/richtexteditor.cpp
index 6dadc8c..8c12e32 100644
--- a/src/ui/richtexteditor.cpp
+++ b/src/ui/richtexteditor.cpp
@@ -68,19 +68,19 @@ void RichTextEditor::setupToolbar(QVBoxLayout *layout) {
// Bold / Italic / Underline
QAction *boldAct = m_toolbar->addAction("B");
boldAct->setCheckable(true);
- boldAct->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Bold/Text Formatting/Text Bold.svg")));
+ boldAct->setIcon(QIcon(QStringLiteral(":/icons/bold.svg")));
QFont boldFont = boldAct->font(); boldFont.setBold(true); boldAct->setFont(boldFont);
connect(boldAct, &QAction::triggered, this, &RichTextEditor::onBold);
QAction *italicAct = m_toolbar->addAction("I");
italicAct->setCheckable(true);
- italicAct->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Outline/Text Formatting/Text Italic.svg")));
+ italicAct->setIcon(QIcon(QStringLiteral(":/icons/italic.svg")));
QFont italicFont = italicAct->font(); italicFont.setItalic(true); italicAct->setFont(italicFont);
connect(italicAct, &QAction::triggered, this, &RichTextEditor::onItalic);
QAction *underlineAct = m_toolbar->addAction("U");
underlineAct->setCheckable(true);
- underlineAct->setIcon(QIcon(QStringLiteral(":/icons/resources/icons/SVG/Outline/Text Formatting/Text Underline.svg")));
+ underlineAct->setIcon(QIcon(QStringLiteral(":/icons/underline.svg")));
QFont uFont = underlineAct->font(); uFont.setUnderline(true); underlineAct->setFont(uFont);
connect(underlineAct, &QAction::triggered, this, &RichTextEditor::onUnderline);
diff --git a/src/ui/rulesmanagerdialog.cpp b/src/ui/rulesmanagerdialog.cpp
index 47fde63..8b050c9 100644
--- a/src/ui/rulesmanagerdialog.cpp
+++ b/src/ui/rulesmanagerdialog.cpp
@@ -1,6 +1,7 @@
#include "rulesmanagerdialog.h"
#include "ruleditordialog.h"
#include "db/dao/ruledao.h"
+#include "db/dao/common_structs.h"
#include "db/dao/categorydao.h"
#include "db/dao/folderdao.h"
#include "services/rulesengine.h"
@@ -81,7 +82,7 @@ void RulesManagerDialog::setupUI()
if (idx > 0) {
QTreeWidgetItem* prev = m_tree->takeTopLevelItem(idx);
m_tree->insertTopLevelItem(idx - 1, prev);
- // TODO: update priority in DB
+ persistPriorityOrder();
}
});
QAction* moveDownAct = menu.addAction(tr("Bajar prioridad"), [this, item]() {
@@ -89,7 +90,7 @@ void RulesManagerDialog::setupUI()
if (idx < m_tree->topLevelItemCount() - 1) {
QTreeWidgetItem* next = m_tree->takeTopLevelItem(idx + 1);
m_tree->insertTopLevelItem(idx + 1, item);
- // TODO: update priority in DB
+ persistPriorityOrder();
}
});
menu.exec(m_tree->viewport()->mapToGlobal(pos));
@@ -296,3 +297,20 @@ void RulesManagerDialog::refresh()
{
loadRules();
}
+
+void RulesManagerDialog::persistPriorityOrder()
+{
+ // Re-assign priority based on tree order (top = lowest number = highest priority).
+ for (int i = 0; i < m_tree->topLevelItemCount(); ++i) {
+ QTreeWidgetItem *item = m_tree->topLevelItem(i);
+ qint64 ruleId = item->data(0, Qt::UserRole).toLongLong();
+ int newPriority = i + 1;
+ item->setText(2, QString::number(newPriority));
+ auto rule = RuleDao::findById(ruleId);
+ if (rule.has_value()) {
+ Rule r = rule.value();
+ r.priority = newPriority;
+ RuleDao::update(r);
+ }
+ }
+}
diff --git a/src/ui/rulesmanagerdialog.h b/src/ui/rulesmanagerdialog.h
index 7f02873..5fc11b6 100644
--- a/src/ui/rulesmanagerdialog.h
+++ b/src/ui/rulesmanagerdialog.h
@@ -41,4 +41,5 @@ private:
void loadRules();
void addRuleToTree(const Rule& rule);
Rule itemToRule(QTreeWidgetItem* item) const;
+ void persistPriorityOrder();
};
\ No newline at end of file