Files
Wino-Mail/Wino.Core.Domain/MenuItems/MenuItemCollection.cs
T

267 lines
9.7 KiB
C#
Raw Normal View History

2024-04-18 01:44:37 +02:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Wino.Core.Domain.Collections;
2024-04-18 01:44:37 +02:00
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
2025-02-16 11:54:23 +01:00
namespace Wino.Core.Domain.MenuItems;
public class MenuItemCollection : ObservableRangeCollection<IMenuItem>
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
// Which types to remove from the list when folders are changing due to selection of new account.
// We don't clear the whole list since we want to keep the New Mail button and account menu items.
private readonly Type[] _preservingTypesForFolderArea = [typeof(AccountMenuItem), typeof(NewMailMenuItem), typeof(MergedAccountMenuItem)];
private readonly IDispatcher _dispatcher;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public MenuItemCollection(IDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
2025-02-16 11:43:30 +01:00
2025-02-16 11:54:23 +01:00
public IEnumerable<IAccountMenuItem> GetAllAccountMenuItems()
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
foreach (var item in rootItems)
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
if (item is MergedAccountMenuItem mergedAccountMenuItem)
{
2026-04-15 01:18:07 +02:00
foreach (var singleItem in mergedAccountMenuItem.SubMenuItems.OfType<IAccountMenuItem>().ToList())
{
2025-02-16 11:54:23 +01:00
yield return singleItem;
2025-02-16 11:43:30 +01:00
}
2025-02-16 11:54:23 +01:00
yield return mergedAccountMenuItem;
}
2025-02-16 11:54:23 +01:00
else if (item is IAccountMenuItem accountMenuItem)
yield return accountMenuItem;
2024-04-18 01:44:37 +02:00
}
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public IEnumerable<IBaseFolderMenuItem> GetAllFolderMenuItems(Guid folderId)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
foreach (var item in rootItems)
2024-04-18 01:44:37 +02:00
{
2026-04-15 01:18:07 +02:00
if (item is IBaseFolderMenuItem folderMenuItem && item is not IMailCategoryMenuItem && item is not IMergedMailCategoryMenuItem)
{
2025-02-16 11:54:23 +01:00
if (folderMenuItem.HandlingFolders.Any(a => a.Id == folderId))
2025-02-16 11:35:43 +01:00
{
2025-02-16 11:54:23 +01:00
yield return folderMenuItem;
}
else if (folderMenuItem.SubMenuItems.Any())
{
2026-04-15 01:18:07 +02:00
foreach (var subItem in folderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>().ToList())
2025-02-16 11:43:30 +01:00
{
2025-02-16 11:54:23 +01:00
if (subItem.HandlingFolders.Any(a => a.Id == folderId))
{
2025-02-16 11:54:23 +01:00
yield return subItem;
}
2025-02-16 11:43:30 +01:00
}
2025-02-16 11:54:23 +01:00
}
}
2024-04-18 01:44:37 +02:00
}
2025-02-16 11:54:23 +01:00
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public bool TryGetAccountMenuItem(Guid accountId, out IAccountMenuItem value)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
value = rootItems.OfType<AccountMenuItem>().FirstOrDefault(a => a.AccountId == accountId);
value ??= rootItems.OfType<MergedAccountMenuItem>().FirstOrDefault(a => a.SubMenuItems.OfType<AccountMenuItem>().Any(b => b.AccountId == accountId));
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return value != null;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Pattern: Look for special folder menu item inside the loaded folders for Windows Mail style menu items.
public bool TryGetWindowsStyleRootSpecialFolderMenuItem(Guid accountId, SpecialFolderType specialFolderType, out FolderMenuItem value)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
value = rootItems.OfType<IBaseFolderMenuItem>()
2025-02-16 11:54:23 +01:00
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.MailAccountId == accountId && b.SpecialFolderType == specialFolderType)) as FolderMenuItem;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return value != null;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Pattern: Find the merged account menu item and return the special folder menu item that belongs to the merged account menu item.
// This will not look for the folders inside individual account menu items inside merged account menu item.
public bool TryGetMergedAccountSpecialFolderMenuItem(Guid mergedInboxId, SpecialFolderType specialFolderType, out IBaseFolderMenuItem value)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
value = rootItems.OfType<MergedAccountFolderMenuItem>()
2025-02-16 11:54:23 +01:00
.Where(a => a.MergedInbox.Id == mergedInboxId)
.FirstOrDefault(a => a.SpecialFolderType == specialFolderType);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return value != null;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public bool TryGetFolderMenuItem(Guid folderId, out IBaseFolderMenuItem value)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
2025-02-16 11:54:23 +01:00
// Root folders
2026-04-15 01:18:07 +02:00
value = rootItems.OfType<IBaseFolderMenuItem>()
.Where(a => a is not IMailCategoryMenuItem && a is not IMergedMailCategoryMenuItem)
2025-02-16 11:54:23 +01:00
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
2026-04-15 01:18:07 +02:00
value ??= rootItems.OfType<FolderMenuItem>()
2025-02-16 11:54:23 +01:00
.SelectMany(a => a.SubMenuItems)
.OfType<IBaseFolderMenuItem>()
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return value != null;
}
2024-04-18 01:44:37 +02:00
2026-04-15 01:18:07 +02:00
public bool TryGetCategoryMenuItem(Guid categoryId, out IBaseFolderMenuItem value)
{
var rootItems = this.ToList();
value = rootItems.OfType<IMailCategoryMenuItem>()
.FirstOrDefault(a => a.MailCategory.Id == categoryId);
value ??= rootItems.OfType<IMergedMailCategoryMenuItem>()
.FirstOrDefault(a => a.Categories.Any(b => b.Id == categoryId)) as IBaseFolderMenuItem;
return value != null;
}
2025-02-16 11:54:23 +01:00
public void UpdateUnreadItemCountsToZero()
{
// Handle the root folders.
2026-04-15 01:18:07 +02:00
foreach (var item in this.OfType<IBaseFolderMenuItem>().ToList())
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
RecursivelyResetUnreadItemCount(item);
}
2025-02-16 11:54:23 +01:00
}
2025-02-16 11:54:23 +01:00
private void RecursivelyResetUnreadItemCount(IBaseFolderMenuItem baseFolderMenuItem)
{
baseFolderMenuItem.UnreadItemCount = 0;
2025-02-16 11:54:23 +01:00
if (baseFolderMenuItem.SubMenuItems == null) return;
2026-04-15 01:18:07 +02:00
foreach (var subMenuItem in baseFolderMenuItem.SubMenuItems.OfType<IBaseFolderMenuItem>().ToList())
2025-02-16 11:54:23 +01:00
{
RecursivelyResetUnreadItemCount(subMenuItem);
}
2025-02-16 11:54:23 +01:00
}
2025-02-16 11:54:23 +01:00
public bool TryGetSpecialFolderMenuItem(Guid accountId, SpecialFolderType specialFolderType, out FolderMenuItem value)
{
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
value = rootItems.OfType<IBaseFolderMenuItem>()
2025-02-16 11:54:23 +01:00
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.MailAccountId == accountId && b.SpecialFolderType == specialFolderType)) as FolderMenuItem;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return value != null;
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
/// <summary>
/// Skips the merged account menu item, but directly returns the Account menu item inside the merged account menu item.
/// </summary>
/// <param name="accountId">Account id to look for.</param>
/// <returns>Direct AccountMenuItem inside the Merged Account menu item if exists.</returns>
public AccountMenuItem GetSpecificAccountMenuItem(Guid accountId)
{
AccountMenuItem accountMenuItem = null;
2026-04-15 01:18:07 +02:00
var rootItems = this.ToList();
2024-04-18 01:44:37 +02:00
2026-04-15 01:18:07 +02:00
accountMenuItem = rootItems.OfType<AccountMenuItem>().FirstOrDefault(a => a.HoldingAccounts.Any(b => b.Id == accountId));
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Look for the items inside the merged accounts if regular menu item is not found.
2026-04-15 01:18:07 +02:00
accountMenuItem ??= rootItems.OfType<MergedAccountMenuItem>()
2025-02-16 11:54:23 +01:00
.FirstOrDefault(a => a.HoldingAccounts.Any(b => b.Id == accountId))?.SubMenuItems
.OfType<AccountMenuItem>()
.FirstOrDefault(a => a.AccountId == accountId);
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
return accountMenuItem;
}
2025-02-16 11:54:23 +01:00
public async Task ReplaceFoldersAsync(IEnumerable<IMenuItem> folders)
{
await _dispatcher.ExecuteOnUIThread(() => ClearFolderAreaMenuItems());
await _dispatcher.ExecuteOnUIThread(() => Items.Add(new SeperatorItem()));
await _dispatcher.ExecuteOnUIThread(() => AddRange(folders, System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
}
2025-02-16 11:54:23 +01:00
/// <summary>
/// Enables/disables account menu items in the list.
/// </summary>
/// <param name="isEnabled">Whether menu items should be enabled or disabled.</param>
public async Task SetAccountMenuItemEnabledStatusAsync(bool isEnabled)
{
2026-04-15 01:18:07 +02:00
var accountItems = this.Where(a => a is IAccountMenuItem).Cast<IAccountMenuItem>().ToList();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
await _dispatcher.ExecuteOnUIThread(() =>
{
foreach (var item in accountItems)
2025-02-16 11:43:30 +01:00
{
2025-02-16 11:54:23 +01:00
item.IsEnabled = isEnabled;
}
});
}
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
public void AddAccountMenuItem(IAccountMenuItem accountMenuItem)
{
var lastAccount = Items.OfType<IAccountMenuItem>().LastOrDefault();
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
// Index 0 is always the New Mail button.
var insertIndex = lastAccount == null ? 1 : Items.IndexOf(lastAccount) + 1;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
Insert(insertIndex, accountMenuItem);
}
2025-02-16 11:35:43 +01:00
2026-02-08 22:20:38 +01:00
public bool RemoveFolderMenuItem(Guid folderId)
{
// Check root-level items.
var rootItem = this.OfType<IBaseFolderMenuItem>()
2026-04-15 01:18:07 +02:00
.Where(a => a is not IMailCategoryMenuItem && a is not IMergedMailCategoryMenuItem)
2026-02-08 22:20:38 +01:00
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
if (rootItem != null)
{
Remove(rootItem);
return true;
}
// Check sub-items of root folders.
2026-04-15 01:18:07 +02:00
foreach (var rootFolder in this.OfType<IBaseFolderMenuItem>().ToList())
2026-02-08 22:20:38 +01:00
{
var subItem = rootFolder.SubMenuItems
.OfType<IBaseFolderMenuItem>()
.FirstOrDefault(a => a.HandlingFolders.Any(b => b.Id == folderId));
if (subItem != null)
{
rootFolder.SubMenuItems.Remove(subItem);
return true;
}
}
return false;
}
2025-02-16 11:54:23 +01:00
private void ClearFolderAreaMenuItems()
{
var itemsToRemove = this.Where(a => !_preservingTypesForFolderArea.Contains(a.GetType())).ToList();
itemsToRemove.ForEach(item =>
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
item.IsExpanded = false;
item.IsSelected = false;
2024-04-18 01:44:37 +02:00
2025-02-16 11:54:23 +01:00
try
2024-04-18 01:44:37 +02:00
{
2025-02-16 11:54:23 +01:00
Remove(item);
}
catch (Exception) { }
});
2024-04-18 01:44:37 +02:00
}
}