Fixing some issues with ItemsView and selections.

This commit is contained in:
Burak Kaan Köse
2025-10-21 22:08:56 +02:00
parent ae7d576967
commit 449c1d3f4d
11 changed files with 657 additions and 187 deletions
+84 -97
View File
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -21,11 +19,13 @@ using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.MailItem;
using Wino.Core.Domain.Models.Menus;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Domain.Models.Reader;
using Wino.Core.Domain.Models.Synchronization;
using Wino.Core.Services;
using Wino.Mail.ViewModels.Collections;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.ViewModels.Helpers;
using Wino.Mail.ViewModels.Messages;
using Wino.Messaging.Client.Mails;
using Wino.Messaging.Server;
@@ -36,8 +36,6 @@ namespace Wino.Mail.ViewModels;
public partial class MailListPageViewModel : MailBaseViewModel,
IRecipient<MailItemNavigationRequested>,
IRecipient<ActiveMailFolderChangedEvent>,
IRecipient<MailItemSelectedEvent>,
IRecipient<MailItemSelectionRemovedEvent>,
IRecipient<AccountSynchronizationCompleted>,
IRecipient<NewMailSynchronizationRequested>,
IRecipient<AccountSynchronizerStateChanged>,
@@ -57,10 +55,10 @@ public partial class MailListPageViewModel : MailBaseViewModel,
private readonly HashSet<Guid> gmailUnreadFolderMarkedAsReadUniqueIds = [];
private IObservable<System.Reactive.EventPattern<NotifyCollectionChangedEventArgs>> selectionChangedObservable = null;
private ThrottledEventHandler _selectionChangedThrottler;
public GroupedEmailCollection MailCollection { get; set; } = new GroupedEmailCollection();
public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
//public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
public ObservableCollection<FolderPivotViewModel> PivotFolders { get; set; } = [];
public ObservableCollection<MailOperationMenuItem> ActionItems { get; set; } = [];
@@ -177,37 +175,56 @@ public partial class MailListPageViewModel : MailBaseViewModel,
mailListLength = statePersistenceService.MailListPaneLength;
selectionChangedObservable = Observable.FromEventPattern<NotifyCollectionChangedEventArgs>(SelectedItems, nameof(SelectedItems.CollectionChanged));
selectionChangedObservable
.Throttle(TimeSpan.FromMilliseconds(100))
.Subscribe(async a =>
_selectionChangedThrottler = new ThrottledEventHandler(100, () =>
{
_ = ExecuteUIThread(() =>
{
await ExecuteUIThread(() => { SelectedItemCollectionUpdated(a.EventArgs); });
});
if (MailCollection.SelectedVisibleCount == 1)
{
ActiveMailItemChanged(MailCollection.SelectedVisibleItems.ElementAt(0));
}
else
{
// At this point, either we don't have any item selected
// or we have multiple item selected. In either case
// there should be no active item.
//MailCollection.MailItemRemoved += (c, removedItem) =>
//{
// if (removedItem is ThreadMailItemViewModel removedThreadViewModelItem)
// {
// foreach (var viewModel in removedThreadViewModelItem.ThreadItems.Cast<MailItemViewModel>())
// {
// if (SelectedItems.Contains(viewModel))
// {
// SelectedItems.Remove(viewModel);
// }
// }
// }
// else if (removedItem is MailItemViewModel removedMailItemViewModel && SelectedItems.Contains(removedMailItemViewModel))
// {
// SelectedItems.Remove(removedMailItemViewModel);
// }
//};
ActiveMailItemChanged(null);
}
NotifyItemSelected();
SetupTopBarActions();
});
});
}
public override void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
MailCollection.SelectionChanged += SelectedItemsChanged;
}
public override void OnNavigatedFrom(NavigationMode mode, object parameters)
{
base.OnNavigatedFrom(mode, parameters);
MailCollection.SelectionChanged -= SelectedItemsChanged;
MailCollection.Dispose();
_selectionChangedThrottler?.Dispose();
_selectionChangedThrottler = null;
}
private void SelectedItemsChanged(object sender, EventArgs e)
{
_selectionChangedThrottler?.Trigger();
}
private void SetupTopBarActions()
{
ActionItems.Clear();
var actions = GetAvailableMailActions(SelectedItems);
var actions = GetAvailableMailActions(MailCollection.SelectedVisibleItems);
actions.ForEach(a => ActionItems.Add(a));
}
@@ -248,13 +265,9 @@ public partial class MailListPageViewModel : MailBaseViewModel,
public bool CanSynchronize => !IsAccountSynchronizerInSynchronization && IsFolderSynchronizationEnabled;
public bool IsFolderSynchronizationEnabled => ActiveFolder?.IsSynchronizationEnabled ?? false;
public int SelectedItemCount => SelectedItems.Count;
public bool HasMultipleItemSelections => SelectedItemCount > 1;
public bool HasSingleItemSelection => SelectedItemCount == 1;
public bool HasSelectedItems => SelectedItems.Any();
public bool IsArchiveSpecialFolder => ActiveFolder?.SpecialFolderType == SpecialFolderType.Archive;
public string SelectedMessageText => HasSelectedItems ? string.Format(Translator.MailsSelected, SelectedItemCount) : Translator.NoMailSelected;
public string SelectedMessageText => MailCollection.SelectedVisibleCount > 0 ? string.Format(Translator.MailsSelected, MailCollection.SelectedVisibleCount) : Translator.NoMailSelected;
/// <summary>
/// Indicates current state of the mail list. Doesn't matter it's loading or no.
@@ -333,13 +346,12 @@ public partial class MailListPageViewModel : MailBaseViewModel,
public void NotifyItemSelected()
{
OnPropertyChanged(nameof(SelectedMessageText));
OnPropertyChanged(nameof(HasSingleItemSelection));
OnPropertyChanged(nameof(HasSelectedItems));
OnPropertyChanged(nameof(SelectedItemCount));
OnPropertyChanged(nameof(HasMultipleItemSelections));
//OnPropertyChanged(nameof(HasSingleItemSelection));
//OnPropertyChanged(nameof(HasSelectedItems));
//OnPropertyChanged(nameof(SelectedItemCount));
//OnPropertyChanged(nameof(HasMultipleItemSelections));
if (SelectedFolderPivot != null)
SelectedFolderPivot.SelectedItemCount = SelectedItemCount;
SelectedFolderPivot?.SelectedItemCount = MailCollection.SelectedItemsCount;
}
private void NotifyItemFoundState()
@@ -360,26 +372,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
});
}
private void SelectedItemCollectionUpdated(NotifyCollectionChangedEventArgs e)
{
if (SelectedItems.Count == 1)
{
ActiveMailItemChanged(SelectedItems[0]);
}
else
{
// At this point, either we don't have any item selected
// or we have multiple item selected. In either case
// there should be no active item.
ActiveMailItemChanged(null);
}
NotifyItemSelected();
SetupTopBarActions();
}
private async Task UpdateFolderPivotsAsync()
{
if (ActiveFolder == null) return;
@@ -440,9 +432,9 @@ public partial class MailListPageViewModel : MailBaseViewModel,
[RelayCommand]
private async Task ExecuteTopBarAction(MailOperationMenuItem menuItem)
{
if (menuItem == null || !SelectedItems.Any()) return;
if (menuItem == null || MailCollection.SelectedVisibleCount == 0) return;
await HandleMailOperation(menuItem.Operation, SelectedItems);
await HandleMailOperation(menuItem.Operation, MailCollection.SelectedVisibleItems);
}
/// <summary>
@@ -452,9 +444,9 @@ public partial class MailListPageViewModel : MailBaseViewModel,
[RelayCommand]
private async Task ExecuteMailOperation(MailOperation mailOperation)
{
if (!SelectedItems.Any()) return;
if (!MailCollection.SelectedVisibleItems.Any()) return;
await HandleMailOperation(mailOperation, SelectedItems);
await HandleMailOperation(mailOperation, MailCollection.SelectedVisibleItems);
}
private async Task HandleMailOperation(MailOperation mailOperation, IEnumerable<MailItemViewModel> mailItems)
@@ -615,9 +607,11 @@ public partial class MailListPageViewModel : MailBaseViewModel,
await listManipulationSemepahore.WaitAsync();
// await MailCollection.AddAsync(addedMail);
await ExecuteUIThread(() => { NotifyItemFoundState(); });
await ExecuteUIThread(() =>
{
MailCollection.AddEmail(new MailItemViewModel(addedMail));
NotifyItemFoundState();
});
}
catch { }
finally
@@ -632,6 +626,7 @@ public partial class MailListPageViewModel : MailBaseViewModel,
Debug.WriteLine($"Updating {updatedMail.Id}-> {updatedMail.UniqueId}");
// TODO
// await MailCollection.UpdateMailCopy(updatedMail);
await ExecuteUIThread(() => { SetupTopBarActions(); });
@@ -658,7 +653,7 @@ public partial class MailListPageViewModel : MailBaseViewModel,
if ((removedFromActiveFolder || removedFromDraftOrSent) && !isDeletedByGmailUnreadFolderAction)
{
bool isDeletedMailSelected = SelectedItems.Any(a => a.MailCopy.UniqueId == removedMail.UniqueId);
bool isDeletedMailSelected = MailCollection.SelectedVisibleItems.Any(a => a.MailCopy.UniqueId == removedMail.UniqueId);
// Automatically select the next item in the list if the setting is enabled.
MailItemViewModel nextItem = null;
@@ -667,12 +662,15 @@ public partial class MailListPageViewModel : MailBaseViewModel,
{
await ExecuteUIThread(() =>
{
// nextItem = MailCollection.GetNextItem(removedMail);
nextItem = MailCollection.GetNextItem(removedMail);
});
}
// Remove the deleted item from the list.
// await MailCollection.RemoveAsync(removedMail);
await ExecuteUIThread(() =>
{
MailCollection.RemoveEmailByMailCopy(removedMail);
});
if (nextItem != null)
WeakReferenceMessenger.Default.Send(new SelectMailItemContainerEvent(nextItem, ScrollToItem: true));
@@ -681,7 +679,10 @@ public partial class MailListPageViewModel : MailBaseViewModel,
// There are no next item to select, but we removed the last item which was selected.
// Clearing selected item will dispose rendering page.
SelectedItems.Clear();
await ExecuteUIThread(() =>
{
MailCollection.ClearSelections();
});
}
await ExecuteUIThread(() => { NotifyItemFoundState(); });
@@ -743,8 +744,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
{
MailCollection.Clear();
SelectedItems.Clear();
if (ActiveFolder == null)
return;
@@ -885,16 +884,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
#region Receivers
void IRecipient<MailItemSelectedEvent>.Receive(MailItemSelectedEvent message)
{
if (!SelectedItems.Contains(message.SelectedMailItem)) SelectedItems.Add(message.SelectedMailItem);
}
void IRecipient<MailItemSelectionRemovedEvent>.Receive(MailItemSelectionRemovedEvent message)
{
if (SelectedItems.Contains(message.RemovedMailItem)) SelectedItems.Remove(message.RemovedMailItem);
}
async void IRecipient<ActiveMailFolderChangedEvent>.Receive(ActiveMailFolderChangedEvent message)
{
NotifyItemSelected();
@@ -993,16 +982,15 @@ public partial class MailListPageViewModel : MailBaseViewModel,
for (int i = 0; i < 3; i++)
{
// TODO: Get container.
//var mailContainer = MailCollection.GetMailItemContainer(message.UniqueMailId);
var mailContainer = MailCollection.GetMailItemContainer(message.UniqueMailId);
//if (mailContainer != null)
//{
// navigatingMailItem = mailContainer.ItemViewModel;
// threadMailItemViewModel = mailContainer.ThreadViewModel;
if (mailContainer != null)
{
navigatingMailItem = mailContainer.ItemViewModel;
threadMailItemViewModel = mailContainer.ThreadViewModel;
// break;
//}
break;
}
}
if (threadMailItemViewModel != null)
@@ -1079,7 +1067,10 @@ public partial class MailListPageViewModel : MailBaseViewModel,
public void Receive(ThumbnailAdded message)
{
// MailCollection.UpdateThumbnails(message.Email);
Dispatcher.ExecuteOnUIThread(() =>
{
MailCollection.UpdateThumbnailsForAddress(message.Email);
});
}
protected override void RegisterRecipients()
@@ -1088,8 +1079,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
Messenger.Register<MailItemNavigationRequested>(this);
Messenger.Register<ActiveMailFolderChangedEvent>(this);
Messenger.Register<MailItemSelectedEvent>(this);
Messenger.Register<MailItemSelectionRemovedEvent>(this);
Messenger.Register<AccountSynchronizationCompleted>(this);
Messenger.Register<NewMailSynchronizationRequested>(this);
Messenger.Register<AccountSynchronizerStateChanged>(this);
@@ -1103,8 +1092,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
Messenger.Unregister<MailItemNavigationRequested>(this);
Messenger.Unregister<ActiveMailFolderChangedEvent>(this);
Messenger.Unregister<MailItemSelectedEvent>(this);
Messenger.Unregister<MailItemSelectionRemovedEvent>(this);
Messenger.Unregister<AccountSynchronizationCompleted>(this);
Messenger.Unregister<NewMailSynchronizationRequested>(this);
Messenger.Unregister<AccountSynchronizerStateChanged>(this);