summaryrefslogtreecommitdiffstats
path: root/src/mainwindow.h
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-13 20:32:47 +0200
committerDanilo M. <danix@danix.xyz>2026-09-13 20:32:47 +0200
commitc7a2444ed5b9bb30b9f10d3e8dff8a6d6b6bb16a (patch)
treede416968b7dbb90e6ec4a8e1c55743ab71eea533 /src/mainwindow.h
parent533c9243bede053f4ea7e1f20de13e72c2b939b8 (diff)
downloadqtmaildir-c7a2444ed5b9bb30b9f10d3e8dff8a6d6b6bb16a.tar.gz
qtmaildir-c7a2444ed5b9bb30b9f10d3e8dff8a6d6b6bb16a.zip
feat: mark spam moves mail to the account's spam folder
Mark spam was a tag-only action that added the spam tag and removed inbox, so a message marked as spam stayed in the inbox on disk. It now MOVES the file into the account's configured spam folder, exactly mirroring Delete: the account-relative spam key is the destination, the move records moved-from: with the origin, and unread and inbox are stripped in the same confirmed write so one undo returns the folder and the tags together. NotmuchWorker::moveMessages already handled a folder generically and applyTags already overwrote an older moved-from: tag, so the worker needed no change; the tests pin that behaviour for the spam destination. Five existing tests used spam as a worker-free, tag-only stand-in for the old Delete. Since spam is now a move too, they are retargeted to flag, the remaining selection-scoped tag-only action.
Diffstat (limited to 'src/mainwindow.h')
-rw-r--r--src/mainwindow.h32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 97d90e5..14bb06f 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -226,6 +226,15 @@ public:
refreshTrashActions();
}
+ /// The trash predicate, exposed because `spam` is a DIFFERENT folder and
+ /// the predicate must not answer for it. A test seam rather than a
+ /// behavioural one: asserting on Delete's visibility would prove the same
+ /// thing only through the label refresh.
+ bool everySelectedRowIsInATrashFolderForTesting() const
+ {
+ return everySelectedRowIsInATrashFolder();
+ }
+
/// Runs a purge without the confirmation, which a test cannot drive: a
/// modal blocks the thread it is shown on (item 84). What this exists to
/// cover is what happens AFTER the user confirms.
@@ -1233,6 +1242,29 @@ private:
/// back where it came from.
void untrashThreads(const QStringList &threadIds);
+ /// Moves each selected row's message to its account's spam folder, tagging
+ /// it `spam` and recording where it came from. Delete's sibling.
+ void spamSelected();
+
+ /// The half of spamSelected() that does the work, given the messages and
+ /// their paths.
+ ///
+ /// Shaped exactly like trashMessages(): paths are passed in rather than
+ /// looked up, because the thread-scoped caller has messages the MODEL has
+ /// never seen.
+ void spamMessages(const QStringList &messageIds,
+ const QHash<QString, QString> &pathById,
+ int messageCount,
+ const QStringList &wholeThreadIds = {});
+
+ /// Moves every message of the named THREADS to their accounts' spam
+ /// folder.
+ ///
+ /// Asynchronous like trashThreads(), and for the same reason: the ids and
+ /// paths of an unexpanded thread's messages live only in the database, so
+ /// this asks the worker and finishes in onThreadMessagesResolved().
+ void spamThreads(const QStringList &threadIds);
+
/// Runs the thread-scoped delete once the worker has resolved the
/// threads to messages.
void onThreadMessagesResolved(const QStringList &messageIds,