Bunch of changes for ItemsView and threads.

This commit is contained in:
Burak Kaan Köse
2025-10-18 11:45:10 +02:00
parent 522a2da114
commit ad135c5e32
18 changed files with 229 additions and 252 deletions
@@ -39,6 +39,7 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
private readonly Dictionary<string, int> _groupHeaderIndexCache = [];
private readonly Dictionary<string, List<object>> _groupItems = [];
private readonly Dictionary<string, ThreadMailItemViewModel> _threadExpanders = [];
private readonly HashSet<Guid> _mailCopyIdHashSet = [];
private bool _disposed;
private bool _isUpdating;
@@ -78,6 +79,11 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
/// </summary>
public int TotalUnreadCount => _sourceItems.Count(e => e.MailCopy?.IsRead == false);
/// <summary>
/// HashSet containing unique IDs of all mail copies in the collection for pagination tracking
/// </summary>
public HashSet<Guid> MailCopyIdHashSet => _mailCopyIdHashSet;
/// <summary>
/// Gets all email items across all groups as a flat collection
/// </summary>
@@ -227,6 +233,9 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
if (email?.MailCopy == null)
return;
// Add to unique ID tracking
_mailCopyIdHashSet.Add(email.MailCopy.UniqueId);
_isUpdating = true;
try
{
@@ -306,6 +315,9 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
if (email?.MailCopy == null)
return;
// Remove from unique ID tracking
_mailCopyIdHashSet.Remove(email.MailCopy.UniqueId);
_isUpdating = true;
try
{
@@ -386,6 +398,12 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
_isUpdating = true;
try
{
// Add to unique ID tracking
foreach (var email in emailList)
{
_mailCopyIdHashSet.Add(email.MailCopy.UniqueId);
}
// For bulk loading, add to source and refresh
foreach (var email in emailList)
{
@@ -430,6 +448,7 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
_groupHeaderIndexCache.Clear();
_groupItems.Clear();
_threadExpanders.Clear();
_mailCopyIdHashSet.Clear();
OnPropertyChanged(nameof(TotalCount));
OnPropertyChanged(nameof(TotalUnreadCount));
+3 -4
View File
@@ -13,14 +13,13 @@ using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Exceptions;
using Wino.Core.Services;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.MailItem;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Extensions;
using Wino.Core.Services;
using Wino.Mail.ViewModels.Data;
using Wino.Messaging.Client.Mails;
using Wino.Messaging.Server;
namespace Wino.Mail.ViewModels;
@@ -411,8 +410,8 @@ public partial class ComposePageViewModel : MailBaseViewModel
// Download missing MIME message using SynchronizationManager
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
CurrentMailDraftItem.MailCopy,
CurrentMailDraftItem.AssignedAccount.Id);
CurrentMailDraftItem.MailCopy,
CurrentMailDraftItem.MailCopy.AssignedAccount.Id);
goto retry;
}
@@ -53,16 +53,13 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IDisposable
/// </summary>
public IReadOnlyList<MailItemViewModel> ThreadEmails => _threadEmails.AsReadOnly();
public MailItemViewModel LatestMailViewModel => _threadEmails.OrderByDescending(e => e.MailCopy?.CreationDate).FirstOrDefault()!;
public ThreadMailItemViewModel(string threadId)
{
_threadId = threadId;
}
partial void OnIsSelectedChanged(bool value)
{
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
@@ -86,6 +83,8 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IDisposable
{
OnPropertyChanged(nameof(Subject));
OnPropertyChanged(nameof(FromName));
OnPropertyChanged(nameof(LatestEmailDate));
OnPropertyChanged(nameof(LatestMailViewModel));
}
+18 -37
View File
@@ -60,14 +60,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
private IObservable<System.Reactive.EventPattern<NotifyCollectionChangedEventArgs>> selectionChangedObservable = null;
public GroupedEmailCollection MailCollection { get; set; } = new GroupedEmailCollection();
//public IEnumerable<MailItemViewModel> SelectedItems
//{
// get
// {
// }
//}
public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
public ObservableCollection<FolderPivotViewModel> PivotFolders { get; set; } = [];
public ObservableCollection<MailOperationMenuItem> ActionItems { get; set; } = [];
@@ -246,11 +238,10 @@ public partial class MailListPageViewModel : MailBaseViewModel,
{
if (SetProperty(ref _selectedSortingOption, value))
{
// TODO: Update sorting in mail collection.
//if (value != null && MailCollection != null)
//{
// MailCollection.SortingType = value.Type;
//}
if (value != null && MailCollection != null)
{
MailCollection.GroupingType = value.Type == SortingOptionType.ReceiveDate ? EmailGroupingType.ByDate : EmailGroupingType.ByFromName;
}
}
}
}
@@ -562,24 +553,24 @@ public partial class MailListPageViewModel : MailBaseViewModel,
[RelayCommand]
private async Task LoadMoreItemsAsync()
{
//if (IsInitializingFolder || IsOnlineSearchEnabled) return;
if (IsInitializingFolder || IsOnlineSearchEnabled) return;
//await ExecuteUIThread(() => { IsInitializingFolder = true; });
await ExecuteUIThread(() => { IsInitializingFolder = true; });
//var initializationOptions = new MailListInitializationOptions(ActiveFolder.HandlingFolders,
// SelectedFilterOption.Type,
// SelectedSortingOption.Type,
// PreferencesService.IsThreadingEnabled,
// SelectedFolderPivot.IsFocused,
// IsInSearchMode ? SearchQuery : string.Empty,
// MailCollection.MailCopyIdHashSet);
var initializationOptions = new MailListInitializationOptions(ActiveFolder.HandlingFolders,
SelectedFilterOption.Type,
SelectedSortingOption.Type,
PreferencesService.IsThreadingEnabled,
SelectedFolderPivot.IsFocused,
IsInSearchMode ? SearchQuery : string.Empty,
MailCollection.MailCopyIdHashSet);
//var items = await _mailService.FetchMailsAsync(initializationOptions).ConfigureAwait(false);
var items = await _mailService.FetchMailsAsync(initializationOptions).ConfigureAwait(false);
//var viewModels = PrepareMailViewModels(items);
var viewModels = PrepareMailViewModels(items);
//await ExecuteUIThread(() => { MailCollection.AddRange(viewModels, clearIdCache: false); });
//await ExecuteUIThread(() => { IsInitializingFolder = false; });
await ExecuteUIThread(() => { MailCollection.AddEmails(viewModels); });
await ExecuteUIThread(() => { IsInitializingFolder = false; });
}
#endregion
@@ -589,7 +580,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
public IEnumerable<MailOperationMenuItem> GetAvailableMailActions(IEnumerable<MailItemViewModel> contextMailItems)
=> _contextMenuItemService.GetMailItemContextMenuActions(contextMailItems.Select(a => a.MailCopy));
private bool ShouldPreventItemAdd(MailCopy mailItem)
{
bool condition = mailItem.IsRead
@@ -733,13 +723,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
private IEnumerable<MailItemViewModel> PrepareMailViewModels(IEnumerable<MailCopy> mailItems)
{
return mailItems.Select(a => new MailItemViewModel(a));
//foreach (var item in mailItems)
//{
// if (item is MailCopy singleMailItem)
// yield return new MailItemViewModel(singleMailItem);
// else if (item is ThreadMailItem threadMailItem)
// yield return new ThreadMailItemViewModel(threadMailItem);
//}
}
[RelayCommand]
@@ -784,7 +767,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
// Here items are sorted and filtered.
List<MailCopy> items = null;
List<MailCopy> onlineSearchItems = null;
bool isDoingSearch = !string.IsNullOrEmpty(SearchQuery);
bool isDoingOnlineSearch = false;
@@ -851,8 +833,7 @@ public partial class MailListPageViewModel : MailBaseViewModel,
PreferencesService.IsThreadingEnabled,
SelectedFolderPivot.IsFocused,
SearchQuery,
default,
onlineSearchItems);
MailCollection.MailCopyIdHashSet);
items = await _mailService.FetchMailsAsync(initializationOptions, cancellationToken).ConfigureAwait(false);
@@ -25,7 +25,6 @@ using Wino.Core.Services;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.ViewModels.Messages;
using Wino.Messaging.Client.Mails;
using Wino.Messaging.Server;
using Wino.Messaging.UI;
using IMailService = Wino.Core.Domain.Interfaces.IMailService;
@@ -355,8 +354,8 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
// Download missing MIME message using SynchronizationManager
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
mailItemViewModel.MailCopy,
mailItemViewModel.AssignedAccount.Id);
mailItemViewModel.MailCopy,
mailItemViewModel.MailCopy.AssignedAccount.Id);
}
catch (OperationCanceledException)
{