diff --git a/Wino.Core.Domain/Enums/MailOperation.cs b/Wino.Core.Domain/Enums/MailOperation.cs
index 483b5607..b7a20b6c 100644
--- a/Wino.Core.Domain/Enums/MailOperation.cs
+++ b/Wino.Core.Domain/Enums/MailOperation.cs
@@ -11,7 +11,8 @@
ChangeFlag,
AlwaysMoveTo,
MoveToFocused,
- RenameFolder
+ RenameFolder,
+ Archive
}
// UI requests
diff --git a/Wino.Core/Requests/ArchiveRequest.cs b/Wino.Core/Requests/ArchiveRequest.cs
new file mode 100644
index 00000000..f519f4d8
--- /dev/null
+++ b/Wino.Core/Requests/ArchiveRequest.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using CommunityToolkit.Mvvm.Messaging;
+using MoreLinq;
+using Wino.Core.Domain.Entities;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Interfaces;
+using Wino.Core.Domain.Models.Requests;
+
+namespace Wino.Core.Requests
+{
+ ///
+ /// Archive message request.
+ /// By default, the message will be moved to the Archive folder.
+ /// For Gmail, 'Archive' label will be removed from the message.
+ ///
+ /// Whether are archiving or unarchiving
+ /// Mail to archive
+ /// Source folder.
+ /// Optional Target folder. Required for ImapSynchronizer and OutlookSynchronizer.
+ public record ArchiveRequest(bool IsArchiving, MailCopy Item, MailItemFolder FromFolder, MailItemFolder ToFolder = null) : RequestBase(Item, MailSynchronizerOperation.Archive), ICustomFolderSynchronizationRequest
+ {
+ public List SynchronizationFolderIds
+ {
+ get
+ {
+ var folderIds = new List { FromFolder.Id };
+
+ if (ToFolder != null)
+ {
+ folderIds.Add(ToFolder.Id);
+ }
+
+ return folderIds;
+ }
+ }
+
+ public override IBatchChangeRequest CreateBatch(IEnumerable matchingItems)
+ => new BatchArchiveRequest(IsArchiving, matchingItems, FromFolder, ToFolder);
+
+ public override void ApplyUIChanges()
+ {
+ WeakReferenceMessenger.Default.Send(new MailRemovedMessage(Item));
+ }
+
+ public override void RevertUIChanges()
+ {
+ WeakReferenceMessenger.Default.Send(new MailAddedMessage(Item));
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public record BatchArchiveRequest(bool IsArchiving, IEnumerable Items, MailItemFolder FromFolder, MailItemFolder ToFolder = null) : BatchRequestBase(Items, MailSynchronizerOperation.Archive)
+ {
+ public override void ApplyUIChanges()
+ {
+ Items.ForEach(item => WeakReferenceMessenger.Default.Send(new MailRemovedMessage(item.Item)));
+ }
+
+ public override void RevertUIChanges()
+ {
+ Items.ForEach(item => WeakReferenceMessenger.Default.Send(new MailAddedMessage(item.Item)));
+ }
+ }
+}
diff --git a/Wino.Core/Services/WinoRequestProcessor.cs b/Wino.Core/Services/WinoRequestProcessor.cs
index 93c51693..768fdaa5 100644
--- a/Wino.Core/Services/WinoRequestProcessor.cs
+++ b/Wino.Core/Services/WinoRequestProcessor.cs
@@ -160,20 +160,37 @@ namespace Wino.Core.Services
}
else if (action == MailOperation.Archive)
{
- // Validate archive folder exists.
+ // For IMAP and Outlook: Validate archive folder exists.
+ // Gmail doesn't need archive folder existence.
- var archiveFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Archive)
+ MailItemFolder archiveFolder = null;
+
+ bool shouldRequireArchiveFolder = mailItem.AssignedAccount.ProviderType == MailProviderType.Outlook
+ || mailItem.AssignedAccount.ProviderType == MailProviderType.IMAP4
+ || mailItem.AssignedAccount.ProviderType == MailProviderType.Office365;
+
+ if (shouldRequireArchiveFolder)
+ {
+ archiveFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Archive)
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Archive, mailItem.AssignedAccount.Id);
+ }
- return new MoveRequest(mailItem, mailItem.AssignedFolder, archiveFolder);
+ return new ArchiveRequest(true, mailItem, mailItem.AssignedFolder, archiveFolder);
}
- else if (action == MailOperation.UnArchive || action == MailOperation.MarkAsNotJunk)
+ else if (action == MailOperation.MarkAsNotJunk)
{
var inboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Inbox)
?? throw new UnavailableSpecialFolderException(SpecialFolderType.Inbox, mailItem.AssignedAccount.Id);
return new MoveRequest(mailItem, mailItem.AssignedFolder, inboxFolder);
}
+ else if (action == MailOperation.UnArchive)
+ {
+ var inboxFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Inbox)
+ ?? throw new UnavailableSpecialFolderException(SpecialFolderType.Inbox, mailItem.AssignedAccount.Id);
+
+ return new ArchiveRequest(false, mailItem, mailItem.AssignedFolder, inboxFolder);
+ }
else if (action == MailOperation.SoftDelete)
{
var trashFolder = await _folderService.GetSpecialFolderByAccountIdAsync(mailItem.AssignedAccount.Id, SpecialFolderType.Deleted)
diff --git a/Wino.Core/Synchronizers/BaseSynchronizer.cs b/Wino.Core/Synchronizers/BaseSynchronizer.cs
index be42895a..c1d700a4 100644
--- a/Wino.Core/Synchronizers/BaseSynchronizer.cs
+++ b/Wino.Core/Synchronizers/BaseSynchronizer.cs
@@ -272,6 +272,9 @@ namespace Wino.Core.Synchronizers
case MailSynchronizerOperation.CreateDraft:
yield return CreateDraft((BatchCreateDraftRequest)item);
break;
+ case MailSynchronizerOperation.Archive:
+ yield return Archive((BatchArchiveRequest)item);
+ break;
}
}
};
@@ -324,6 +327,7 @@ namespace Wino.Core.Synchronizers
public virtual IEnumerable> MoveToFocused(BatchMoveToFocusedRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
public virtual IEnumerable> CreateDraft(BatchCreateDraftRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
public virtual IEnumerable> SendDraft(BatchSendDraftRequestRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
+ public virtual IEnumerable> Archive(BatchArchiveRequest request) => throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedSynchronizerOperation, this.GetType()));
///
/// Downloads a single missing message from synchronizer and saves it to given FileId from IMailItem.
diff --git a/Wino.Core/Synchronizers/GmailSynchronizer.cs b/Wino.Core/Synchronizers/GmailSynchronizer.cs
index bad599be..357edcf1 100644
--- a/Wino.Core/Synchronizers/GmailSynchronizer.cs
+++ b/Wino.Core/Synchronizers/GmailSynchronizer.cs
@@ -635,6 +635,28 @@ namespace Wino.Core.Synchronizers
});
}
+ public override IEnumerable> Archive(BatchArchiveRequest request)
+ {
+ return CreateBatchedHttpBundleFromGroup(request, (items) =>
+ {
+ var batchModifyRequest = new BatchModifyMessagesRequest
+ {
+ Ids = items.Select(a => a.Item.Id.ToString()).ToList()
+ };
+
+ if (request.IsArchiving)
+ {
+ batchModifyRequest.RemoveLabelIds = new[] { GoogleIntegratorExtensions.INBOX_LABEL_ID };
+ }
+ else
+ {
+ batchModifyRequest.AddLabelIds = new[] { GoogleIntegratorExtensions.INBOX_LABEL_ID };
+ }
+
+ return _gmailService.Users.Messages.BatchModify(batchModifyRequest, "me");
+ });
+ }
+
public override IEnumerable> SendDraft(BatchSendDraftRequestRequest request)
{
return CreateHttpBundle(request, (item) =>
diff --git a/Wino.Core/Synchronizers/ImapSynchronizer.cs b/Wino.Core/Synchronizers/ImapSynchronizer.cs
index ea59cc16..befdf353 100644
--- a/Wino.Core/Synchronizers/ImapSynchronizer.cs
+++ b/Wino.Core/Synchronizers/ImapSynchronizer.cs
@@ -272,6 +272,9 @@ namespace Wino.Core.Synchronizers
}, request);
}
+ public override IEnumerable> Archive(BatchArchiveRequest request)
+ => Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
+
public override IEnumerable> SendDraft(BatchSendDraftRequestRequest request)
{
return CreateTaskBundle(async (ImapClient client) =>
diff --git a/Wino.Core/Synchronizers/OutlookSynchronizer.cs b/Wino.Core/Synchronizers/OutlookSynchronizer.cs
index 8e609c8e..4392c5ff 100644
--- a/Wino.Core/Synchronizers/OutlookSynchronizer.cs
+++ b/Wino.Core/Synchronizers/OutlookSynchronizer.cs
@@ -572,6 +572,9 @@ namespace Wino.Core.Synchronizers
return [deleteBundle, sendMailRequest];
}
+ public override IEnumerable> Archive(BatchArchiveRequest request)
+ => Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
+
public override async Task DownloadMissingMimeMessageAsync(IMailItem mailItem,
MailKit.ITransferProgress transferProgress = null,
CancellationToken cancellationToken = default)