Files
Wino-Mail/Wino.Mail.ViewModels/MailCategoryManagementPageViewModel.cs
2026-04-20 19:38:37 +02:00

250 lines
9.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Wino.Core.Domain;
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.Navigation;
using Wino.Core.Requests.Category;
using Wino.Core.Services;
namespace Wino.Mail.ViewModels;
public partial class MailCategoryManagementPageViewModel : MailBaseViewModel
{
private readonly IMailCategoryService _mailCategoryService;
private readonly IAccountService _accountService;
private readonly IMailDialogService _dialogService;
private readonly IWinoRequestDelegator _winoRequestDelegator;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanRefresh))]
public partial MailAccount Account { get; set; }
public ObservableCollection<MailCategory> Categories { get; } = [];
public bool CanRefresh => Account?.ProviderType == MailProviderType.Outlook;
public bool HasCategories => Categories.Count > 0;
public MailCategoryManagementPageViewModel(
IMailCategoryService mailCategoryService,
IAccountService accountService,
IMailDialogService dialogService,
IWinoRequestDelegator winoRequestDelegator)
{
_mailCategoryService = mailCategoryService;
_accountService = accountService;
_dialogService = dialogService;
_winoRequestDelegator = winoRequestDelegator;
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
if (parameters is not Guid accountId)
return;
Account = await _accountService.GetAccountAsync(accountId);
if (Account != null)
{
await LoadCategoriesAsync();
}
}
[RelayCommand]
private Task AddCategoryAsync()
=> CreateOrUpdateCategoryAsync();
[RelayCommand]
private async Task RefreshCategoriesAsync()
{
if (!CanRefresh)
return;
var shouldContinue = await _dialogService.ShowConfirmationDialogAsync(
Translator.MailCategoryManagementPage_RefreshConfirmationMessage,
Translator.Buttons_Refresh,
Translator.Buttons_Refresh).ConfigureAwait(false);
if (!shouldContinue)
return;
await _mailCategoryService.DeleteCategoriesAsync(Account.Id).ConfigureAwait(false);
await SynchronizationManager.Instance.SynchronizeCategoriesAsync(Account.Id).ConfigureAwait(false);
await LoadCategoriesAsync().ConfigureAwait(false);
}
public Task EditCategoryAsync(MailCategory category)
=> CreateOrUpdateCategoryAsync(category);
public async Task DeleteCategoryAsync(MailCategory category)
{
if (category == null)
return;
var shouldDelete = await _dialogService.ShowConfirmationDialogAsync(
string.Format(Translator.MailCategoryManagementPage_DeleteConfirmationMessage, category.Name),
Translator.MailCategoryManagementPage_DeleteConfirmationTitle,
Translator.Buttons_Delete).ConfigureAwait(false);
if (!shouldDelete)
return;
var deleteRequest = await BuildDeleteCategoryRequestAsync(category).ConfigureAwait(false);
await _mailCategoryService.DeleteCategoryAsync(category.Id).ConfigureAwait(false);
await QueueOutlookCategoryRequestsAsync(deleteRequest).ConfigureAwait(false);
await LoadCategoriesAsync().ConfigureAwait(false);
}
public async Task SetFavoriteAsync(MailCategory category, bool isFavorite)
{
if (category == null)
return;
await _mailCategoryService.ToggleFavoriteAsync(category.Id, isFavorite).ConfigureAwait(false);
await LoadCategoriesAsync().ConfigureAwait(false);
}
private async Task CreateOrUpdateCategoryAsync(MailCategory existingCategory = null)
{
var dialogResult = await _dialogService.ShowEditMailCategoryDialogAsync(existingCategory).ConfigureAwait(false);
if (dialogResult == null)
return;
if (string.IsNullOrWhiteSpace(dialogResult.Name))
{
await _dialogService.ShowMessageAsync(
Translator.MailCategoryDialog_InvalidNameMessage,
Translator.MailCategoryDialog_InvalidNameTitle,
WinoCustomMessageDialogIcon.Warning).ConfigureAwait(false);
return;
}
var normalizedName = dialogResult.Name.Trim();
var categoryIdToExclude = existingCategory?.Id;
var alreadyExists = await _mailCategoryService.CategoryNameExistsAsync(Account.Id, normalizedName, categoryIdToExclude).ConfigureAwait(false);
if (alreadyExists)
{
await _dialogService.ShowMessageAsync(
Translator.MailCategoryDialog_DuplicateMessage,
Translator.MailCategoryDialog_DuplicateTitle,
WinoCustomMessageDialogIcon.Warning).ConfigureAwait(false);
return;
}
if (existingCategory == null)
{
var newCategory = new MailCategory
{
Id = Guid.NewGuid(),
MailAccountId = Account.Id,
Name = normalizedName,
BackgroundColorHex = dialogResult.BackgroundColorHex,
TextColorHex = dialogResult.TextColorHex,
Source = Account.ProviderType == MailProviderType.Outlook ? MailCategorySource.Outlook : MailCategorySource.Local
};
await _mailCategoryService.CreateCategoryAsync(newCategory).ConfigureAwait(false);
if (Account.ProviderType == MailProviderType.Outlook)
{
await _winoRequestDelegator.ExecuteAsync(Account.Id, [new MailCategoryCreateRequest(newCategory)]).ConfigureAwait(false);
}
}
else
{
var previousName = existingCategory.Name;
var previousRemoteId = existingCategory.RemoteId;
existingCategory.Name = normalizedName;
existingCategory.BackgroundColorHex = dialogResult.BackgroundColorHex;
existingCategory.TextColorHex = dialogResult.TextColorHex;
await _mailCategoryService.UpdateCategoryAsync(existingCategory).ConfigureAwait(false);
if (Account.ProviderType == MailProviderType.Outlook)
{
if (string.IsNullOrWhiteSpace(previousRemoteId))
{
await _winoRequestDelegator.ExecuteAsync(Account.Id, [new MailCategoryCreateRequest(existingCategory)]).ConfigureAwait(false);
}
else
{
var affectedMessages = await BuildAffectedMessageTargetsAsync(existingCategory.Id).ConfigureAwait(false);
var updateRequest = new MailCategoryUpdateRequest(existingCategory, previousName, previousRemoteId, affectedMessages);
await _winoRequestDelegator.ExecuteAsync(Account.Id, [updateRequest]).ConfigureAwait(false);
}
}
}
await LoadCategoriesAsync().ConfigureAwait(false);
}
private async Task<MailCategoryDeleteRequest> BuildDeleteCategoryRequestAsync(MailCategory category)
{
if (category == null || Account?.ProviderType != MailProviderType.Outlook)
return null;
var mailCopies = await _mailCategoryService.GetMailCopiesForCategoryAsync(category.Id).ConfigureAwait(false);
var affectedMessages = new List<MailCategoryMessageUpdateTarget>();
foreach (var mailCopy in mailCopies.Where(a => !string.IsNullOrWhiteSpace(a.Id)))
{
var remainingNames = await _mailCategoryService.GetCategoryNamesForMailAsync(mailCopy.UniqueId).ConfigureAwait(false);
var categoryNames = remainingNames
.Where(a => !string.Equals(a, category.Name, StringComparison.OrdinalIgnoreCase))
.ToList();
affectedMessages.Add(new MailCategoryMessageUpdateTarget(mailCopy.Id, categoryNames));
}
return new MailCategoryDeleteRequest(category, category.RemoteId, affectedMessages);
}
private async Task<IReadOnlyList<MailCategoryMessageUpdateTarget>> BuildAffectedMessageTargetsAsync(Guid categoryId)
{
var mailCopies = await _mailCategoryService.GetMailCopiesForCategoryAsync(categoryId).ConfigureAwait(false);
var affectedMessages = new List<MailCategoryMessageUpdateTarget>();
foreach (var mailCopy in mailCopies.Where(a => !string.IsNullOrWhiteSpace(a.Id)))
{
var categoryNames = await _mailCategoryService.GetCategoryNamesForMailAsync(mailCopy.UniqueId).ConfigureAwait(false);
affectedMessages.Add(new MailCategoryMessageUpdateTarget(mailCopy.Id, categoryNames));
}
return affectedMessages;
}
private Task QueueOutlookCategoryRequestsAsync(params IRequestBase[] requests)
=> Account?.ProviderType == MailProviderType.Outlook && requests.Any(a => a != null)
? _winoRequestDelegator.ExecuteAsync(Account.Id, requests.Where(a => a != null))
: Task.CompletedTask;
private async Task LoadCategoriesAsync()
{
var categories = await _mailCategoryService.GetCategoriesAsync(Account.Id).ConfigureAwait(false);
await ExecuteUIThread(() =>
{
Categories.Clear();
foreach (var category in categories)
{
Categories.Add(category);
}
OnPropertyChanged(nameof(HasCategories));
});
}
}