From e009bebfafb957461f73c322484b31431f22b9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Fri, 21 Jun 2024 02:11:18 +0200 Subject: [PATCH] Fixed an issue where local draft is deleted via hover over action or delete button instead of discard button. Disabled discarding local drafts in compose page. --- Wino.Core.Domain/Entities/MailCopy.cs | 6 +++ Wino.Core.Domain/Enums/MailOperation.cs | 1 + Wino.Core/Services/WinoRequestProcessor.cs | 19 ++++++- Wino.Mail.ViewModels/ComposePageViewModel.cs | 51 ++++++++++--------- .../Data/MailItemViewModel.cs | 4 -- Wino.Mail/Views/ComposePage.xaml | 5 +- 6 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Wino.Core.Domain/Entities/MailCopy.cs b/Wino.Core.Domain/Entities/MailCopy.cs index de56aa79..5075227f 100644 --- a/Wino.Core.Domain/Entities/MailCopy.cs +++ b/Wino.Core.Domain/Entities/MailCopy.cs @@ -107,6 +107,12 @@ namespace Wino.Core.Domain.Entities /// public string DraftId { get; set; } + /// + /// Whether this mail is only created locally. + /// + [Ignore] + public bool IsLocalDraft => !string.IsNullOrEmpty(DraftId) && DraftId.StartsWith(Constants.LocalDraftStartPrefix); + /// /// Whether this copy is draft or not. /// diff --git a/Wino.Core.Domain/Enums/MailOperation.cs b/Wino.Core.Domain/Enums/MailOperation.cs index d221a090..483b5607 100644 --- a/Wino.Core.Domain/Enums/MailOperation.cs +++ b/Wino.Core.Domain/Enums/MailOperation.cs @@ -44,6 +44,7 @@ DarkEditor, LightEditor, Print, + DiscardLocalDraft, Navigate // For toast activation } } diff --git a/Wino.Core/Services/WinoRequestProcessor.cs b/Wino.Core/Services/WinoRequestProcessor.cs index 598395ff..93c51693 100644 --- a/Wino.Core/Services/WinoRequestProcessor.cs +++ b/Wino.Core/Services/WinoRequestProcessor.cs @@ -25,6 +25,7 @@ namespace Wino.Core.Services private readonly IPreferencesService _preferencesService; private readonly IAccountService _accountService; private readonly IDialogService _dialogService; + private readonly IMailService _mailService; /// /// Set of rules that defines which action should be executed if user wants to toggle an action. @@ -42,13 +43,15 @@ namespace Wino.Core.Services IKeyPressService keyPressService, IPreferencesService preferencesService, IAccountService accountService, - IDialogService dialogService) : base(databaseService) + IDialogService dialogService, + IMailService mailService) : base(databaseService) { _folderService = folderService; _keyPressService = keyPressService; _preferencesService = preferencesService; _accountService = accountService; _dialogService = dialogService; + _mailService = mailService; } public async Task> PrepareRequestsAsync(MailOperationPreperationRequest preperationRequest) @@ -91,7 +94,11 @@ namespace Wino.Core.Services foreach (var item in preperationRequest.MailItems) { - requests.Add(await GetSingleRequestAsync(item, action, moveTargetStructure, preperationRequest.ToggleExecution)); + var singleRequest = await GetSingleRequestAsync(item, action, moveTargetStructure, preperationRequest.ToggleExecution); + + if (singleRequest == null) continue; + + requests.Add(singleRequest); } return requests; @@ -110,6 +117,10 @@ namespace Wino.Core.Services if (action == MailOperation.SoftDelete && mailItem.IsDraft) action = MailOperation.HardDelete; + // Rule: Soft/Hard deletes on local drafts are always discard local draft. + if ((action == MailOperation.SoftDelete || action == MailOperation.HardDelete) && mailItem.IsLocalDraft) + action = MailOperation.DiscardLocalDraft; + // Rule: Toggle actions must be reverted if ToggleExecution is passed true. if (shouldToggleActions) { @@ -179,8 +190,12 @@ namespace Wino.Core.Services } else if (action == MailOperation.AlwaysMoveToFocused || action == MailOperation.AlwaysMoveToOther) return new AlwaysMoveToRequest(mailItem, action == MailOperation.AlwaysMoveToFocused); + else if (action == MailOperation.DiscardLocalDraft) + await _mailService.DeleteMailAsync(mailItem.AssignedAccount.Id, mailItem.Id); else throw new NotSupportedException(string.Format(Translator.Exception_UnsupportedAction, action)); + + return null; } public async Task PrepareFolderRequestAsync(FolderOperation operation, IMailItemFolder mailItemFolder) diff --git a/Wino.Mail.ViewModels/ComposePageViewModel.cs b/Wino.Mail.ViewModels/ComposePageViewModel.cs index 0cbc30e8..2e083e74 100644 --- a/Wino.Mail.ViewModels/ComposePageViewModel.cs +++ b/Wino.Mail.ViewModels/ComposePageViewModel.cs @@ -32,21 +32,23 @@ namespace Wino.Mail.ViewModels // Update is triggered when we leave the page. private bool isUpdatingMimeBlocked = false; - public bool CanSendMail => ComposingAccount != null && !IsLocalDraft && currentMimeMessage != null; + private bool canSendMail => ComposingAccount != null && !IsLocalDraft && CurrentMimeMessage != null; + [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] + [NotifyCanExecuteChangedFor(nameof(SendCommand))] + [ObservableProperty] private MimeMessage currentMimeMessage = null; + private readonly BodyBuilder bodyBuilder = new BodyBuilder(); - public bool IsLocalDraft => CurrentMailDraftItem != null - && !string.IsNullOrEmpty(CurrentMailDraftItem.DraftId) - && CurrentMailDraftItem.DraftId.StartsWith(Constants.LocalDraftStartPrefix); - + public bool IsLocalDraft => CurrentMailDraftItem?.MailCopy?.IsLocalDraft ?? true; #region Properties [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsLocalDraft))] - [NotifyPropertyChangedFor(nameof(CanSendMail))] + [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] + [NotifyCanExecuteChangedFor(nameof(SendCommand))] private MailItemViewModel currentMailDraftItem; [ObservableProperty] @@ -62,6 +64,8 @@ namespace Wino.Mail.ViewModels private string subject; [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] + [NotifyCanExecuteChangedFor(nameof(SendCommand))] private MailAccount composingAccount; [ObservableProperty] @@ -136,7 +140,7 @@ namespace Wino.Mail.ViewModels private void RemoveAttachment(MailAttachmentViewModel attachmentViewModel) => IncludedAttachments.Remove(attachmentViewModel); - [RelayCommand] + [RelayCommand(CanExecute = nameof(canSendMail))] private async Task SendAsync() { // TODO: More detailed mail validations. @@ -161,20 +165,20 @@ namespace Wino.Mail.ViewModels var assignedAccount = CurrentMailDraftItem.AssignedAccount; var sentFolder = await _folderService.GetSpecialFolderByAccountIdAsync(assignedAccount.Id, SpecialFolderType.Sent); - var draftSendPreparationRequest = new SendDraftPreparationRequest(CurrentMailDraftItem.MailCopy, currentMimeMessage, CurrentMailDraftItem.AssignedFolder, sentFolder, CurrentMailDraftItem.AssignedAccount.Preferences); + var draftSendPreparationRequest = new SendDraftPreparationRequest(CurrentMailDraftItem.MailCopy, CurrentMimeMessage, CurrentMailDraftItem.AssignedFolder, sentFolder, CurrentMailDraftItem.AssignedAccount.Preferences); await _worker.ExecuteAsync(draftSendPreparationRequest); } private async Task UpdateMimeChangesAsync() { - if (isUpdatingMimeBlocked || currentMimeMessage == null || ComposingAccount == null || CurrentMailDraftItem == null) return; + if (isUpdatingMimeBlocked || CurrentMimeMessage == null || ComposingAccount == null || CurrentMailDraftItem == null) return; // Save recipients. - SaveAddressInfo(ToItems, currentMimeMessage.To); - SaveAddressInfo(CCItemsItems, currentMimeMessage.Cc); - SaveAddressInfo(BCCItems, currentMimeMessage.Bcc); + SaveAddressInfo(ToItems, CurrentMimeMessage.To); + SaveAddressInfo(CCItemsItems, CurrentMimeMessage.Cc); + SaveAddressInfo(BCCItems, CurrentMimeMessage.Bcc); SaveImportance(); SaveSubject(); @@ -184,13 +188,13 @@ namespace Wino.Mail.ViewModels await UpdateMailCopyAsync(); // Save mime file. - await _mimeFileService.SaveMimeMessageAsync(CurrentMailDraftItem.MailCopy.FileId, currentMimeMessage, ComposingAccount.Id).ConfigureAwait(false); + await _mimeFileService.SaveMimeMessageAsync(CurrentMailDraftItem.MailCopy.FileId, CurrentMimeMessage, ComposingAccount.Id).ConfigureAwait(false); } private async Task UpdateMailCopyAsync() { - CurrentMailDraftItem.Subject = currentMimeMessage.Subject; - CurrentMailDraftItem.PreviewText = currentMimeMessage.TextBody; + CurrentMailDraftItem.Subject = CurrentMimeMessage.Subject; + CurrentMailDraftItem.PreviewText = CurrentMimeMessage.TextBody; // Update database. await _mailService.UpdateMailAsync(CurrentMailDraftItem.MailCopy); @@ -208,13 +212,13 @@ namespace Wino.Mail.ViewModels } } - private void SaveImportance() { currentMimeMessage.Importance = IsImportanceSelected ? SelectedMessageImportance : MessageImportance.Normal; } + private void SaveImportance() { CurrentMimeMessage.Importance = IsImportanceSelected ? SelectedMessageImportance : MessageImportance.Normal; } private void SaveSubject() { if (Subject != null) { - currentMimeMessage.Subject = Subject; + CurrentMimeMessage.Subject = Subject; } } @@ -227,10 +231,10 @@ namespace Wino.Mail.ViewModels bodyBuilder.TextBody = HtmlAgilityPackExtensions.GetPreviewText(bodyBuilder.HtmlBody); if (bodyBuilder.HtmlBody != null && bodyBuilder.TextBody != null) - currentMimeMessage.Body = bodyBuilder.ToMessageBody(); + CurrentMimeMessage.Body = bodyBuilder.ToMessageBody(); } - [RelayCommand] + [RelayCommand(CanExecute = nameof(canSendMail))] private async Task DiscardAsync() { if (ComposingAccount == null) @@ -248,7 +252,7 @@ namespace Wino.Mail.ViewModels isUpdatingMimeBlocked = true; // Don't send delete request for local drafts. Just delete the record and mime locally. - if (CurrentMailDraftItem.IsLocalDraft) + if (CurrentMailDraftItem.MailCopy.IsLocalDraft) { await _mailService.DeleteMailAsync(ComposingAccount.Id, CurrentMailDraftItem.Id); } @@ -413,9 +417,8 @@ namespace Wino.Mail.ViewModels Subject = replyingMime.Subject; - currentMimeMessage = replyingMime; + CurrentMimeMessage = replyingMime; - OnPropertyChanged(nameof(CanSendMail)); Messenger.Send(new CreateNewComposeMailRequested(renderModel)); }); } @@ -484,7 +487,9 @@ namespace Wino.Mail.ViewModels await ExecuteUIThread(() => { CurrentMailDraftItem.Update(updatedMail); - OnPropertyChanged(nameof(CanSendMail)); + + DiscardCommand.NotifyCanExecuteChanged(); + SendCommand.NotifyCanExecuteChanged(); }); } } diff --git a/Wino.Mail.ViewModels/Data/MailItemViewModel.cs b/Wino.Mail.ViewModels/Data/MailItemViewModel.cs index bc147bc1..e7104246 100644 --- a/Wino.Mail.ViewModels/Data/MailItemViewModel.cs +++ b/Wino.Mail.ViewModels/Data/MailItemViewModel.cs @@ -1,6 +1,5 @@ using System; using CommunityToolkit.Mvvm.ComponentModel; -using Wino.Core.Domain; using Wino.Core.Domain.Entities; using Wino.Core.Domain.Models.MailItem; @@ -13,8 +12,6 @@ namespace Wino.Mail.ViewModels.Data { public MailCopy MailCopy { get; private set; } = mailCopy; - public bool IsLocalDraft => !string.IsNullOrEmpty(DraftId) && DraftId.StartsWith(Constants.LocalDraftStartPrefix); - public Guid UniqueId => ((IMailItem)MailCopy).UniqueId; public string ThreadId => ((IMailItem)MailCopy).ThreadId; public string MessageId => ((IMailItem)MailCopy).MessageId; @@ -96,7 +93,6 @@ namespace Wino.Mail.ViewModels.Data OnPropertyChanged(nameof(DraftId)); OnPropertyChanged(nameof(Subject)); OnPropertyChanged(nameof(PreviewText)); - OnPropertyChanged(nameof(IsLocalDraft)); } } } diff --git a/Wino.Mail/Views/ComposePage.xaml b/Wino.Mail/Views/ComposePage.xaml index f965662a..7faf05df 100644 --- a/Wino.Mail/Views/ComposePage.xaml +++ b/Wino.Mail/Views/ComposePage.xaml @@ -152,10 +152,7 @@ - +