Reset all filters after navigation and clear button re-initializing mail list

This commit is contained in:
Aleh Khantsevich
2024-05-08 02:05:42 +02:00
parent bed8d71f7e
commit b788531e47
4 changed files with 213 additions and 226 deletions

View File

@@ -51,7 +51,7 @@ namespace Wino.Mail.ViewModels
* to prevent them from being removed from the list when they are marked as read.
*/
private HashSet<Guid> gmailUnreadFolderMarkedAsReadUniqueIds = new HashSet<Guid>();
private readonly HashSet<Guid> gmailUnreadFolderMarkedAsReadUniqueIds = [];
private IObservable<System.Reactive.EventPattern<NotifyCollectionChangedEventArgs>> selectionChangedObservable = null;
@@ -68,7 +68,6 @@ namespace Wino.Mail.ViewModels
public IPreferencesService PreferencesService { get; }
private readonly IMailService _mailService;
private readonly INotificationBuilder _notificationBuilder;
private readonly IFolderService _folderService;
private readonly IWinoSynchronizerFactory _winoSynchronizerFactory;
private readonly IThreadingStrategyProvider _threadingStrategyProvider;
@@ -100,12 +99,15 @@ namespace Wino.Mail.ViewModels
private FilterOption _selectedFilterOption;
private SortingOption _selectedSortingOption;
// Indicates state when folder is initializing. It can happen after folder navigation, search or filter change applied.
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(IsEmpty))]
[NotifyPropertyChangedFor(nameof(IsCriteriaFailed))]
[NotifyPropertyChangedFor(nameof(IsFolderEmpty))]
private bool isInitializingFolder;
private bool isLoadMoreItemsLoading;
[ObservableProperty]
private InfoBarMessageType barSeverity;
@@ -118,10 +120,21 @@ namespace Wino.Mail.ViewModels
[ObservableProperty]
private bool isBarOpen;
/// <summary>
/// Current folder that is being represented from the menu.
/// </summary>
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSynchronize))]
[NotifyPropertyChangedFor(nameof(IsFolderSynchronizationEnabled))]
private IBaseFolderMenuItem activeFolder;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSynchronize))]
private bool isAccountSynchronizerInSynchronization;
public MailListPageViewModel(IDialogService dialogService,
IWinoNavigationService navigationService,
IMailService mailService,
INotificationBuilder notificationBuilder,
IStatePersistanceService statePersistanceService,
IFolderService folderService,
IWinoSynchronizerFactory winoSynchronizerFactory,
@@ -136,7 +149,6 @@ namespace Wino.Mail.ViewModels
NavigationService = navigationService;
_mailService = mailService;
_notificationBuilder = notificationBuilder;
_folderService = folderService;
_winoSynchronizerFactory = winoSynchronizerFactory;
_threadingStrategyProvider = threadingStrategyProvider;
@@ -156,53 +168,6 @@ namespace Wino.Mail.ViewModels
});
}
/// <summary>
/// Executes the requested mail operation for currently selected items.
/// </summary>
/// <param name="operation">Action to execute for selected items.</param>
[RelayCommand]
private async Task MailOperationAsync(int mailOperationIndex)
{
if (!SelectedItems.Any()) return;
// Commands don't like enums. So it has to be int.
var operation = (MailOperation)mailOperationIndex;
var package = new MailOperationPreperationRequest(operation, SelectedItems.Select(a => a.MailCopy));
await ExecuteMailOperationAsync(package);
}
/// <summary>
/// Sens a new message to synchronize current folder.
/// </summary>
[RelayCommand]
private void SyncFolder()
{
if (!CanSynchronize) return;
// Only synchronize listed folders.
// When doing linked inbox sync, we need to save the sync id to report progress back only once.
// Otherwise, we will report progress for each folder and that's what we don't want.
trackingSynchronizationId = Guid.NewGuid();
completedTrackingSynchronizationCount = 0;
foreach (var folder in ActiveFolder.HandlingFolders)
{
var options = new SynchronizationOptions()
{
AccountId = folder.MailAccountId,
Type = SynchronizationType.Custom,
SynchronizationFolderIds = [folder.Id],
GroupedSynchronizationTrackingId = trackingSynchronizationId
};
Messenger.Send(new NewSynchronizationRequested(options));
}
}
private async void ActiveMailItemChanged(MailItemViewModel selectedMailItemViewModel)
{
if (_activeMailItem == selectedMailItemViewModel) return;
@@ -278,34 +243,18 @@ namespace Wino.Mail.ViewModels
}
}
/// <summary>
/// Current folder that is being represented from the menu.
/// </summary>
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSynchronize))]
[NotifyPropertyChangedFor(nameof(IsFolderSynchronizationEnabled))]
private IBaseFolderMenuItem activeFolder;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSynchronize))]
private bool isAccountSynchronizerInSynchronization;
public bool CanSynchronize => !IsAccountSynchronizerInSynchronization && IsFolderSynchronizationEnabled;
public bool IsFolderSynchronizationEnabled => ActiveFolder?.IsSynchronizationEnabled ?? false;
#region Properties
public bool CanSynchronize => !IsAccountSynchronizerInSynchronization && IsFolderSynchronizationEnabled;
public bool IsFolderSynchronizationEnabled => ActiveFolder?.IsSynchronizationEnabled ?? false;
public int SelectedItemCount => SelectedItems.Count;
public bool HasMultipleItemSelections => SelectedItemCount > 1;
public bool HasSelectedItems => SelectedItems.Any();
public bool IsArchiveSpecialFolder => ActiveFolder?.SpecialFolderType == SpecialFolderType.Archive;
public bool IsEmpty => !IsPerformingSearch && MailCollection.Count == 0;
public bool IsEmpty => !IsInitializingFolder && !IsPerformingSearch && MailCollection.Count == 0;
public bool IsCriteriaFailed => IsEmpty && IsInSearchMode;
public bool IsFolderEmpty => !IsInitializingFolder && IsEmpty && !IsInSearchMode;
private bool _isPerformingSearch;
public bool IsPerformingSearch
{
get => _isPerformingSearch;
@@ -318,7 +267,7 @@ namespace Wino.Mail.ViewModels
}
}
public bool IsInSearchMode => !string.IsNullOrEmpty(SearchQuery);
public bool IsInSearchMode { get; set; }
#endregion
@@ -444,6 +393,55 @@ namespace Wino.Mail.ViewModels
SelectedFolderPivot = PivotFolders.FirstOrDefault();
}
#region Commands
/// <summary>
/// Executes the requested mail operation for currently selected items.
/// </summary>
/// <param name="operation">Action to execute for selected items.</param>
[RelayCommand]
private async Task MailOperationAsync(int mailOperationIndex)
{
if (!SelectedItems.Any()) return;
// Commands don't like enums. So it has to be int.
var operation = (MailOperation)mailOperationIndex;
var package = new MailOperationPreperationRequest(operation, SelectedItems.Select(a => a.MailCopy));
await ExecuteMailOperationAsync(package);
}
/// <summary>
/// Sens a new message to synchronize current folder.
/// </summary>
[RelayCommand]
private void SyncFolder()
{
if (!CanSynchronize) return;
// Only synchronize listed folders.
// When doing linked inbox sync, we need to save the sync id to report progress back only once.
// Otherwise, we will report progress for each folder and that's what we don't want.
trackingSynchronizationId = Guid.NewGuid();
completedTrackingSynchronizationCount = 0;
foreach (var folder in ActiveFolder.HandlingFolders)
{
var options = new SynchronizationOptions()
{
AccountId = folder.MailAccountId,
Type = SynchronizationType.Custom,
SynchronizationFolderIds = [folder.Id],
GroupedSynchronizationTrackingId = trackingSynchronizationId
};
Messenger.Send(new NewSynchronizationRequested(options));
}
}
[RelayCommand]
private async Task SelectedPivotChanged()
{
@@ -472,6 +470,74 @@ namespace Wino.Mail.ViewModels
await InitializeFolderAsync();
}
[RelayCommand]
public async Task PerformSearchAsync()
{
try
{
if (string.IsNullOrEmpty(SearchQuery) && IsInSearchMode)
{
IsInSearchMode = false;
await InitializeFolderAsync();
}
if (!string.IsNullOrEmpty(SearchQuery))
{
IsInSearchMode = true;
IsPerformingSearch = true;
await InitializeFolderAsync();
}
}
finally
{
IsPerformingSearch = false;
}
}
[RelayCommand]
private async Task EnableFolderSynchronizationAsync()
{
if (ActiveFolder == null) return;
foreach (var folder in ActiveFolder.HandlingFolders)
{
await _folderService.ChangeFolderSynchronizationStateAsync(folder.Id, true);
}
// TODO
//ActiveFolder.IsSynchronizationEnabled = true;
//OnPropertyChanged(nameof(IsFolderSynchronizationEnabled));
//OnPropertyChanged(nameof(CanSynchronize));
//SyncFolderCommand?.Execute(null);
}
[RelayCommand]
private async Task LoadMoreItemsAsync()
{
if (IsInitializingFolder) return;
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 items = await _mailService.FetchMailsAsync(initializationOptions).ConfigureAwait(false);
var viewModels = PrepareMailViewModels(items);
await ExecuteUIThread(() => { MailCollection.AddRange(viewModels, clearIdCache: false); });
await ExecuteUIThread(() => { IsInitializingFolder = false; });
}
#endregion
public IEnumerable<MailItemViewModel> GetTargetMailItemViewModels(IMailItem clickedItem)
{
// Threat threads as a whole and include everything in the group. Except single selections outside of the thread.
@@ -496,7 +562,7 @@ namespace Wino.Mail.ViewModels
if (includedInSelectedItems)
contextMailItems = SelectedItems;
else
contextMailItems = new List<MailItemViewModel>() { clickedMailItemViewModel };
contextMailItems = [clickedMailItemViewModel];
}
return contextMailItems;
@@ -506,7 +572,7 @@ namespace Wino.Mail.ViewModels
=> _contextMenuItemService.GetMailItemContextMenuActions(contextMailItems);
public void ChangeCustomFocusedState(IEnumerable<IMailItem> mailItems, bool isFocused)
=> mailItems.Where(a => a is MailItemViewModel).Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = isFocused);
=> mailItems.OfType<MailItemViewModel>().ForEach(a => a.IsCustomFocused = isFocused);
private bool ShouldPreventItemAdd(IMailItem mailItem)
{
@@ -650,29 +716,6 @@ namespace Wino.Mail.ViewModels
}
}
[RelayCommand]
private async Task LoadMoreItemsAsync()
{
if (IsInitializingFolder) return;
await ExecuteUIThread(() => { IsInitializingFolder = true; });
var initializationOptions = new MailListInitializationOptions(ActiveFolder.HandlingFolders,
SelectedFilterOption.Type,
SelectedSortingOption.Type,
PreferencesService.IsThreadingEnabled,
SelectedFolderPivot.IsFocused,
SearchQuery,
MailCollection.MailCopyIdHashSet);
var items = await _mailService.FetchMailsAsync(initializationOptions).ConfigureAwait(false);
var viewModels = PrepareMailViewModels(items);
await ExecuteUIThread(() => { MailCollection.AddRange(viewModels, clearIdCache: false); });
await ExecuteUIThread(() => { IsInitializingFolder = false; });
}
private async Task InitializeFolderAsync()
{
if (SelectedFilterOption == null || SelectedFolderPivot == null || SelectedSortingOption == null)
@@ -680,10 +723,6 @@ namespace Wino.Mail.ViewModels
try
{
// Clear search query if not performing search.
if (!IsPerformingSearch)
SearchQuery = string.Empty;
MailCollection.Clear();
MailCollection.MailCopyIdHashSet.Clear();
@@ -768,53 +807,12 @@ namespace Wino.Mail.ViewModels
}
}
[RelayCommand]
private async Task EnableFolderSynchronizationAsync()
{
if (ActiveFolder == null) return;
#region Receivers
void IRecipient<MailItemSelectedEvent>.Receive(MailItemSelectedEvent message)
=> SelectedItems.Add(message.SelectedMailItem);
foreach (var folder in ActiveFolder.HandlingFolders)
{
await _folderService.ChangeFolderSynchronizationStateAsync(folder.Id, true);
}
// TODO
//ActiveFolder.IsSynchronizationEnabled = true;
//OnPropertyChanged(nameof(IsFolderSynchronizationEnabled));
//OnPropertyChanged(nameof(CanSynchronize));
//SyncFolderCommand?.Execute(null);
}
void IRecipient<MailItemNavigationRequested>.Receive(MailItemNavigationRequested message)
{
// Find mail item and add to selected items.
MailItemViewModel navigatingMailItem = null;
ThreadMailItemViewModel threadMailItemViewModel = null;
for (int i = 0; i < 3; i++)
{
var mailContainer = MailCollection.GetMailItemContainer(message.UniqueMailId);
if (mailContainer != null)
{
navigatingMailItem = mailContainer.ItemViewModel;
threadMailItemViewModel = mailContainer.ThreadViewModel;
break;
}
}
if (threadMailItemViewModel != null)
threadMailItemViewModel.IsThreadExpanded = true;
if (navigatingMailItem != null)
WeakReferenceMessenger.Default.Send(new SelectMailItemContainerEvent(navigatingMailItem, message.ScrollToItem));
else
Debugger.Break();
}
void IRecipient<MailItemSelectionRemovedEvent>.Receive(MailItemSelectionRemovedEvent message)
=> SelectedItems.Remove(message.RemovedMailItem);
async void IRecipient<ActiveMailFolderChangedEvent>.Receive(ActiveMailFolderChangedEvent message)
{
@@ -835,6 +833,9 @@ namespace Wino.Mail.ViewModels
// Prepare Focused - Other or folder name tabs.
UpdateFolderPivots();
// Reset filters and sorting options.
ResetFilters();
await InitializeFolderAsync();
// TODO: This should be done in a better way.
@@ -847,14 +848,15 @@ namespace Wino.Mail.ViewModels
message.FolderInitLoadAwaitTask?.TrySetResult(true);
isChangingFolder = false;
void ResetFilters()
{
SelectedFilterOption = FilterOptions[0];
SelectedSortingOption = SortingOptions[0];
SearchQuery = string.Empty;
}
}
void IRecipient<MailItemSelectedEvent>.Receive(MailItemSelectedEvent message)
=> SelectedItems.Add(message.SelectedMailItem);
void IRecipient<MailItemSelectionRemovedEvent>.Receive(MailItemSelectionRemovedEvent message)
=> SelectedItems.Remove(message.RemovedMailItem);
public void Receive(AccountSynchronizationCompleted message)
{
if (ActiveFolder == null) return;
@@ -889,24 +891,40 @@ namespace Wino.Mail.ViewModels
}
}
void IRecipient<MailItemNavigationRequested>.Receive(MailItemNavigationRequested message)
{
// Find mail item and add to selected items.
MailItemViewModel navigatingMailItem = null;
ThreadMailItemViewModel threadMailItemViewModel = null;
for (int i = 0; i < 3; i++)
{
var mailContainer = MailCollection.GetMailItemContainer(message.UniqueMailId);
if (mailContainer != null)
{
navigatingMailItem = mailContainer.ItemViewModel;
threadMailItemViewModel = mailContainer.ThreadViewModel;
break;
}
}
if (threadMailItemViewModel != null)
threadMailItemViewModel.IsThreadExpanded = true;
if (navigatingMailItem != null)
WeakReferenceMessenger.Default.Send(new SelectMailItemContainerEvent(navigatingMailItem, message.ScrollToItem));
else
Debugger.Break();
}
#endregion
public async void Receive(NewSynchronizationRequested message)
=> await ExecuteUIThread(() => { OnPropertyChanged(nameof(CanSynchronize)); });
[RelayCommand]
public async Task PerformSearchAsync()
{
try
{
IsPerformingSearch = !string.IsNullOrEmpty(SearchQuery);
await InitializeFolderAsync();
}
finally
{
IsPerformingSearch = false;
}
}
public async void Receive(AccountSynchronizerStateChanged message)
=> await CheckIfAccountIsSynchronizingAsync();