Info panel for synchronizers in shell.
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Wino.Core.Domain.Models.Synchronization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a single grouped synchronization action displayed in the sync status flyout.
|
||||||
|
/// For example: "Deleting 3 mail(s)" or "Marking folder as read".
|
||||||
|
/// </summary>
|
||||||
|
public class SynchronizationActionItem
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
public Guid AccountId { get; set; }
|
||||||
|
public string AccountName { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
@@ -84,6 +84,22 @@
|
|||||||
"Buttons_Yes": "Yes",
|
"Buttons_Yes": "Yes",
|
||||||
"Sync_SynchronizingFolder": "Synchronizing {0} {1}%",
|
"Sync_SynchronizingFolder": "Synchronizing {0} {1}%",
|
||||||
"Sync_DownloadedMessages": "Downloaded {0} messages from {1}",
|
"Sync_DownloadedMessages": "Downloaded {0} messages from {1}",
|
||||||
|
"SyncAction_Archiving": "Archiving {0} mail(s)",
|
||||||
|
"SyncAction_ClearingFlag": "Unflagging {0} mail(s)",
|
||||||
|
"SyncAction_CreatingDraft": "Creating draft",
|
||||||
|
"SyncAction_Deleting": "Deleting {0} mail(s)",
|
||||||
|
"SyncAction_EmptyingFolder": "Emptying folder",
|
||||||
|
"SyncAction_MarkingAsRead": "Marking {0} mail(s) as read",
|
||||||
|
"SyncAction_MarkingAsUnread": "Marking {0} mail(s) as unread",
|
||||||
|
"SyncAction_MarkingFolderAsRead": "Marking folder as read",
|
||||||
|
"SyncAction_Moving": "Moving {0} mail(s)",
|
||||||
|
"SyncAction_MovingToFocused": "Moving {0} mail(s) to Focused",
|
||||||
|
"SyncAction_RenamingFolder": "Renaming folder",
|
||||||
|
"SyncAction_SendingMail": "Sending mail",
|
||||||
|
"SyncAction_SettingFlag": "Flagging {0} mail(s)",
|
||||||
|
"SyncAction_SynchronizingAccount": "Synchronizing {0}",
|
||||||
|
"SyncAction_SynchronizingAccounts": "Synchronizing {0} account(s)",
|
||||||
|
"SyncAction_Unarchiving": "Unarchiving {0} mail(s)",
|
||||||
"CalendarAllDayEventSummary": "all-day events",
|
"CalendarAllDayEventSummary": "all-day events",
|
||||||
"CalendarDisplayOptions_Color": "Color",
|
"CalendarDisplayOptions_Color": "Color",
|
||||||
"CalendarDisplayOptions_Expand": "Expand",
|
"CalendarDisplayOptions_Expand": "Expand",
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Wino.Core.Domain;
|
||||||
|
using Wino.Core.Domain.Enums;
|
||||||
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
|
using Wino.Core.Requests.Folder;
|
||||||
|
using Wino.Core.Requests.Mail;
|
||||||
|
|
||||||
|
namespace Wino.Core.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts queued synchronization requests into user-facing action descriptions.
|
||||||
|
/// </summary>
|
||||||
|
public static class SynchronizationActionHelper
|
||||||
|
{
|
||||||
|
public static List<SynchronizationActionItem> CreateActionItems(
|
||||||
|
IEnumerable<IRequestBase> requests, Guid accountId, string accountName)
|
||||||
|
{
|
||||||
|
var items = new List<SynchronizationActionItem>();
|
||||||
|
|
||||||
|
// Group mail action requests by operation
|
||||||
|
var mailRequests = requests.OfType<IMailActionRequest>();
|
||||||
|
var mailGroups = mailRequests.GroupBy(r => GetMailActionKey(r));
|
||||||
|
|
||||||
|
foreach (var group in mailGroups)
|
||||||
|
{
|
||||||
|
var description = GetMailActionDescription(group.Key, group.ToList());
|
||||||
|
|
||||||
|
if (description != null)
|
||||||
|
{
|
||||||
|
items.Add(new SynchronizationActionItem
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
AccountName = accountName,
|
||||||
|
Description = description
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle folder action requests individually
|
||||||
|
var folderRequests = requests.OfType<IFolderActionRequest>();
|
||||||
|
foreach (var folderRequest in folderRequests)
|
||||||
|
{
|
||||||
|
var description = GetFolderActionDescription(folderRequest);
|
||||||
|
|
||||||
|
if (description != null)
|
||||||
|
{
|
||||||
|
items.Add(new SynchronizationActionItem
|
||||||
|
{
|
||||||
|
AccountId = accountId,
|
||||||
|
AccountName = accountName,
|
||||||
|
Description = description
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a key that differentiates MarkRead vs MarkUnread, Flag vs Unflag, Archive vs Unarchive.
|
||||||
|
/// </summary>
|
||||||
|
private static string GetMailActionKey(IMailActionRequest request)
|
||||||
|
{
|
||||||
|
return request switch
|
||||||
|
{
|
||||||
|
MarkReadRequest r => r.IsRead ? "MarkRead" : "MarkUnread",
|
||||||
|
ChangeFlagRequest r => r.IsFlagged ? "SetFlag" : "ClearFlag",
|
||||||
|
ArchiveRequest r => r.IsArchiving ? "Archive" : "Unarchive",
|
||||||
|
_ => request.Operation.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMailActionDescription(string actionKey, List<IMailActionRequest> requests)
|
||||||
|
{
|
||||||
|
int count = requests.Count;
|
||||||
|
|
||||||
|
return actionKey switch
|
||||||
|
{
|
||||||
|
"MarkRead" => string.Format(Translator.SyncAction_MarkingAsRead, count),
|
||||||
|
"MarkUnread" => string.Format(Translator.SyncAction_MarkingAsUnread, count),
|
||||||
|
"Delete" => string.Format(Translator.SyncAction_Deleting, count),
|
||||||
|
"Move" => string.Format(Translator.SyncAction_Moving, count),
|
||||||
|
"Archive" => string.Format(Translator.SyncAction_Archiving, count),
|
||||||
|
"Unarchive" => string.Format(Translator.SyncAction_Unarchiving, count),
|
||||||
|
"SetFlag" => string.Format(Translator.SyncAction_SettingFlag, count),
|
||||||
|
"ClearFlag" => string.Format(Translator.SyncAction_ClearingFlag, count),
|
||||||
|
"CreateDraft" => Translator.SyncAction_CreatingDraft,
|
||||||
|
"Send" => Translator.SyncAction_SendingMail,
|
||||||
|
"MoveToFocused" => string.Format(Translator.SyncAction_MovingToFocused, count),
|
||||||
|
"AlwaysMoveTo" => string.Format(Translator.SyncAction_Moving, count),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetFolderActionDescription(IFolderActionRequest request)
|
||||||
|
{
|
||||||
|
return request switch
|
||||||
|
{
|
||||||
|
RenameFolderRequest => Translator.SyncAction_RenamingFolder,
|
||||||
|
EmptyFolderRequest => Translator.SyncAction_EmptyingFolder,
|
||||||
|
MarkFolderAsReadRequest => Translator.SyncAction_MarkingFolderAsRead,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,9 +13,11 @@ using Wino.Core.Domain.Models.Calendar;
|
|||||||
using Wino.Core.Domain.Models.Folders;
|
using Wino.Core.Domain.Models.Folders;
|
||||||
using Wino.Core.Domain.Models.MailItem;
|
using Wino.Core.Domain.Models.MailItem;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
|
using Wino.Core.Helpers;
|
||||||
using Wino.Core.Requests.Calendar;
|
using Wino.Core.Requests.Calendar;
|
||||||
using Wino.Core.Requests.Mail;
|
using Wino.Core.Requests.Mail;
|
||||||
using Wino.Messaging.Server;
|
using Wino.Messaging.Server;
|
||||||
|
using Wino.Messaging.UI;
|
||||||
|
|
||||||
namespace Wino.Core.Services;
|
namespace Wino.Core.Services;
|
||||||
|
|
||||||
@@ -24,14 +26,17 @@ public class WinoRequestDelegator : IWinoRequestDelegator
|
|||||||
private readonly IWinoRequestProcessor _winoRequestProcessor;
|
private readonly IWinoRequestProcessor _winoRequestProcessor;
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly IMailDialogService _dialogService;
|
private readonly IMailDialogService _dialogService;
|
||||||
|
private readonly IAccountService _accountService;
|
||||||
|
|
||||||
public WinoRequestDelegator(IWinoRequestProcessor winoRequestProcessor,
|
public WinoRequestDelegator(IWinoRequestProcessor winoRequestProcessor,
|
||||||
IFolderService folderService,
|
IFolderService folderService,
|
||||||
IMailDialogService dialogService)
|
IMailDialogService dialogService,
|
||||||
|
IAccountService accountService)
|
||||||
{
|
{
|
||||||
_winoRequestProcessor = winoRequestProcessor;
|
_winoRequestProcessor = winoRequestProcessor;
|
||||||
_folderService = folderService;
|
_folderService = folderService;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
|
_accountService = accountService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(MailOperationPreperationRequest request)
|
public async Task ExecuteAsync(MailOperationPreperationRequest request)
|
||||||
@@ -82,14 +87,20 @@ public class WinoRequestDelegator : IWinoRequestDelegator
|
|||||||
var accountIds = requests.GroupBy(a => a.Item.AssignedAccount.Id);
|
var accountIds = requests.GroupBy(a => a.Item.AssignedAccount.Id);
|
||||||
|
|
||||||
// Queue requests for each account and start synchronization.
|
// Queue requests for each account and start synchronization.
|
||||||
foreach (var accountId in accountIds)
|
foreach (var accountGroup in accountIds)
|
||||||
{
|
{
|
||||||
foreach (var accountRequest in accountId)
|
foreach (var accountRequest in accountGroup)
|
||||||
{
|
{
|
||||||
await QueueRequestAsync(accountRequest, accountId.Key);
|
await QueueRequestAsync(accountRequest, accountGroup.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
await QueueSynchronizationAsync(accountId.Key);
|
var account = accountGroup.First().Item.AssignedAccount;
|
||||||
|
var actionItems = SynchronizationActionHelper.CreateActionItems(accountGroup, accountGroup.Key, account.Name);
|
||||||
|
|
||||||
|
if (actionItems.Count > 0)
|
||||||
|
WeakReferenceMessenger.Default.Send(new SynchronizationActionsAdded(accountGroup.Key, account.Name, actionItems));
|
||||||
|
|
||||||
|
await QueueSynchronizationAsync(accountGroup.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,23 +128,28 @@ public class WinoRequestDelegator : IWinoRequestDelegator
|
|||||||
if (request == null) return;
|
if (request == null) return;
|
||||||
|
|
||||||
await QueueRequestAsync(request, accountId);
|
await QueueRequestAsync(request, accountId);
|
||||||
|
await SendSyncActionsAddedAsync([request], accountId);
|
||||||
await QueueSynchronizationAsync(accountId);
|
await QueueSynchronizationAsync(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(DraftPreparationRequest draftPreperationRequest)
|
public async Task ExecuteAsync(DraftPreparationRequest draftPreperationRequest)
|
||||||
{
|
{
|
||||||
var request = new CreateDraftRequest(draftPreperationRequest);
|
var request = new CreateDraftRequest(draftPreperationRequest);
|
||||||
|
var accountId = draftPreperationRequest.Account.Id;
|
||||||
|
|
||||||
await QueueRequestAsync(request, draftPreperationRequest.Account.Id);
|
await QueueRequestAsync(request, accountId);
|
||||||
await QueueSynchronizationAsync(draftPreperationRequest.Account.Id);
|
await SendSyncActionsAddedAsync([request], accountId, draftPreperationRequest.Account.Name);
|
||||||
|
await QueueSynchronizationAsync(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(SendDraftPreparationRequest sendDraftPreperationRequest)
|
public async Task ExecuteAsync(SendDraftPreparationRequest sendDraftPreperationRequest)
|
||||||
{
|
{
|
||||||
var request = new SendDraftRequest(sendDraftPreperationRequest);
|
var request = new SendDraftRequest(sendDraftPreperationRequest);
|
||||||
|
var account = sendDraftPreperationRequest.MailItem.AssignedAccount;
|
||||||
|
|
||||||
await QueueRequestAsync(request, sendDraftPreperationRequest.MailItem.AssignedAccount.Id);
|
await QueueRequestAsync(request, account.Id);
|
||||||
await QueueSynchronizationAsync(sendDraftPreperationRequest.MailItem.AssignedAccount.Id);
|
await SendSyncActionsAddedAsync([request], account.Id, account.Name);
|
||||||
|
await QueueSynchronizationAsync(account.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExecuteAsync(CalendarOperationPreparationRequest calendarPreparationRequest)
|
public async Task ExecuteAsync(CalendarOperationPreparationRequest calendarPreparationRequest)
|
||||||
@@ -187,6 +203,20 @@ public class WinoRequestDelegator : IWinoRequestDelegator
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SendSyncActionsAddedAsync(IEnumerable<IRequestBase> requests, Guid accountId, string accountName = null)
|
||||||
|
{
|
||||||
|
if (accountName == null)
|
||||||
|
{
|
||||||
|
var account = await _accountService.GetAccountAsync(accountId);
|
||||||
|
accountName = account?.Name ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var actionItems = SynchronizationActionHelper.CreateActionItems(requests, accountId, accountName);
|
||||||
|
|
||||||
|
if (actionItems.Count > 0)
|
||||||
|
WeakReferenceMessenger.Default.Send(new SynchronizationActionsAdded(accountId, accountName, actionItems));
|
||||||
|
}
|
||||||
|
|
||||||
private Task QueueCalendarSynchronizationAsync(Guid accountId)
|
private Task QueueCalendarSynchronizationAsync(Guid accountId)
|
||||||
{
|
{
|
||||||
var options = new CalendarSynchronizationOptions()
|
var options = new CalendarSynchronizationOptions()
|
||||||
|
|||||||
@@ -215,6 +215,8 @@ public abstract class WinoSynchronizer<TBaseRequest, TMessageType, TCalendarEven
|
|||||||
|
|
||||||
await ExecuteNativeRequestsAsync(nativeRequests, activeSynchronizationCancellationToken).ConfigureAwait(false);
|
await ExecuteNativeRequestsAsync(nativeRequests, activeSynchronizationCancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Messenger.Send(new SynchronizationActionsCompleted(Account.Id));
|
||||||
|
|
||||||
PublishUnreadItemChanges();
|
PublishUnreadItemChanges();
|
||||||
|
|
||||||
// Execute request sync options should be re-calculated after execution.
|
// Execute request sync options should be re-calculated after execution.
|
||||||
@@ -399,6 +401,8 @@ public abstract class WinoSynchronizer<TBaseRequest, TMessageType, TCalendarEven
|
|||||||
|
|
||||||
await ExecuteNativeRequestsAsync(nativeRequests, cancellationToken).ConfigureAwait(false);
|
await ExecuteNativeRequestsAsync(nativeRequests, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Messenger.Send(new SynchronizationActionsCompleted(Account.Id));
|
||||||
|
|
||||||
// Let servers to finish their job. Sometimes the servers don't respond immediately.
|
// Let servers to finish their job. Sometimes the servers don't respond immediately.
|
||||||
shouldDelayExecution = requestCopies.Any(a => a.ResynchronizationDelay > 0);
|
shouldDelayExecution = requestCopies.Any(a => a.ResynchronizationDelay > 0);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
xmlns:local="using:Wino.Mail.WinUI"
|
xmlns:local="using:Wino.Mail.WinUI"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:notifyicon="using:H.NotifyIcon"
|
xmlns:notifyicon="using:H.NotifyIcon"
|
||||||
|
xmlns:syncModels="using:Wino.Core.Domain.Models.Synchronization"
|
||||||
xmlns:winuiex="using:WinUIEx"
|
xmlns:winuiex="using:WinUIEx"
|
||||||
Title="ShellWindow"
|
Title="ShellWindow"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
@@ -34,7 +35,58 @@
|
|||||||
IsPaneToggleButtonVisible="True"
|
IsPaneToggleButtonVisible="True"
|
||||||
PaneToggleRequested="PaneButtonClicked">
|
PaneToggleRequested="PaneButtonClicked">
|
||||||
<TitleBar.RightHeader>
|
<TitleBar.RightHeader>
|
||||||
<Grid>
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<!-- Sync Status Button -->
|
||||||
|
<Button
|
||||||
|
x:Name="SyncStatusButton"
|
||||||
|
Padding="8,4"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||||
|
<ProgressRing
|
||||||
|
Width="16"
|
||||||
|
Height="16"
|
||||||
|
IsActive="True" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="SyncStatusText"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||||
|
</StackPanel>
|
||||||
|
<Button.Flyout>
|
||||||
|
<Flyout x:Name="SyncStatusFlyout" Placement="Bottom">
|
||||||
|
<ItemsRepeater x:Name="SyncActionsRepeater" ItemsSource="{x:Bind SyncActionItems}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="syncModels:SynchronizationActionItem">
|
||||||
|
<Grid
|
||||||
|
MinWidth="280"
|
||||||
|
MaxWidth="400"
|
||||||
|
Padding="0,6"
|
||||||
|
ColumnSpacing="8">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressRing
|
||||||
|
Width="16"
|
||||||
|
Height="16"
|
||||||
|
IsActive="True" />
|
||||||
|
<StackPanel Grid.Column="1">
|
||||||
|
<TextBlock
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
|
Text="{x:Bind AccountName}" />
|
||||||
|
<TextBlock Text="{x:Bind Description}" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</Flyout>
|
||||||
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
|
<!-- Mail/Calendar Mode Switcher -->
|
||||||
<controls:Segmented x:Name="AppModeSegmentedControl" SelectionChanged="SegmentedChanged">
|
<controls:Segmented x:Name="AppModeSegmentedControl" SelectionChanged="SegmentedChanged">
|
||||||
<controls:SegmentedItem>
|
<controls:SegmentedItem>
|
||||||
<controls:SegmentedItem.Icon>
|
<controls:SegmentedItem.Icon>
|
||||||
@@ -53,7 +105,7 @@
|
|||||||
</controls:SegmentedItem.Icon>
|
</controls:SegmentedItem.Icon>
|
||||||
</controls:SegmentedItem>
|
</controls:SegmentedItem>
|
||||||
</controls:Segmented>
|
</controls:Segmented>
|
||||||
</Grid>
|
</StackPanel>
|
||||||
</TitleBar.RightHeader>
|
</TitleBar.RightHeader>
|
||||||
</TitleBar>
|
</TitleBar>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
@@ -7,7 +9,9 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
|
using Wino.Core.Domain;
|
||||||
using Wino.Core.Domain.Interfaces;
|
using Wino.Core.Domain.Interfaces;
|
||||||
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
using Wino.Mail.WinUI.Interfaces;
|
using Wino.Mail.WinUI.Interfaces;
|
||||||
using Wino.Messaging.Client.Shell;
|
using Wino.Messaging.Client.Shell;
|
||||||
using Wino.Messaging.UI;
|
using Wino.Messaging.UI;
|
||||||
@@ -16,7 +20,11 @@ using WinUIEx;
|
|||||||
|
|
||||||
namespace Wino.Mail.WinUI;
|
namespace Wino.Mail.WinUI;
|
||||||
|
|
||||||
public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient<ApplicationThemeChanged>, IRecipient<TitleBarShellContentUpdated>
|
public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||||
|
IRecipient<ApplicationThemeChanged>,
|
||||||
|
IRecipient<TitleBarShellContentUpdated>,
|
||||||
|
IRecipient<SynchronizationActionsAdded>,
|
||||||
|
IRecipient<SynchronizationActionsCompleted>
|
||||||
{
|
{
|
||||||
public IStatePersistanceService StatePersistanceService { get; } = WinoApplication.Current.Services.GetService<IStatePersistanceService>() ?? throw new Exception("StatePersistanceService not registered in DI container.");
|
public IStatePersistanceService StatePersistanceService { get; } = WinoApplication.Current.Services.GetService<IStatePersistanceService>() ?? throw new Exception("StatePersistanceService not registered in DI container.");
|
||||||
public IPreferencesService PreferencesService { get; } = WinoApplication.Current.Services.GetService<IPreferencesService>() ?? throw new Exception("PreferencesService not registered in DI container.");
|
public IPreferencesService PreferencesService { get; } = WinoApplication.Current.Services.GetService<IPreferencesService>() ?? throw new Exception("PreferencesService not registered in DI container.");
|
||||||
@@ -25,6 +33,8 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
|
|||||||
public ICommand ShowWinoCommand { get; set; }
|
public ICommand ShowWinoCommand { get; set; }
|
||||||
public ICommand ExitWinoCommand { get; set; }
|
public ICommand ExitWinoCommand { get; set; }
|
||||||
|
|
||||||
|
public ObservableCollection<SynchronizationActionItem> SyncActionItems { get; } = new();
|
||||||
|
|
||||||
public ShellWindow()
|
public ShellWindow()
|
||||||
{
|
{
|
||||||
RegisterRecipients();
|
RegisterRecipients();
|
||||||
@@ -172,6 +182,46 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
|
|||||||
UpdateTitleBarColors(message.IsUnderlyingThemeDark);
|
UpdateTitleBarColors(message.IsUnderlyingThemeDark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Receive(SynchronizationActionsAdded message)
|
||||||
|
{
|
||||||
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
foreach (var action in message.Actions)
|
||||||
|
SyncActionItems.Add(action);
|
||||||
|
|
||||||
|
UpdateSyncStatusVisibility();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Receive(SynchronizationActionsCompleted message)
|
||||||
|
{
|
||||||
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
var toRemove = SyncActionItems.Where(a => a.AccountId == message.AccountId).ToList();
|
||||||
|
|
||||||
|
foreach (var item in toRemove)
|
||||||
|
SyncActionItems.Remove(item);
|
||||||
|
|
||||||
|
UpdateSyncStatusVisibility();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSyncStatusVisibility()
|
||||||
|
{
|
||||||
|
SyncStatusButton.Visibility = SyncActionItems.Any()
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Collapsed;
|
||||||
|
|
||||||
|
var distinctAccounts = SyncActionItems.Select(a => a.AccountId).Distinct().Count();
|
||||||
|
|
||||||
|
SyncStatusText.Text = distinctAccounts switch
|
||||||
|
{
|
||||||
|
0 => string.Empty,
|
||||||
|
1 => string.Format(Translator.SyncAction_SynchronizingAccount, SyncActionItems.First().AccountName),
|
||||||
|
_ => string.Format(Translator.SyncAction_SynchronizingAccounts, distinctAccounts)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateTitleBarColors(bool isDarkTheme)
|
private void UpdateTitleBarColors(bool isDarkTheme)
|
||||||
{
|
{
|
||||||
DispatcherQueue.TryEnqueue(() =>
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
@@ -250,12 +300,16 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
|
|||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Register<TitleBarShellContentUpdated>(this);
|
WeakReferenceMessenger.Default.Register<TitleBarShellContentUpdated>(this);
|
||||||
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
WeakReferenceMessenger.Default.Register<ApplicationThemeChanged>(this);
|
||||||
|
WeakReferenceMessenger.Default.Register<SynchronizationActionsAdded>(this);
|
||||||
|
WeakReferenceMessenger.Default.Register<SynchronizationActionsCompleted>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnregisterRecipients()
|
private void UnregisterRecipients()
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Unregister<TitleBarShellContentUpdated>(this);
|
WeakReferenceMessenger.Default.Unregister<TitleBarShellContentUpdated>(this);
|
||||||
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
|
WeakReferenceMessenger.Default.Unregister<ApplicationThemeChanged>(this);
|
||||||
|
WeakReferenceMessenger.Default.Unregister<SynchronizationActionsAdded>(this);
|
||||||
|
WeakReferenceMessenger.Default.Unregister<SynchronizationActionsCompleted>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SegmentedChanged(object sender, SelectionChangedEventArgs e)
|
private void SegmentedChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
|
|
||||||
|
namespace Wino.Messaging.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sent when synchronization requests are queued for an account.
|
||||||
|
/// Contains grouped action descriptions for the UI to display.
|
||||||
|
/// </summary>
|
||||||
|
public record SynchronizationActionsAdded(
|
||||||
|
Guid AccountId,
|
||||||
|
string AccountName,
|
||||||
|
List<SynchronizationActionItem> Actions) : UIMessageBase<SynchronizationActionsAdded>;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Wino.Messaging.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sent when all queued synchronization requests for an account have been executed.
|
||||||
|
/// </summary>
|
||||||
|
public record SynchronizationActionsCompleted(
|
||||||
|
Guid AccountId) : UIMessageBase<SynchronizationActionsCompleted>;
|
||||||
Reference in New Issue
Block a user