Bunch of changes for ItemsView and threads.
This commit is contained in:
+27
-27
@@ -15,56 +15,56 @@
|
|||||||
<PackageVersion Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.2.250402" />
|
<PackageVersion Include="CommunityToolkit.WinUI.Controls.TokenizingTextBox" Version="8.2.250402" />
|
||||||
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
<PackageVersion Include="CommunityToolkit.WinUI.Extensions" Version="8.2.250402" />
|
||||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250926-build.2293" />
|
<PackageVersion Include="CommunityToolkit.Labs.WinUI.Controls.MarkdownTextBlock" Version="0.1.250926-build.2293" />
|
||||||
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
||||||
<PackageVersion Include="CommunityToolkit.Labs.WinUI.DependencyPropertyGenerator" Version="0.1.250926-build.2293" />
|
<PackageVersion Include="CommunityToolkit.Labs.WinUI.DependencyPropertyGenerator" Version="0.1.250926-build.2293" />
|
||||||
<PackageVersion Include="EmailValidation" Version="1.3.0" />
|
<PackageVersion Include="EmailValidation" Version="1.3.0" />
|
||||||
<PackageVersion Include="gravatar-dotnet" Version="0.1.3" />
|
<PackageVersion Include="gravatar-dotnet" Version="0.1.3" />
|
||||||
<PackageVersion Include="HtmlAgilityPack" Version="1.12.0" />
|
<PackageVersion Include="HtmlAgilityPack" Version="1.12.4" />
|
||||||
<PackageVersion Include="Ical.Net" Version="4.3.1" />
|
<PackageVersion Include="Ical.Net" Version="4.3.1" />
|
||||||
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
|
<PackageVersion Include="IsExternalInit" Version="1.0.3" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.4" />
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.10" />
|
||||||
<PackageVersion Include="Microsoft.Graph" Version="5.75.0" />
|
<PackageVersion Include="Microsoft.Graph" Version="5.94.0" />
|
||||||
<PackageVersion Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
<PackageVersion Include="Microsoft.Graphics.Win2D" Version="1.3.2" />
|
||||||
<PackageVersion Include="Microsoft.Identity.Client" Version="4.77.1" />
|
<PackageVersion Include="Microsoft.Identity.Client" Version="4.77.1" />
|
||||||
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.70.1" />
|
<PackageVersion Include="Microsoft.Identity.Client.Broker" Version="4.77.1" />
|
||||||
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.70.1" />
|
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.77.1" />
|
||||||
<PackageVersion Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.14" />
|
<PackageVersion Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.2.14" />
|
||||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="3.0.0" />
|
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="3.0.0" />
|
||||||
<PackageVersion Include="MimeKit" Version="4.11.0" />
|
<PackageVersion Include="MimeKit" Version="4.14.0" />
|
||||||
<PackageVersion Include="morelinq" Version="4.4.0" />
|
<PackageVersion Include="morelinq" Version="4.4.0" />
|
||||||
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
|
<PackageVersion Include="Nito.AsyncEx" Version="5.1.2" />
|
||||||
<PackageVersion Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
<PackageVersion Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
|
||||||
<PackageVersion Include="NodaTime" Version="3.2.2" />
|
<PackageVersion Include="NodaTime" Version="3.2.2" />
|
||||||
<PackageVersion Include="Sentry.Serilog" Version="5.15.1" />
|
<PackageVersion Include="Sentry.Serilog" Version="5.16.1" />
|
||||||
<PackageVersion Include="Serilog" Version="4.2.0" />
|
<PackageVersion Include="Serilog" Version="4.3.0" />
|
||||||
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
|
<PackageVersion Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
<PackageVersion Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||||
<PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
|
<PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
|
||||||
<PackageVersion Include="SkiaSharp" Version="3.116.1" />
|
<PackageVersion Include="SkiaSharp" Version="3.119.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="SqlKata" Version="4.0.1" />
|
<PackageVersion Include="SqlKata" Version="4.0.1" />
|
||||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.4" />
|
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||||
<PackageVersion Include="System.Text.Json" Version="9.0.4" />
|
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
<PackageVersion Include="H.NotifyIcon.WinUI" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.WinUI" Version="2.3.1" />
|
||||||
<PackageVersion Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
<PackageVersion Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
|
||||||
<PackageVersion Include="Google.Apis.Auth" Version="1.69.0" />
|
<PackageVersion Include="Google.Apis.Auth" Version="1.72.0" />
|
||||||
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3667" />
|
<PackageVersion Include="Google.Apis.Calendar.v3" Version="1.69.0.3746" />
|
||||||
<PackageVersion Include="Google.Apis.Gmail.v1" Version="1.68.0.3427" />
|
<PackageVersion Include="Google.Apis.Gmail.v1" Version="1.70.0.3833" />
|
||||||
<PackageVersion Include="Google.Apis.PeopleService.v1" Version="1.68.0.3359" />
|
<PackageVersion Include="Google.Apis.PeopleService.v1" Version="1.69.0.3785" />
|
||||||
<PackageVersion Include="HtmlKit" Version="1.2.0" />
|
<PackageVersion Include="HtmlKit" Version="1.2.0" />
|
||||||
<PackageVersion Include="MailKit" Version="4.11.0" />
|
<PackageVersion Include="MailKit" Version="4.14.1" />
|
||||||
<PackageVersion Include="TimePeriodLibrary.NET" Version="2.1.6" />
|
<PackageVersion Include="TimePeriodLibrary.NET" Version="2.1.6" />
|
||||||
<PackageVersion Include="System.Reactive" Version="6.0.1" />
|
<PackageVersion Include="System.Reactive" Version="6.1.0" />
|
||||||
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.4" />
|
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
|
||||||
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.4" />
|
<PackageVersion Include="System.Text.Encodings.Web" Version="9.0.10" />
|
||||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250916003" />
|
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="2.0.250930001-experimental1" />
|
||||||
<PackageVersion Include="WinUIEx" Version="2.8.0" />
|
<PackageVersion Include="WinUIEx" Version="2.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -12,5 +12,7 @@ public record MailListInitializationOptions(IEnumerable<IMailItemFolder> Folders
|
|||||||
bool CreateThreads,
|
bool CreateThreads,
|
||||||
bool? IsFocusedOnly,
|
bool? IsFocusedOnly,
|
||||||
string SearchQuery,
|
string SearchQuery,
|
||||||
IEnumerable<Guid> ExistingUniqueIds,
|
HashSet<Guid> ExistingUniqueIds = null,
|
||||||
List<MailCopy> PreFetchMailCopies = null);
|
List<MailCopy> PreFetchMailCopies = null,
|
||||||
|
int Skip = 0,
|
||||||
|
int Take = 0);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
<Platforms>x86;x64;arm64</Platforms>
|
<Platforms>x86;x64;arm64</Platforms>
|
||||||
@@ -57,7 +57,6 @@
|
|||||||
<PackageReference Include="MimeKit" />
|
<PackageReference Include="MimeKit" />
|
||||||
<PackageReference Include="MailKit" />
|
<PackageReference Include="MailKit" />
|
||||||
<PackageReference Include="sqlite-net-pcl" />
|
<PackageReference Include="sqlite-net-pcl" />
|
||||||
<PackageReference Include="System.Text.Json" />
|
|
||||||
<PackageReference Include="TimePeriodLibrary.NET" />
|
<PackageReference Include="TimePeriodLibrary.NET" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public static class XamlHelpers
|
|||||||
|
|
||||||
#region Converters
|
#region Converters
|
||||||
|
|
||||||
|
public static Thickness GetMailItemControlMargin(bool isDisplayedInThread) => isDisplayedInThread ? new Thickness(40, 0, 6, 0) : new Thickness(6, 0, 6, 0);
|
||||||
public static bool IsMultiple(int count) => count > 1;
|
public static bool IsMultiple(int count) => count > 1;
|
||||||
public static bool ReverseIsMultiple(int count) => count < 1;
|
public static bool ReverseIsMultiple(int count) => count < 1;
|
||||||
public static PopupPlacementMode GetPlaccementModeForCalendarType(CalendarDisplayType type)
|
public static PopupPlacementMode GetPlaccementModeForCalendarType(CalendarDisplayType type)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
private readonly Dictionary<string, int> _groupHeaderIndexCache = [];
|
private readonly Dictionary<string, int> _groupHeaderIndexCache = [];
|
||||||
private readonly Dictionary<string, List<object>> _groupItems = [];
|
private readonly Dictionary<string, List<object>> _groupItems = [];
|
||||||
private readonly Dictionary<string, ThreadMailItemViewModel> _threadExpanders = [];
|
private readonly Dictionary<string, ThreadMailItemViewModel> _threadExpanders = [];
|
||||||
|
private readonly HashSet<Guid> _mailCopyIdHashSet = [];
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _isUpdating;
|
private bool _isUpdating;
|
||||||
|
|
||||||
@@ -78,6 +79,11 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int TotalUnreadCount => _sourceItems.Count(e => e.MailCopy?.IsRead == false);
|
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>
|
/// <summary>
|
||||||
/// Gets all email items across all groups as a flat collection
|
/// Gets all email items across all groups as a flat collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -227,6 +233,9 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
if (email?.MailCopy == null)
|
if (email?.MailCopy == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Add to unique ID tracking
|
||||||
|
_mailCopyIdHashSet.Add(email.MailCopy.UniqueId);
|
||||||
|
|
||||||
_isUpdating = true;
|
_isUpdating = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -306,6 +315,9 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
if (email?.MailCopy == null)
|
if (email?.MailCopy == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Remove from unique ID tracking
|
||||||
|
_mailCopyIdHashSet.Remove(email.MailCopy.UniqueId);
|
||||||
|
|
||||||
_isUpdating = true;
|
_isUpdating = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -386,6 +398,12 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
_isUpdating = true;
|
_isUpdating = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Add to unique ID tracking
|
||||||
|
foreach (var email in emailList)
|
||||||
|
{
|
||||||
|
_mailCopyIdHashSet.Add(email.MailCopy.UniqueId);
|
||||||
|
}
|
||||||
|
|
||||||
// For bulk loading, add to source and refresh
|
// For bulk loading, add to source and refresh
|
||||||
foreach (var email in emailList)
|
foreach (var email in emailList)
|
||||||
{
|
{
|
||||||
@@ -430,6 +448,7 @@ public partial class GroupedEmailCollection : ObservableObject, IRecipient<Prope
|
|||||||
_groupHeaderIndexCache.Clear();
|
_groupHeaderIndexCache.Clear();
|
||||||
_groupItems.Clear();
|
_groupItems.Clear();
|
||||||
_threadExpanders.Clear();
|
_threadExpanders.Clear();
|
||||||
|
_mailCopyIdHashSet.Clear();
|
||||||
|
|
||||||
OnPropertyChanged(nameof(TotalCount));
|
OnPropertyChanged(nameof(TotalCount));
|
||||||
OnPropertyChanged(nameof(TotalUnreadCount));
|
OnPropertyChanged(nameof(TotalUnreadCount));
|
||||||
|
|||||||
@@ -13,14 +13,13 @@ using Wino.Core.Domain.Entities.Mail;
|
|||||||
using Wino.Core.Domain.Entities.Shared;
|
using Wino.Core.Domain.Entities.Shared;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Exceptions;
|
using Wino.Core.Domain.Exceptions;
|
||||||
using Wino.Core.Services;
|
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Navigation;
|
using Wino.Core.Domain.Models.Navigation;
|
||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
|
using Wino.Core.Services;
|
||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Messaging.Client.Mails;
|
using Wino.Messaging.Client.Mails;
|
||||||
using Wino.Messaging.Server;
|
|
||||||
|
|
||||||
namespace Wino.Mail.ViewModels;
|
namespace Wino.Mail.ViewModels;
|
||||||
|
|
||||||
@@ -411,8 +410,8 @@ public partial class ComposePageViewModel : MailBaseViewModel
|
|||||||
|
|
||||||
// Download missing MIME message using SynchronizationManager
|
// Download missing MIME message using SynchronizationManager
|
||||||
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
|
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
|
||||||
CurrentMailDraftItem.MailCopy,
|
CurrentMailDraftItem.MailCopy,
|
||||||
CurrentMailDraftItem.AssignedAccount.Id);
|
CurrentMailDraftItem.MailCopy.AssignedAccount.Id);
|
||||||
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,16 +53,13 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<MailItemViewModel> ThreadEmails => _threadEmails.AsReadOnly();
|
public IReadOnlyList<MailItemViewModel> ThreadEmails => _threadEmails.AsReadOnly();
|
||||||
|
|
||||||
|
public MailItemViewModel LatestMailViewModel => _threadEmails.OrderByDescending(e => e.MailCopy?.CreationDate).FirstOrDefault()!;
|
||||||
|
|
||||||
public ThreadMailItemViewModel(string threadId)
|
public ThreadMailItemViewModel(string threadId)
|
||||||
{
|
{
|
||||||
_threadId = threadId;
|
_threadId = threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnIsSelectedChanged(bool value)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@@ -86,6 +83,8 @@ public partial class ThreadMailItemViewModel : ObservableRecipient, IDisposable
|
|||||||
{
|
{
|
||||||
OnPropertyChanged(nameof(Subject));
|
OnPropertyChanged(nameof(Subject));
|
||||||
OnPropertyChanged(nameof(FromName));
|
OnPropertyChanged(nameof(FromName));
|
||||||
|
OnPropertyChanged(nameof(LatestEmailDate));
|
||||||
|
OnPropertyChanged(nameof(LatestMailViewModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,14 +60,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
private IObservable<System.Reactive.EventPattern<NotifyCollectionChangedEventArgs>> selectionChangedObservable = null;
|
private IObservable<System.Reactive.EventPattern<NotifyCollectionChangedEventArgs>> selectionChangedObservable = null;
|
||||||
|
|
||||||
public GroupedEmailCollection MailCollection { get; set; } = new GroupedEmailCollection();
|
public GroupedEmailCollection MailCollection { get; set; } = new GroupedEmailCollection();
|
||||||
|
|
||||||
//public IEnumerable<MailItemViewModel> SelectedItems
|
|
||||||
//{
|
|
||||||
// get
|
|
||||||
// {
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
|
public ObservableCollection<MailItemViewModel> SelectedItems { get; set; } = [];
|
||||||
public ObservableCollection<FolderPivotViewModel> PivotFolders { get; set; } = [];
|
public ObservableCollection<FolderPivotViewModel> PivotFolders { get; set; } = [];
|
||||||
public ObservableCollection<MailOperationMenuItem> ActionItems { get; set; } = [];
|
public ObservableCollection<MailOperationMenuItem> ActionItems { get; set; } = [];
|
||||||
@@ -246,11 +238,10 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
{
|
{
|
||||||
if (SetProperty(ref _selectedSortingOption, value))
|
if (SetProperty(ref _selectedSortingOption, value))
|
||||||
{
|
{
|
||||||
// TODO: Update sorting in mail collection.
|
if (value != null && MailCollection != null)
|
||||||
//if (value != null && MailCollection != null)
|
{
|
||||||
//{
|
MailCollection.GroupingType = value.Type == SortingOptionType.ReceiveDate ? EmailGroupingType.ByDate : EmailGroupingType.ByFromName;
|
||||||
// MailCollection.SortingType = value.Type;
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,24 +553,24 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task LoadMoreItemsAsync()
|
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,
|
var initializationOptions = new MailListInitializationOptions(ActiveFolder.HandlingFolders,
|
||||||
// SelectedFilterOption.Type,
|
SelectedFilterOption.Type,
|
||||||
// SelectedSortingOption.Type,
|
SelectedSortingOption.Type,
|
||||||
// PreferencesService.IsThreadingEnabled,
|
PreferencesService.IsThreadingEnabled,
|
||||||
// SelectedFolderPivot.IsFocused,
|
SelectedFolderPivot.IsFocused,
|
||||||
// IsInSearchMode ? SearchQuery : string.Empty,
|
IsInSearchMode ? SearchQuery : string.Empty,
|
||||||
// MailCollection.MailCopyIdHashSet);
|
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(() => { MailCollection.AddEmails(viewModels); });
|
||||||
//await ExecuteUIThread(() => { IsInitializingFolder = false; });
|
await ExecuteUIThread(() => { IsInitializingFolder = false; });
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -589,7 +580,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
public IEnumerable<MailOperationMenuItem> GetAvailableMailActions(IEnumerable<MailItemViewModel> contextMailItems)
|
public IEnumerable<MailOperationMenuItem> GetAvailableMailActions(IEnumerable<MailItemViewModel> contextMailItems)
|
||||||
=> _contextMenuItemService.GetMailItemContextMenuActions(contextMailItems.Select(a => a.MailCopy));
|
=> _contextMenuItemService.GetMailItemContextMenuActions(contextMailItems.Select(a => a.MailCopy));
|
||||||
|
|
||||||
|
|
||||||
private bool ShouldPreventItemAdd(MailCopy mailItem)
|
private bool ShouldPreventItemAdd(MailCopy mailItem)
|
||||||
{
|
{
|
||||||
bool condition = mailItem.IsRead
|
bool condition = mailItem.IsRead
|
||||||
@@ -733,13 +723,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
private IEnumerable<MailItemViewModel> PrepareMailViewModels(IEnumerable<MailCopy> mailItems)
|
private IEnumerable<MailItemViewModel> PrepareMailViewModels(IEnumerable<MailCopy> mailItems)
|
||||||
{
|
{
|
||||||
return mailItems.Select(a => new MailItemViewModel(a));
|
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]
|
[RelayCommand]
|
||||||
@@ -784,7 +767,6 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
// Here items are sorted and filtered.
|
// Here items are sorted and filtered.
|
||||||
|
|
||||||
List<MailCopy> items = null;
|
List<MailCopy> items = null;
|
||||||
List<MailCopy> onlineSearchItems = null;
|
|
||||||
|
|
||||||
bool isDoingSearch = !string.IsNullOrEmpty(SearchQuery);
|
bool isDoingSearch = !string.IsNullOrEmpty(SearchQuery);
|
||||||
bool isDoingOnlineSearch = false;
|
bool isDoingOnlineSearch = false;
|
||||||
@@ -851,8 +833,7 @@ public partial class MailListPageViewModel : MailBaseViewModel,
|
|||||||
PreferencesService.IsThreadingEnabled,
|
PreferencesService.IsThreadingEnabled,
|
||||||
SelectedFolderPivot.IsFocused,
|
SelectedFolderPivot.IsFocused,
|
||||||
SearchQuery,
|
SearchQuery,
|
||||||
default,
|
MailCollection.MailCopyIdHashSet);
|
||||||
onlineSearchItems);
|
|
||||||
|
|
||||||
items = await _mailService.FetchMailsAsync(initializationOptions, cancellationToken).ConfigureAwait(false);
|
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.Data;
|
||||||
using Wino.Mail.ViewModels.Messages;
|
using Wino.Mail.ViewModels.Messages;
|
||||||
using Wino.Messaging.Client.Mails;
|
using Wino.Messaging.Client.Mails;
|
||||||
using Wino.Messaging.Server;
|
|
||||||
using Wino.Messaging.UI;
|
using Wino.Messaging.UI;
|
||||||
using IMailService = Wino.Core.Domain.Interfaces.IMailService;
|
using IMailService = Wino.Core.Domain.Interfaces.IMailService;
|
||||||
|
|
||||||
@@ -355,8 +354,8 @@ public partial class MailRenderingPageViewModel : MailBaseViewModel,
|
|||||||
|
|
||||||
// Download missing MIME message using SynchronizationManager
|
// Download missing MIME message using SynchronizationManager
|
||||||
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
|
await SynchronizationManager.Instance.DownloadMimeMessageAsync(
|
||||||
mailItemViewModel.MailCopy,
|
mailItemViewModel.MailCopy,
|
||||||
mailItemViewModel.AssignedAccount.Id);
|
mailItemViewModel.MailCopy.AssignedAccount.Id);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:abstract="using:Wino.Views.Abstract"
|
xmlns:abstract="using:Wino.Views.Abstract"
|
||||||
xmlns:advanced="using:Wino.Controls.Advanced"
|
|
||||||
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
|
||||||
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||||
xmlns:controls="using:Wino.Controls"
|
xmlns:controls="using:Wino.Controls"
|
||||||
@@ -356,7 +355,6 @@
|
|||||||
<Grid
|
<Grid
|
||||||
x:Name="RootGrid"
|
x:Name="RootGrid"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
Background="{ThemeResource WinoApplicationBackgroundColor}"
|
|
||||||
ColumnSpacing="0"
|
ColumnSpacing="0"
|
||||||
RowSpacing="0">
|
RowSpacing="0">
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,46 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using CommunityToolkit.WinUI;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
namespace Wino.Mail.WinUI.Controls.Advanced;
|
namespace Wino.Mail.WinUI.Controls.Advanced;
|
||||||
|
|
||||||
public partial class WinoItemsView : ItemsView
|
public partial class WinoItemsView : ItemsView
|
||||||
{
|
{
|
||||||
|
private const string PART_ScrollView = nameof(PART_ScrollView);
|
||||||
|
|
||||||
|
private ScrollView? _internalScrollView;
|
||||||
|
|
||||||
|
[GeneratedDependencyProperty]
|
||||||
|
public partial ICommand LoadMoreCommand { get; set; }
|
||||||
|
|
||||||
public IEnumerable<object>? CastedItemsSource => ItemsSource as IEnumerable<object>;
|
public IEnumerable<object>? CastedItemsSource => ItemsSource as IEnumerable<object>;
|
||||||
|
|
||||||
public WinoItemsView()
|
public WinoItemsView()
|
||||||
{
|
{
|
||||||
DefaultStyleKey = typeof(ItemsView);
|
DefaultStyleKey = typeof(ItemsView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate()
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate();
|
||||||
|
|
||||||
|
_internalScrollView = GetTemplateChild("PART_ScrollView") as ScrollView ?? throw new System.Exception("Can't find the ScrollView in WinoItemsView.");
|
||||||
|
|
||||||
|
_internalScrollView.ViewChanged -= InternalScrollViewPositionChanged;
|
||||||
|
_internalScrollView.ViewChanged += InternalScrollViewPositionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InternalScrollViewPositionChanged(ScrollView sender, object args)
|
||||||
|
{
|
||||||
|
if (_internalScrollView == null) return;
|
||||||
|
|
||||||
|
// No need to raise init request if there are no items in the list.
|
||||||
|
if (ItemsSource == null) return;
|
||||||
|
|
||||||
|
double progress = sender.VerticalOffset / sender.ScrollableHeight;
|
||||||
|
|
||||||
|
// Trigger when scrolled past 90% of total height
|
||||||
|
if (progress >= 0.9) LoadMoreCommand?.Execute(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ using Wino.Core.Domain;
|
|||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
using Wino.Core.Domain.Models;
|
using Wino.Core.Domain.Models;
|
||||||
using Wino.Core.Domain.Models.Reader;
|
using Wino.Core.Domain.Models.Reader;
|
||||||
using Wino.Core.WinUI;
|
|
||||||
using Wino.Core.WinUI.Extensions;
|
using Wino.Core.WinUI.Extensions;
|
||||||
using Wino.Mail.WinUI;
|
using Wino.Mail.WinUI;
|
||||||
|
|
||||||
@@ -140,7 +139,7 @@ public sealed partial class WebViewEditorControl : Control, IDisposable
|
|||||||
{
|
{
|
||||||
this.DefaultStyleKey = typeof(WebViewEditorControl);
|
this.DefaultStyleKey = typeof(WebViewEditorControl);
|
||||||
|
|
||||||
IsEditorDarkMode = WinoApplication.Current.UnderlyingThemeService.IsUnderlyingThemeDark();
|
IsEditorDarkMode = Core.WinUI.WinoApplication.Current.UnderlyingThemeService.IsUnderlyingThemeDark();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async void OnApplyTemplate()
|
protected override async void OnApplyTemplate()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<!-- SystemBackdrop will be set by NewThemeService -->
|
<!-- SystemBackdrop will be set by NewThemeService -->
|
||||||
|
|
||||||
<Grid>
|
<Grid Background="{ThemeResource WinoApplicationBackgroundColor}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
BackRequested="BackButtonClicked"
|
BackRequested="BackButtonClicked"
|
||||||
|
Background="Transparent"
|
||||||
IsBackButtonVisible="{x:Bind StatePersistanceService.IsBackButtonVisible, Mode=OneWay}"
|
IsBackButtonVisible="{x:Bind StatePersistanceService.IsBackButtonVisible, Mode=OneWay}"
|
||||||
IsPaneToggleButtonVisible="True"
|
IsPaneToggleButtonVisible="True"
|
||||||
PaneToggleRequested="PaneButtonClicked" />
|
PaneToggleRequested="PaneButtonClicked" />
|
||||||
|
|
||||||
<Frame
|
<Frame
|
||||||
x:Name="MainShellFrame"
|
x:Name="MainShellFrame"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
|||||||
@@ -67,104 +67,34 @@
|
|||||||
<animations:OpacityAnimation To="0.0" Duration="0:0:1" />
|
<animations:OpacityAnimation To="0.0" Duration="0:0:1" />
|
||||||
</animations:Implicit.HideAnimations>
|
</animations:Implicit.HideAnimations>
|
||||||
|
|
||||||
<Grid Height="80">
|
<controls:MailItemDisplayInformationControl
|
||||||
<!-- Thread background -->
|
Margin="{x:Bind helpers:XamlHelpers.GetMailItemControlMargin(IsDisplayedInThread), Mode=OneWay}"
|
||||||
<Grid
|
x:DefaultBindMode="OneWay"
|
||||||
HorizontalAlignment="Stretch"
|
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||||
VerticalAlignment="Stretch"
|
ContextRequested="MailItemContextRequested"
|
||||||
Background="{ThemeResource CardStrokeColorDefaultBrush}"
|
DisplayMode="{Binding ElementName=root, Path=ViewModel.PreferencesService.MailItemDisplayMode, Mode=OneWay}"
|
||||||
Visibility="{x:Bind IsDisplayedInThread, Mode=OneWay}" />
|
HoverActionExecutedCommand="{Binding ElementName=root, Path=ViewModel.ExecuteHoverActionCommand}"
|
||||||
|
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||||
<Grid Padding="8,4,12,4">
|
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||||
<Grid.ColumnDefinitions>
|
IsThumbnailUpdated="{x:Bind ThumbnailUpdatedEvent, Mode=OneWay}"
|
||||||
<ColumnDefinition Width="Auto" />
|
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||||
<ColumnDefinition Width="*" />
|
MailItem="{x:Bind MailCopy, Mode=OneWay}"
|
||||||
<ColumnDefinition Width="Auto" />
|
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||||
</Grid.ColumnDefinitions>
|
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||||
|
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}" />
|
||||||
<!-- Left: PersonPicture -->
|
|
||||||
<PersonPicture
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="40"
|
|
||||||
Height="40"
|
|
||||||
Margin="0,0,12,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
DisplayName="{x:Bind FromName, Mode=OneWay}" />
|
|
||||||
|
|
||||||
<!-- Center: Content -->
|
|
||||||
<StackPanel
|
|
||||||
Grid.Column="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Spacing="2">
|
|
||||||
<!-- Subject -->
|
|
||||||
<TextBlock
|
|
||||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByReadState(IsRead), Mode=OneWay}"
|
|
||||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
|
||||||
MaxLines="1"
|
|
||||||
Text="{x:Bind Subject, Mode=OneWay}"
|
|
||||||
TextTrimming="CharacterEllipsis" />
|
|
||||||
|
|
||||||
<!-- Sender Name -->
|
|
||||||
<TextBlock
|
|
||||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByReadState(IsRead), Mode=OneWay}"
|
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
|
||||||
MaxLines="1"
|
|
||||||
Text="{x:Bind FromName, Mode=OneWay}"
|
|
||||||
TextTrimming="CharacterEllipsis" />
|
|
||||||
|
|
||||||
<!-- Preview Text -->
|
|
||||||
<TextBlock
|
|
||||||
Foreground="{ThemeResource TextFillColorTertiaryBrush}"
|
|
||||||
MaxLines="1"
|
|
||||||
Text="{x:Bind PreviewText, Mode=OneWay}"
|
|
||||||
TextTrimming="CharacterEllipsis" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- Right: Indicators -->
|
|
||||||
<StackPanel
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="12,0,0,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Spacing="4">
|
|
||||||
|
|
||||||
<!-- Unread Indicator (show when IsRead is false) -->
|
|
||||||
<Ellipse
|
|
||||||
Width="8"
|
|
||||||
Height="8"
|
|
||||||
Fill="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
|
||||||
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(IsRead), Mode=OneWay}" />
|
|
||||||
|
|
||||||
<!-- Flagged Indicator -->
|
|
||||||
<FontIcon
|
|
||||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
|
||||||
FontSize="12"
|
|
||||||
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
|
||||||
Glyph=""
|
|
||||||
Visibility="{x:Bind IsFlagged, Mode=OneWay}" />
|
|
||||||
|
|
||||||
<!-- Attachment Indicator -->
|
|
||||||
<FontIcon
|
|
||||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
|
||||||
FontSize="12"
|
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
|
||||||
Glyph=""
|
|
||||||
Visibility="{x:Bind HasAttachments, Mode=OneWay}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</ItemContainer>
|
</ItemContainer>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="ThreadExpanderTemplate" x:DataType="viewModelData:ThreadMailItemViewModel">
|
<DataTemplate x:Key="ThreadExpanderTemplate" x:DataType="viewModelData:ThreadMailItemViewModel">
|
||||||
<ItemContainer Tag="{x:Bind}" Tapped="ThreadContainerTapped">
|
<ItemContainer
|
||||||
<Grid
|
CanUserSelect="UserCannotSelect"
|
||||||
Padding="4,12,0,12"
|
RightTapped="ThreadContainerRightTapped"
|
||||||
Background="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
|
Tag="{x:Bind}"
|
||||||
ColumnSpacing="8">
|
Tapped="ThreadContainerTapped">
|
||||||
|
<Grid Padding="4,0,0,0" ColumnSpacing="8">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Expansion indicator -->
|
<!-- Expansion indicator -->
|
||||||
@@ -177,42 +107,34 @@
|
|||||||
Glyph="" />
|
Glyph="" />
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
|
|
||||||
<!-- Thread content -->
|
<controls:MailItemDisplayInformationControl
|
||||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
Grid.Column="1"
|
||||||
<TextBlock
|
x:DefaultBindMode="OneWay"
|
||||||
FontWeight="SemiBold"
|
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
ContextRequested="MailItemContextRequested"
|
||||||
Text="{x:Bind Subject, Mode=OneWay}"
|
DisplayMode="{Binding ElementName=root, Path=ViewModel.PreferencesService.MailItemDisplayMode, Mode=OneWay}"
|
||||||
TextTrimming="CharacterEllipsis" />
|
HoverActionExecutedCommand="{Binding ElementName=root, Path=ViewModel.ExecuteHoverActionCommand}"
|
||||||
<TextBlock
|
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
IsThumbnailUpdated="{x:Bind LatestMailViewModel.ThumbnailUpdatedEvent, Mode=OneWay}"
|
||||||
Text="{x:Bind LatestEmailDate, Mode=OneWay}"
|
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||||
TextTrimming="CharacterEllipsis" />
|
MailItem="{x:Bind LatestMailViewModel.MailCopy, Mode=OneWay}"
|
||||||
</StackPanel>
|
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||||
|
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||||
<!-- Email count badge -->
|
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}" />
|
||||||
<Border
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="8,0,12,0"
|
|
||||||
Padding="6,2"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Background="{ThemeResource AccentTextFillColorPrimaryBrush}"
|
|
||||||
CornerRadius="8">
|
|
||||||
<TextBlock
|
|
||||||
Foreground="White"
|
|
||||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
|
||||||
Text="{x:Bind EmailCount, Mode=OneWay}" />
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</ItemContainer>
|
</ItemContainer>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="DateGroupHeaderTemplate" x:DataType="data:DateGroupHeader">
|
<DataTemplate x:Key="DateGroupHeaderTemplate" x:DataType="data:DateGroupHeader">
|
||||||
<ItemContainer IsHitTestVisible="False">
|
<ItemContainer
|
||||||
|
CanUserSelect="UserCannotSelect"
|
||||||
|
IsEnabled="False"
|
||||||
|
IsHitTestVisible="False">
|
||||||
<Grid Padding="12,8" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
|
<Grid Padding="12,8" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
|
||||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
Style="{ThemeResource CaptionTextBlockStyle}"
|
||||||
Text="{x:Bind DisplayName, Mode=OneWay}" />
|
Text="{x:Bind DisplayName, Mode=OneWay}" />
|
||||||
@@ -221,7 +143,10 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="SenderGroupHeaderTemplate" x:DataType="data:SenderGroupHeader">
|
<DataTemplate x:Key="SenderGroupHeaderTemplate" x:DataType="data:SenderGroupHeader">
|
||||||
<ItemContainer IsHitTestVisible="False">
|
<ItemContainer
|
||||||
|
CanUserSelect="UserCannotSelect"
|
||||||
|
IsEnabled="False"
|
||||||
|
IsHitTestVisible="False">
|
||||||
<Grid Padding="12,8" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
|
<Grid Padding="12,8" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@@ -503,15 +428,18 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<advanced:WinoItemsView
|
<advanced:WinoItemsView
|
||||||
x:Name="MailListView"
|
x:Name="MailListView"
|
||||||
Margin="4"
|
Margin="4"
|
||||||
ItemTemplate="{StaticResource MailItemContainerSelector}"
|
ItemTemplate="{StaticResource MailItemContainerSelector}"
|
||||||
ItemsSource="{x:Bind ViewModel.MailCollection.Items, Mode=OneTime}"
|
ItemsSource="{x:Bind ViewModel.MailCollection.Items, Mode=OneTime}"
|
||||||
Layout="{StaticResource DefaultItemsViewLayout}"
|
Layout="{StaticResource DefaultItemsViewLayout}"
|
||||||
|
LoadMoreCommand="{x:Bind ViewModel.LoadMoreItemsCommand}"
|
||||||
SelectionChanged="ListSelectionChanged"
|
SelectionChanged="ListSelectionChanged"
|
||||||
SelectionMode="Extended" />
|
SelectionMode="Extended" />
|
||||||
|
|
||||||
|
|
||||||
<!-- Try online search panel. -->
|
<!-- Try online search panel. -->
|
||||||
<Grid Grid.Row="1" Visibility="{x:Bind ViewModel.IsOnlineSearchButtonVisible, Mode=OneWay}">
|
<Grid Grid.Row="1" Visibility="{x:Bind ViewModel.IsOnlineSearchButtonVisible, Mode=OneWay}">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Microsoft.UI.Xaml.Media.Animation;
|
|||||||
using Microsoft.UI.Xaml.Navigation;
|
using Microsoft.UI.Xaml.Navigation;
|
||||||
using MoreLinq;
|
using MoreLinq;
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
|
using Wino.Controls;
|
||||||
using Wino.Core.Domain;
|
using Wino.Core.Domain;
|
||||||
using Wino.Core.Domain.Enums;
|
using Wino.Core.Domain.Enums;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
@@ -74,7 +75,7 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
|||||||
|
|
||||||
// Dispose all WinoListView items.
|
// Dispose all WinoListView items.
|
||||||
|
|
||||||
MailListView.Dispose();
|
// MailListView.Dispose();
|
||||||
|
|
||||||
this.Bindings.StopTracking();
|
this.Bindings.StopTracking();
|
||||||
|
|
||||||
@@ -162,31 +163,24 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
|||||||
// Context is requested from a single mail point, but we might have multiple selected items.
|
// Context is requested from a single mail point, but we might have multiple selected items.
|
||||||
// This menu should be calculated based on all selected items by providers.
|
// This menu should be calculated based on all selected items by providers.
|
||||||
|
|
||||||
//if (sender is MailItemDisplayInformationControl control && args.TryGetPosition(sender, out Point p))
|
if (sender is MailItemDisplayInformationControl control && args.TryGetPosition(sender, out Point p))
|
||||||
//{
|
{
|
||||||
// await FocusManager.TryFocusAsync(control, FocusState.Keyboard);
|
if (control.DataContext is MailItemViewModel clickedMailItemContext)
|
||||||
|
{
|
||||||
|
var targetItems = ViewModel.MailCollection.AllItems.Where(a => a.IsSelected);
|
||||||
|
var availableActions = ViewModel.GetAvailableMailActions(targetItems);
|
||||||
|
|
||||||
// if (control.DataContext is IMailItem clickedMailItemContext)
|
if (!availableActions?.Any() ?? false) return;
|
||||||
// {
|
|
||||||
// var targetItems = ViewModel.GetTargetMailItemViewModels(clickedMailItemContext);
|
|
||||||
// var availableActions = ViewModel.GetAvailableMailActions(targetItems);
|
|
||||||
|
|
||||||
// if (!availableActions?.Any() ?? false) return;
|
var clickedOperation = await GetMailOperationFromFlyoutAsync(availableActions, control, p.X, p.Y);
|
||||||
// var t = targetItems.ElementAt(0);
|
|
||||||
|
|
||||||
// ViewModel.ChangeCustomFocusedState(targetItems, true);
|
if (clickedOperation == null) return;
|
||||||
|
|
||||||
// var clickedOperation = await GetMailOperationFromFlyoutAsync(availableActions, control, p.X, p.Y);
|
var prepRequest = new MailOperationPreperationRequest(clickedOperation.Operation, targetItems.Select(a => a.MailCopy));
|
||||||
|
|
||||||
// ViewModel.ChangeCustomFocusedState(targetItems, false);
|
await ViewModel.ExecuteMailOperationAsync(prepRequest);
|
||||||
|
}
|
||||||
// if (clickedOperation == null) return;
|
}
|
||||||
|
|
||||||
// var prepRequest = new MailOperationPreperationRequest(clickedOperation.Operation, targetItems.Select(a => a.MailCopy));
|
|
||||||
|
|
||||||
// await ViewModel.ExecuteMailOperationAsync(prepRequest);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<MailOperationMenuItem> GetMailOperationFromFlyoutAsync(IEnumerable<MailOperationMenuItem> availableActions,
|
private async Task<MailOperationMenuItem> GetMailOperationFromFlyoutAsync(IEnumerable<MailOperationMenuItem> availableActions,
|
||||||
@@ -507,22 +501,7 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
|||||||
private void DeleteAllInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
|
private void DeleteAllInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
|
||||||
=> ViewModel.ExecuteMailOperationCommand.Execute(MailOperation.SoftDelete);
|
=> ViewModel.ExecuteMailOperationCommand.Execute(MailOperation.SoftDelete);
|
||||||
|
|
||||||
private void ThreadContainerTapped(object sender, TappedRoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (sender is ItemContainer container && container.Tag is ThreadMailItemViewModel expander)
|
|
||||||
{
|
|
||||||
// Toggle expansion state
|
|
||||||
expander.IsThreadExpanded = !expander.IsThreadExpanded;
|
|
||||||
|
|
||||||
// Find the expander icon and animate its rotation using Composition APIs
|
|
||||||
var expanderIcon = WinoVisualTreeHelper.GetChildObject<FontIcon>(container, "ExpanderIcon");
|
|
||||||
if (expanderIcon != null)
|
|
||||||
{
|
|
||||||
var targetAngle = expander.IsThreadExpanded ? 90f : 0f;
|
|
||||||
AnimateRotationWithComposition(expanderIcon, targetAngle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Animates the rotation using high-performance Composition APIs
|
/// Animates the rotation using high-performance Composition APIs
|
||||||
@@ -561,4 +540,32 @@ public sealed partial class MailListPage : MailListPageAbstract,
|
|||||||
UpdateSelectAllButtonStatus();
|
UpdateSelectAllButtonStatus();
|
||||||
UpdateAdaptiveness();
|
UpdateAdaptiveness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ThreadContainerRightTapped(object sender, RightTappedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ItemContainer container && container.Tag is ThreadMailItemViewModel expander)
|
||||||
|
{
|
||||||
|
expander.IsThreadExpanded = !expander.IsThreadExpanded;
|
||||||
|
|
||||||
|
// Select all.
|
||||||
|
ViewModel.MailCollection.AllItems.Where(a => expander.ThreadEmails.Contains(a)).ForEach(a => a.IsSelected = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThreadContainerTapped(object sender, TappedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ItemContainer container && container.Tag is ThreadMailItemViewModel expander)
|
||||||
|
{
|
||||||
|
// Toggle expansion state
|
||||||
|
expander.IsThreadExpanded = !expander.IsThreadExpanded;
|
||||||
|
|
||||||
|
// Find the expander icon and animate its rotation using Composition APIs
|
||||||
|
var expanderIcon = WinoVisualTreeHelper.GetChildObject<FontIcon>(container, "ExpanderIcon");
|
||||||
|
if (expanderIcon != null)
|
||||||
|
{
|
||||||
|
var targetAngle = expander.IsThreadExpanded ? 90f : 0f;
|
||||||
|
AnimateRotationWithComposition(expanderIcon, targetAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="ElementThemeSelectionDisabledTextBlock"
|
x:Name="ElementThemeSelectionDisabledTextBlock"
|
||||||
|
Margin="4,0,0,0"
|
||||||
x:Load="{x:Bind ViewModel.CanSelectElementTheme, Mode=OneWay, Converter={StaticResource ReverseBooleanConverter}}"
|
x:Load="{x:Bind ViewModel.CanSelectElementTheme, Mode=OneWay, Converter={StaticResource ReverseBooleanConverter}}"
|
||||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||||
Text="{x:Bind domain:Translator.SettingsElementThemeSelectionDisabled}" />
|
Text="{x:Bind domain:Translator.SettingsElementThemeSelectionDisabled}" />
|
||||||
@@ -149,7 +150,10 @@
|
|||||||
</controls:SettingsExpander>
|
</controls:SettingsExpander>
|
||||||
|
|
||||||
<!-- Backdrop Selection -->
|
<!-- Backdrop Selection -->
|
||||||
<controls:SettingsCard Description="Choose the backdrop effect for your app window" Header="Window Backdrop">
|
<controls:SettingsCard
|
||||||
|
Description="Choose the backdrop effect for your app window"
|
||||||
|
Header="Window Backdrop"
|
||||||
|
IsEnabled="{x:Bind ViewModel.CanSelectElementTheme, Mode=OneWay}">
|
||||||
<controls:SettingsCard.HeaderIcon>
|
<controls:SettingsCard.HeaderIcon>
|
||||||
<PathIcon Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z" />
|
<PathIcon Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z" />
|
||||||
</controls:SettingsCard.HeaderIcon>
|
</controls:SettingsCard.HeaderIcon>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public class MailService : BaseDatabaseService, IMailService
|
|||||||
private readonly IContactService _contactService;
|
private readonly IContactService _contactService;
|
||||||
private readonly IAccountService _accountService;
|
private readonly IAccountService _accountService;
|
||||||
private readonly ISignatureService _signatureService;
|
private readonly ISignatureService _signatureService;
|
||||||
|
|
||||||
private readonly IMimeFileService _mimeFileService;
|
private readonly IMimeFileService _mimeFileService;
|
||||||
private readonly IPreferencesService _preferencesService;
|
private readonly IPreferencesService _preferencesService;
|
||||||
|
|
||||||
@@ -192,15 +193,23 @@ public class MailService : BaseDatabaseService, IMailService
|
|||||||
.OrWhereContains("MailCopy.FromName", options.SearchQuery)
|
.OrWhereContains("MailCopy.FromName", options.SearchQuery)
|
||||||
.OrWhereContains("MailCopy.FromAddress", options.SearchQuery));
|
.OrWhereContains("MailCopy.FromAddress", options.SearchQuery));
|
||||||
|
|
||||||
|
// Support pagination by excluding already fetched items
|
||||||
if (options.ExistingUniqueIds?.Any() ?? false)
|
if (options.ExistingUniqueIds?.Any() ?? false)
|
||||||
{
|
{
|
||||||
query.WhereNotIn("MailCopy.UniqueId", options.ExistingUniqueIds);
|
query.WhereNotIn("MailCopy.UniqueId", options.ExistingUniqueIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (options.Skip > 0)
|
// Support skip for pagination
|
||||||
//{
|
if (options.Skip > 0)
|
||||||
// query.Skip(options.Skip);
|
{
|
||||||
//}
|
query.Skip(options.Skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support custom take count for pagination
|
||||||
|
if (options.Take > 0)
|
||||||
|
{
|
||||||
|
query.Take(options.Take);
|
||||||
|
}
|
||||||
|
|
||||||
return query.GetRawQuery();
|
return query.GetRawQuery();
|
||||||
}
|
}
|
||||||
@@ -218,7 +227,6 @@ public class MailService : BaseDatabaseService, IMailService
|
|||||||
{
|
{
|
||||||
// If not just do the query.
|
// If not just do the query.
|
||||||
var query = BuildMailFetchQuery(options);
|
var query = BuildMailFetchQuery(options);
|
||||||
|
|
||||||
mails = await Connection.QueryAsync<MailCopy>(query);
|
mails = await Connection.QueryAsync<MailCopy>(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,9 +247,6 @@ public class MailService : BaseDatabaseService, IMailService
|
|||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
// Threading is disabled. Just return everything as it is.
|
|
||||||
// mails.Sort(options.SortingOptionType == SortingOptionType.ReceiveDate ? new DateComparer() : new NameComparer());
|
|
||||||
|
|
||||||
return [.. mails];
|
return [.. mails];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,7 +1010,7 @@ public class MailService : BaseDatabaseService, IMailService
|
|||||||
|
|
||||||
public async Task<List<MailCopy>> GetExistingMailsAsync(Guid folderId, IEnumerable<MailKit.UniqueId> uniqueIds)
|
public async Task<List<MailCopy>> GetExistingMailsAsync(Guid folderId, IEnumerable<MailKit.UniqueId> uniqueIds)
|
||||||
{
|
{
|
||||||
var localMailIds = uniqueIds.Where(a => a != null).Select(a => MailkitClientExtensions.CreateUid(folderId, a.Id)).ToArray();
|
var localMailIds = uniqueIds.Select(a => MailkitClientExtensions.CreateUid(folderId, a.Id)).ToArray();
|
||||||
|
|
||||||
var query = new Query(nameof(MailCopy))
|
var query = new Query(nameof(MailCopy))
|
||||||
.WhereIn("Id", localMailIds)
|
.WhereIn("Id", localMailIds)
|
||||||
|
|||||||
@@ -14,9 +14,14 @@
|
|||||||
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
||||||
<packageSource key="nuget">
|
<packageSource key="nuget">
|
||||||
<package pattern="*" />
|
<package pattern="*" />
|
||||||
|
<package pattern="CommunityToolkit.Common" />
|
||||||
|
<package pattern="Microsoft.*" />
|
||||||
|
<package pattern="Newtonsoft.Json" />
|
||||||
|
<package pattern="CommunityToolkit.WinUI.Extensions" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
<packageSource key="labsFeed">
|
<packageSource key="labsFeed">
|
||||||
<package pattern="CommunityToolkit.Labs.*" />
|
<package pattern="CommunityToolkit.Labs.*" />
|
||||||
|
<package pattern="CommunityToolkit.WinUI.Extensions" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
</packageSourceMapping>
|
</packageSourceMapping>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
Reference in New Issue
Block a user