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.
|
- 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 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(...)`.
|
- 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;
|
namespace Wino.Calendar.ViewModels;
|
||||||
|
|
||||||
public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
||||||
|
ICalendarShellClient,
|
||||||
IRecipient<VisibleDateRangeChangedMessage>,
|
IRecipient<VisibleDateRangeChangedMessage>,
|
||||||
IRecipient<CalendarEnableStatusChangedMessage>,
|
IRecipient<CalendarEnableStatusChangedMessage>,
|
||||||
IRecipient<NavigateManageAccountsRequested>,
|
IRecipient<NavigateManageAccountsRequested>,
|
||||||
@@ -40,6 +41,17 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
public IStatePersistanceService StatePersistenceService { get; }
|
public IStatePersistanceService StatePersistenceService { get; }
|
||||||
public IAccountCalendarStateService AccountCalendarStateService { get; }
|
public IAccountCalendarStateService AccountCalendarStateService { get; }
|
||||||
public INavigationService NavigationService { 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 MenuItems { get; private set; }
|
||||||
public MenuItemCollection FooterItems { 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 ManageAccountsMenuItem _manageAccountsMenuItem = new();
|
||||||
private readonly SettingsItem _settingsItem = new();
|
private readonly SettingsItem _settingsItem = new();
|
||||||
private readonly StoreUpdateMenuItem _storeUpdateMenuItem = new();
|
private readonly StoreUpdateMenuItem _storeUpdateMenuItem = new();
|
||||||
private readonly NewMailMenuItem _newEventMenuItem = new();
|
private readonly NewCalendarEventMenuItem _newEventMenuItem = new();
|
||||||
|
|
||||||
// For updating account calendars asynchronously.
|
// For updating account calendars asynchronously.
|
||||||
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1);
|
||||||
@@ -146,6 +158,10 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
|
var activationContext = parameters as ShellModeActivationContext;
|
||||||
|
var isModeResetActivation = activationContext != null;
|
||||||
|
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||||
|
|
||||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
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
|
// between Mail and Calendar modes. Back/forward restoration should not
|
||||||
// force a new CalendarPage navigation, otherwise pages like
|
// force a new CalendarPage navigation, otherwise pages like
|
||||||
// CalendarEventComposePage get dropped from the inner frame stack.
|
// CalendarEventComposePage get dropped from the inner frame stack.
|
||||||
if (mode != NavigationMode.New)
|
if (mode != NavigationMode.New && !isModeResetActivation)
|
||||||
{
|
{
|
||||||
UpdateDateNavigationHeaderItems();
|
UpdateDateNavigationHeaderItems();
|
||||||
await InitializeAccountCalendarsAsync();
|
await InitializeAccountCalendarsAsync();
|
||||||
@@ -168,7 +184,10 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
await InitializeAccountCalendarsAsync();
|
await InitializeAccountCalendarsAsync();
|
||||||
ValidateConfiguredNewEventCalendar();
|
ValidateConfiguredNewEventCalendar();
|
||||||
|
|
||||||
await ShowWhatIsNewIfNeededAsync();
|
if (shouldRunStartupFlows)
|
||||||
|
{
|
||||||
|
await ShowWhatIsNewIfNeededAsync();
|
||||||
|
}
|
||||||
|
|
||||||
TodayClicked();
|
TodayClicked();
|
||||||
}
|
}
|
||||||
@@ -601,6 +620,18 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel,
|
|||||||
|
|
||||||
return (startDate, startDate.AddMinutes(30));
|
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",
|
"SystemFolderConfigSetupSuccess_Title": "System Folders Setup",
|
||||||
"SystemTrayMenu_ShowWino": "Open Wino Mail",
|
"SystemTrayMenu_ShowWino": "Open Wino Mail",
|
||||||
"SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar",
|
"SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar",
|
||||||
"SystemTrayMenu_ShowWinoContacts": "Open Wino Contacts",
|
|
||||||
"SystemTrayMenu_ExitWino": "Exit",
|
"SystemTrayMenu_ExitWino": "Exit",
|
||||||
"TestingImapConnectionMessage": "Testing server connection...",
|
"TestingImapConnectionMessage": "Testing server connection...",
|
||||||
"TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore 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;
|
namespace Wino.Mail.ViewModels;
|
||||||
|
|
||||||
public partial class MailAppShellViewModel : MailBaseViewModel,
|
public partial class MailAppShellViewModel : MailBaseViewModel,
|
||||||
|
IMailShellClient,
|
||||||
IRecipient<NavigateManageAccountsRequested>,
|
IRecipient<NavigateManageAccountsRequested>,
|
||||||
IRecipient<MailtoProtocolMessageRequested>,
|
IRecipient<MailtoProtocolMessageRequested>,
|
||||||
IRecipient<RefreshUnreadCountsMessage>,
|
IRecipient<RefreshUnreadCountsMessage>,
|
||||||
@@ -67,6 +68,9 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
public IStatePersistanceService StatePersistenceService { get; }
|
public IStatePersistanceService StatePersistenceService { get; }
|
||||||
public IPreferencesService PreferencesService { get; }
|
public IPreferencesService PreferencesService { get; }
|
||||||
public INavigationService NavigationService { get; }
|
public INavigationService NavigationService { get; }
|
||||||
|
public WinoApplicationMode Mode => WinoApplicationMode.Mail;
|
||||||
|
public bool HandlesNavigationSelection => true;
|
||||||
|
public IMenuItem CreatePrimaryMenuItem => CreateMailMenuItem;
|
||||||
|
|
||||||
private readonly IFolderService _folderService;
|
private readonly IFolderService _folderService;
|
||||||
private readonly IConfigurationService _configurationService;
|
private readonly IConfigurationService _configurationService;
|
||||||
@@ -227,10 +231,14 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
{
|
{
|
||||||
base.OnNavigatedTo(mode, parameters);
|
base.OnNavigatedTo(mode, parameters);
|
||||||
|
|
||||||
|
var activationContext = parameters as ShellModeActivationContext;
|
||||||
|
var isModeResetActivation = activationContext != null;
|
||||||
|
var shouldRunStartupFlows = activationContext?.IsInitialActivation ?? true;
|
||||||
|
|
||||||
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
|
||||||
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
|
// Preserve current mail/folder selection and active rendering page when
|
||||||
// switching back from Calendar mode. Recreating menu/folder state here
|
// switching back from Calendar mode. Recreating menu/folder state here
|
||||||
@@ -252,13 +260,16 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
|
|||||||
await ProcessLaunchOptionsAsync();
|
await ProcessLaunchOptionsAsync();
|
||||||
await ValidateWebView2RuntimeAsync();
|
await ValidateWebView2RuntimeAsync();
|
||||||
|
|
||||||
if (!Debugger.IsAttached)
|
if (shouldRunStartupFlows && !Debugger.IsAttached)
|
||||||
{
|
{
|
||||||
await ForceAllAccountSynchronizationsAsync();
|
await ForceAllAccountSynchronizationsAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await ShowWhatIsNewIfNeededAsync();
|
if (shouldRunStartupFlows)
|
||||||
await MakeSureEnableStartupLaunchAsync();
|
{
|
||||||
|
await ShowWhatIsNewIfNeededAsync();
|
||||||
|
await MakeSureEnableStartupLaunchAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ValidateWebView2RuntimeAsync()
|
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"
|
x:Class="Wino.Mail.WinUI.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
|
||||||
|
xmlns:coreStyles="using:Wino.Mail.WinUI.Styles"
|
||||||
xmlns:local="using:Wino.Mail.WinUI"
|
xmlns:local="using:Wino.Mail.WinUI"
|
||||||
xmlns:styles="using:Wino.Styles"
|
xmlns:styles="using:Wino.Styles"
|
||||||
xmlns:uwp="using:Wino.Mail.WinUI">
|
xmlns:uwp="using:Wino.Mail.WinUI">
|
||||||
@@ -10,7 +12,101 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
<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="ms-appx:///CommunityToolkit.WinUI.Controls.Segmented/Segmented/Segmented.xaml" />
|
||||||
<ResourceDictionary Source="Controls/ListView/WinoListViewStyles.xaml" />
|
<ResourceDictionary Source="Controls/ListView/WinoListViewStyles.xaml" />
|
||||||
<ResourceDictionary Source="Styles/ItemContainerStyles.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.Navigation;
|
||||||
using Wino.Core.Domain.Models.Synchronization;
|
using Wino.Core.Domain.Models.Synchronization;
|
||||||
using Wino.Mail.Services;
|
using Wino.Mail.Services;
|
||||||
|
using Wino.Mail.WinUI.ViewModels;
|
||||||
using Wino.Mail.ViewModels;
|
using Wino.Mail.ViewModels;
|
||||||
using Wino.Mail.ViewModels.Data;
|
using Wino.Mail.ViewModels.Data;
|
||||||
using Wino.Mail.WinUI.Activation;
|
using Wino.Mail.WinUI.Activation;
|
||||||
@@ -142,6 +143,13 @@ public partial class App : WinoApplication,
|
|||||||
{
|
{
|
||||||
services.AddSingleton(typeof(MailAppShellViewModel));
|
services.AddSingleton(typeof(MailAppShellViewModel));
|
||||||
services.AddSingleton(typeof(CalendarAppShellViewModel));
|
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(MailListPageViewModel));
|
||||||
services.AddTransient(typeof(MailRenderingPageViewModel));
|
services.AddTransient(typeof(MailRenderingPageViewModel));
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:domain="using:Wino.Core.Domain">
|
xmlns:domain="using:Wino.Core.Domain"
|
||||||
|
Loaded="ControlLoaded"
|
||||||
|
Unloaded="ControlUnloaded">
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<controls:Segmented
|
<controls:Segmented
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ public sealed partial class AppModeFooterSwitcherControl : UserControl
|
|||||||
_navigationService = WinoApplication.Current.Services.GetRequiredService<INavigationService>();
|
_navigationService = WinoApplication.Current.Services.GetRequiredService<INavigationService>();
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Loaded += ControlLoaded;
|
|
||||||
Unloaded += ControlUnloaded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ControlLoaded(object sender, RoutedEventArgs e)
|
private void ControlLoaded(object sender, RoutedEventArgs e)
|
||||||
@@ -34,7 +31,6 @@ public sealed partial class AppModeFooterSwitcherControl : UserControl
|
|||||||
{
|
{
|
||||||
_statePersistenceService.StatePropertyChanged -= StatePropertyChanged;
|
_statePersistenceService.StatePropertyChanged -= StatePropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StatePropertyChanged(object? sender, string propertyName)
|
private void StatePropertyChanged(object? sender, string propertyName)
|
||||||
{
|
{
|
||||||
if (propertyName != nameof(IStatePersistanceService.ApplicationMode))
|
if (propertyName != nameof(IStatePersistanceService.ApplicationMode))
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||||
|
|
||||||
<ResourceDictionary Source="Styles/Colors.xaml" />
|
<ResourceDictionary Source="/Styles/Colors.xaml" />
|
||||||
<ResourceDictionary Source="Styles/ContentPresenters.xaml" />
|
<ResourceDictionary Source="/Styles/ContentPresenters.xaml" />
|
||||||
<ResourceDictionary Source="Styles/Converters.xaml" />
|
<ResourceDictionary Source="/Styles/Converters.xaml" />
|
||||||
<ResourceDictionary Source="Styles/FontIcons.xaml" />
|
<ResourceDictionary Source="/Styles/FontIcons.xaml" />
|
||||||
<ResourceDictionary Source="Styles/WinoInfoBar.xaml" />
|
<ResourceDictionary Source="/Styles/WinoInfoBar.xaml" />
|
||||||
<ResourceDictionary Source="Styles/SharedStyles.xaml" />
|
<ResourceDictionary Source="/Styles/SharedStyles.xaml" />
|
||||||
<ResourceDictionary Source="Styles/IconTemplates.xaml" />
|
<ResourceDictionary Source="/Styles/IconTemplates.xaml" />
|
||||||
|
|
||||||
<styles:CustomMessageDialogStyles />
|
<styles:CustomMessageDialogStyles />
|
||||||
<styles:DataTemplates />
|
<styles:DataTemplates />
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"Wino.Mail.WinUI (Package)": {
|
"Wino.Mail.WinUI (Package)": {
|
||||||
"commandName": "MsixPackage",
|
"commandName": "MsixPackage",
|
||||||
"doNotLaunchApp": false
|
"doNotLaunchApp": false,
|
||||||
|
"nativeDebugging": true
|
||||||
},
|
},
|
||||||
"Wino.Mail.WinUI (Unpackaged)": {
|
"Wino.Mail.WinUI (Unpackaged)": {
|
||||||
"commandName": "Project"
|
"commandName": "Project"
|
||||||
|
|||||||
@@ -21,13 +21,16 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector
|
|||||||
public DataTemplate CreateNewFolderTemplate { get; set; } = null!;
|
public DataTemplate CreateNewFolderTemplate { get; set; } = null!;
|
||||||
public DataTemplate SeperatorTemplate { get; set; } = null!;
|
public DataTemplate SeperatorTemplate { get; set; } = null!;
|
||||||
public DataTemplate NewMailTemplate { get; set; } = null!;
|
public DataTemplate NewMailTemplate { get; set; } = null!;
|
||||||
|
public DataTemplate CalendarNewEventTemplate { get; set; } = null!;
|
||||||
public DataTemplate CategoryItemsTemplate { get; set; } = null!;
|
public DataTemplate CategoryItemsTemplate { get; set; } = null!;
|
||||||
public DataTemplate FixAuthenticationIssueTemplate { get; set; } = null!;
|
public DataTemplate FixAuthenticationIssueTemplate { get; set; } = null!;
|
||||||
public DataTemplate FixMissingFolderConfigTemplate { get; set; } = null!;
|
public DataTemplate FixMissingFolderConfigTemplate { get; set; } = null!;
|
||||||
|
|
||||||
protected override DataTemplate SelectTemplateCore(object item)
|
protected override DataTemplate SelectTemplateCore(object item)
|
||||||
{
|
{
|
||||||
if (item is NewMailMenuItem)
|
if (item is NewCalendarEventMenuItem)
|
||||||
|
return CalendarNewEventTemplate;
|
||||||
|
else if (item is NewMailMenuItem)
|
||||||
return NewMailTemplate;
|
return NewMailTemplate;
|
||||||
else if (item is ContactsMenuItem)
|
else if (item is ContactsMenuItem)
|
||||||
return ContactsMenuItemTemplate;
|
return ContactsMenuItemTemplate;
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ using Wino.Mail.WinUI;
|
|||||||
using Wino.Mail.WinUI.Interfaces;
|
using Wino.Mail.WinUI.Interfaces;
|
||||||
using Wino.Mail.WinUI.Models;
|
using Wino.Mail.WinUI.Models;
|
||||||
using Wino.Mail.WinUI.Services;
|
using Wino.Mail.WinUI.Services;
|
||||||
|
using Wino.Mail.WinUI.Views;
|
||||||
using Wino.Mail.WinUI.Views.Calendar;
|
using Wino.Mail.WinUI.Views.Calendar;
|
||||||
using Wino.Messaging.Client.Calendar;
|
using Wino.Messaging.Client.Calendar;
|
||||||
using Wino.Messaging.Client.Mails;
|
using Wino.Messaging.Client.Mails;
|
||||||
using Wino.Messaging.Client.Navigation;
|
using Wino.Messaging.Client.Navigation;
|
||||||
using Wino.Mail.WinUI.Views.Contacts;
|
|
||||||
using Wino.Views;
|
using Wino.Views;
|
||||||
using Wino.Views.Account;
|
using Wino.Views.Account;
|
||||||
using Wino.Views.Mail;
|
using Wino.Views.Mail;
|
||||||
@@ -33,6 +33,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
private readonly IStatePersistanceService _statePersistanceService;
|
private readonly IStatePersistanceService _statePersistanceService;
|
||||||
private readonly IDispatcher _dispatcher;
|
private readonly IDispatcher _dispatcher;
|
||||||
private readonly IWinoWindowManager _windowManager;
|
private readonly IWinoWindowManager _windowManager;
|
||||||
|
private NavigationTransitionInfo? _pendingInnerShellTransition;
|
||||||
|
|
||||||
private WinoPage[] _renderingPageTypes = new WinoPage[]
|
private WinoPage[] _renderingPageTypes = new WinoPage[]
|
||||||
{
|
{
|
||||||
@@ -192,48 +193,33 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
if (coreFrame == null) return false;
|
if (coreFrame == null) return false;
|
||||||
|
|
||||||
var currentMode = _statePersistanceService.ApplicationMode;
|
var currentMode = _statePersistanceService.ApplicationMode;
|
||||||
|
var isInitialShellNavigation = coreFrame.Content is not IShellHost;
|
||||||
|
|
||||||
// Update the application mode in state persistence service
|
// Update the application mode in state persistence service
|
||||||
_statePersistanceService.ApplicationMode = mode;
|
_statePersistanceService.ApplicationMode = mode;
|
||||||
_statePersistanceService.AppModeTitle = GetApplicationModeTitle(mode);
|
_statePersistanceService.AppModeTitle = GetApplicationModeTitle(mode);
|
||||||
|
|
||||||
var targetPageType = mode switch
|
if (coreFrame.Content is IShellHost activeShell && activeShell.HasShellContent && currentMode == mode)
|
||||||
{
|
|
||||||
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)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Check if we can go back to the target page
|
_pendingInnerShellTransition = isInitialShellNavigation
|
||||||
if (coreFrame.CanGoBack && coreFrame.BackStack.Count > 0)
|
? null
|
||||||
|
: GetApplicationModeTransitionInfo(currentMode, mode);
|
||||||
|
|
||||||
|
if (coreFrame.Content is not IShellHost)
|
||||||
{
|
{
|
||||||
var previousPage = coreFrame.BackStack[coreFrame.BackStack.Count - 1];
|
coreFrame.BackStack.Clear();
|
||||||
if (previousPage.SourcePageType == targetPageType)
|
coreFrame.ForwardStack.Clear();
|
||||||
{
|
coreFrame.Navigate(typeof(WinoAppShell), null, new SuppressNavigationTransitionInfo());
|
||||||
coreFrame.GoBack(transitionInfo);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we can go forward to the target page
|
if (coreFrame.Content is IShellHost shell)
|
||||||
if (coreFrame.CanGoForward && coreFrame.ForwardStack.Count > 0)
|
|
||||||
{
|
{
|
||||||
var nextPage = coreFrame.ForwardStack[coreFrame.ForwardStack.Count - 1];
|
shell.ActivateMode(mode, isInitialShellNavigation);
|
||||||
if (nextPage.SourcePageType == targetPageType)
|
return true;
|
||||||
{
|
|
||||||
coreFrame.GoForward();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigate to the target page only if it's not in the navigation stack
|
_pendingInnerShellTransition = null;
|
||||||
coreFrame.Navigate(targetPageType, null, transitionInfo);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +286,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return innerShellFrame.Navigate(pageType, parameter);
|
return NavigateInnerShellFrame(innerShellFrame, pageType, parameter, transition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -318,14 +304,14 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var transitionInfo = GetNavigationTransitionInfo(transition);
|
|
||||||
|
|
||||||
// This page must be opened in the Frame placed in MailListingPage.
|
// This page must be opened in the Frame placed in MailListingPage.
|
||||||
if (isMailListingPageActive && frame == NavigationReferenceFrame.RenderingFrame)
|
if (isMailListingPageActive && frame == NavigationReferenceFrame.RenderingFrame)
|
||||||
{
|
{
|
||||||
var listingFrame = GetCoreFrameInternal(NavigationReferenceFrame.RenderingFrame);
|
var listingFrame = GetCoreFrameInternal(NavigationReferenceFrame.RenderingFrame);
|
||||||
if (listingFrame == null) return false;
|
if (listingFrame == null) return false;
|
||||||
|
|
||||||
|
var transitionInfo = GetNavigationTransitionInfo(transition);
|
||||||
|
|
||||||
// Active page is mail list page and we are opening a mail item.
|
// Active page is mail list page and we are opening a mail item.
|
||||||
// No navigation needed, just refresh the rendered mail item.
|
// No navigation needed, just refresh the rendered mail item.
|
||||||
if (listingFrame.Content != null
|
if (listingFrame.Content != null
|
||||||
@@ -361,7 +347,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
|
|||||||
|
|
||||||
if ((currentFrameType != null && currentFrameType != pageType) || currentFrameType == null)
|
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);
|
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)
|
public void GoBack(Core.Domain.Enums.NavigationTransitionEffect slideEffect = Core.Domain.Enums.NavigationTransitionEffect.FromRight)
|
||||||
=> ExecuteOnNavigationThread(() => GoBackInternal(slideEffect));
|
=> ExecuteOnNavigationThread(() => GoBackInternal(slideEffect));
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
<MenuFlyout AreOpenCloseAnimationsEnabled="False">
|
<MenuFlyout AreOpenCloseAnimationsEnabled="False">
|
||||||
<MenuFlyoutItem Command="{x:Bind ShowWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ShowWino}" />
|
<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 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 />
|
<MenuFlyoutSeparator />
|
||||||
<MenuFlyoutItem Command="{x:Bind ExitWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ExitWino}" />
|
<MenuFlyoutItem Command="{x:Bind ExitWinoCommand}" Text="{x:Bind domain:Translator.SystemTrayMenu_ExitWino}" />
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ using Wino.Core.Domain.Models.Synchronization;
|
|||||||
using Wino.Extensions;
|
using Wino.Extensions;
|
||||||
using Wino.Mail.WinUI.Activation;
|
using Wino.Mail.WinUI.Activation;
|
||||||
using Wino.Mail.WinUI.Interfaces;
|
using Wino.Mail.WinUI.Interfaces;
|
||||||
|
using Wino.Mail.WinUI.Views;
|
||||||
using Wino.Messaging.Client.Shell;
|
using Wino.Messaging.Client.Shell;
|
||||||
using Wino.Messaging.UI;
|
using Wino.Messaging.UI;
|
||||||
using Wino.Views;
|
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
|
|
||||||
namespace Wino.Mail.WinUI;
|
namespace Wino.Mail.WinUI;
|
||||||
@@ -139,12 +139,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
|||||||
_ = StartCalendarReminderServerAsync();
|
_ = StartCalendarReminderServerAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mail shell has shell content only for mail list page
|
if (e.Content is BasePage basePage)
|
||||||
// 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)
|
|
||||||
ShellTitleBar.Content = basePage.ShellContent;
|
ShellTitleBar.Content = basePage.ShellContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +167,9 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
|
|||||||
|
|
||||||
public void Receive(TitleBarShellContentUpdated message)
|
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">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<DataTemplate x:Key="CalendarNewEventTemplate" x:DataType="menu:NewMailMenuItem">
|
<DataTemplate x:Key="CalendarNewEventTemplate" x:DataType="menu:NewCalendarEventMenuItem">
|
||||||
<coreControls:WinoNavigationViewItem
|
<coreControls:WinoNavigationViewItem
|
||||||
Height="50"
|
Height="50"
|
||||||
DataContext="{x:Bind}"
|
DataContext="{x:Bind}"
|
||||||
@@ -73,6 +73,7 @@
|
|||||||
|
|
||||||
<coreSelectors:NavigationMenuTemplateSelector
|
<coreSelectors:NavigationMenuTemplateSelector
|
||||||
x:Key="NavigationMenuTemplateSelector"
|
x:Key="NavigationMenuTemplateSelector"
|
||||||
|
CalendarNewEventTemplate="{StaticResource CalendarNewEventTemplate}"
|
||||||
NewMailTemplate="{StaticResource CalendarNewEventTemplate}"
|
NewMailTemplate="{StaticResource CalendarNewEventTemplate}"
|
||||||
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
RatingItemTemplate="{StaticResource RatingItemTemplate}"
|
||||||
SeperatorTemplate="{StaticResource SeperatorTemplate}" />
|
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