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:
@@ -67,6 +67,9 @@ namespace Wino.Core.Domain.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
public static MailItemFolder CreateMoreFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.More, FolderName = Translator.MoreFolderNameOverride };
|
||||
public static MailItemFolder CreateCategoriesFolder() => new MailItemFolder() { IsSticky = true, SpecialFolderType = SpecialFolderType.Category, FolderName = Translator.CategoriesFolderNameOverride };
|
||||
|
||||
public override string ToString() => FolderName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
ChangeFlag,
|
||||
AlwaysMoveTo,
|
||||
MoveToFocused,
|
||||
Archive,
|
||||
RenameFolder,
|
||||
Archive
|
||||
EmptyFolder,
|
||||
MarkFolderRead,
|
||||
}
|
||||
|
||||
// UI requests
|
||||
|
||||
@@ -5,9 +5,17 @@ namespace Wino.Core.Domain.Interfaces
|
||||
{
|
||||
public interface IAccountMenuItem : IMenuItem
|
||||
{
|
||||
bool IsEnabled { get; set; }
|
||||
double SynchronizationProgress { get; set; }
|
||||
int UnreadItemCount { get; set; }
|
||||
IEnumerable<MailAccount> HoldingAccounts { get; }
|
||||
void UpdateAccount(MailAccount account);
|
||||
}
|
||||
|
||||
public interface IMergedAccountMenuItem : IAccountMenuItem
|
||||
{
|
||||
int MergedAccountCount { get; }
|
||||
|
||||
MergedInbox Parameter { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Wino.Core.Domain.Interfaces
|
||||
Task<IMailItemFolder> ShowMoveMailFolderDialogAsync(List<IMailItemFolder> availableFolders);
|
||||
Task<AccountCreationDialogResult> ShowNewAccountMailProviderDialogAsync(List<IProviderDetail> availableProviders);
|
||||
IAccountCreationDialog GetAccountCreationDialog(MailProviderType type);
|
||||
Task<string> ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription);
|
||||
Task<string> ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription, string primaryButtonText);
|
||||
Task<MailAccount> ShowEditAccountDialogAsync(MailAccount account);
|
||||
Task<MailAccount> ShowAccountPickerDialogAsync(List<MailAccount> availableAccounts);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Wino.Core.Domain.Interfaces
|
||||
int UnreadItemCount { get; set; }
|
||||
SpecialFolderType SpecialFolderType { get; }
|
||||
IEnumerable<IMailItemFolder> HandlingFolders { get; }
|
||||
IEnumerable<IMenuItem> SubMenuItems { get; }
|
||||
bool IsMoveTarget { get; }
|
||||
bool IsSticky { get; }
|
||||
bool IsSystemFolder { get; }
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Synchronization;
|
||||
@@ -15,13 +16,10 @@ namespace Wino.Core.Domain.Interfaces
|
||||
Task<MailItemFolder> GetFolderAsync(Guid folderId);
|
||||
Task<MailItemFolder> GetFolderAsync(Guid accountId, string remoteFolderId);
|
||||
Task<List<MailItemFolder>> GetFoldersAsync(Guid accountId);
|
||||
Task<List<MailItemFolder>> GetUnreadUpdateFoldersAsync(Guid accountId);
|
||||
Task SetSpecialFolderAsync(Guid folderId, SpecialFolderType type);
|
||||
Task<MailItemFolder> GetSpecialFolderByAccountIdAsync(Guid accountId, SpecialFolderType type);
|
||||
Task<int> GetCurrentItemCountForFolder(Guid folderId);
|
||||
Task<int> GetFolderNotificationBadgeAsync(Guid folderId);
|
||||
Task ChangeStickyStatusAsync(Guid folderId, bool isSticky);
|
||||
Task UpdateCustomServerMailListAsync(Guid accountId, List<MailItemFolder> folders);
|
||||
|
||||
Task<MailAccount> UpdateSystemFolderConfigurationAsync(Guid accountId, SystemFolderConfiguration configuration);
|
||||
Task ChangeFolderSynchronizationStateAsync(Guid folderId, bool isSynchronizationEnabled);
|
||||
@@ -39,16 +37,6 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// </summary>
|
||||
Task<List<MailFolderPairMetadata>> GetMailFolderPairMetadatasAsync(string mailCopyId);
|
||||
|
||||
// v2
|
||||
|
||||
/// <summary>
|
||||
/// Performs bulk update for the given folders.
|
||||
/// Used in Gmail.
|
||||
/// </summary>
|
||||
/// <param name="accountId">Account that folders belong to.</param>
|
||||
/// <param name="allFolders">Folders to update.</param>
|
||||
Task BulkUpdateFolderStructureAsync(Guid accountId, List<MailItemFolder> allFolders);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the folder for the given account by remote folder id.
|
||||
/// </summary>
|
||||
@@ -84,12 +72,23 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// <param name="folderId">Folder to update.</param>
|
||||
Task UpdateFolderLastSyncDateAsync(Guid folderId);
|
||||
|
||||
Task TestAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the given folder.
|
||||
/// </summary>
|
||||
/// <param name="folder">Folder to update.</param>
|
||||
Task UpdateFolderAsync(MailItemFolder folder);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active folder menu items for the given account for UI.
|
||||
/// </summary>
|
||||
/// <param name="accountMenuItem">Account to get folder menu items for.</param>
|
||||
Task<IEnumerable<IMenuItem>> GetAccountFoldersForDisplayAsync(IAccountMenuItem accountMenuItem);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of unread item counts for the given account ids.
|
||||
/// Every folder that is marked as show unread badge is included.
|
||||
/// </summary>
|
||||
/// <param name="accountIds">Account ids to get unread folder counts for.</param>
|
||||
Task<List<UnreadItemCountResult>> GetUnreadItemCountResultsAsync(IEnumerable<Guid> accountIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,6 @@ namespace Wino.Core.Domain.Interfaces
|
||||
Task<MailCopy> CreateDraftAsync(MailAccount composerAccount, MimeMessage generatedReplyMime, MimeMessage replyingMimeMessage = null, IMailItem replyingMailItem = null);
|
||||
Task<List<IMailItem>> FetchMailsAsync(MailListInitializationOptions options);
|
||||
|
||||
Task<List<string>> GetMailIdsByFolderIdAsync(Guid folderId);
|
||||
|
||||
// v2
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all mail copies for all folders.
|
||||
/// </summary>
|
||||
@@ -84,5 +80,17 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="mailCopyId">Native mail id of the message.</param>
|
||||
Task<bool> IsMailExistsAsync(string mailCopyId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all mails for given folder id.
|
||||
/// </summary>
|
||||
/// <param name="folderId">Folder id to get mails for</param>
|
||||
Task<List<MailCopy>> GetMailsByFolderIdAsync(Guid folderId);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all unread mails for given folder id.
|
||||
/// </summary>
|
||||
/// <param name="folderId">Folder id to get unread mails for.</param>
|
||||
Task<List<MailCopy>> GetUnreadMailsByFolderIdAsync(Guid folderId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,15 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// Reverts the UI changes applied by <see cref="ApplyUIChanges"/> if the request fails.
|
||||
/// </summary>
|
||||
void RevertUIChanges();
|
||||
|
||||
/// <summary>
|
||||
/// Whether synchronizations should be delayed after executing this request.
|
||||
/// Specially Outlook sometimes don't report changes back immidiately after sending the API request.
|
||||
/// This results following synchronization to miss the changes.
|
||||
/// We add small delay for the following synchronization after executing current requests to overcome this issue.
|
||||
/// Default is false.
|
||||
/// </summary>
|
||||
bool DelayExecution { get; }
|
||||
}
|
||||
|
||||
public interface IRequest : IRequestBase
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
@@ -28,8 +27,7 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// <summary>
|
||||
/// Prepares requires IRequest collection for folder actions and executes them via proper synchronizers.
|
||||
/// </summary>
|
||||
/// <param name="operation">Folder operation to execute.</param>
|
||||
/// <param name="folderStructure">Target folder</param>
|
||||
Task ExecuteAsync(FolderOperation operation, IMailItemFolder folderStructure);
|
||||
/// <param name="folderOperationPreperationRequest">Folder prep request.</param>
|
||||
Task ExecuteAsync(FolderOperationPreperationRequest folderOperationPreperationRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Requests;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces
|
||||
{
|
||||
public interface IWinoRequestProcessor
|
||||
{
|
||||
Task<IRequest> PrepareFolderRequestAsync(FolderOperation operation, IMailItemFolder mailItemFolder);
|
||||
/// <summary>
|
||||
/// Prepares proper folder action requests for synchronizers to execute.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>Base request that synchronizer can execute.</returns>
|
||||
Task<IRequestBase> PrepareFolderRequestAsync(FolderOperationPreperationRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares proper Wino requests for synchronizers to execute categorized by AccountId and FolderId.
|
||||
@@ -17,6 +20,7 @@ namespace Wino.Core.Domain.Interfaces
|
||||
/// <param name="operation">User action</param>
|
||||
/// <param name="mailCopyIds">Selected mails.</param>
|
||||
/// <exception cref="UnavailableSpecialFolderException">When required folder target is not available for account.</exception>
|
||||
/// <returns>Base request that synchronizer can execute.</returns>
|
||||
Task<List<IRequest>> PrepareRequestsAsync(MailOperationPreperationRequest request);
|
||||
}
|
||||
}
|
||||
|
||||
13
Wino.Core.Domain/Models/Accounts/UnreadItemCountResult.cs
Normal file
13
Wino.Core.Domain/Models/Accounts/UnreadItemCountResult.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Wino.Core.Domain.Enums;
|
||||
|
||||
namespace Wino.Core.Domain.Models.Accounts
|
||||
{
|
||||
public class UnreadItemCountResult
|
||||
{
|
||||
public Guid FolderId { get; set; }
|
||||
public Guid AccountId { get; set; }
|
||||
public SpecialFolderType SpecialFolderType { get; set; }
|
||||
public int UnreadItemCount { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Enums;
|
||||
|
||||
namespace Wino.Core.Domain.Models.Folders
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates a request to prepare a folder operation like Rename, Delete, etc.
|
||||
/// </summary>
|
||||
/// <param name="Action">Folder operation.</param>
|
||||
/// <param name="Folder">Target folder.</param>
|
||||
public record FolderOperationPreperationRequest(FolderOperation Action, MailItemFolder Folder) { }
|
||||
}
|
||||
@@ -9,61 +9,31 @@ namespace Wino.Core.Domain.Models.MailItem
|
||||
/// <summary>
|
||||
/// Encapsulates the options for preparing requests to execute mail operations for mail items like Move, Delete, MarkAsRead, etc.
|
||||
/// </summary>
|
||||
public class MailOperationPreperationRequest
|
||||
/// <param name="Action"> Action to execute. </param>
|
||||
/// <param name="MailItems"> Mail copies execute the action on. </param>
|
||||
/// <param name="ToggleExecution"> Whether the operation can be reverted if needed.
|
||||
/// eg. MarkAsRead on already read item will set the action to MarkAsUnread.
|
||||
/// This is used in hover actions for example. </param>
|
||||
/// <param name="IgnoreHardDeleteProtection"> Whether hard delete protection should be ignored.
|
||||
/// Discard draft requests for example should ignore hard delete protection. </param>
|
||||
/// <param name="MoveTargetFolder"> Moving folder for the Move operation.
|
||||
/// If null and the action is Move, the user will be prompted to select a folder. </param>
|
||||
public record MailOperationPreperationRequest(MailOperation Action, IEnumerable<MailCopy> MailItems, bool ToggleExecution, bool IgnoreHardDeleteProtection, IMailItemFolder MoveTargetFolder)
|
||||
{
|
||||
public MailOperationPreperationRequest(MailOperation action,
|
||||
IEnumerable<MailCopy> mailItems,
|
||||
bool toggleExecution = false,
|
||||
IMailItemFolder moveTargetFolder = null,
|
||||
bool ignoreHardDeleteProtection = false)
|
||||
bool ignoreHardDeleteProtection = false) : this(action, mailItems ?? throw new ArgumentNullException(nameof(mailItems)), toggleExecution, ignoreHardDeleteProtection, moveTargetFolder)
|
||||
{
|
||||
Action = action;
|
||||
MailItems = mailItems ?? throw new ArgumentNullException(nameof(mailItems));
|
||||
ToggleExecution = toggleExecution;
|
||||
MoveTargetFolder = moveTargetFolder;
|
||||
IgnoreHardDeleteProtection = ignoreHardDeleteProtection;
|
||||
}
|
||||
|
||||
public MailOperationPreperationRequest(MailOperation action,
|
||||
MailCopy singleMailItem,
|
||||
bool toggleExecution = false,
|
||||
IMailItemFolder moveTargetFolder = null,
|
||||
bool ignoreHardDeleteProtection = false)
|
||||
bool ignoreHardDeleteProtection = false) : this(action, new List<MailCopy>() { singleMailItem }, toggleExecution, ignoreHardDeleteProtection, moveTargetFolder)
|
||||
{
|
||||
Action = action;
|
||||
MailItems = new List<MailCopy>() { singleMailItem };
|
||||
ToggleExecution = toggleExecution;
|
||||
MoveTargetFolder = moveTargetFolder;
|
||||
IgnoreHardDeleteProtection = ignoreHardDeleteProtection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action to execute.
|
||||
/// </summary>
|
||||
public MailOperation Action { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mail copies execute the action on.
|
||||
/// </summary>
|
||||
public IEnumerable<MailCopy> MailItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the operation can be reverted if needed.
|
||||
/// eg. MarkAsRead on already read item will set the action to MarkAsUnread.
|
||||
/// This is used in hover actions for example.
|
||||
/// </summary>
|
||||
public bool ToggleExecution { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether hard delete protection should be ignored.
|
||||
/// Discard draft requests for example should ignore hard delete protection.
|
||||
/// </summary>
|
||||
public bool IgnoreHardDeleteProtection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Moving folder for the Move operation.
|
||||
/// If null and the action is Move, the user will be prompted to select a folder.
|
||||
/// </summary>
|
||||
public IMailItemFolder MoveTargetFolder { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
public enum NavigationTransitionType
|
||||
{
|
||||
None, // Supress
|
||||
DrillIn,
|
||||
DrillIn
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,23 @@ namespace Wino.Core.Domain.Models.Requests
|
||||
public abstract IBatchChangeRequest CreateBatch(IEnumerable<IRequest> requests);
|
||||
public abstract void ApplyUIChanges();
|
||||
public abstract void RevertUIChanges();
|
||||
|
||||
public virtual bool DelayExecution => false;
|
||||
}
|
||||
|
||||
public abstract record FolderRequestBase(MailItemFolder Folder, MailSynchronizerOperation Operation) : IFolderRequest
|
||||
{
|
||||
public abstract void ApplyUIChanges();
|
||||
public abstract void RevertUIChanges();
|
||||
|
||||
public virtual bool DelayExecution => false;
|
||||
}
|
||||
|
||||
public abstract record BatchRequestBase(IEnumerable<IRequest> Items, MailSynchronizerOperation Operation) : IBatchChangeRequest
|
||||
{
|
||||
public abstract void ApplyUIChanges();
|
||||
public abstract void RevertUIChanges();
|
||||
|
||||
public virtual bool DelayExecution => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@
|
||||
"DialogMessage_UnlinkAccountsConfirmationTitle": "Unlink Accounts",
|
||||
"DialogMessage_EmptySubjectConfirmation": "Missin Subject",
|
||||
"DialogMessage_EmptySubjectConfirmationMessage": "Message has no subject. Do you want to continue?",
|
||||
"DialogMessage_RenameFolderTitle": "Rename Folder",
|
||||
"DialogMessage_RenameFolderMessage": "Enter new name for this folder",
|
||||
"DialogMessage_UnsubscribeConfirmationTitle": "Unsubscribe",
|
||||
"DialogMessage_UnsubscribeConfirmationOneClickMessage": "Do you want to stop getting messages from {0}?",
|
||||
"DialogMessage_UnsubscribeConfirmationGoToWebsiteMessage": "To stop getting messages from {0}, go to their website to unsubscribe.",
|
||||
|
||||
535
Wino.Core.Domain/Translator.Designer.cs
generated
535
Wino.Core.Domain/Translator.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user