New shell experience.
This commit is contained in:
@@ -142,6 +142,8 @@ private string searchQuery = string.Empty;
|
||||
- For dependency properties in WinUI code, always prefer `[GeneratedDependencyProperty]` from CommunityToolkit over manual `DependencyProperty.Register(...)` declarations.
|
||||
- In ViewModels, update all UI-bound properties/collections via `ExecuteUIThread(...)` (especially after awaited calls and any use of `ConfigureAwait(false)`).
|
||||
- In `EventDetailsPageViewModel.LoadAttendeesAsync`, never mutate `CurrentEvent.Attendees` outside `ExecuteUIThread(...)`.
|
||||
- Never create pure C# controls or controls that heavily manipulate UI structure from `.cs` files. Define controls in XAML and keep UI composition in XAML.
|
||||
- For XAML-backed controls and pages, wire framework events like `Loaded`, `Unloaded`, and input events from XAML, not by subscribing in constructors in `.xaml.cs`.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ using Wino.Messaging.UI;
|
||||
namespace Wino.Calendar.ViewModels;
|
||||
|
||||
public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
ICalendarShellClient,
|
||||
IRecipient<VisibleDateRangeChangedMessage>,
|
||||
IRecipient<CalendarEnableStatusChangedMessage>,
|
||||
IRecipient<NavigateManageAccountsRequested>,
|
||||
@@ -40,6 +41,17 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
public IStatePersistanceService StatePersistenceService { get; }
|
||||
public IAccountCalendarStateService AccountCalendarStateService { get; }
|
||||
public INavigationService NavigationService { get; }
|
||||
public WinoApplicationMode Mode => WinoApplicationMode.Calendar;
|
||||
public bool HandlesNavigationSelection => false;
|
||||
System.Collections.IEnumerable ICalendarShellClient.GroupedAccountCalendars => AccountCalendarStateService.GroupedAccountCalendars;
|
||||
System.Collections.IEnumerable ICalendarShellClient.DateNavigationHeaderItems => DateNavigationHeaderItems;
|
||||
object IShellClient.SelectedMenuItem
|
||||
{
|
||||
get => null;
|
||||
set { }
|
||||
}
|
||||
System.Windows.Input.ICommand ICalendarShellClient.TodayClickedCommand => TodayClickedCommand;
|
||||
System.Windows.Input.ICommand ICalendarShellClient.DateClickedCommand => DateClickedCommand;
|
||||
|
||||
public MenuItemCollection MenuItems { get; private set; }
|
||||
public MenuItemCollection FooterItems { get; private set; }
|
||||
@@ -78,7 +90,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
private readonly ManageAccountsMenuItem _manageAccountsMenuItem = new();
|
||||
private readonly SettingsItem _settingsItem = new();
|
||||
private readonly StoreUpdateMenuItem _storeUpdateMenuItem = new();
|
||||
private readonly NewMailMenuItem _newEventMenuItem = new();
|
||||
private readonly NewCalendarEventMenuItem _newEventMenuItem = new();
|
||||
|
||||
// For updating account calendars asynchronously.
|
||||
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
||||
@@ -146,6 +158,10 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
|
||||
var activationContext = parameters as ShellModeActivationContext;
|
||||
var isModeResetActivation = activationContext != null;
|
||||
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||
|
||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||
|
||||
@@ -155,7 +171,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
// between Mail and Calendar modes. Back/forward restoration should not
|
||||
// force a new CalendarPage navigation, otherwise pages like
|
||||
// CalendarEventComposePage get dropped from the inner frame stack.
|
||||
if (mode != NavigationMode.New)
|
||||
if (mode != NavigationMode.New && !isModeResetActivation)
|
||||
{
|
||||
UpdateDateNavigationHeaderItems();
|
||||
await InitializeAccountCalendarsAsync();
|
||||
@@ -168,7 +184,10 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
await InitializeAccountCalendarsAsync();
|
||||
ValidateConfiguredNewEventCalendar();
|
||||
|
||||
await ShowWhatIsNewIfNeededAsync();
|
||||
if (shouldRunStartupFlows)
|
||||
{
|
||||
await ShowWhatIsNewIfNeededAsync();
|
||||
}
|
||||
|
||||
TodayClicked();
|
||||
}
|
||||
@@ -601,6 +620,18 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||
|
||||
return (startDate, startDate.AddMinutes(30));
|
||||
}
|
||||
|
||||
void IShellClient.Activate(ShellModeActivationContext activationContext)
|
||||
=> OnNavigatedTo(NavigationMode.New, activationContext);
|
||||
|
||||
void IShellClient.Deactivate()
|
||||
=> OnNavigatedFrom(NavigationMode.New, null!);
|
||||
|
||||
Task IShellClient.HandleNavigationItemInvokedAsync(IMenuItem menuItem)
|
||||
=> menuItem == null ? Task.CompletedTask : HandleNavigationItemInvokedAsync(menuItem);
|
||||
|
||||
Task IShellClient.HandleNavigationSelectionChangedAsync(IMenuItem menuItem)
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#nullable enable
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.MenuItems;
|
||||
using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Calendar;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
|
||||
namespace Wino.Core.Domain.Interfaces;
|
||||
|
||||
public interface IShellClient : INotifyPropertyChanged
|
||||
{
|
||||
WinoApplicationMode Mode { get; }
|
||||
IDispatcher Dispatcher { get; set; }
|
||||
MenuItemCollection? MenuItems { get; }
|
||||
object? SelectedMenuItem { get; set; }
|
||||
bool HandlesNavigationSelection { get; }
|
||||
|
||||
void Activate(ShellModeActivationContext activationContext);
|
||||
void Deactivate();
|
||||
Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem);
|
||||
Task HandleNavigationSelectionChangedAsync(IMenuItem? menuItem);
|
||||
Task KeyboardShortcutHook(KeyboardShortcutTriggerDetails args);
|
||||
}
|
||||
|
||||
public interface IMailShellClient : IShellClient
|
||||
{
|
||||
IMenuItem CreatePrimaryMenuItem { get; }
|
||||
|
||||
IEnumerable<FolderOperationMenuItem> GetFolderContextMenuActions(IBaseFolderMenuItem folder);
|
||||
Task NavigateFolderAsync(IBaseFolderMenuItem baseFolderMenuItem, TaskCompletionSource<bool>? folderInitAwaitTask = null);
|
||||
Task ChangeLoadedAccountAsync(IAccountMenuItem clickedBaseAccountMenuItem, bool navigateInbox = true);
|
||||
Task PerformFolderOperationAsync(FolderOperation operation, IBaseFolderMenuItem folderMenuItem);
|
||||
Task PerformMoveOperationAsync(IEnumerable<MailCopy> items, IBaseFolderMenuItem targetFolderMenuItem);
|
||||
Task CreateNewMailForAsync(MailAccount account);
|
||||
}
|
||||
|
||||
public interface ICalendarShellClient : IShellClient
|
||||
{
|
||||
IStatePersistanceService StatePersistenceService { get; }
|
||||
IEnumerable DateNavigationHeaderItems { get; }
|
||||
int SelectedDateNavigationHeaderIndex { get; }
|
||||
DateRange? HighlightedDateRange { get; }
|
||||
ICommand TodayClickedCommand { get; }
|
||||
ICommand DateClickedCommand { get; }
|
||||
IEnumerable GroupedAccountCalendars { get; }
|
||||
}
|
||||
|
||||
public interface IShellViewModel
|
||||
{
|
||||
WinoApplicationMode CurrentMode { get; }
|
||||
IShellClient CurrentClient { get; }
|
||||
MenuItemCollection? CurrentMenuItems { get; }
|
||||
object? SelectedMenuItem { get; set; }
|
||||
|
||||
void SetCurrentMode(WinoApplicationMode mode);
|
||||
IShellClient GetClient(WinoApplicationMode mode);
|
||||
}
|
||||
|
||||
public interface IShellHost
|
||||
{
|
||||
bool HasShellContent { get; }
|
||||
|
||||
void ActivateMode(WinoApplicationMode mode, bool isInitialActivation);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Wino.Core.Domain.MenuItems;
|
||||
|
||||
public sealed class NewCalendarEventMenuItem : NewMailMenuItem { }
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Wino.Core.Domain.Models.Navigation;
|
||||
|
||||
public sealed class ShellModeActivationContext
|
||||
{
|
||||
public bool IsInitialActivation { get; init; }
|
||||
}
|
||||
@@ -952,7 +952,6 @@
|
||||
"SystemFolderConfigSetupSuccess_Title": "System Folders Setup",
|
||||
"SystemTrayMenu_ShowWino": "Open Wino Mail",
|
||||
"SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar",
|
||||
"SystemTrayMenu_ShowWinoContacts": "Open Wino Contacts",
|
||||
"SystemTrayMenu_ExitWino": "Exit",
|
||||
"TestingImapConnectionMessage": "Testing server connection...",
|
||||
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.",
|
||||
|
||||
@@ -29,6 +29,7 @@ using Wino.Messaging.UI;
|
||||
namespace Wino.Mail.ViewModels;
|
||||
|
||||
public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
IMailShellClient,
|
||||
IRecipient<NavigateManageAccountsRequested>,
|
||||
IRecipient<MailtoProtocolMessageRequested>,
|
||||
IRecipient<RefreshUnreadCountsMessage>,
|
||||
@@ -67,6 +68,9 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
public IStatePersistanceService StatePersistenceService { get; }
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
public INavigationService NavigationService { get; }
|
||||
public WinoApplicationMode Mode => WinoApplicationMode.Mail;
|
||||
public bool HandlesNavigationSelection => true;
|
||||
public IMenuItem CreatePrimaryMenuItem => CreateMailMenuItem;
|
||||
|
||||
private readonly IFolderService _folderService;
|
||||
private readonly IConfigurationService _configurationService;
|
||||
@@ -227,10 +231,14 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
|
||||
var activationContext = parameters as ShellModeActivationContext;
|
||||
var isModeResetActivation = activationContext != null;
|
||||
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||
|
||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||
PreferencesService.PreferenceChanged += PreferencesServiceChanged;
|
||||
|
||||
if (mode == NavigationMode.Back)
|
||||
if (mode == NavigationMode.Back && !isModeResetActivation)
|
||||
{
|
||||
// Preserve current mail/folder selection and active rendering page when
|
||||
// switching back from Calendar mode. Recreating menu/folder state here
|
||||
@@ -252,13 +260,16 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
await ProcessLaunchOptionsAsync();
|
||||
await ValidateWebView2RuntimeAsync();
|
||||
|
||||
if (!Debugger.IsAttached)
|
||||
if (shouldRunStartupFlows && !Debugger.IsAttached)
|
||||
{
|
||||
await ForceAllAccountSynchronizationsAsync();
|
||||
}
|
||||
|
||||
await ShowWhatIsNewIfNeededAsync();
|
||||
await MakeSureEnableStartupLaunchAsync();
|
||||
if (shouldRunStartupFlows)
|
||||
{
|
||||
await ShowWhatIsNewIfNeededAsync();
|
||||
await MakeSureEnableStartupLaunchAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ValidateWebView2RuntimeAsync()
|
||||
@@ -1258,6 +1269,18 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void IShellClient.Activate(ShellModeActivationContext activationContext)
|
||||
=> OnNavigatedTo(NavigationMode.New, activationContext);
|
||||
|
||||
void IShellClient.Deactivate()
|
||||
=> OnNavigatedFrom(NavigationMode.New, null!);
|
||||
|
||||
Task IShellClient.HandleNavigationItemInvokedAsync(IMenuItem menuItem)
|
||||
=> MenuItemInvokedOrSelectedAsync(menuItem);
|
||||
|
||||
Task IShellClient.HandleNavigationSelectionChangedAsync(IMenuItem menuItem)
|
||||
=> menuItem == null ? Task.CompletedTask : MenuItemInvokedOrSelectedAsync(menuItem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
x:Class="Wino.Mail.WinUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||
xmlns:coreStyles="using:Wino.Mail.WinUI.Styles"
|
||||
xmlns:local="using:Wino.Mail.WinUI"
|
||||
xmlns:styles="using:Wino.Styles"
|
||||
xmlns:uwp="using:Wino.Mail.WinUI">
|
||||
@@ -10,7 +12,101 @@
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<uwp:CoreGeneric />
|
||||
<ResourceDictionary Source="/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ContentPresenters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/Converters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/FontIcons.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WinoInfoBar.xaml" />
|
||||
<ResourceDictionary Source="/Styles/SharedStyles.xaml" />
|
||||
<ResourceDictionary Source="/Styles/IconTemplates.xaml" />
|
||||
|
||||
<coreStyles:CustomMessageDialogStyles />
|
||||
<coreStyles:DataTemplates />
|
||||
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="ScrollViewer">
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
|
||||
</Style>
|
||||
|
||||
<SolidColorBrush x:Key="CommandBarBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="CommandBarBackgroundOpen" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="CommandBarBorderBrushOpen" Color="Transparent" />
|
||||
<Thickness x:Key="CommandBarBorderThicknessOpen">0</Thickness>
|
||||
|
||||
<StaticResource x:Key="AppBarToggleButtonBackgroundChecked" ResourceKey="SystemAccentColor" />
|
||||
<StaticResource x:Key="AppBarToggleButtonBackgroundCheckedPointerOver" ResourceKey="SystemAccentColor" />
|
||||
<StaticResource x:Key="AppBarToggleButtonBackgroundCheckedPressed" ResourceKey="SystemAccentColor" />
|
||||
|
||||
<Thickness x:Key="ImapSetupDialogSubPagePadding">24,24,24,24</Thickness>
|
||||
|
||||
<Style x:Key="PageRootBorderStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="{ThemeResource WinoContentZoneBackgroud}" />
|
||||
<Setter Property="BorderBrush" Value="{StaticResource CardStrokeColorDefaultBrush}" />
|
||||
<Setter Property="CornerRadius" Value="7" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="InformationAreaGridStyle" TargetType="Grid">
|
||||
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource DividerStrokeColorDefaultBrush}" />
|
||||
<Setter Property="CornerRadius" Value="8" />
|
||||
<Setter Property="Padding" Value="16" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="StackPanel">
|
||||
<Setter Property="ChildrenTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection>
|
||||
<EntranceThemeTransition IsStaggeringEnabled="False" />
|
||||
</TransitionCollection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="WinoDialogStyle"
|
||||
BasedOn="{StaticResource DefaultContentDialogStyle}"
|
||||
TargetType="ContentDialog">
|
||||
<Setter Property="CornerRadius" Value="8" />
|
||||
<Setter Property="Padding" Value="24" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="coreControls:WinoNavigationViewItem">
|
||||
<Setter Property="ContentTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="PageStyle" TargetType="Page">
|
||||
<Setter Property="Margin" Value="-1,0,0,0" />
|
||||
<Setter Property="Padding" Value="12" />
|
||||
<Setter Property="Background" Value="{ThemeResource AppBarBackgroundColor}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Padding="12">
|
||||
<ContentPresenter />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<x:Double x:Key="SettingsCardSpacing">4</x:Double>
|
||||
|
||||
<Style
|
||||
x:Key="SettingsSectionHeaderTextBlockStyle"
|
||||
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Style.Setters>
|
||||
<Setter Property="Margin" Value="1,30,0,6" />
|
||||
</Style.Setters>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
|
||||
<ResourceDictionary Source="Controls/ListView/WinoListViewStyles.xaml" />
|
||||
<ResourceDictionary Source="Styles/ItemContainerStyles.xaml" />
|
||||
|
||||
@@ -24,6 +24,7 @@ using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Domain.Models.Synchronization;
|
||||
using Wino.Mail.Services;
|
||||
using Wino.Mail.WinUI.ViewModels;
|
||||
using Wino.Mail.ViewModels;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.WinUI.Activation;
|
||||
@@ -142,6 +143,13 @@ public partial class App : WinoApplication,
|
||||
{
|
||||
services.AddSingleton(typeof(MailAppShellViewModel));
|
||||
services.AddSingleton(typeof(CalendarAppShellViewModel));
|
||||
services.AddSingleton(typeof(ContactsShellClient));
|
||||
services.AddSingleton(typeof(WinoAppShellViewModel));
|
||||
services.AddSingleton<IMailShellClient>(serviceProvider => serviceProvider.GetRequiredService<MailAppShellViewModel>());
|
||||
services.AddSingleton<ICalendarShellClient>(serviceProvider => serviceProvider.GetRequiredService<CalendarAppShellViewModel>());
|
||||
services.AddSingleton<IShellClient>(serviceProvider => serviceProvider.GetRequiredService<MailAppShellViewModel>());
|
||||
services.AddSingleton<IShellClient>(serviceProvider => serviceProvider.GetRequiredService<CalendarAppShellViewModel>());
|
||||
services.AddSingleton<IShellClient>(serviceProvider => serviceProvider.GetRequiredService<ContactsShellClient>());
|
||||
|
||||
services.AddTransient(typeof(MailListPageViewModel));
|
||||
services.AddTransient(typeof(MailRenderingPageViewModel));
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:domain="using:Wino.Core.Domain">
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
Loaded="ControlLoaded"
|
||||
Unloaded="ControlUnloaded">
|
||||
|
||||
<Grid>
|
||||
<controls:Segmented
|
||||
|
||||
@@ -19,9 +19,6 @@ public sealed partial class AppModeFooterSwitcherControl : UserControl
|
||||
_navigationService = WinoApplication.Current.Services.GetRequiredService<INavigationService>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += ControlLoaded;
|
||||
Unloaded += ControlUnloaded;
|
||||
}
|
||||
|
||||
private void ControlLoaded(object sender, RoutedEventArgs e)
|
||||
@@ -34,7 +31,6 @@ public sealed partial class AppModeFooterSwitcherControl : UserControl
|
||||
{
|
||||
_statePersistenceService.StatePropertyChanged -= StatePropertyChanged;
|
||||
}
|
||||
|
||||
private void StatePropertyChanged(object? sender, string propertyName)
|
||||
{
|
||||
if (propertyName != nameof(IStatePersistanceService.ApplicationMode))
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
|
||||
<ResourceDictionary Source="Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="Styles/ContentPresenters.xaml" />
|
||||
<ResourceDictionary Source="Styles/Converters.xaml" />
|
||||
<ResourceDictionary Source="Styles/FontIcons.xaml" />
|
||||
<ResourceDictionary Source="Styles/WinoInfoBar.xaml" />
|
||||
<ResourceDictionary Source="Styles/SharedStyles.xaml" />
|
||||
<ResourceDictionary Source="Styles/IconTemplates.xaml" />
|
||||
<ResourceDictionary Source="/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ContentPresenters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/Converters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/FontIcons.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WinoInfoBar.xaml" />
|
||||
<ResourceDictionary Source="/Styles/SharedStyles.xaml" />
|
||||
<ResourceDictionary Source="/Styles/IconTemplates.xaml" />
|
||||
|
||||
<styles:CustomMessageDialogStyles />
|
||||
<styles:DataTemplates />
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"profiles": {
|
||||
"Wino.Mail.WinUI (Package)": {
|
||||
"commandName": "MsixPackage",
|
||||
"doNotLaunchApp": false
|
||||
"doNotLaunchApp": false,
|
||||
"nativeDebugging": true
|
||||
},
|
||||
"Wino.Mail.WinUI (Unpackaged)": {
|
||||
"commandName": "Project"
|
||||
|
||||
@@ -21,13 +21,16 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector
|
||||
public DataTemplate CreateNewFolderTemplate { get; set; } = null!;
|
||||
public DataTemplate SeperatorTemplate { get; set; } = null!;
|
||||
public DataTemplate NewMailTemplate { get; set; } = null!;
|
||||
public DataTemplate CalendarNewEventTemplate { get; set; } = null!;
|
||||
public DataTemplate CategoryItemsTemplate { get; set; } = null!;
|
||||
public DataTemplate FixAuthenticationIssueTemplate { get; set; } = null!;
|
||||
public DataTemplate FixMissingFolderConfigTemplate { get; set; } = null!;
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item)
|
||||
{
|
||||
if (item is NewMailMenuItem)
|
||||
if (item is NewCalendarEventMenuItem)
|
||||
return CalendarNewEventTemplate;
|
||||
else if (item is NewMailMenuItem)
|
||||
return NewMailTemplate;
|
||||
else if (item is ContactsMenuItem)
|
||||
return ContactsMenuItemTemplate;
|
||||
|
||||
@@ -15,11 +15,11 @@ using Wino.Mail.WinUI;
|
||||
using Wino.Mail.WinUI.Interfaces;
|
||||
using Wino.Mail.WinUI.Models;
|
||||
using Wino.Mail.WinUI.Services;
|
||||
using Wino.Mail.WinUI.Views;
|
||||
using Wino.Mail.WinUI.Views.Calendar;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Mails;
|
||||
using Wino.Messaging.Client.Navigation;
|
||||
using Wino.Mail.WinUI.Views.Contacts;
|
||||
using Wino.Views;
|
||||
using Wino.Views.Account;
|
||||
using Wino.Views.Mail;
|
||||
@@ -33,6 +33,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
private readonly IStatePersistanceService _statePersistanceService;
|
||||
private readonly IDispatcher _dispatcher;
|
||||
private readonly IWinoWindowManager _windowManager;
|
||||
private NavigationTransitionInfo? _pendingInnerShellTransition;
|
||||
|
||||
private WinoPage[] _renderingPageTypes = new WinoPage[]
|
||||
{
|
||||
@@ -192,48 +193,33 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
if (coreFrame == null) return false;
|
||||
|
||||
var currentMode = _statePersistanceService.ApplicationMode;
|
||||
var isInitialShellNavigation = coreFrame.Content is not IShellHost;
|
||||
|
||||
// Update the application mode in state persistence service
|
||||
_statePersistanceService.ApplicationMode = mode;
|
||||
_statePersistanceService.AppModeTitle = GetApplicationModeTitle(mode);
|
||||
|
||||
var targetPageType = mode switch
|
||||
{
|
||||
WinoApplicationMode.Calendar => typeof(CalendarAppShell),
|
||||
WinoApplicationMode.Contacts => typeof(ContactsAppShell),
|
||||
_ => typeof(MailAppShell)
|
||||
};
|
||||
var currentPageType = coreFrame.Content?.GetType();
|
||||
var transitionInfo = GetApplicationModeTransitionInfo(currentMode, mode);
|
||||
|
||||
// If already on the target page, do nothing
|
||||
if (currentPageType == targetPageType)
|
||||
if (coreFrame.Content is IShellHost activeShell && activeShell.HasShellContent && currentMode == mode)
|
||||
return true;
|
||||
|
||||
// Check if we can go back to the target page
|
||||
if (coreFrame.CanGoBack && coreFrame.BackStack.Count > 0)
|
||||
_pendingInnerShellTransition = isInitialShellNavigation
|
||||
? null
|
||||
: GetApplicationModeTransitionInfo(currentMode, mode);
|
||||
|
||||
if (coreFrame.Content is not IShellHost)
|
||||
{
|
||||
var previousPage = coreFrame.BackStack[coreFrame.BackStack.Count - 1];
|
||||
if (previousPage.SourcePageType == targetPageType)
|
||||
{
|
||||
coreFrame.GoBack(transitionInfo);
|
||||
return true;
|
||||
}
|
||||
coreFrame.BackStack.Clear();
|
||||
coreFrame.ForwardStack.Clear();
|
||||
coreFrame.Navigate(typeof(WinoAppShell), null, new SuppressNavigationTransitionInfo());
|
||||
}
|
||||
|
||||
// Check if we can go forward to the target page
|
||||
if (coreFrame.CanGoForward && coreFrame.ForwardStack.Count > 0)
|
||||
if (coreFrame.Content is IShellHost shell)
|
||||
{
|
||||
var nextPage = coreFrame.ForwardStack[coreFrame.ForwardStack.Count - 1];
|
||||
if (nextPage.SourcePageType == targetPageType)
|
||||
{
|
||||
coreFrame.GoForward();
|
||||
return true;
|
||||
}
|
||||
shell.ActivateMode(mode, isInitialShellNavigation);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Navigate to the target page only if it's not in the navigation stack
|
||||
coreFrame.Navigate(targetPageType, null, transitionInfo);
|
||||
_pendingInnerShellTransition = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -300,7 +286,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
}
|
||||
}
|
||||
|
||||
return innerShellFrame.Navigate(pageType, parameter);
|
||||
return NavigateInnerShellFrame(innerShellFrame, pageType, parameter, transition);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -318,14 +304,14 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
return true;
|
||||
}
|
||||
|
||||
var transitionInfo = GetNavigationTransitionInfo(transition);
|
||||
|
||||
// This page must be opened in the Frame placed in MailListingPage.
|
||||
if (isMailListingPageActive && frame == NavigationReferenceFrame.RenderingFrame)
|
||||
{
|
||||
var listingFrame = GetCoreFrameInternal(NavigationReferenceFrame.RenderingFrame);
|
||||
if (listingFrame == null) return false;
|
||||
|
||||
var transitionInfo = GetNavigationTransitionInfo(transition);
|
||||
|
||||
// Active page is mail list page and we are opening a mail item.
|
||||
// No navigation needed, just refresh the rendered mail item.
|
||||
if (listingFrame.Content != null
|
||||
@@ -361,7 +347,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
|
||||
if ((currentFrameType != null && currentFrameType != pageType) || currentFrameType == null)
|
||||
{
|
||||
return innerShellFrame.Navigate(pageType, parameter, transitionInfo);
|
||||
return NavigateInnerShellFrame(innerShellFrame, pageType, parameter, transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,6 +415,24 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
||||
return new LoadCalendarMessage(targetDate, initiative);
|
||||
}
|
||||
|
||||
private bool NavigateInnerShellFrame(Frame frame, Type pageType, object? parameter, NavigationTransitionType transition)
|
||||
{
|
||||
var transitionInfo = ConsumeInnerShellTransitionOrDefault(transition);
|
||||
return frame.Navigate(pageType, parameter, transitionInfo);
|
||||
}
|
||||
|
||||
private NavigationTransitionInfo ConsumeInnerShellTransitionOrDefault(NavigationTransitionType transition)
|
||||
{
|
||||
if (_pendingInnerShellTransition != null)
|
||||
{
|
||||
var transitionInfo = _pendingInnerShellTransition;
|
||||
_pendingInnerShellTransition = null;
|
||||
return transitionInfo;
|
||||
}
|
||||
|
||||
return GetNavigationTransitionInfo(transition);
|
||||
}
|
||||
|
||||
public void GoBack(Core.Domain.Enums.NavigationTransitionEffect slideEffect = Core.Domain.Enums.NavigationTransitionEffect.FromRight)
|
||||
=> ExecuteOnNavigationThread(() => GoBackInternal(slideEffect));
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<MenuFlyout AreOpenCloseAnimationsEnabled="False">
|
||||
<MenuFlyoutItem Command="{x:Bind ShowWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWino}" />
|
||||
<MenuFlyoutItem Command="{x:Bind ShowWinoCalendarCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWinoCalendar}" />
|
||||
<MenuFlyoutItem Command="{x:Bind ShowWinoContactsCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWinoContacts}" />
|
||||
<!--<MenuFlyoutItem Command="{x:Bind ShowWinoContactsCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWinoContacts}" />-->
|
||||
<MenuFlyoutSeparator />
|
||||
<MenuFlyoutItem Command="{x:Bind ExitWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ExitWino}" />
|
||||
</MenuFlyout>
|
||||
|
||||
@@ -16,9 +16,9 @@ using Wino.Core.Domain.Models.Synchronization;
|
||||
using Wino.Extensions;
|
||||
using Wino.Mail.WinUI.Activation;
|
||||
using Wino.Mail.WinUI.Interfaces;
|
||||
using Wino.Mail.WinUI.Views;
|
||||
using Wino.Messaging.Client.Shell;
|
||||
using Wino.Messaging.UI;
|
||||
using Wino.Views;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Wino.Mail.WinUI;
|
||||
@@ -139,12 +139,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
_ = StartCalendarReminderServerAsync();
|
||||
}
|
||||
|
||||
// Mail shell has shell content only for mail list page
|
||||
// Thus, we check if the current content is MailAppShell
|
||||
|
||||
if (sender is Frame mainFrame && mainFrame.Content is MailAppShell mailAppShellPage)
|
||||
ShellTitleBar.Content = mailAppShellPage.TopShellContent;
|
||||
else if (e.Content is BasePage basePage)
|
||||
if (e.Content is BasePage basePage)
|
||||
ShellTitleBar.Content = basePage.ShellContent;
|
||||
}
|
||||
|
||||
@@ -172,9 +167,9 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
||||
|
||||
public void Receive(TitleBarShellContentUpdated message)
|
||||
{
|
||||
if (MainShellFrame.Content is MailAppShell shellPage)
|
||||
if (MainShellFrame.Content is WinoAppShell shellPage)
|
||||
{
|
||||
ShellTitleBar.Content = shellPage.TopShellContent;
|
||||
ShellTitleBar.Content = shellPage.ShellContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Threading.Tasks;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.MenuItems;
|
||||
using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.ViewModels;
|
||||
|
||||
namespace Wino.Mail.WinUI.ViewModels;
|
||||
|
||||
public sealed class ContactsShellClient(INavigationService navigationService) : CoreBaseViewModel, IShellClient
|
||||
{
|
||||
public WinoApplicationMode Mode => WinoApplicationMode.Contacts;
|
||||
public MenuItemCollection? MenuItems { get; private set; }
|
||||
public object? SelectedMenuItem { get; set; }
|
||||
public bool HandlesNavigationSelection => false;
|
||||
|
||||
protected override void OnDispatcherAssigned()
|
||||
{
|
||||
base.OnDispatcherAssigned();
|
||||
MenuItems ??= new MenuItemCollection(Dispatcher);
|
||||
}
|
||||
|
||||
public void Activate(ShellModeActivationContext activationContext)
|
||||
{
|
||||
OnNavigatedTo(NavigationMode.New, activationContext);
|
||||
navigationService.Navigate(WinoPage.ContactsPage, null, NavigationReferenceFrame.InnerShellFrame);
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
OnNavigatedFrom(NavigationMode.New, null!);
|
||||
}
|
||||
|
||||
public Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem) => Task.CompletedTask;
|
||||
|
||||
public Task HandleNavigationSelectionChangedAsync(IMenuItem? menuItem) => Task.CompletedTask;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.MenuItems;
|
||||
using Wino.Core.ViewModels;
|
||||
|
||||
namespace Wino.Mail.WinUI.ViewModels;
|
||||
|
||||
public sealed class WinoAppShellViewModel : CoreBaseViewModel, IShellViewModel
|
||||
{
|
||||
private readonly Dictionary<WinoApplicationMode, IShellClient> _shellClients;
|
||||
private WinoApplicationMode _currentMode;
|
||||
|
||||
public WinoAppShellViewModel(IMailShellClient mailClient,
|
||||
ICalendarShellClient calendarClient,
|
||||
IEnumerable<IShellClient> shellClients,
|
||||
IPreferencesService preferencesService,
|
||||
IStatePersistanceService statePersistenceService,
|
||||
INavigationService navigationService)
|
||||
{
|
||||
MailClient = mailClient;
|
||||
CalendarClient = calendarClient;
|
||||
PreferencesService = preferencesService;
|
||||
StatePersistenceService = statePersistenceService;
|
||||
NavigationService = navigationService;
|
||||
|
||||
_shellClients = shellClients.ToDictionary(client => client.Mode);
|
||||
|
||||
foreach (var client in _shellClients.Values)
|
||||
{
|
||||
client.PropertyChanged += ChildPropertyChanged;
|
||||
}
|
||||
|
||||
StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged;
|
||||
}
|
||||
|
||||
public IMailShellClient MailClient { get; }
|
||||
public ICalendarShellClient CalendarClient { get; }
|
||||
public IPreferencesService PreferencesService { get; }
|
||||
public IStatePersistanceService StatePersistenceService { get; }
|
||||
public INavigationService NavigationService { get; }
|
||||
|
||||
public WinoApplicationMode CurrentMode
|
||||
{
|
||||
get => _currentMode;
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _currentMode, value))
|
||||
{
|
||||
OnPropertyChanged(nameof(CurrentClient));
|
||||
OnPropertyChanged(nameof(CurrentMenuItems));
|
||||
OnPropertyChanged(nameof(IsMailMode));
|
||||
OnPropertyChanged(nameof(IsCalendarMode));
|
||||
OnPropertyChanged(nameof(IsContactsMode));
|
||||
OnPropertyChanged(nameof(SelectedMenuItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IShellClient CurrentClient => GetClient(CurrentMode);
|
||||
public bool IsMailMode => CurrentMode == WinoApplicationMode.Mail;
|
||||
public bool IsCalendarMode => CurrentMode == WinoApplicationMode.Calendar;
|
||||
public bool IsContactsMode => CurrentMode == WinoApplicationMode.Contacts;
|
||||
public MenuItemCollection? CurrentMenuItems => CurrentClient.MenuItems;
|
||||
|
||||
public object? SelectedMenuItem
|
||||
{
|
||||
get => CurrentClient.SelectedMenuItem;
|
||||
set
|
||||
{
|
||||
if (!ReferenceEquals(CurrentClient.SelectedMenuItem, value))
|
||||
{
|
||||
CurrentClient.SelectedMenuItem = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDispatcherAssigned()
|
||||
{
|
||||
base.OnDispatcherAssigned();
|
||||
|
||||
foreach (var client in _shellClients.Values)
|
||||
{
|
||||
client.Dispatcher = Dispatcher;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(CurrentMenuItems));
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(Core.Domain.Models.Navigation.NavigationMode mode, object parameters)
|
||||
{
|
||||
base.OnNavigatedTo(mode, parameters);
|
||||
CurrentMode = StatePersistenceService.ApplicationMode;
|
||||
}
|
||||
|
||||
public IShellClient GetClient(WinoApplicationMode mode)
|
||||
=> _shellClients[mode];
|
||||
|
||||
public void SetCurrentMode(WinoApplicationMode mode)
|
||||
{
|
||||
CurrentMode = mode;
|
||||
OnPropertyChanged(nameof(CurrentMenuItems));
|
||||
}
|
||||
|
||||
private void ChildPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (ReferenceEquals(sender, CurrentClient))
|
||||
{
|
||||
if (e.PropertyName == nameof(IShellClient.SelectedMenuItem))
|
||||
{
|
||||
OnPropertyChanged(nameof(SelectedMenuItem));
|
||||
}
|
||||
|
||||
if (e.PropertyName == nameof(IShellClient.MenuItems))
|
||||
{
|
||||
OnPropertyChanged(nameof(CurrentMenuItems));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StatePersistenceServiceChanged(object? sender, string propertyName)
|
||||
{
|
||||
if (propertyName == nameof(IStatePersistanceService.ApplicationMode))
|
||||
{
|
||||
SetCurrentMode(StatePersistenceService.ApplicationMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Wino.Mail.WinUI.ViewModels;
|
||||
|
||||
namespace Wino.Mail.WinUI.Views.Abstract;
|
||||
|
||||
public abstract class WinoAppShellAbstract : BasePage<WinoAppShellViewModel>
|
||||
{
|
||||
protected WinoAppShellAbstract()
|
||||
{
|
||||
NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<DataTemplate x:Key="CalendarNewEventTemplate" x:DataType="menu:NewMailMenuItem">
|
||||
<DataTemplate x:Key="CalendarNewEventTemplate" x:DataType="menu:NewCalendarEventMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
Height="50"
|
||||
DataContext="{x:Bind}"
|
||||
@@ -73,6 +73,7 @@
|
||||
|
||||
<coreSelectors:NavigationMenuTemplateSelector
|
||||
x:Key="NavigationMenuTemplateSelector"
|
||||
CalendarNewEventTemplate="{StaticResource CalendarNewEventTemplate}"
|
||||
NewMailTemplate="{StaticResource CalendarNewEventTemplate}"
|
||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||
SeperatorTemplate="{StaticResource SeperatorTemplate}" />
|
||||
|
||||
@@ -0,0 +1,730 @@
|
||||
<abstract:WinoAppShellAbstract
|
||||
x:Class="Wino.Mail.WinUI.Views.WinoAppShell"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract"
|
||||
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||
xmlns:calendarControls="using:Wino.Calendar.Controls"
|
||||
xmlns:communityControls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:controls1="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||
xmlns:coreConverters="using:Wino.Mail.WinUI.Converters"
|
||||
xmlns:coreSelectors="using:Wino.Mail.WinUI.Selectors"
|
||||
xmlns:data="using:Wino.Calendar.ViewModels.Data"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:menu="using:Wino.Core.Domain.MenuItems"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
Loaded="OnLoaded"
|
||||
PreviewKeyDown="OnPreviewKeyDown"
|
||||
x:Name="Root"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
|
||||
<coreConverters:HexToColorBrushConverter x:Key="HexToColorBrushConverter" />
|
||||
|
||||
<!-- Clickable New Style Account Template -->
|
||||
<DataTemplate x:Key="ClickableAccountMenuTemplate" x:DataType="menu:AccountMenuItem">
|
||||
<controls:AccountNavigationItem
|
||||
x:Name="AccountItem"
|
||||
Height="50"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BindingData="{x:Bind}"
|
||||
DataContext="{x:Bind}"
|
||||
IsActiveAccount="{x:Bind IsSelected, Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
SelectsOnInvoked="False"
|
||||
Style="{StaticResource SingleAccountNavigationViewItemTemplate}">
|
||||
<coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<EdgeUIThemeTransition Edge="Top" />
|
||||
</TransitionCollection>
|
||||
</coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon
|
||||
FontSize="12"
|
||||
Foreground="{x:Bind AccountColorHex, Converter={StaticResource HexToColorBrushConverter}, Mode=OneWay}"
|
||||
Icon="{x:Bind helpers:XamlHelpers.GetProviderIcon(Parameter)}" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
Background="{ThemeResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="AccountNameTextblock"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind AccountName, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<TextBlock
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind Parameter.Address, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Converter={StaticResource ReverseBooleanToVisibilityConverter}, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="SyncStatusText"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SynchronizationStatus, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<PathIcon
|
||||
x:Name="AttentionIcon"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="{x:Bind IsAttentionRequired, Mode=OneWay}"
|
||||
Data="F1 M 2.021484 18.769531 C 1.767578 18.769531 1.52832 18.720703 1.303711 18.623047 C 1.079102 18.525391 0.880534 18.391928 0.708008 18.222656 C 0.535482 18.053385 0.398763 17.856445 0.297852 17.631836 C 0.19694 17.407227 0.146484 17.167969 0.146484 16.914062 C 0.146484 16.614584 0.211589 16.328125 0.341797 16.054688 L 7.695312 1.347656 C 7.851562 1.035156 8.082682 0.784506 8.388672 0.595703 C 8.694661 0.406902 9.023438 0.3125 9.375 0.3125 C 9.726562 0.3125 10.055338 0.406902 10.361328 0.595703 C 10.667317 0.784506 10.898438 1.035156 11.054688 1.347656 L 18.408203 16.054688 C 18.53841 16.328125 18.603516 16.614584 18.603516 16.914062 C 18.603516 17.167969 18.553059 17.407227 18.452148 17.631836 C 18.351236 17.856445 18.216145 18.053385 18.046875 18.222656 C 17.877604 18.391928 17.679035 18.525391 17.451172 18.623047 C 17.223307 18.720703 16.982422 18.769531 16.728516 18.769531 Z M 16.728516 17.519531 C 16.884766 17.519531 17.027994 17.460938 17.158203 17.34375 C 17.28841 17.226562 17.353516 17.086588 17.353516 16.923828 C 17.353516 16.806641 17.330729 16.702475 17.285156 16.611328 L 9.931641 1.904297 C 9.879557 1.793621 9.80306 1.708984 9.702148 1.650391 C 9.601236 1.591797 9.492188 1.5625 9.375 1.5625 C 9.257812 1.5625 9.148763 1.593426 9.047852 1.655273 C 8.946939 1.717123 8.870442 1.800131 8.818359 1.904297 L 1.464844 16.611328 C 1.419271 16.702475 1.396484 16.803387 1.396484 16.914062 C 1.396484 17.083334 1.459961 17.226562 1.586914 17.34375 C 1.713867 17.460938 1.858724 17.519531 2.021484 17.519531 Z M 8.75 11.875 L 8.75 6.875 C 8.75 6.705729 8.811849 6.559245 8.935547 6.435547 C 9.059244 6.31185 9.205729 6.25 9.375 6.25 C 9.544271 6.25 9.690755 6.31185 9.814453 6.435547 C 9.93815 6.559245 10 6.705729 10 6.875 L 10 11.875 C 10 12.044271 9.93815 12.190756 9.814453 12.314453 C 9.690755 12.438151 9.544271 12.5 9.375 12.5 C 9.205729 12.5 9.059244 12.438151 8.935547 12.314453 C 8.811849 12.190756 8.75 12.044271 8.75 11.875 Z M 8.4375 14.375 C 8.4375 14.114584 8.528646 13.893229 8.710938 13.710938 C 8.893229 13.528646 9.114583 13.4375 9.375 13.4375 C 9.635416 13.4375 9.856771 13.528646 10.039062 13.710938 C 10.221354 13.893229 10.3125 14.114584 10.3125 14.375 C 10.3125 14.635417 10.221354 14.856771 10.039062 15.039062 C 9.856771 15.221354 9.635416 15.3125 9.375 15.3125 C 9.114583 15.3125 8.893229 15.221354 8.710938 15.039062 C 8.528646 14.856771 8.4375 14.635417 8.4375 14.375 Z "
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}" />
|
||||
|
||||
<muxc:ProgressRing
|
||||
x:Name="SynchronizationProgressBar"
|
||||
Grid.Column="2"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind IsProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</controls:AccountNavigationItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Fix account issues. -->
|
||||
<!-- Authentication -->
|
||||
<DataTemplate x:Key="FixAuthenticationIssueTemplate" x:DataType="menu:FixAccountIssuesMenuItem">
|
||||
<coreControls:WinoNavigationViewItem SelectsOnInvoked="False">
|
||||
<coreControls:WinoNavigationViewItem.Content>
|
||||
<TextBlock
|
||||
Margin="0,10"
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||
HorizontalTextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<Run Text="Account credentials can not be verified." /><LineBreak /><Run Text="Click here to fix it." />
|
||||
</TextBlock>
|
||||
</coreControls:WinoNavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Missing system folder config. -->
|
||||
<DataTemplate x:Key="FixMissingFolderConfig" x:DataType="menu:FixAccountIssuesMenuItem">
|
||||
<coreControls:WinoNavigationViewItem SelectsOnInvoked="False">
|
||||
<coreControls:WinoNavigationViewItem.Content>
|
||||
<TextBlock
|
||||
Margin="0,10"
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||
HorizontalTextAlignment="Center"
|
||||
TextWrapping="WrapWholeWords">
|
||||
<Run Text="Account is missing system folder configuration." /><LineBreak /><LineBreak /><Run Text="Click here to fix it." />
|
||||
</TextBlock>
|
||||
</coreControls:WinoNavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- New Mail -->
|
||||
<DataTemplate x:Key="CreateNewMailTemplate" x:DataType="menu:NewMailMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
Height="50"
|
||||
DataContext="{x:Bind}"
|
||||
SelectsOnInvoked="False">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon Icon="NewMail" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<TextBlock
|
||||
Margin="0,-2,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.MenuNewMail}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Inbox or any other folders. -->
|
||||
<DataTemplate x:Key="FolderMenuTemplate" x:DataType="menu:FolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="40"
|
||||
AllowDrop="True"
|
||||
ContextRequested="MenuItemContextRequested"
|
||||
DataContext="{x:Bind}"
|
||||
DragEnter="ItemDragEnterOnFolder"
|
||||
DragLeave="ItemDragLeaveFromFolder"
|
||||
Drop="ItemDroppedOnFolder"
|
||||
FontSize="50"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems, Mode=OneWay}"
|
||||
SelectsOnInvoked="{x:Bind IsMoveTarget, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="{x:Bind FolderName, Mode=OneWay}">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(Parameter.SpecialFolderType)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:NavigationViewItem.Content>
|
||||
<Grid
|
||||
x:Name="FolderBackgroundGrid"
|
||||
MaxHeight="36"
|
||||
Padding="2"
|
||||
VerticalAlignment="Center">
|
||||
<Grid
|
||||
x:Name="BackgroundColorGrid"
|
||||
x:Load="{x:Bind HasTextColor, Mode=OneWay}"
|
||||
Background="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(Parameter.BackgroundColorHex), Mode=OneWay}"
|
||||
CornerRadius="3">
|
||||
<TextBlock
|
||||
x:Name="CustomColorTitle"
|
||||
Margin="4,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Foreground="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(Parameter.TextColorHex), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
x:Name="NormalTitle"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="{x:Bind HasTextColor, Converter={StaticResource ReverseBooleanConverter}}"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</muxc:NavigationViewItem.Content>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Inbox -->
|
||||
<DataTemplate x:Key="MergedAccountTemplate" x:DataType="menu:MergedAccountMenuItem">
|
||||
<controls:AccountNavigationItem
|
||||
x:Name="AccountItem"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BindingData="{x:Bind}"
|
||||
DataContext="{x:Bind}"
|
||||
IsActiveAccount="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems}"
|
||||
SelectsOnInvoked="False"
|
||||
Style="{StaticResource SingleAccountNavigationViewItemTemplate}">
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<EdgeUIThemeTransition Edge="Top" />
|
||||
</TransitionCollection>
|
||||
</coreControls:WinoNavigationViewItem.ContentTransitions>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<PathIcon Data="F1 M 8.613281 17.5 C 8.75 17.942709 8.945312 18.359375 9.199219 18.75 L 4.921875 18.75 C 4.433594 18.75 3.966471 18.650717 3.520508 18.452148 C 3.074544 18.25358 2.683919 17.986654 2.348633 17.651367 C 2.013346 17.31608 1.746419 16.925455 1.547852 16.479492 C 1.349284 16.033529 1.25 15.566406 1.25 15.078125 L 1.25 4.921875 C 1.25 4.433594 1.349284 3.966473 1.547852 3.520508 C 1.746419 3.074545 2.013346 2.68392 2.348633 2.348633 C 2.683919 2.013348 3.074544 1.74642 3.520508 1.547852 C 3.966471 1.349285 4.433594 1.25 4.921875 1.25 L 15.078125 1.25 C 15.566406 1.25 16.033527 1.349285 16.479492 1.547852 C 16.925455 1.74642 17.31608 2.013348 17.651367 2.348633 C 17.986652 2.68392 18.25358 3.074545 18.452148 3.520508 C 18.650715 3.966473 18.75 4.433594 18.75 4.921875 L 18.75 6.572266 C 18.580729 6.344402 18.390299 6.132813 18.178711 5.9375 C 17.967121 5.742188 17.740885 5.566407 17.5 5.410156 L 17.5 4.951172 C 17.5 4.625651 17.433268 4.314779 17.299805 4.018555 C 17.16634 3.722332 16.987305 3.461914 16.762695 3.237305 C 16.538086 3.012695 16.277668 2.83366 15.981445 2.700195 C 15.685221 2.566732 15.374349 2.5 15.048828 2.5 L 4.951172 2.5 C 4.619141 2.5 4.303385 2.568359 4.003906 2.705078 C 3.704427 2.841797 3.44401 3.02409 3.222656 3.251953 C 3.001302 3.479818 2.825521 3.745117 2.695312 4.047852 C 2.565104 4.350587 2.5 4.66797 2.5 5 L 13.310547 5 C 12.60091 5.266928 11.998697 5.683594 11.503906 6.25 L 2.5 6.25 L 2.5 15.048828 C 2.5 15.38737 2.568359 15.704753 2.705078 16.000977 C 2.841797 16.297201 3.024088 16.55599 3.251953 16.777344 C 3.479818 16.998697 3.745117 17.174479 4.047852 17.304688 C 4.350586 17.434896 4.667969 17.5 5 17.5 Z" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
|
||||
<Grid Height="50">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel VerticalAlignment="Center" Spacing="0">
|
||||
<TextBlock
|
||||
x:Name="AccountNameTextblock"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsChildSelected), Mode=OneWay}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind MergedAccountName, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SynchronizationStatus, Mode=OneWay}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
MaxLines="1"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(IsSynchronizationProgressVisible), Mode=OneWay}">
|
||||
<Run Text="{x:Bind MergedAccountCount, Mode=OneWay}" /><Run Text="{x:Bind domain:Translator.MenuMergedAccountItemAccountsSuffix}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<muxc:ProgressRing
|
||||
x:Name="SynchronizationProgressBar"
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}"
|
||||
IsIndeterminate="{x:Bind IsProgressIndeterminate, Mode=OneWay}"
|
||||
Visibility="{x:Bind IsSynchronizationProgressVisible, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</controls:AccountNavigationItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Account Common Folder Item -->
|
||||
<DataTemplate x:Key="MergedAccountFolderMenuItemTemplate" x:DataType="menu:MergedAccountFolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="30"
|
||||
AllowDrop="True"
|
||||
ContextRequested="MenuItemContextRequested"
|
||||
DataContext="{x:Bind}"
|
||||
DragEnter="ItemDragEnterOnFolder"
|
||||
DragLeave="ItemDragLeaveFromFolder"
|
||||
Drop="ItemDroppedOnFolder"
|
||||
FontSize="50"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
SelectsOnInvoked="True"
|
||||
ToolTipService.ToolTip="{x:Bind FolderName, Mode=OneWay}">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(FolderType)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
<muxc:NavigationViewItem.InfoBadge>
|
||||
<muxc:InfoBadge
|
||||
x:Name="FolderInfoBadge"
|
||||
Background="{StaticResource SystemAccentColor}"
|
||||
Foreground="White"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.CountToVisibilityConverter(UnreadItemCount), Mode=OneWay}"
|
||||
Value="{x:Bind UnreadItemCount, Mode=OneWay}" />
|
||||
</muxc:NavigationViewItem.InfoBadge>
|
||||
<Grid
|
||||
x:Name="FolderBackgroundGrid"
|
||||
Padding="2"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
x:Name="NormalTitle"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsSelected), Mode=OneWay}"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind FolderName, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Merged Account More Expansion Item -->
|
||||
<DataTemplate x:Key="MergedAccountMoreFolderItemTemplate" x:DataType="menu:MergedAccountMoreFolderMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
MinHeight="30"
|
||||
Content="{x:Bind domain:Translator.More}"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightByChildSelectedState(IsSelected), Mode=OneWay}"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
|
||||
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
|
||||
MenuItemsSource="{x:Bind SubMenuItems, Mode=OneWay}"
|
||||
SelectsOnInvoked="True">
|
||||
<animations:Implicit.Animations>
|
||||
<animations:ScaleAnimation Duration="0:0:0.5" />
|
||||
</animations:Implicit.Animations>
|
||||
<coreControls:WinoNavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon FontSize="64" Icon="{x:Bind helpers:XamlHelpers.GetSpecialFolderPathIconGeometry(enums:SpecialFolderType.More)}" />
|
||||
</coreControls:WinoNavigationViewItem.Icon>
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="CalendarNewEventTemplate" x:DataType="menu:NewCalendarEventMenuItem">
|
||||
<coreControls:WinoNavigationViewItem
|
||||
Height="50"
|
||||
DataContext="{x:Bind}"
|
||||
SelectsOnInvoked="False">
|
||||
<muxc:NavigationViewItem.Icon>
|
||||
<coreControls:WinoFontIcon Icon="NewMail" />
|
||||
</muxc:NavigationViewItem.Icon>
|
||||
<TextBlock
|
||||
Margin="0,-2,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="16"
|
||||
Style="{StaticResource FlyoutPickerTitleTextBlockStyle}"
|
||||
Text="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton}" />
|
||||
</coreControls:WinoNavigationViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<coreSelectors:NavigationMenuTemplateSelector
|
||||
x:Key="NavigationMenuTemplateSelector"
|
||||
CalendarNewEventTemplate="{StaticResource CalendarNewEventTemplate}"
|
||||
ClickableAccountMenuTemplate="{StaticResource ClickableAccountMenuTemplate}"
|
||||
FixAuthenticationIssueTemplate="{StaticResource FixAuthenticationIssueTemplate}"
|
||||
FixMissingFolderConfigTemplate="{StaticResource FixMissingFolderConfig}"
|
||||
FolderMenuTemplate="{StaticResource FolderMenuTemplate}"
|
||||
MergedAccountFolderTemplate="{StaticResource MergedAccountFolderMenuItemTemplate}"
|
||||
MergedAccountMoreExpansionItemTemplate="{StaticResource MergedAccountMoreFolderItemTemplate}"
|
||||
MergedAccountTemplate="{StaticResource MergedAccountTemplate}"
|
||||
NewMailTemplate="{StaticResource CreateNewMailTemplate}"
|
||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||
SeperatorTemplate="{StaticResource SeperatorTemplate}"
|
||||
StoreUpdateItemTemplate="{StaticResource StoreUpdateItemTemplate}" />
|
||||
|
||||
<Style
|
||||
x:Key="CalendarNavigationButtonStyle"
|
||||
BasedOn="{StaticResource DefaultButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Margin" Value="0,4,0,0" />
|
||||
<Setter Property="Padding" Value="8,4,8,6" />
|
||||
<Setter Property="CornerRadius" Value="6" />
|
||||
<Setter Property="Width" Value="40" />
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
|
||||
<abstract:WinoAppShellAbstract.ShellContent>
|
||||
<Grid Margin="4,0,0,0" Background="Transparent">
|
||||
<ContentPresenter x:Name="DynamicPageShellContentPresenter" />
|
||||
<Grid
|
||||
x:Name="CalendarShellContentRoot"
|
||||
Visibility="Collapsed"
|
||||
ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid x:Name="ShellContentArea" ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel
|
||||
x:Name="NavigationTitleStack"
|
||||
Grid.Column="0"
|
||||
Margin="0,0,12,4"
|
||||
Orientation="Horizontal"
|
||||
Spacing="6">
|
||||
<Button
|
||||
x:Name="PreviousDateButton"
|
||||
Click="PreviousDateClicked"
|
||||
Style="{StaticResource CalendarNavigationButtonStyle}">
|
||||
<PathIcon x:Name="PreviousDateButtonPathIcon" Data="F1 M 8.72 18.599998 C 8.879999 18.733334 9.059999 18.799999 9.26 18.799999 C 9.459999 18.799999 9.633332 18.719999 9.78 18.559999 C 9.926666 18.4 10 18.219999 10 18.019999 C 10 17.82 9.92 17.653332 9.76 17.52 L 4.52 12.559999 L 17.24 12.559999 C 17.453333 12.559999 17.633331 12.486667 17.779999 12.339999 C 17.926666 12.193334 18 12.013333 18 11.799999 C 18 11.586666 17.926666 11.406667 17.779999 11.259999 C 17.633331 11.113333 17.453333 11.039999 17.24 11.039999 L 4.52 11.039999 L 9.76 6.08 C 9.973333 5.893333 10.046666 5.653332 9.98 5.359999 C 9.913333 5.066666 9.74 4.880001 9.46 4.799999 C 9.179999 4.720001 8.933332 4.786667 8.72 5 L 2.32 11.08 C 2.16 11.24 2.053333 11.426666 2 11.639999 C 1.973333 11.746666 1.973333 11.853333 2 11.959999 C 2.053333 12.173333 2.16 12.360001 2.32 12.52 Z " />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="NextDateButton"
|
||||
Click="NextDateClicked"
|
||||
Style="{StaticResource CalendarNavigationButtonStyle}">
|
||||
<PathIcon x:Name="NextDateButtonPathIcon" Data="F1 M 11.28 5 C 11.12 4.866667 10.94 4.806667 10.74 4.82 C 10.539999 4.833334 10.366666 4.913334 10.219999 5.059999 C 10.073333 5.206665 10 5.379999 10 5.58 C 10 5.779999 10.08 5.946667 10.24 6.08 L 15.48 11.039999 L 2.76 11.039999 C 2.546667 11.039999 2.366667 11.113333 2.22 11.259999 C 2.073333 11.406667 2 11.586666 2 11.799999 C 2 12.013333 2.073333 12.193334 2.22 12.339999 C 2.366667 12.486667 2.546667 12.559999 2.76 12.559999 L 15.48 12.559999 L 10.24 17.52 C 10.026667 17.706665 9.953333 17.946667 10.02 18.24 C 10.086666 18.533333 10.259999 18.719999 10.54 18.799999 C 10.82 18.879999 11.066667 18.813334 11.28 18.599998 L 17.68 12.52 C 17.84 12.360001 17.946667 12.173333 18 11.959999 C 18 11.853333 18 11.746666 18 11.639999 C 17.946667 11.426666 17.84 11.24 17.68 11.08 Z " />
|
||||
</Button>
|
||||
|
||||
<calendarControls:CustomCalendarFlipView
|
||||
x:Name="DayHeaderNavigationItemsFlipView"
|
||||
MaxHeight="30"
|
||||
Margin="8,4,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Left"
|
||||
Background="Transparent"
|
||||
FontSize="14"
|
||||
FontWeight="Normal"
|
||||
IsHitTestVisible="False"
|
||||
>
|
||||
<FlipView.ItemTemplate>
|
||||
<DataTemplate x:DataType="x:String">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="18"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{x:Bind}" />
|
||||
</DataTemplate>
|
||||
</FlipView.ItemTemplate>
|
||||
</calendarControls:CustomCalendarFlipView>
|
||||
</StackPanel>
|
||||
|
||||
<AutoSuggestBox
|
||||
x:Name="SearchBox"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="Transparent"
|
||||
PlaceholderText="Search" />
|
||||
</Grid>
|
||||
|
||||
<calendarControls:WinoCalendarTypeSelectorControl
|
||||
x:Name="CalendarTypeSelector"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</abstract:WinoAppShellAbstract.ShellContent>
|
||||
|
||||
<Grid
|
||||
x:Name="RootGrid"
|
||||
Padding="0"
|
||||
ColumnSpacing="0"
|
||||
RowSpacing="0">
|
||||
|
||||
<muxc:NavigationView
|
||||
x:Name="navigationView"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="-1,-1,0,0"
|
||||
Style="{StaticResource CalendarShellNavigationViewStyle}"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
AlwaysShowHeader="True"
|
||||
DisplayModeChanged="NavigationViewDisplayModeChanged"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsPaneOpen="{x:Bind ViewModel.PreferencesService.IsNavigationPaneOpened, Mode=TwoWay}"
|
||||
IsPaneToggleButtonVisible="False"
|
||||
IsSettingsVisible="False"
|
||||
IsTabStop="True"
|
||||
IsTitleBarAutoPaddingEnabled="False"
|
||||
ItemInvoked="NavigationViewItemInvoked"
|
||||
MenuItemTemplateSelector="{StaticResource NavigationMenuTemplateSelector}"
|
||||
OpenPaneLength="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||
PaneDisplayMode="Auto"
|
||||
PaneOpening="NavigationPaneOpening"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Hidden"
|
||||
SelectionChanged="MenuSelectionChanged">
|
||||
<muxc:NavigationView.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition />
|
||||
</TransitionCollection>
|
||||
</muxc:NavigationView.ContentTransitions>
|
||||
<muxc:NavigationView.PaneCustomContent>
|
||||
<Grid x:Name="PaneCustomContent" Padding="0,0,0,6" Visibility="Collapsed">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<calendarControls:WinoCalendarView
|
||||
x:Name="CalendarView"
|
||||
Grid.Row="0"
|
||||
Margin="0,12,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
TodayBackgroundColor="{ThemeResource SystemAccentColor}" />
|
||||
|
||||
<ListView
|
||||
x:Name="CalendarHostListView"
|
||||
Grid.Row="1"
|
||||
SelectionMode="None">
|
||||
<ListView.Header>
|
||||
<TextBlock
|
||||
Margin="20,12,12,12"
|
||||
FontSize="16"
|
||||
Text="Calendars" />
|
||||
</ListView.Header>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="data:GroupedAccountCalendarViewModel">
|
||||
<muxc:Expander
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}">
|
||||
<muxc:Expander.Header>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox
|
||||
Width="26"
|
||||
MinWidth="0"
|
||||
IsChecked="{x:Bind IsCheckedState, Mode=TwoWay}"
|
||||
IsThreeState="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap">
|
||||
<Run FontWeight="SemiBold" Text="{x:Bind Account.Name}" />
|
||||
<Run FontSize="12" Text="(" /><Run FontSize="12" Text="{x:Bind Account.Address}" /><Run FontSize="12" Text=")" />
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</muxc:Expander.Header>
|
||||
<muxc:Expander.Content>
|
||||
<ItemsControl ItemsSource="{x:Bind AccountCalendars}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="data:AccountCalendarViewModel">
|
||||
<CheckBox
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
IsChecked="{x:Bind IsChecked, Mode=TwoWay}">
|
||||
<Grid Margin="0,0,0,5" ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Ellipse
|
||||
Width="20"
|
||||
Height="20"
|
||||
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{x:Bind Name, Mode=OneWay}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</CheckBox>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</muxc:Expander.Content>
|
||||
</muxc:Expander>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</muxc:NavigationView.PaneCustomContent>
|
||||
<Grid ColumnSpacing="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<controls1:PropertySizer
|
||||
Width="1"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Transparent"
|
||||
Binding="{x:Bind ViewModel.StatePersistenceService.OpenPaneLength, Mode=TwoWay}"
|
||||
Canvas.ZIndex="20"
|
||||
Foreground="Transparent"
|
||||
IsHitTestVisible="{x:Bind navigationView.IsPaneOpen, Mode=OneWay}"
|
||||
IsTabStop="False"
|
||||
Maximum="1000"
|
||||
Minimum="116" />
|
||||
|
||||
<!-- Main Content -->
|
||||
<Frame
|
||||
x:Name="InnerShellFrame"
|
||||
Padding="0,0,7,7"
|
||||
IsNavigationStackEnabled="True"
|
||||
Navigated="ShellFrameContentNavigated">
|
||||
<Frame.ContentTransitions>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Frame.ContentTransitions>
|
||||
</Frame>
|
||||
|
||||
<!-- InfoBar -->
|
||||
<coreControls:WinoInfoBar
|
||||
x:Name="ShellInfoBar"
|
||||
MaxWidth="700"
|
||||
Margin="0,60,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
IsClosable="False"
|
||||
IsOpen="False" />
|
||||
|
||||
<!-- Teaching Tip -->
|
||||
<muxc:TeachingTip
|
||||
x:Name="ShellTip"
|
||||
IsOpen="False"
|
||||
PreferredPlacement="Bottom"
|
||||
Target="{x:Bind ShellInfoBar}" />
|
||||
</Grid>
|
||||
</muxc:NavigationView>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="LowResolutionStates">
|
||||
<VisualState x:Name="BigScreen">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="1200" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="navigationView.IsPaneOpen" Value="True" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SmallScreen">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="NavigationTitleStack.Visibility" Value="Collapsed" />
|
||||
<Setter Target="SearchBox.(Grid.ColumnSpan)" Value="2" />
|
||||
<Setter Target="navigationView.IsPaneOpen" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="CalendarOrientationStates">
|
||||
<VisualState x:Name="HorizontalCalendar" />
|
||||
<VisualState x:Name="VerticalCalendar">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="DayHeaderNavigationItemsFlipView.ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel Orientation="Vertical" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Target="PreviousDateButtonPathIcon.Data" Value="F1 M 3.2 10.52 C 2.986666 10.733333 2.92 10.98 3 11.259999 C 3.08 11.54 3.266666 11.713333 3.56 11.78 C 3.853333 11.846666 4.093333 11.773333 4.28 11.559999 L 9.24 6.32 L 9.24 19.039999 C 9.24 19.253332 9.313333 19.433332 9.46 19.58 C 9.606666 19.726665 9.786666 19.799999 10 19.799999 C 10.213333 19.799999 10.393332 19.726665 10.54 19.58 C 10.686666 19.433332 10.76 19.253332 10.76 19.039999 L 10.76 6.32 L 15.719999 11.559999 C 15.906666 11.773333 16.139999 11.846666 16.42 11.78 C 16.700001 11.713333 16.886665 11.54 16.98 11.259999 C 17.073332 10.98 17.013332 10.733333 16.799999 10.52 L 10.719999 4.119999 C 10.559999 3.959999 10.373333 3.853333 10.16 3.799999 C 10.053333 3.799999 9.946667 3.799999 9.84 3.799999 C 9.626666 3.853333 9.439999 3.959999 9.28 4.119999 Z " />
|
||||
<Setter Target="NextDateButtonPathIcon.Data" Value="F1 M 16.799999 13.079999 C 16.933332 12.92 16.993332 12.74 16.98 12.539999 C 16.966665 12.34 16.886665 12.166667 16.74 12.02 C 16.593334 11.873333 16.42 11.799999 16.219999 11.799999 C 16.02 11.799999 15.853333 11.879999 15.719999 12.039999 L 10.76 17.279999 L 10.76 4.559999 C 10.76 4.346666 10.686666 4.166668 10.54 4.02 C 10.393332 3.873333 10.213333 3.799999 10 3.799999 C 9.786666 3.799999 9.606666 3.873333 9.46 4.02 C 9.313333 4.166668 9.24 4.346666 9.24 4.559999 L 9.24 17.279999 L 4.28 12.039999 C 4.146667 11.879999 3.98 11.799999 3.78 11.799999 C 3.58 11.799999 3.4 11.873333 3.24 12.02 C 3.08 12.166667 3 12.34 3 12.539999 C 3 12.74 3.066667 12.92 3.2 13.079999 L 9.28 19.48 C 9.439999 19.639999 9.626666 19.746666 9.84 19.799999 C 9.946667 19.799999 10.053333 19.799999 10.16 19.799999 C 10.373333 19.746666 10.559999 19.639999 10.719999 19.48 Z " />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
<VisualStateGroup x:Name="ShellStateContentGroup">
|
||||
<VisualState x:Name="DefaultShellContentState" />
|
||||
<VisualState x:Name="EventDetailsContentState">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ShellContentArea.Visibility" Value="Collapsed" />
|
||||
<Setter Target="CalendarTypeSelector.Visibility" Value="Collapsed" />
|
||||
<Setter Target="CalendarView.IsEnabled" Value="False" />
|
||||
<Setter Target="CalendarHostListView.IsEnabled" Value="False" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</abstract:WinoAppShellAbstract>
|
||||
|
||||
|
||||
@@ -0,0 +1,679 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.Foundation;
|
||||
using Wino.Calendar.Controls;
|
||||
using Wino.Calendar.ViewModels;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Mail.ViewModels;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.WinUI.Controls;
|
||||
using Wino.MenuFlyouts;
|
||||
using Wino.MenuFlyouts.Context;
|
||||
using Wino.Messaging.Client.Accounts;
|
||||
using Wino.Messaging.Client.Calendar;
|
||||
using Wino.Messaging.Client.Mails;
|
||||
using Wino.Messaging.Client.Shell;
|
||||
|
||||
namespace Wino.Mail.WinUI.Views;
|
||||
|
||||
public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
|
||||
IShellHost,
|
||||
IRecipient<AccountMenuItemExtended>,
|
||||
IRecipient<NavigateMailFolderEvent>,
|
||||
IRecipient<CreateNewMailWithMultipleAccountsRequested>,
|
||||
IRecipient<CalendarDisplayTypeChangedMessage>
|
||||
{
|
||||
private const string StateHorizontalCalendar = "HorizontalCalendar";
|
||||
private const string StateVerticalCalendar = "VerticalCalendar";
|
||||
private const string StateDefaultShellContent = "DefaultShellContentState";
|
||||
private const string StateEventDetailsContent = "EventDetailsContentState";
|
||||
private WinoApplicationMode? _activeMode;
|
||||
|
||||
public WinoAppShell()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel.MailClient.PropertyChanged += MailClientPropertyChanged;
|
||||
ViewModel.CalendarClient.PropertyChanged += CalendarClientPropertyChanged;
|
||||
ViewModel.StatePersistenceService.StatePropertyChanged += StatePersistenceServiceChanged;
|
||||
CalendarTypeSelector.RegisterPropertyChangedCallback(WinoCalendarTypeSelectorControl.SelectedTypeProperty, CalendarTypeSelectorSelectedTypeChanged);
|
||||
|
||||
InitializeCalendarControls();
|
||||
ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType);
|
||||
UpdateEventDetailsVisualState();
|
||||
ApplyTitleBarContent();
|
||||
}
|
||||
|
||||
public bool HasShellContent => InnerShellFrame.Content != null;
|
||||
|
||||
public Frame GetShellFrame() => InnerShellFrame;
|
||||
|
||||
public void ActivateMode(WinoApplicationMode mode, bool isInitialActivation)
|
||||
{
|
||||
if (_activeMode == mode && InnerShellFrame.Content != null)
|
||||
return;
|
||||
|
||||
DeactivateCurrentMode();
|
||||
|
||||
_activeMode = mode;
|
||||
ViewModel.SetCurrentMode(mode);
|
||||
|
||||
RefreshNavigationViewBindings(syncMailSelection: mode != WinoApplicationMode.Mail);
|
||||
|
||||
//InnerShellFrame.IsNavigationStackEnabled = mode == WinoApplicationMode.Calendar;
|
||||
//InnerShellFrame.BackStack.Clear();
|
||||
//InnerShellFrame.ForwardStack.Clear();
|
||||
|
||||
ApplyModeLayout();
|
||||
UpdateTitleBarSubtitle();
|
||||
|
||||
var activationContext = new ShellModeActivationContext
|
||||
{
|
||||
IsInitialActivation = isInitialActivation
|
||||
};
|
||||
|
||||
ViewModel.CurrentClient.Activate(activationContext);
|
||||
|
||||
ApplyTitleBarContent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
DeactivateCurrentMode();
|
||||
Bindings.StopTracking();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateNavigationPaneLayout(navigationView.DisplayMode);
|
||||
RefreshNavigationViewBindings();
|
||||
RefreshCalendarControls();
|
||||
|
||||
if (_activeMode == null)
|
||||
{
|
||||
ActivateMode(ViewModel.StatePersistenceService.ApplicationMode, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyModeLayout()
|
||||
{
|
||||
var isCalendarMode = ViewModel.IsCalendarMode;
|
||||
|
||||
CalendarShellContentRoot.Visibility = isCalendarMode ? Visibility.Visible : Visibility.Collapsed;
|
||||
DynamicPageShellContentPresenter.Visibility = isCalendarMode ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
RefreshCalendarControls();
|
||||
ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType);
|
||||
UpdateEventDetailsVisualState();
|
||||
UpdateTitleBarSubtitle();
|
||||
UpdateNavigationPaneLayout(navigationView.DisplayMode);
|
||||
ApplyTitleBarContent();
|
||||
}
|
||||
|
||||
private void DeactivateCurrentMode()
|
||||
{
|
||||
if (_activeMode == WinoApplicationMode.Mail)
|
||||
{
|
||||
ViewModel.MailClient.Deactivate();
|
||||
}
|
||||
else if (_activeMode == WinoApplicationMode.Calendar)
|
||||
{
|
||||
ViewModel.CalendarClient.Deactivate();
|
||||
}
|
||||
else if (_activeMode == WinoApplicationMode.Contacts)
|
||||
{
|
||||
ViewModel.CurrentClient.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTitleBarContent()
|
||||
{
|
||||
if (ViewModel.IsCalendarMode)
|
||||
{
|
||||
CalendarShellContentRoot.Visibility = Visibility.Visible;
|
||||
DynamicPageShellContentPresenter.Visibility = Visibility.Collapsed;
|
||||
return;
|
||||
}
|
||||
|
||||
CalendarShellContentRoot.Visibility = Visibility.Collapsed;
|
||||
DynamicPageShellContentPresenter.Visibility = Visibility.Visible;
|
||||
DynamicPageShellContentPresenter.Content = InnerShellFrame.Content is BasePage page ? page.ShellContent : null;
|
||||
}
|
||||
|
||||
private void UpdateTitleBarSubtitle()
|
||||
{
|
||||
if (ViewModel.IsContactsMode)
|
||||
{
|
||||
ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewModel.IsCalendarMode)
|
||||
{
|
||||
ViewModel.StatePersistenceService.CoreWindowTitle = ViewModel.CalendarClient.HighlightedDateRange?.ToString() ?? string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty;
|
||||
}
|
||||
|
||||
private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType)
|
||||
{
|
||||
DayHeaderNavigationItemsFlipView.DisplayType = displayType;
|
||||
|
||||
if (CalendarTypeSelector.SelectedType != displayType)
|
||||
{
|
||||
CalendarTypeSelector.SelectedType = displayType;
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, displayType == Core.Domain.Enums.CalendarDisplayType.Month
|
||||
? StateVerticalCalendar
|
||||
: StateHorizontalCalendar, false);
|
||||
}
|
||||
|
||||
private void InitializeCalendarControls()
|
||||
{
|
||||
CalendarTypeSelector.TodayClickedCommand = ViewModel.CalendarClient.TodayClickedCommand;
|
||||
CalendarView.DateClickedCommand = ViewModel.CalendarClient.DateClickedCommand;
|
||||
DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems;
|
||||
CalendarHostListView.ItemsSource = ViewModel.CalendarClient.GroupedAccountCalendars;
|
||||
|
||||
RefreshCalendarControls();
|
||||
}
|
||||
|
||||
private void RefreshCalendarControls()
|
||||
{
|
||||
DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems;
|
||||
DayHeaderNavigationItemsFlipView.SelectedIndex = ViewModel.CalendarClient.SelectedDateNavigationHeaderIndex;
|
||||
CalendarTypeSelector.DisplayDayCount = ViewModel.CalendarClient.StatePersistenceService.DayDisplayCount;
|
||||
CalendarView.HighlightedDateRange = ViewModel.CalendarClient.HighlightedDateRange;
|
||||
CalendarHostListView.ItemsSource = ViewModel.CalendarClient.GroupedAccountCalendars;
|
||||
}
|
||||
|
||||
private void RefreshNavigationViewBindings(bool syncMailSelection = true)
|
||||
{
|
||||
navigationView.MenuItemsSource = ViewModel.CurrentMenuItems;
|
||||
|
||||
navigationView.SelectionChanged -= MenuSelectionChanged;
|
||||
navigationView.SelectedItem = ViewModel.CurrentClient.HandlesNavigationSelection && syncMailSelection
|
||||
? ViewModel.SelectedMenuItem
|
||||
: null;
|
||||
navigationView.SelectionChanged += MenuSelectionChanged;
|
||||
}
|
||||
|
||||
private void UpdateEventDetailsVisualState()
|
||||
{
|
||||
VisualStateManager.GoToState(this,
|
||||
ViewModel.StatePersistenceService.IsEventDetailsVisible ? StateEventDetailsContent : StateDefaultShellContent,
|
||||
false);
|
||||
}
|
||||
|
||||
private void CalendarTypeSelectorSelectedTypeChanged(DependencyObject sender, DependencyProperty dp)
|
||||
{
|
||||
var selectedType = CalendarTypeSelector.SelectedType;
|
||||
|
||||
if (ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType != selectedType)
|
||||
{
|
||||
ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType = selectedType;
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviousDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoPreviousDateRequestedMessage());
|
||||
|
||||
private void NextDateClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new GoNextDateRequestedMessage());
|
||||
|
||||
public void Receive(CalendarDisplayTypeChangedMessage message) => ManageCalendarDisplayType(message.NewDisplayType);
|
||||
|
||||
private async void NavigationViewItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
|
||||
{
|
||||
if (ViewModel.IsCalendarMode)
|
||||
{
|
||||
if (args.InvokedItemContainer is FrameworkElement { DataContext: IMenuItem menuItem })
|
||||
{
|
||||
await ViewModel.CalendarClient.HandleNavigationItemInvokedAsync(menuItem);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem)
|
||||
{
|
||||
if (winoNavigationViewItem.SelectsOnInvoked)
|
||||
return;
|
||||
|
||||
await ViewModel.CurrentClient.HandleNavigationItemInvokedAsync(winoNavigationViewItem.DataContext as IMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async void MenuSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (!ViewModel.IsMailMode)
|
||||
return;
|
||||
|
||||
if (args.SelectedItem is IMenuItem invokedMenuItem)
|
||||
{
|
||||
await ViewModel.CurrentClient.HandleNavigationSelectionChangedAsync(invokedMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(AccountMenuItemExtended message)
|
||||
{
|
||||
if (!ViewModel.IsMailMode)
|
||||
return;
|
||||
|
||||
_ = DispatcherQueue.EnqueueAsync(async () =>
|
||||
{
|
||||
if (message.FolderId == default)
|
||||
return;
|
||||
|
||||
if (ViewModel.MailClient.MenuItems!.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem))
|
||||
{
|
||||
foundMenuItem.Expand();
|
||||
await ViewModel.MailClient.NavigateFolderAsync(foundMenuItem);
|
||||
navigationView.SelectedItem = foundMenuItem;
|
||||
|
||||
if (message.NavigateMailItem != null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.NavigateMailItem == null)
|
||||
return;
|
||||
|
||||
if (ViewModel.MailClient.MenuItems!.TryGetAccountMenuItem(message.NavigateMailItem.AssignedAccount.Id, out IAccountMenuItem accountMenuItem))
|
||||
{
|
||||
await ViewModel.MailClient.ChangeLoadedAccountAsync(accountMenuItem, navigateInbox: false);
|
||||
|
||||
if (ViewModel.MailClient.MenuItems!.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem accountFolderMenuItem))
|
||||
{
|
||||
accountFolderMenuItem.Expand();
|
||||
await ViewModel.MailClient.NavigateFolderAsync(accountFolderMenuItem);
|
||||
navigationView.SelectedItem = accountFolderMenuItem;
|
||||
WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Receive(NavigateMailFolderEvent message)
|
||||
{
|
||||
if (!ViewModel.IsMailMode || message.BaseFolderMenuItem == null)
|
||||
return;
|
||||
|
||||
if (navigationView.SelectedItem != message.BaseFolderMenuItem)
|
||||
{
|
||||
var navigateFolderArgs = new NavigateMailFolderEventArgs(message.BaseFolderMenuItem, message.FolderInitLoadAwaitTask);
|
||||
|
||||
ViewModel.NavigationService.Navigate(WinoPage.MailListPage, navigateFolderArgs, NavigationReferenceFrame.InnerShellFrame);
|
||||
|
||||
navigationView.SelectionChanged -= MenuSelectionChanged;
|
||||
navigationView.SelectedItem = message.BaseFolderMenuItem;
|
||||
navigationView.SelectionChanged += MenuSelectionChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.FolderInitLoadAwaitTask?.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShellFrameContentNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
ApplyTitleBarContent();
|
||||
|
||||
if (ViewModel.IsMailMode)
|
||||
{
|
||||
RefreshNavigationViewBindings();
|
||||
}
|
||||
}
|
||||
|
||||
private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args)
|
||||
{
|
||||
if (!ViewModel.IsMailMode)
|
||||
return;
|
||||
|
||||
if (sender is WinoNavigationViewItem menuItem &&
|
||||
menuItem.DataContext is IBaseFolderMenuItem baseFolderMenuItem &&
|
||||
baseFolderMenuItem.IsMoveTarget &&
|
||||
args.TryGetPosition(sender, out Point p))
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
var source = new TaskCompletionSource<FolderOperationMenuItem>();
|
||||
var actions = ViewModel.MailClient.GetFolderContextMenuActions(baseFolderMenuItem);
|
||||
var flyout = new FolderOperationFlyout(actions, source);
|
||||
|
||||
flyout.ShowAt(menuItem, new FlyoutShowOptions
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Standard,
|
||||
Position = new Point(p.X + 30, p.Y - 20)
|
||||
});
|
||||
|
||||
var operation = await source.Task;
|
||||
flyout.Dispose();
|
||||
|
||||
if (operation != null)
|
||||
{
|
||||
await ViewModel.MailClient.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(CreateNewMailWithMultipleAccountsRequested message)
|
||||
{
|
||||
if (!ViewModel.IsMailMode)
|
||||
return;
|
||||
|
||||
var container = navigationView.ContainerFromMenuItem(ViewModel.MailClient.CreatePrimaryMenuItem);
|
||||
var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.MailClient.CreateNewMailForAsync);
|
||||
|
||||
flyout.ShowAt(container, new FlyoutShowOptions
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Auto,
|
||||
Placement = FlyoutPlacementMode.Right
|
||||
});
|
||||
}
|
||||
|
||||
private void NavigationPaneOpening(NavigationView sender, object args)
|
||||
{
|
||||
if (!ViewModel.IsMailMode)
|
||||
return;
|
||||
|
||||
if (sender.DisplayMode == NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem)
|
||||
{
|
||||
selectedFolderMenuItem.Expand();
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
|
||||
=> UpdateNavigationPaneLayout(args.DisplayMode);
|
||||
|
||||
private void MailClientPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(IShellClient.SelectedMenuItem) && ViewModel.IsMailMode)
|
||||
{
|
||||
navigationView.SelectionChanged -= MenuSelectionChanged;
|
||||
navigationView.SelectedItem = ViewModel.MailClient.SelectedMenuItem;
|
||||
navigationView.SelectionChanged += MenuSelectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalendarClientPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(ICalendarShellClient.DateNavigationHeaderItems))
|
||||
{
|
||||
DayHeaderNavigationItemsFlipView.ItemsSource = ViewModel.CalendarClient.DateNavigationHeaderItems;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.PropertyName == nameof(ICalendarShellClient.SelectedDateNavigationHeaderIndex))
|
||||
{
|
||||
DayHeaderNavigationItemsFlipView.SelectedIndex = ViewModel.CalendarClient.SelectedDateNavigationHeaderIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.PropertyName == nameof(ICalendarShellClient.HighlightedDateRange))
|
||||
{
|
||||
CalendarView.HighlightedDateRange = ViewModel.CalendarClient.HighlightedDateRange;
|
||||
UpdateTitleBarSubtitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void StatePersistenceServiceChanged(object? sender, string propertyName)
|
||||
{
|
||||
if (propertyName == nameof(IStatePersistanceService.CalendarDisplayType))
|
||||
{
|
||||
ManageCalendarDisplayType(ViewModel.CalendarClient.StatePersistenceService.CalendarDisplayType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyName == nameof(IStatePersistanceService.DayDisplayCount))
|
||||
{
|
||||
CalendarTypeSelector.DisplayDayCount = ViewModel.CalendarClient.StatePersistenceService.DayDisplayCount;
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyName == nameof(IStatePersistanceService.IsEventDetailsVisible))
|
||||
{
|
||||
UpdateEventDetailsVisualState();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNavigationPaneLayout(NavigationViewDisplayMode displayMode)
|
||||
{
|
||||
if (ViewModel.IsCalendarMode)
|
||||
{
|
||||
PaneCustomContent.Visibility = displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen
|
||||
? Visibility.Visible
|
||||
: Visibility.Collapsed;
|
||||
|
||||
InnerShellFrame.Margin = new Thickness(0);
|
||||
return;
|
||||
}
|
||||
|
||||
PaneCustomContent.Visibility = Visibility.Collapsed;
|
||||
InnerShellFrame.Margin = displayMode == NavigationViewDisplayMode.Minimal
|
||||
? new Thickness(7, 0, 0, 0)
|
||||
: new Thickness(0);
|
||||
}
|
||||
|
||||
private async void OnPreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.KeyStatus.RepeatCount > 1 || ShouldIgnoreShortcut())
|
||||
return;
|
||||
|
||||
var key = NormalizeKey(e.Key);
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return;
|
||||
|
||||
var mode = ViewModel.CurrentMode;
|
||||
var shortcutService = WinoApplication.Current.Services.GetRequiredService<IKeyboardShortcutService>();
|
||||
var shortcut = await shortcutService.GetShortcutForKeyAsync(mode, key, GetCurrentModifierKeys());
|
||||
|
||||
if (shortcut == null)
|
||||
return;
|
||||
|
||||
var details = new KeyboardShortcutTriggerDetails
|
||||
{
|
||||
ShortcutId = shortcut.Id,
|
||||
Mode = shortcut.Mode,
|
||||
Action = shortcut.Action,
|
||||
Key = shortcut.Key,
|
||||
ModifierKeys = shortcut.ModifierKeys,
|
||||
Sender = sender,
|
||||
Origin = FocusManager.GetFocusedElement(XamlRoot)
|
||||
};
|
||||
|
||||
await ViewModel.CurrentClient.KeyboardShortcutHook(details);
|
||||
|
||||
if (InnerShellFrame.Content is BasePage activePage && activePage.AssociatedViewModel != null)
|
||||
{
|
||||
await activePage.AssociatedViewModel.KeyboardShortcutHook(details);
|
||||
}
|
||||
|
||||
if (details.Handled)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldIgnoreShortcut()
|
||||
{
|
||||
var focusedElement = FocusManager.GetFocusedElement(XamlRoot);
|
||||
|
||||
if (focusedElement is TextBox or AutoSuggestBox or PasswordBox or RichEditBox or ComboBox)
|
||||
return true;
|
||||
|
||||
if (focusedElement is FrameworkElement frameworkElement)
|
||||
{
|
||||
var typeName = frameworkElement.GetType().Name;
|
||||
if (typeName.Contains("WebView", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void ItemDroppedOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
if (sender is WinoNavigationViewItem droppedContainer)
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = false;
|
||||
|
||||
if (CanContinueDragDrop(droppedContainer, e) && droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder)
|
||||
{
|
||||
var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
if (dragPackage == null)
|
||||
return;
|
||||
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
var mailCopies = ExtractMailCopies(dragPackage).ToList();
|
||||
await ViewModel.MailClient.PerformMoveOperationAsync(mailCopies, draggingFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragLeaveFromFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
if (sender is WinoNavigationViewItem leavingContainer)
|
||||
{
|
||||
leavingContainer.IsDraggingItemOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanContinueDragDrop(WinoNavigationViewItem interactingContainer, DragEventArgs args)
|
||||
{
|
||||
if (!ViewModel.IsMailMode || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage)))
|
||||
return false;
|
||||
|
||||
var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
if (dragPackage == null || !dragPackage.DraggingMails.Any())
|
||||
return false;
|
||||
|
||||
if (interactingContainer.IsSelected)
|
||||
return false;
|
||||
|
||||
if (interactingContainer.DataContext is not IBaseFolderMenuItem folderMenuItem || !folderMenuItem.IsMoveTarget)
|
||||
return false;
|
||||
|
||||
var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId);
|
||||
var draggedMails = ExtractMailCopies(dragPackage).ToList();
|
||||
|
||||
return draggedMails.Any() && draggedMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id));
|
||||
}
|
||||
|
||||
private static IEnumerable<MailCopy> ExtractMailCopies(MailDragPackage dragPackage)
|
||||
{
|
||||
foreach (var item in dragPackage.DraggingMails)
|
||||
{
|
||||
if (item is MailCopy mailCopy)
|
||||
{
|
||||
yield return mailCopy;
|
||||
}
|
||||
else if (item is MailItemViewModel singleMailItemViewModel)
|
||||
{
|
||||
yield return singleMailItemViewModel.MailCopy;
|
||||
}
|
||||
else if (item is ThreadMailItemViewModel threadViewModel)
|
||||
{
|
||||
foreach (var threadMail in threadViewModel.ThreadEmails)
|
||||
{
|
||||
yield return threadMail.MailCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragEnterOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e))
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = true;
|
||||
|
||||
if (droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder)
|
||||
{
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ModifierKeys GetCurrentModifierKeys()
|
||||
{
|
||||
var modifiers = ModifierKeys.None;
|
||||
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Control;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Alt;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
modifiers |= ModifierKeys.Shift;
|
||||
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down) ||
|
||||
Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down))
|
||||
{
|
||||
modifiers |= ModifierKeys.Windows;
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
private static string NormalizeKey(Windows.System.VirtualKey key)
|
||||
{
|
||||
return key switch
|
||||
{
|
||||
Windows.System.VirtualKey.Control or
|
||||
Windows.System.VirtualKey.LeftControl or
|
||||
Windows.System.VirtualKey.RightControl or
|
||||
Windows.System.VirtualKey.Menu or
|
||||
Windows.System.VirtualKey.LeftMenu or
|
||||
Windows.System.VirtualKey.RightMenu or
|
||||
Windows.System.VirtualKey.Shift or
|
||||
Windows.System.VirtualKey.LeftShift or
|
||||
Windows.System.VirtualKey.RightShift or
|
||||
Windows.System.VirtualKey.LeftWindows or
|
||||
Windows.System.VirtualKey.RightWindows => string.Empty,
|
||||
_ => key.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
protected override void RegisterRecipients()
|
||||
{
|
||||
base.RegisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Register<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Register<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateMailFolderEvent>(this);
|
||||
WeakReferenceMessenger.Default.Register<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
|
||||
protected override void UnregisterRecipients()
|
||||
{
|
||||
base.UnregisterRecipients();
|
||||
|
||||
WeakReferenceMessenger.Default.Unregister<AccountMenuItemExtended>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CreateNewMailWithMultipleAccountsRequested>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<NavigateMailFolderEvent>(this);
|
||||
WeakReferenceMessenger.Default.Unregister<CalendarDisplayTypeChangedMessage>(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user