Add local mail pinning support
This commit is contained in:
@@ -12,6 +12,7 @@ using Serilog;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Messaging.Client.Mails;
|
||||
using Wino.Messaging.UI;
|
||||
@@ -139,10 +140,24 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
||||
|
||||
private object GetGroupingKey(IMailListItem mailItem)
|
||||
{
|
||||
if (mailItem.IsPinned)
|
||||
return MailListGroupKey.Pinned;
|
||||
|
||||
if (SortingType == SortingOptionType.ReceiveDate)
|
||||
return mailItem.CreationDate.ToLocalTime().Date;
|
||||
else
|
||||
return mailItem.FromName;
|
||||
return new MailListGroupKey(false, mailItem.CreationDate.ToLocalTime().Date);
|
||||
|
||||
return new MailListGroupKey(false, mailItem.FromName);
|
||||
}
|
||||
|
||||
private bool ShouldReinsertForChanges(MailCopyChangeFlags changedProperties)
|
||||
{
|
||||
if ((changedProperties & (MailCopyChangeFlags.ThreadId | MailCopyChangeFlags.IsPinned)) != 0)
|
||||
return true;
|
||||
|
||||
if (SortingType == SortingOptionType.ReceiveDate)
|
||||
return (changedProperties & MailCopyChangeFlags.CreationDate) != 0;
|
||||
|
||||
return (changedProperties & (MailCopyChangeFlags.FromName | MailCopyChangeFlags.FromAddress)) != 0;
|
||||
}
|
||||
|
||||
private void UpdateUniqueIdHashes(IMailHashContainer itemContainer, bool isAdd)
|
||||
@@ -608,7 +623,7 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
||||
}
|
||||
});
|
||||
|
||||
if ((appliedChanges & MailCopyChangeFlags.ThreadId) != 0)
|
||||
if (ShouldReinsertForChanges(appliedChanges))
|
||||
{
|
||||
await ReinsertUpdatedItemAsync(updatedItem, wasSelected, existingItem.IsBusy);
|
||||
return;
|
||||
@@ -993,6 +1008,16 @@ public class WinoMailCollection : ObservableRecipient, IRecipient<SelectedItemsC
|
||||
if (updates.Count == 0)
|
||||
return;
|
||||
|
||||
if (changedProperties == MailCopyChangeFlags.None || ShouldReinsertForChanges(changedProperties))
|
||||
{
|
||||
foreach (var update in updates)
|
||||
{
|
||||
await UpdateExistingItemAsync(update.ItemContainer, update.UpdatedMail, mailUpdateSource, changedProperties);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await ExecuteUIThread(() =>
|
||||
{
|
||||
foreach (var update in updates)
|
||||
|
||||
@@ -17,6 +17,7 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(CreationDate))]
|
||||
[NotifyPropertyChangedFor(nameof(IsFlagged))]
|
||||
[NotifyPropertyChangedFor(nameof(IsPinned))]
|
||||
[NotifyPropertyChangedFor(nameof(FromName))]
|
||||
[NotifyPropertyChangedFor(nameof(IsFocused))]
|
||||
[NotifyPropertyChangedFor(nameof(IsRead))]
|
||||
@@ -82,6 +83,12 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
set => SetProperty(MailCopy.IsFlagged, value, MailCopy, (u, n) => u.IsFlagged = n);
|
||||
}
|
||||
|
||||
public bool IsPinned
|
||||
{
|
||||
get => MailCopy.IsPinned;
|
||||
set => SetProperty(MailCopy.IsPinned, value, MailCopy, (u, n) => u.IsPinned = n);
|
||||
}
|
||||
|
||||
public string FromName
|
||||
{
|
||||
get => string.IsNullOrEmpty(MailCopy.FromName) ? MailCopy.FromAddress : MailCopy.FromName;
|
||||
@@ -233,6 +240,7 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
{
|
||||
nameof(CreationDate) or nameof(SortingDate) => MailCopyChangeFlags.CreationDate,
|
||||
nameof(IsFlagged) => MailCopyChangeFlags.IsFlagged,
|
||||
nameof(IsPinned) => MailCopyChangeFlags.IsPinned,
|
||||
nameof(FromName) or nameof(SortingName) => MailCopyChangeFlags.FromName,
|
||||
nameof(IsFocused) => MailCopyChangeFlags.IsFocused,
|
||||
nameof(IsRead) => MailCopyChangeFlags.IsRead,
|
||||
@@ -293,12 +301,13 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
changedFlags |= SetIfChanged(MailCopy.Importance, source.Importance, value => MailCopy.Importance = value, MailCopyChangeFlags.Importance);
|
||||
changedFlags |= SetIfChanged(MailCopy.IsRead, source.IsRead, value => MailCopy.IsRead = value, MailCopyChangeFlags.IsRead);
|
||||
changedFlags |= SetIfChanged(MailCopy.IsFlagged, source.IsFlagged, value => MailCopy.IsFlagged = value, MailCopyChangeFlags.IsFlagged);
|
||||
changedFlags |= SetIfChanged(MailCopy.IsPinned, source.IsPinned, value => MailCopy.IsPinned = value, MailCopyChangeFlags.IsPinned);
|
||||
changedFlags |= SetIfChanged(MailCopy.IsFocused, source.IsFocused, value => MailCopy.IsFocused = value, MailCopyChangeFlags.IsFocused);
|
||||
changedFlags |= SetIfChanged(MailCopy.FileId, source.FileId, value => MailCopy.FileId = value, MailCopyChangeFlags.FileId);
|
||||
changedFlags |= SetIfChanged(MailCopy.ItemType, source.ItemType, value => MailCopy.ItemType = value, MailCopyChangeFlags.ItemType);
|
||||
changedFlags |= SetIfChanged(MailCopy.SenderContact, source.SenderContact, value => MailCopy.SenderContact = value, MailCopyChangeFlags.SenderContact);
|
||||
changedFlags |= SetIfChanged(MailCopy.AssignedAccount, source.AssignedAccount, value => MailCopy.AssignedAccount = value, MailCopyChangeFlags.AssignedAccount);
|
||||
changedFlags |= SetIfChanged(MailCopy.AssignedFolder, source.AssignedFolder, value => MailCopy.AssignedFolder = value, MailCopyChangeFlags.AssignedFolder);
|
||||
changedFlags |= SetIfChangedIfNotNull(MailCopy.SenderContact, source.SenderContact, value => MailCopy.SenderContact = value, MailCopyChangeFlags.SenderContact);
|
||||
changedFlags |= SetIfChangedIfNotNull(MailCopy.AssignedAccount, source.AssignedAccount, value => MailCopy.AssignedAccount = value, MailCopyChangeFlags.AssignedAccount);
|
||||
changedFlags |= SetIfChangedIfNotNull(MailCopy.AssignedFolder, source.AssignedFolder, value => MailCopy.AssignedFolder = value, MailCopyChangeFlags.AssignedFolder);
|
||||
changedFlags |= SetIfChanged(MailCopy.UniqueId, source.UniqueId, value => MailCopy.UniqueId = value, MailCopyChangeFlags.UniqueId);
|
||||
changedFlags |= SetIfChanged(MailCopy.IsReadReceiptRequested, source.IsReadReceiptRequested, value => MailCopy.IsReadReceiptRequested = value, MailCopyChangeFlags.ReadReceiptState);
|
||||
changedFlags |= SetIfChanged(MailCopy.ReadReceiptStatus, source.ReadReceiptStatus, value => MailCopy.ReadReceiptStatus = value, MailCopyChangeFlags.ReadReceiptState);
|
||||
@@ -353,6 +362,14 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
return flag;
|
||||
}
|
||||
|
||||
private static MailCopyChangeFlags SetIfChangedIfNotNull<T>(T currentValue, T newValue, Action<T> setter, MailCopyChangeFlags flag) where T : class
|
||||
{
|
||||
if (newValue == null)
|
||||
return MailCopyChangeFlags.None;
|
||||
|
||||
return SetIfChanged(currentValue, newValue, setter, flag);
|
||||
}
|
||||
|
||||
private void RaisePropertyChanges(MailCopyChangeFlags changedFlags)
|
||||
{
|
||||
if (changedFlags == MailCopyChangeFlags.None)
|
||||
@@ -377,6 +394,9 @@ public partial class MailItemViewModel(MailCopy mailCopy) : ObservableRecipient,
|
||||
if ((changedFlags & MailCopyChangeFlags.IsFlagged) != 0)
|
||||
Queue(nameof(IsFlagged));
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.IsPinned) != 0)
|
||||
Queue(nameof(IsPinned));
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.FromName) != 0)
|
||||
{
|
||||
Queue(nameof(FromName));
|
||||
|
||||
@@ -91,6 +91,11 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
/// </summary>
|
||||
public bool IsFlagged => ThreadEmails.Any(e => e.IsFlagged);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether any email in this thread is pinned.
|
||||
/// </summary>
|
||||
public bool IsPinned => ThreadEmails.Any(e => e.IsPinned);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the latest email is focused
|
||||
/// </summary>
|
||||
@@ -182,6 +187,7 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
[NotifyPropertyChangedFor(nameof(HasAttachments))]
|
||||
[NotifyPropertyChangedFor(nameof(IsCalendarEvent))]
|
||||
[NotifyPropertyChangedFor(nameof(IsFlagged))]
|
||||
[NotifyPropertyChangedFor(nameof(IsPinned))]
|
||||
[NotifyPropertyChangedFor(nameof(IsFocused))]
|
||||
[NotifyPropertyChangedFor(nameof(IsRead))]
|
||||
[NotifyPropertyChangedFor(nameof(HasReadReceiptTracking))]
|
||||
@@ -473,6 +479,9 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IMailListIte
|
||||
if ((changedFlags & MailCopyChangeFlags.IsFlagged) != 0 || changedFlags == MailCopyChangeFlags.All)
|
||||
Queue(nameof(IsFlagged));
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.IsPinned) != 0 || changedFlags == MailCopyChangeFlags.All)
|
||||
Queue(nameof(IsPinned));
|
||||
|
||||
if ((changedFlags & MailCopyChangeFlags.IsRead) != 0 || changedFlags == MailCopyChangeFlags.All)
|
||||
Queue(nameof(IsRead));
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@@ -760,6 +761,17 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
||||
await _winoRequestDelegator.ExecuteAsync(accountId, requests).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task ChangePinnedStatusAsync(IEnumerable<MailItemViewModel> targetItems, bool isPinned)
|
||||
{
|
||||
var uniqueIds = targetItems?
|
||||
.Where(a => a?.MailCopy != null)
|
||||
.Select(a => a.MailCopy.UniqueId)
|
||||
.Distinct()
|
||||
.ToList() ?? [];
|
||||
|
||||
return _mailService.ChangePinnedStatusAsync(uniqueIds, isPinned);
|
||||
}
|
||||
|
||||
private bool ShouldPreventItemAdd(MailCopy mailItem)
|
||||
{
|
||||
bool condition = mailItem.IsRead
|
||||
@@ -1553,13 +1565,28 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
||||
}
|
||||
}
|
||||
|
||||
var initialExistingIds = new ConcurrentDictionary<Guid, bool>(MailCollection.MailCopyIdHashSet);
|
||||
var localPinnedItems = new List<MailCopy>();
|
||||
|
||||
if (!isDoingOnlineSearch)
|
||||
{
|
||||
var pinnedOptions = CreateInitializationOptions(SearchQuery, MailCollection.MailCopyIdHashSet);
|
||||
localPinnedItems = await _mailService.FetchPinnedMailsAsync(pinnedOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var pinnedItem in localPinnedItems)
|
||||
{
|
||||
initialExistingIds.TryAdd(pinnedItem.UniqueId, true);
|
||||
}
|
||||
}
|
||||
|
||||
var initializationOptions = CreateInitializationOptions(
|
||||
isDoingOnlineSearch ? string.Empty : SearchQuery,
|
||||
MailCollection.MailCopyIdHashSet,
|
||||
initialExistingIds,
|
||||
onlineSearchItems,
|
||||
isDoingOnlineSearch);
|
||||
|
||||
items = await _mailService.FetchMailsAsync(initializationOptions, cancellationToken).ConfigureAwait(false);
|
||||
items = localPinnedItems.Count > 0 ? [.. localPinnedItems, .. items] : items;
|
||||
|
||||
if (!listManipulationCancellationTokenSource.IsCancellationRequested)
|
||||
{
|
||||
|
||||
@@ -604,6 +604,15 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
if (initializedMailItemViewModel == null)
|
||||
return;
|
||||
|
||||
var assignedFolder = initializedMailItemViewModel.MailCopy.AssignedFolder;
|
||||
|
||||
if (assignedFolder == null)
|
||||
{
|
||||
Log.Warning("Skipping folder-specific mail commands because AssignedFolder is missing for {MailUniqueId}",
|
||||
initializedMailItemViewModel.MailCopy.UniqueId);
|
||||
return;
|
||||
}
|
||||
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.Seperator));
|
||||
|
||||
// You can't do these to draft items.
|
||||
@@ -625,7 +634,7 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
}
|
||||
|
||||
// Archive - Unarchive
|
||||
if (initializedMailItemViewModel.MailCopy.AssignedFolder.SpecialFolderType == SpecialFolderType.Archive)
|
||||
if (assignedFolder.SpecialFolderType == SpecialFolderType.Archive)
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.UnArchive));
|
||||
else
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.Archive));
|
||||
@@ -647,10 +656,10 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
||||
else
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.MarkAsRead, true, false));
|
||||
|
||||
if (initializedMailItemViewModel.MailCopy.AssignedFolder.SpecialFolderType == SpecialFolderType.Junk)
|
||||
if (assignedFolder.SpecialFolderType == SpecialFolderType.Junk)
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.MarkAsNotJunk, true, true));
|
||||
else if (!initializedMailItemViewModel.IsDraft &&
|
||||
initializedMailItemViewModel.MailCopy.AssignedFolder.SpecialFolderType != SpecialFolderType.Sent)
|
||||
assignedFolder.SpecialFolderType != SpecialFolderType.Sent)
|
||||
MenuItems.Add(MailOperationMenuItem.Create(MailOperation.MoveToJunk, true, true));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user