Add mail categories support
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using SQLite;
|
||||
using Wino.Core.Domain.Enums;
|
||||
|
||||
namespace Wino.Core.Domain.Entities.Mail;
|
||||
|
||||
public class MailCategory
|
||||
{
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid MailAccountId { get; set; }
|
||||
|
||||
public string RemoteId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool IsFavorite { get; set; }
|
||||
|
||||
public string BackgroundColorHex { get; set; }
|
||||
|
||||
public string TextColorHex { get; set; }
|
||||
|
||||
public MailCategorySource Source { get; set; } = MailCategorySource.Local;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using SQLite;
|
||||
|
||||
namespace Wino.Core.Domain.Entities.Mail;
|
||||
|
||||
public class MailCategoryAssignment
|
||||
{
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid MailCategoryId { get; set; }
|
||||
|
||||
public Guid MailCopyUniqueId { get; set; }
|
||||
}
|
||||
@@ -132,5 +132,10 @@ public class MailAccount
|
||||
/// </summary>
|
||||
public bool IsAliasSyncSupported => ProviderType == MailProviderType.Gmail || ProviderType == MailProviderType.Outlook;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the account can perform category definition sync type.
|
||||
/// </summary>
|
||||
public bool IsCategorySyncSupported => ProviderType == MailProviderType.Outlook;
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Wino.Core.Domain.Enums;
|
||||
|
||||
public enum MailCategorySource
|
||||
{
|
||||
Local,
|
||||
Outlook
|
||||
}
|
||||
@@ -13,6 +13,7 @@ public enum MailSynchronizerOperation
|
||||
AlwaysMoveTo,
|
||||
MoveToFocused,
|
||||
Archive,
|
||||
UpdateCategories,
|
||||
}
|
||||
|
||||
public enum FolderSynchronizerOperation
|
||||
@@ -35,6 +36,13 @@ public enum CalendarSynchronizerOperation
|
||||
TentativeEvent,
|
||||
}
|
||||
|
||||
public enum CategorySynchronizerOperation
|
||||
{
|
||||
CreateCategory,
|
||||
UpdateCategory,
|
||||
DeleteCategory,
|
||||
}
|
||||
|
||||
// UI requests
|
||||
public enum MailOperation
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
public enum MailSynchronizationType
|
||||
{
|
||||
UpdateProfile, // Only update profile information
|
||||
Categories, // Only update mail categories
|
||||
ExecuteRequests, // Run the queued requests, and then synchronize if needed.
|
||||
FoldersOnly, // Only synchronize folder metadata.
|
||||
InboxOnly, // Only Inbox, Sent, Draft and Deleted folders.
|
||||
|
||||
@@ -24,6 +24,7 @@ public enum WinoPage
|
||||
AppPreferencesPage,
|
||||
SettingOptionsPage,
|
||||
AliasManagementPage,
|
||||
MailCategoryManagementPage,
|
||||
ImapCalDavSettingsPage,
|
||||
KeyboardShortcutsPage,
|
||||
CalendarPage,
|
||||
|
||||
@@ -14,6 +14,22 @@ public interface IFolderMenuItem : IBaseFolderMenuItem
|
||||
|
||||
public interface IMergedAccountFolderMenuItem : IBaseFolderMenuItem { }
|
||||
|
||||
public interface IMailCategoryMenuItem : IBaseFolderMenuItem
|
||||
{
|
||||
Entities.Mail.MailCategory MailCategory { get; }
|
||||
string TextColorHex { get; }
|
||||
string BackgroundColorHex { get; }
|
||||
bool HasTextColor { get; }
|
||||
}
|
||||
|
||||
public interface IMergedMailCategoryMenuItem : IBaseFolderMenuItem
|
||||
{
|
||||
IReadOnlyList<Entities.Mail.MailCategory> Categories { get; }
|
||||
string TextColorHex { get; }
|
||||
string BackgroundColorHex { get; }
|
||||
bool HasTextColor { get; }
|
||||
}
|
||||
|
||||
public interface IBaseFolderMenuItem : IMenuItem
|
||||
{
|
||||
string FolderName { get; }
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces;
|
||||
|
||||
public interface IMailCategoryService
|
||||
{
|
||||
Task<List<MailCategory>> GetCategoriesAsync(Guid accountId);
|
||||
Task<List<MailCategory>> GetFavoriteCategoriesAsync(Guid accountId);
|
||||
Task<MailCategory> GetCategoryAsync(Guid categoryId);
|
||||
Task<bool> CategoryNameExistsAsync(Guid accountId, string name, Guid? excludedCategoryId = null);
|
||||
Task<MailCategory> CreateCategoryAsync(MailCategory category);
|
||||
Task UpdateCategoryAsync(MailCategory category);
|
||||
Task DeleteCategoryAsync(Guid categoryId);
|
||||
Task DeleteCategoriesAsync(Guid accountId);
|
||||
Task ToggleFavoriteAsync(Guid categoryId, bool isFavorite);
|
||||
Task UpdateRemoteIdAsync(Guid categoryId, string remoteId);
|
||||
Task ReplaceCategoriesAsync(Guid accountId, IEnumerable<MailCategory> categories);
|
||||
Task ReplaceMailAssignmentsAsync(Guid accountId, Guid mailCopyUniqueId, IEnumerable<string> categoryNames);
|
||||
Task AssignCategoryAsync(Guid categoryId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task UnassignCategoryAsync(Guid categoryId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<MailCategory>> GetCategoriesForMailAsync(Guid accountId, IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<Guid>> GetAssignedCategoryIdsForAllAsync(IEnumerable<Guid> mailCopyUniqueIds);
|
||||
Task<List<string>> GetCategoryNamesForMailAsync(Guid mailCopyUniqueId);
|
||||
Task<List<MailCopy>> GetMailCopiesForCategoryAsync(Guid categoryId);
|
||||
Task<List<UnreadCategoryCountResult>> GetUnreadCategoryCountResultsAsync(IEnumerable<Guid> accountIds);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces;
|
||||
|
||||
@@ -51,6 +52,13 @@ public interface IMailDialogService : IDialogServiceBase
|
||||
/// <returns>Created alias model if not canceled.</returns>
|
||||
Task<ICreateAccountAliasDialog> ShowCreateAccountAliasDialogAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Presents a dialog to the user for mail category creation/modification.
|
||||
/// </summary>
|
||||
#pragma warning disable CS8625
|
||||
Task<MailCategoryDialogResult> ShowEditMailCategoryDialogAsync(MailCategory category = null);
|
||||
#pragma warning restore CS8625
|
||||
|
||||
/// <summary>
|
||||
/// Presents a dialog to the user to show email source.
|
||||
/// </summary>
|
||||
|
||||
@@ -72,3 +72,9 @@ public interface ICalendarActionRequest : IRequestBase
|
||||
Guid? LocalCalendarItemId { get; }
|
||||
CalendarSynchronizerOperation Operation { get; }
|
||||
}
|
||||
|
||||
public interface ICategoryActionRequest : IRequestBase
|
||||
{
|
||||
Guid AccountId { get; }
|
||||
CategorySynchronizerOperation Operation { get; }
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@ public interface ISynchronizationManager
|
||||
Task<MailSynchronizationResult> SynchronizeAliasesAsync(Guid accountId,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Handles category synchronization for the given account.
|
||||
/// </summary>
|
||||
Task<MailSynchronizationResult> SynchronizeCategoriesAsync(Guid accountId,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Handles profile synchronization for the given account.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
@@ -36,4 +38,9 @@ public interface IWinoRequestDelegator
|
||||
/// </summary>
|
||||
/// <param name="calendarOperationPreparationRequest">Calendar preparation request.</param>
|
||||
Task ExecuteAsync(CalendarOperationPreparationRequest calendarOperationPreparationRequest);
|
||||
|
||||
/// <summary>
|
||||
/// Queues pre-built requests for a single account and triggers synchronization.
|
||||
/// </summary>
|
||||
Task ExecuteAsync(Guid accountId, IEnumerable<IRequestBase> requests);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
|
||||
namespace Wino.Core.Domain.MenuItems;
|
||||
|
||||
public partial class MailCategoryMenuItem : MenuItemBase<MailCategory, IMenuItem>, IFolderMenuItem, IMailCategoryMenuItem
|
||||
{
|
||||
private IReadOnlyList<IMailItemFolder> _handlingFolders;
|
||||
|
||||
[ObservableProperty]
|
||||
private int unreadItemCount;
|
||||
|
||||
public MailCategoryMenuItem(MailCategory category, MailAccount parentAccount, IEnumerable<IMailItemFolder> handlingFolders, IMenuItem parentMenuItem)
|
||||
: base(category, category.Id, parentMenuItem)
|
||||
{
|
||||
ParentAccount = parentAccount;
|
||||
_handlingFolders = handlingFolders?.ToList() ?? [];
|
||||
}
|
||||
|
||||
public string FolderName => Parameter.Name;
|
||||
public bool IsSynchronizationEnabled => false;
|
||||
public SpecialFolderType SpecialFolderType => SpecialFolderType.Other;
|
||||
public IEnumerable<IMailItemFolder> HandlingFolders => _handlingFolders;
|
||||
public new ObservableCollection<IMenuItem> SubMenuItems { get; } = [];
|
||||
public bool IsMoveTarget => true;
|
||||
public bool IsSticky => false;
|
||||
public bool IsSystemFolder => false;
|
||||
public bool ShowUnreadCount => true;
|
||||
public string AssignedAccountName => ParentAccount?.Name;
|
||||
public MailAccount ParentAccount { get; private set; }
|
||||
public string TextColorHex => Parameter.TextColorHex;
|
||||
public string BackgroundColorHex => Parameter.BackgroundColorHex;
|
||||
public bool HasTextColor => !string.IsNullOrWhiteSpace(Parameter.TextColorHex);
|
||||
public MailCategory MailCategory => Parameter;
|
||||
|
||||
public void UpdateFolder(IMailItemFolder folder)
|
||||
{
|
||||
}
|
||||
|
||||
public void UpdateParentAccounnt(MailAccount account) => ParentAccount = account;
|
||||
}
|
||||
@@ -22,11 +22,13 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
public IEnumerable<IAccountMenuItem> GetAllAccountMenuItems()
|
||||
{
|
||||
foreach (var item in this)
|
||||
var rootItems = this.ToList();
|
||||
|
||||
foreach (var item in rootItems)
|
||||
{
|
||||
if (item is MergedAccountMenuItem mergedAccountMenuItem)
|
||||
{
|
||||
foreach (var singleItem in mergedAccountMenuItem.SubMenuItems.OfType<IAccountMenuItem>())
|
||||
foreach (var singleItem in mergedAccountMenuItem.SubMenuItems.OfType<IAccountMenuItem>().ToList())
|
||||
{
|
||||
yield return singleItem;
|
||||
}
|
||||
@@ -40,9 +42,11 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
public IEnumerable<IBaseFolderMenuItem> GetAllFolderMenuItems(Guid folderId)
|
||||
{
|
||||
foreach (var item in this)
|
||||
var rootItems = this.ToList();
|
||||
|
||||
foreach (var item in rootItems)
|
||||
{
|
||||
if (item is IBaseFolderMenuItem folderMenuItem)
|
||||
if (item is IBaseFolderMenuItem folderMenuItem && item is not IMailCategoryMenuItem && item is not IMergedMailCategoryMenuItem)
|
||||
{
|
||||
if (folderMenuItem.HandlingFolders.Any(a => a.Id == folderId))
|
||||
{
|
||||
@@ -50,7 +54,7 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
}
|
||||
else if (folderMenuItem.SubMenuItems.Any())
|
||||
{
|
||||
foreach (var subItem in folderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>())
|
||||
foreach (var subItem in folderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>().ToList())
|
||||
{
|
||||
if (subItem.HandlingFolders.Any(a => a.Id == folderId))
|
||||
{
|
||||
@@ -65,8 +69,10 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
public bool TryGetAccountMenuItem(Guid accountId, out IAccountMenuItem value)
|
||||
{
|
||||
value = this.OfType<AccountMenuItem>().FirstOrDefault(a => a.AccountId == accountId);
|
||||
value ??= this.OfType<MergedAccountMenuItem>().FirstOrDefault(a => a.SubMenuItems.OfType<AccountMenuItem>().Where(b => b.AccountId == accountId) != null);
|
||||
var rootItems = this.ToList();
|
||||
|
||||
value = rootItems.OfType<AccountMenuItem>().FirstOrDefault(a => a.AccountId == accountId);
|
||||
value ??= rootItems.OfType<MergedAccountMenuItem>().FirstOrDefault(a => a.SubMenuItems.OfType<AccountMenuItem>().Any(b => b.AccountId == accountId));
|
||||
|
||||
return value != null;
|
||||
}
|
||||
@@ -74,7 +80,9 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
// Pattern: Look for special folder menu item inside the loaded folders for Windows Mail style menu items.
|
||||
public bool TryGetWindowsStyleRootSpecialFolderMenuItem(Guid accountId, SpecialFolderType specialFolderType, out FolderMenuItem value)
|
||||
{
|
||||
value = this.OfType<IBaseFolderMenuItem>()
|
||||
var rootItems = this.ToList();
|
||||
|
||||
value = rootItems.OfType<IBaseFolderMenuItem>()
|
||||
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.MailAccountId == accountId && b.SpecialFolderType == specialFolderType)) as FolderMenuItem;
|
||||
|
||||
return value != null;
|
||||
@@ -84,7 +92,9 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
// This will not look for the folders inside individual account menu items inside merged account menu item.
|
||||
public bool TryGetMergedAccountSpecialFolderMenuItem(Guid mergedInboxId, SpecialFolderType specialFolderType, out IBaseFolderMenuItem value)
|
||||
{
|
||||
value = this.OfType<MergedAccountFolderMenuItem>()
|
||||
var rootItems = this.ToList();
|
||||
|
||||
value = rootItems.OfType<MergedAccountFolderMenuItem>()
|
||||
.Where(a => a.MergedInbox.Id == mergedInboxId)
|
||||
.FirstOrDefault(a => a.SpecialFolderType == specialFolderType);
|
||||
|
||||
@@ -93,11 +103,14 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
public bool TryGetFolderMenuItem(Guid folderId, out IBaseFolderMenuItem value)
|
||||
{
|
||||
var rootItems = this.ToList();
|
||||
|
||||
// Root folders
|
||||
value = this.OfType<IBaseFolderMenuItem>()
|
||||
value = rootItems.OfType<IBaseFolderMenuItem>()
|
||||
.Where(a => a is not IMailCategoryMenuItem && a is not IMergedMailCategoryMenuItem)
|
||||
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
|
||||
|
||||
value ??= this.OfType<FolderMenuItem>()
|
||||
value ??= rootItems.OfType<FolderMenuItem>()
|
||||
.SelectMany(a => a.SubMenuItems)
|
||||
.OfType<IBaseFolderMenuItem>()
|
||||
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
|
||||
@@ -105,10 +118,23 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public bool TryGetCategoryMenuItem(Guid categoryId, out IBaseFolderMenuItem value)
|
||||
{
|
||||
var rootItems = this.ToList();
|
||||
|
||||
value = rootItems.OfType<IMailCategoryMenuItem>()
|
||||
.FirstOrDefault(a => a.MailCategory.Id == categoryId);
|
||||
|
||||
value ??= rootItems.OfType<IMergedMailCategoryMenuItem>()
|
||||
.FirstOrDefault(a => a.Categories.Any(b => b.Id == categoryId)) as IBaseFolderMenuItem;
|
||||
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public void UpdateUnreadItemCountsToZero()
|
||||
{
|
||||
// Handle the root folders.
|
||||
foreach (var item in this.OfType<IBaseFolderMenuItem>())
|
||||
foreach (var item in this.OfType<IBaseFolderMenuItem>().ToList())
|
||||
{
|
||||
RecursivelyResetUnreadItemCount(item);
|
||||
}
|
||||
@@ -120,7 +146,7 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
if (baseFolderMenuItem.SubMenuItems == null) return;
|
||||
|
||||
foreach (var subMenuItem in baseFolderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>())
|
||||
foreach (var subMenuItem in baseFolderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>().ToList())
|
||||
{
|
||||
RecursivelyResetUnreadItemCount(subMenuItem);
|
||||
}
|
||||
@@ -128,7 +154,9 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
|
||||
public bool TryGetSpecialFolderMenuItem(Guid accountId, SpecialFolderType specialFolderType, out FolderMenuItem value)
|
||||
{
|
||||
value = this.OfType<IBaseFolderMenuItem>()
|
||||
var rootItems = this.ToList();
|
||||
|
||||
value = rootItems.OfType<IBaseFolderMenuItem>()
|
||||
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.MailAccountId == accountId && b.SpecialFolderType == specialFolderType)) as FolderMenuItem;
|
||||
|
||||
return value != null;
|
||||
@@ -142,11 +170,12 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
public AccountMenuItem GetSpecificAccountMenuItem(Guid accountId)
|
||||
{
|
||||
AccountMenuItem accountMenuItem = null;
|
||||
var rootItems = this.ToList();
|
||||
|
||||
accountMenuItem = this.OfType<AccountMenuItem>().FirstOrDefault(a => a.HoldingAccounts.Any(b => b.Id == accountId));
|
||||
accountMenuItem = rootItems.OfType<AccountMenuItem>().FirstOrDefault(a => a.HoldingAccounts.Any(b => b.Id == accountId));
|
||||
|
||||
// Look for the items inside the merged accounts if regular menu item is not found.
|
||||
accountMenuItem ??= this.OfType<MergedAccountMenuItem>()
|
||||
accountMenuItem ??= rootItems.OfType<MergedAccountMenuItem>()
|
||||
.FirstOrDefault(a => a.HoldingAccounts.Any(b => b.Id == accountId))?.SubMenuItems
|
||||
.OfType<AccountMenuItem>()
|
||||
.FirstOrDefault(a => a.AccountId == accountId);
|
||||
@@ -167,7 +196,7 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
/// <param name="isEnabled">Whether menu items should be enabled or disabled.</param>
|
||||
public async Task SetAccountMenuItemEnabledStatusAsync(bool isEnabled)
|
||||
{
|
||||
var accountItems = this.Where(a => a is IAccountMenuItem).Cast<IAccountMenuItem>();
|
||||
var accountItems = this.Where(a => a is IAccountMenuItem).Cast<IAccountMenuItem>().ToList();
|
||||
|
||||
await _dispatcher.ExecuteOnUIThread(() =>
|
||||
{
|
||||
@@ -192,6 +221,7 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
{
|
||||
// Check root-level items.
|
||||
var rootItem = this.OfType<IBaseFolderMenuItem>()
|
||||
.Where(a => a is not IMailCategoryMenuItem && a is not IMergedMailCategoryMenuItem)
|
||||
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
|
||||
|
||||
if (rootItem != null)
|
||||
@@ -201,7 +231,7 @@ public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
|
||||
}
|
||||
|
||||
// Check sub-items of root folders.
|
||||
foreach (var rootFolder in this.OfType<IBaseFolderMenuItem>())
|
||||
foreach (var rootFolder in this.OfType<IBaseFolderMenuItem>().ToList())
|
||||
{
|
||||
var subItem = rootFolder.SubMenuItems
|
||||
.OfType<IBaseFolderMenuItem>()
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
|
||||
namespace Wino.Core.Domain.MenuItems;
|
||||
|
||||
public partial class MergedMailCategoryMenuItem : MenuItemBase<List<MailCategory>, IMenuItem>, IMergedAccountFolderMenuItem, IMergedMailCategoryMenuItem
|
||||
{
|
||||
private readonly IReadOnlyList<IMailItemFolder> _handlingFolders;
|
||||
|
||||
[ObservableProperty]
|
||||
private int unreadItemCount;
|
||||
|
||||
public MergedMailCategoryMenuItem(List<MailCategory> categories, IEnumerable<IMailItemFolder> handlingFolders, MergedInbox mergedInbox)
|
||||
: base(categories, null, null)
|
||||
{
|
||||
_handlingFolders = handlingFolders?.ToList() ?? [];
|
||||
MergedInbox = mergedInbox;
|
||||
}
|
||||
|
||||
public string FolderName => Parameter.FirstOrDefault()?.Name ?? string.Empty;
|
||||
public bool IsSynchronizationEnabled => false;
|
||||
public SpecialFolderType SpecialFolderType => SpecialFolderType.Other;
|
||||
public IEnumerable<IMailItemFolder> HandlingFolders => _handlingFolders;
|
||||
public bool IsMoveTarget => true;
|
||||
public bool IsSticky => false;
|
||||
public bool IsSystemFolder => false;
|
||||
public bool ShowUnreadCount => true;
|
||||
public string AssignedAccountName => MergedInbox?.Name;
|
||||
public MergedInbox MergedInbox { get; }
|
||||
public string TextColorHex => Parameter.FirstOrDefault()?.TextColorHex;
|
||||
public string BackgroundColorHex => Parameter.FirstOrDefault()?.BackgroundColorHex;
|
||||
public bool HasTextColor => !string.IsNullOrWhiteSpace(TextColorHex);
|
||||
public IReadOnlyList<MailCategory> Categories => Parameter;
|
||||
|
||||
public void UpdateFolder(IMailItemFolder folder)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Wino.Core.Domain.Models.Accounts;
|
||||
|
||||
public class UnreadCategoryCountResult
|
||||
{
|
||||
public Guid CategoryId { get; set; }
|
||||
public Guid AccountId { get; set; }
|
||||
public int UnreadItemCount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
public sealed record MailCategoryColorOption(string BackgroundColorHex, string TextColorHex);
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
public sealed record MailCategoryDialogResult(string Name, string BackgroundColorHex, string TextColorHex);
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Wino.Core.Domain.Models.MailItem;
|
||||
|
||||
public static class MailCategoryPalette
|
||||
{
|
||||
public static IReadOnlyList<MailCategoryColorOption> DefaultOptions { get; } =
|
||||
[
|
||||
new("#FEE2E2", "#991B1B"),
|
||||
new("#FECACA", "#7F1D1D"),
|
||||
new("#FFEDD5", "#9A3412"),
|
||||
new("#FED7AA", "#7C2D12"),
|
||||
new("#FEF3C7", "#92400E"),
|
||||
new("#FDE68A", "#78350F"),
|
||||
new("#ECFCCB", "#3F6212"),
|
||||
new("#D9F99D", "#365314"),
|
||||
new("#DCFCE7", "#166534"),
|
||||
new("#BBF7D0", "#14532D"),
|
||||
new("#CCFBF1", "#115E59"),
|
||||
new("#99F6E4", "#134E4A"),
|
||||
new("#CFFAFE", "#155E75"),
|
||||
new("#A5F3FC", "#164E63"),
|
||||
new("#DBEAFE", "#1D4ED8"),
|
||||
new("#BFDBFE", "#1E3A8A"),
|
||||
new("#E0E7FF", "#4338CA"),
|
||||
new("#DDD6FE", "#5B21B6"),
|
||||
new("#F3E8FF", "#7E22CE"),
|
||||
new("#FCE7F3", "#9D174D")
|
||||
];
|
||||
}
|
||||
@@ -9,4 +9,5 @@ public record NewMailItemPackage(
|
||||
MailCopy Copy,
|
||||
MimeMessage Mime,
|
||||
string AssignedRemoteFolderId,
|
||||
IReadOnlyList<AccountContact> ExtractedContacts = null);
|
||||
IReadOnlyList<AccountContact> ExtractedContacts = null,
|
||||
IReadOnlyList<string> CategoryNames = null);
|
||||
|
||||
@@ -17,4 +17,8 @@ public record MailListInitializationOptions(IEnumerable<IMailItemFolder> Folders
|
||||
List<MailCopy> PreFetchMailCopies = null,
|
||||
bool DeduplicateByServerId = false,
|
||||
int Skip = 0,
|
||||
int Take = 0);
|
||||
int Take = 0)
|
||||
{
|
||||
public IReadOnlyList<Guid> CategoryIds { get; init; }
|
||||
public bool IsCategoryView => CategoryIds?.Count > 0;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ public abstract record CalendarRequestBase(CalendarItem Item) : RequestBase<Cale
|
||||
public virtual Guid? LocalCalendarItemId => Item?.Id;
|
||||
}
|
||||
|
||||
public abstract record CategoryRequestBase(Guid AccountId) : RequestBase<CategorySynchronizerOperation>, ICategoryActionRequest
|
||||
{
|
||||
}
|
||||
|
||||
public class BatchCollection<TRequestType> : List<TRequestType>, IUIChangeRequest where TRequestType : IUIChangeRequest
|
||||
{
|
||||
public BatchCollection(IEnumerable<TRequestType> collection) : base(collection)
|
||||
|
||||
@@ -170,6 +170,7 @@ public static class SettingsNavigationInfoProvider
|
||||
WinoPage.AccountDetailsPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.MergedAccountDetailsPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.AliasManagementPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.MailCategoryManagementPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.SignatureManagementPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.ImapCalDavSettingsPage => WinoPage.ManageAccountsPage,
|
||||
WinoPage.CreateEmailTemplatePage => WinoPage.EmailTemplatesPage,
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
"BasicIMAPSetupDialog_Password": "Password",
|
||||
"BasicIMAPSetupDialog_Title": "IMAP Account",
|
||||
"Busy": "Busy",
|
||||
"Buttons_Add": "Add",
|
||||
"Buttons_AddAccount": "Add Account",
|
||||
"Buttons_FixAccount": "Fix Account",
|
||||
"Buttons_AddNewAlias": "Add New Alias",
|
||||
@@ -875,10 +876,28 @@
|
||||
"SettingsManageAccountSettings_Title": "Manage Accounts",
|
||||
"SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.",
|
||||
"SettingsManageAliases_Title": "Aliases",
|
||||
"SettingsMailCategories_Description": "Manage synchronized and local categories for this account.",
|
||||
"SettingsMailCategories_Title": "Categories",
|
||||
"SettingsEditAccountDetails_Title": "Edit Account Details",
|
||||
"SettingsEditAccountDetails_Description": "Change account name, sender name and assign a new color if you like.",
|
||||
"EditAccountDetailsPage_SaveSuccess_Title": "Changes Saved",
|
||||
"EditAccountDetailsPage_SaveSuccess_Message": "Your account details have been updated successfully.",
|
||||
"MailCategoryManagementPage_Title": "Categories",
|
||||
"MailCategoryManagementPage_Description": "Create, edit, delete, and favorite categories for this account.",
|
||||
"MailCategoryManagementPage_Empty": "No categories yet.",
|
||||
"MailCategoryManagementPage_DeleteConfirmationTitle": "Delete Category",
|
||||
"MailCategoryManagementPage_DeleteConfirmationMessage": "Delete category \"{0}\"?",
|
||||
"MailCategoryManagementPage_RefreshConfirmationMessage": "This will delete all your local categories, and re-synchronize everything from the server. Do you want to continue?",
|
||||
"MailCategoryMenuItem": "Category",
|
||||
"MailCategoryDialog_CreateTitle": "Create category",
|
||||
"MailCategoryDialog_EditTitle": "Edit category",
|
||||
"MailCategoryDialog_Name": "Name",
|
||||
"MailCategoryDialog_NamePlaceholder": "Category name",
|
||||
"MailCategoryDialog_Color": "Color",
|
||||
"MailCategoryDialog_InvalidNameTitle": "Category name required",
|
||||
"MailCategoryDialog_InvalidNameMessage": "Enter a category name to continue.",
|
||||
"MailCategoryDialog_DuplicateTitle": "Category already exists",
|
||||
"MailCategoryDialog_DuplicateMessage": "A category with the same name already exists for this account.",
|
||||
"SettingsManageLink_Description": "Move items to add new link or remove existing link.",
|
||||
"SettingsManageLink_Title": "Manage Link",
|
||||
"SettingsMarkAsRead_Description": "Change what should happen to the selected item.",
|
||||
@@ -1491,11 +1510,13 @@
|
||||
"AccountSetup_Step_TestingCalendarAuth": "Testing calendar authentication",
|
||||
"AccountSetup_Step_SavingAccount": "Saving account information",
|
||||
"AccountSetup_Step_FetchingCalendarMetadata": "Fetching calendar metadata",
|
||||
"AccountSetup_Step_SyncingCategories": "Synchronizing categories",
|
||||
"AccountSetup_Step_SyncingAliases": "Synchronizing aliases",
|
||||
"AccountSetup_Step_Finalizing": "Finalizing setup",
|
||||
"AccountSetup_FailureMessage": "Setup failed. Go back to fix your settings, or try again later.",
|
||||
"AccountSetup_SuccessMessage": "Your account has been set up successfully!",
|
||||
"AccountSetup_GoBackButton": "Go Back",
|
||||
"AccountSetup_TryAgainButton": "Try Again",
|
||||
"Exception_FailedToSynchronizeCategories": "Failed to synchronize categories",
|
||||
"ImapCalDavSettings_AutoDiscoveryFailed": "Auto-discovery failed. Please enter settings manually in the Advanced tab."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user