Folder operations, Gmail folder sync improvements and rework of menu items. (#273)

* New rename folder dialog keys.

* Insfra work for folder operations and rename folder code.

* RenameFolder for Gmail.

* Fixed input dialog to take custom take for primary button.

* Missing rename for DS call.

* Outlook to throw exception in case of error.

* Implemented rename folder functionality for Outlook.

* Remove default primary text from input dialog.

* Fixed an issue where outlook folder rename does not work.

* Disable vertical scroll for composing page editor items.

* Fixing some issues with imap folder sync.

* fix copy pasta

* TODO folder update/removed overrides for shell.

* New rename folder dialog keys.

* Insfra work for folder operations and rename folder code.

* RenameFolder for Gmail.

* Fixed input dialog to take custom take for primary button.

* Missing rename for DS call.

* Outlook to throw exception in case of error.

* Implemented rename folder functionality for Outlook.

* Remove default primary text from input dialog.

* Fixed an issue where outlook folder rename does not work.

* Disable vertical scroll for composing page editor items.

* Fixing some issues with imap folder sync.

* fix copy pasta

* TODO folder update/removed overrides for shell.

* New rename folder dialog keys.

* Insfra work for folder operations and rename folder code.

* RenameFolder for Gmail.

* Fixed input dialog to take custom take for primary button.

* Missing rename for DS call.

* Outlook to throw exception in case of error.

* Implemented rename folder functionality for Outlook.

* Remove default primary text from input dialog.

* Fixed an issue where outlook folder rename does not work.

* Disable vertical scroll for composing page editor items.

* Fixing some issues with imap folder sync.

* fix copy pasta

* TODO folder update/removed overrides for shell.

* New rename folder dialog keys.

* Fixed an issue where redundant older updates causing pivots to be re-created.

* New empty folder request

* New rename folder dialog keys.

* Insfra work for folder operations and rename folder code.

* RenameFolder for Gmail.

* Fixed input dialog to take custom take for primary button.

* Missing rename for DS call.

* Outlook to throw exception in case of error.

* Implemented rename folder functionality for Outlook.

* Remove default primary text from input dialog.

* Fixed an issue where outlook folder rename does not work.

* Fixing some issues with imap folder sync.

* fix copy pasta

* TODO folder update/removed overrides for shell.

* New rename folder dialog keys.

* New rename folder dialog keys.

* New rename folder dialog keys.

* Fixed an issue where redundant older updates causing pivots to be re-created.

* New empty folder request

* Enable empty folder on base sync.

* Move updates on event listeners.

* Remove folder UI messages.

* Reworked folder synchronization for gmail.

* Loading folders on the fly as the selected account changed instead of relying on cached menu items.

* Merged account folder items, re-navigating to existing rendering page.

* - Reworked merged account menu system.
- Reworked unread item count loadings.
- Fixed back button visibility.
- Instant rendering of mails if renderer is active.
- Animation fixes.
- Menu item re-load crash/hang fixes.

* Handle folder renaming on the UI.

* Empty folder for all synchronizers.

* New execution delay mechanism and handling folder mark as read for all synchronizers.

* Revert UI changes on failure for IMAP.

* Remove duplicate translation keys.

* Cleanup.
This commit is contained in:
Burak Kaan Köse
2024-07-09 01:05:16 +02:00
committed by GitHub
parent ac01006398
commit 536fbb23a1
67 changed files with 1396 additions and 1585 deletions

View File

@@ -273,7 +273,13 @@ namespace Wino.Core.Synchronizers
}
public override IEnumerable<IRequestBundle<ImapRequest>> Archive(BatchArchiveRequest request)
=> Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
=> Move(new BatchMoveRequest(request.Items, request.FromFolder, request.ToFolder));
public override IEnumerable<IRequestBundle<ImapRequest>> EmptyFolder(EmptyFolderRequest request)
=> Delete(new BatchDeleteRequest(request.MailsToDelete.Select(a => new DeleteRequest(a))));
public override IEnumerable<IRequestBundle<ImapRequest>> MarkFolderAsRead(MarkFolderAsReadRequest request)
=> MarkRead(new BatchMarkReadRequest(request.MailsToMarkRead.Select(a => new MarkReadRequest(a, true)), true));
public override IEnumerable<IRequestBundle<ImapRequest>> SendDraft(BatchSendDraftRequestRequest request)
{
@@ -351,6 +357,15 @@ namespace Wino.Core.Synchronizers
_clientPool.Release(client);
}
public override IEnumerable<IRequestBundle<ImapRequest>> RenameFolder(RenameFolderRequest request)
{
return CreateTaskBundle(async (ImapClient client) =>
{
var folder = await client.GetFolderAsync(request.Folder.RemoteFolderId).ConfigureAwait(false);
await folder.RenameAsync(folder.ParentFolder, request.NewFolderName).ConfigureAwait(false);
}, request);
}
#endregion
public override async Task<List<NewMailItemPackage>> CreateNewMailPackagesAsync(ImapMessageCreationPackage message, MailItemFolder assignedFolder, CancellationToken cancellationToken = default)
@@ -406,10 +421,7 @@ namespace Wino.Core.Synchronizers
// Therefore this should be avoided as many times as possible.
// This may create some inconsistencies, but nothing we can do...
if (options.Type == SynchronizationType.FoldersOnly || options.Type == SynchronizationType.Full)
{
await SynchronizeFoldersAsync(cancellationToken).ConfigureAwait(false);
}
await SynchronizeFoldersAsync(cancellationToken).ConfigureAwait(false);
if (options.Type != SynchronizationType.FoldersOnly)
{
@@ -492,7 +504,7 @@ namespace Wino.Core.Synchronizers
}
catch (Exception)
{
item.Request.RevertUIChanges();
throw;
}
finally
@@ -546,26 +558,20 @@ namespace Wino.Core.Synchronizers
localFolder.SpecialFolderType = SpecialFolderType.Starred;
}
/// <summary>
/// Whether the local folder should be updated with the remote folder.
/// </summary>
/// <param name="remoteFolder">Remote folder</param>
/// <param name="localFolder">Local folder.</param>
private bool ShouldUpdateFolder(IMailFolder remoteFolder, MailItemFolder localFolder)
{
return remoteFolder.Name != localFolder.FolderName;
}
private async Task SynchronizeFoldersAsync(CancellationToken cancellationToken = default)
{
// https://www.rfc-editor.org/rfc/rfc4549#section-1.1
var localFolders = await _imapChangeProcessor.GetLocalIMAPFoldersAsync(Account.Id).ConfigureAwait(false);
var localFolders = await _imapChangeProcessor.GetLocalFoldersAsync(Account.Id).ConfigureAwait(false);
ImapClient executorClient = null;
try
{
List<MailItemFolder> insertedFolders = new();
List<MailItemFolder> updatedFolders = new();
List<MailItemFolder> deletedFolders = new();
executorClient = await _clientPool.GetClientAsync().ConfigureAwait(false);
var remoteFolders = (await executorClient.GetFoldersAsync(executorClient.PersonalNamespaces[0], cancellationToken: cancellationToken)).ToList();
@@ -575,8 +581,6 @@ namespace Wino.Core.Synchronizers
// 1.a If local folder doesn't exists remotely, delete it.
// 1.b If local folder exists remotely, check if it is still a valid folder. If UidValidity is changed, delete it.
List<MailItemFolder> deletedFolders = new();
foreach (var localFolder in localFolders)
{
IMailFolder remoteFolder = null;
@@ -628,8 +632,6 @@ namespace Wino.Core.Synchronizers
var nameSpace = executorClient.PersonalNamespaces[0];
// var remoteFolders = (await executorClient.GetFoldersAsync(nameSpace, cancellationToken: cancellationToken)).ToList();
IMailFolder inbox = executorClient.Inbox;
// Sometimes Inbox is the root namespace. We need to check for that.
@@ -684,18 +686,19 @@ namespace Wino.Core.Synchronizers
await remoteFolder.CloseAsync(cancellationToken: cancellationToken);
localFolders.Add(localFolder);
insertedFolders.Add(localFolder);
}
else
{
// Update existing folder. Right now we only update the name.
// TODO: Moving servers around different parents. This is not supported right now.
// TODO: Moving folders around different parents. This is not supported right now.
// We will need more comphrensive folder update mechanism to support this.
if (ShouldUpdateFolder(remoteFolder, existingLocalFolder))
{
existingLocalFolder.FolderName = remoteFolder.Name;
updatedFolders.Add(existingLocalFolder);
}
else
{
@@ -705,13 +708,16 @@ namespace Wino.Core.Synchronizers
}
}
if (localFolders.Any())
// Process changes in order-> Insert, Update. Deleted ones are already processed.
foreach (var folder in insertedFolders)
{
await _imapChangeProcessor.UpdateFolderStructureAsync(Account.Id, localFolders);
await _imapChangeProcessor.InsertFolderAsync(folder).ConfigureAwait(false);
}
else
foreach (var folder in updatedFolders)
{
_logger.Information("No update is needed for imap folders.");
await _imapChangeProcessor.UpdateFolderAsync(folder).ConfigureAwait(false);
}
}
catch (Exception ex)
@@ -729,6 +735,8 @@ namespace Wino.Core.Synchronizers
}
}
private async Task<IEnumerable<string>> SynchronizeFolderInternalAsync(MailItemFolder folder, CancellationToken cancellationToken = default)
{
if (!folder.IsSynchronizationEnabled) return default;
@@ -978,5 +986,14 @@ namespace Wino.Core.Synchronizers
_clientPool.Release(_synchronizationClient);
}
}
/// <summary>
/// Whether the local folder should be updated with the remote folder.
/// IMAP only compares folder name for now.
/// </summary>
/// <param name="remoteFolder">Remote folder</param>
/// <param name="localFolder">Local folder.</param>
public bool ShouldUpdateFolder(IMailFolder remoteFolder, MailItemFolder localFolder) => remoteFolder.Name != localFolder.FolderName;
}
}