diff --git a/Wino.Mail.WinUI/MailAppShell.xaml b/Wino.Mail.WinUI/MailAppShell.xaml deleted file mode 100644 index abf075a3..00000000 --- a/Wino.Mail.WinUI/MailAppShell.xaml +++ /dev/null @@ -1,479 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Wino.Mail.WinUI/MailAppShell.xaml.cs b/Wino.Mail.WinUI/MailAppShell.xaml.cs deleted file mode 100644 index aa295da5..00000000 --- a/Wino.Mail.WinUI/MailAppShell.xaml.cs +++ /dev/null @@ -1,432 +0,0 @@ -using System; -using System.Collections.Generic; -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.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.Data; -using Wino.Mail.WinUI; -using Wino.Mail.WinUI.Controls; -using Wino.MenuFlyouts; -using Wino.MenuFlyouts.Context; -using Wino.Messaging.Client.Accounts; -using Wino.Messaging.Client.Mails; -using Wino.Messaging.Client.Shell; -using Wino.Messaging.UI; -using Wino.Views.Abstract; - -namespace Wino.Views; - -public sealed partial class MailAppShell : MailAppShellAbstract, - IRecipient, - IRecipient, - IRecipient -{ - public Frame GetShellFrame() => InnerShellFrame; - - [GeneratedDependencyProperty] - public partial UIElement? TopShellContent { get; set; } - - public MailAppShell() : base() - { - InitializeComponent(); - PreviewKeyDown += OnPreviewKeyDown; - } - - protected override void OnNavigatedFrom(NavigationEventArgs e) - { - base.OnNavigatedFrom(e); - - Bindings.StopTracking(); - } - - private async void ItemDroppedOnFolder(object sender, DragEventArgs e) - { - // Validate package content. - if (sender is WinoNavigationViewItem droppedContainer) - { - droppedContainer.IsDraggingItemOver = false; - - if (CanContinueDragDrop(droppedContainer, e)) - { - if (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.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) - { - // TODO: Maybe override caption with some information why the validation failed? - // Note: Caption has a max length. It may be trimmed in some languages. - - if (interactingContainer == null || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage))) return false; - - var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; - - // Invalid package. - if (dragPackage == null || !dragPackage.DraggingMails.Any()) return false; - - // Check whether source and target folder are the same. - if (interactingContainer.IsSelected) return false; - - // Check if the interacting container is a folder. - if (!(interactingContainer.DataContext is IBaseFolderMenuItem folderMenuItem)) return false; - - // Check if the folder is a move target. - if (!folderMenuItem.IsMoveTarget) return false; - - // Check whether the moving item's account has at least one same as the target folder's account. - var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId); - - var draggedMails = ExtractMailCopies(dragPackage); - - if (!draggedMails.Any()) return false; - if (!draggedMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false; - - return true; - } - - private static IEnumerable 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) - { - // Validate package content. - if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e)) - { - droppedContainer.IsDraggingItemOver = true; - - var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem; - - if (draggingFolder == null) return; - - e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; - e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName); - } - } - - public async void Receive(AccountMenuItemExtended message) - { - await DispatcherQueue.EnqueueAsync(async () => - { - if (message.FolderId == default) return; - - if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem)) - { - foundMenuItem.Expand(); - - await ViewModel.NavigateFolderAsync(foundMenuItem); - - navigationView.SelectedItem = foundMenuItem; - - if (message.NavigateMailItem == null) return; - - // At this point folder is navigated and items are loaded. - WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true)); - } - else if (ViewModel.MenuItems.TryGetAccountMenuItem(message.NavigateMailItem.AssignedAccount.Id, out IAccountMenuItem accountMenuItem)) - { - // Loaded account is different. First change the folder items and navigate. - - await ViewModel.ChangeLoadedAccountAsync(accountMenuItem, navigateInbox: false); - - // Find the folder. - - if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem accountFolderMenuItem)) - { - accountFolderMenuItem.Expand(); - - await ViewModel.NavigateFolderAsync(accountFolderMenuItem); - - navigationView.SelectedItem = accountFolderMenuItem; - - // At this point folder is navigated and items are loaded. - WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId, ScrollToItem: true)); - } - } - }); - } - - private async void MenuSelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) - { - if (args.SelectedItem is IMenuItem invokedMenuItem) - { - await ViewModel.MenuItemInvokedOrSelectedAsync(invokedMenuItem); - } - } - - private async void NavigationViewItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args) - { - // SelectsOnInvoked is handled in MenuSelectionChanged. - // This part is only for the items that are not selectable. - if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem) - { - if (winoNavigationViewItem.SelectsOnInvoked) return; - - await ViewModel.MenuItemInvokedOrSelectedAsync(winoNavigationViewItem.DataContext as IMenuItem); - } - } - - public void Receive(NavigateMailFolderEvent message) - { - if (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); - - // Prevent double navigation. - navigationView.SelectionChanged -= MenuSelectionChanged; - navigationView.SelectedItem = message.BaseFolderMenuItem; - navigationView.SelectionChanged += MenuSelectionChanged; - } - else - { - // Complete the init task since we are already on the right page. - message.FolderInitLoadAwaitTask?.TrySetResult(true); - } - } - - private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) => TopShellContent = ((BasePage)e.Content).ShellContent; - - partial void OnTopShellContentChanged(UIElement? newValue) => WeakReferenceMessenger.Default.Send(new TitleBarShellContentUpdated()); - - private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args) - { - // Delegate this request to ViewModel. - // VM will prepare available actions for this folder and show Menu Flyout. - - 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(); - - var actions = ViewModel.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(); - - // No action selected. - if (operation == null) return; - - await ViewModel.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem); - } - } - - public void Receive(CreateNewMailWithMultipleAccountsRequested message) - { - // Find the NewMail menu item container. - - var container = navigationView.ContainerFromMenuItem(ViewModel.CreateMailMenuItem); - - var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.CreateNewMailForAsync); - - flyout.ShowAt(container, new FlyoutShowOptions() - { - ShowMode = FlyoutShowMode.Auto, - Placement = FlyoutPlacementMode.Right - }); - } - - private void NavigationPaneOpening(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) - { - // It's annoying that NavigationView doesn't respect expansion state of the items in Minimal display mode. - // Expanded items are collaped, and users need to expand them again. - // Regardless of the reason, we will expand the selected item if it's a folder with parent account for visibility. - - if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem) - { - selectedFolderMenuItem.Expand(); - } - } - - private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) - { - if (args.DisplayMode == NavigationViewDisplayMode.Minimal) - { - InnerShellFrame.Margin = new Thickness(7, 0, 0, 0); - } - else - { - InnerShellFrame.Margin = 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 shortcutService = WinoApplication.Current.Services.GetRequiredService(); - var shortcut = await shortcutService.GetShortcutForKeyAsync(WinoApplicationMode.Mail, 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.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 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(this); - WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); - } - - protected override void UnregisterRecipients() - { - base.UnregisterRecipients(); - - WeakReferenceMessenger.Default.Unregister(this); - WeakReferenceMessenger.Default.Unregister(this); - WeakReferenceMessenger.Default.Unregister(this); - } -} diff --git a/Wino.Mail.WinUI/Views/Abstract/CalendarAppShellAbstract .cs b/Wino.Mail.WinUI/Views/Abstract/CalendarAppShellAbstract .cs deleted file mode 100644 index 446fde16..00000000 --- a/Wino.Mail.WinUI/Views/Abstract/CalendarAppShellAbstract .cs +++ /dev/null @@ -1,12 +0,0 @@ -using Wino.Calendar.ViewModels; -using Wino.Mail.WinUI; - -namespace Wino.Mail.Views.Abstract; - -public abstract class CalendarAppShellAbstract : BasePage -{ - protected CalendarAppShellAbstract() - { - NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled; - } -} diff --git a/Wino.Mail.WinUI/Views/Abstract/MailAppShellAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/MailAppShellAbstract.cs deleted file mode 100644 index 48a9f9fe..00000000 --- a/Wino.Mail.WinUI/Views/Abstract/MailAppShellAbstract.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Wino.Mail.ViewModels; -using Wino.Mail.WinUI; - -namespace Wino.Views.Abstract; - -public abstract class MailAppShellAbstract : BasePage -{ - protected MailAppShellAbstract() - { - NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Disabled; - } -} diff --git a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml b/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml deleted file mode 100644 index ad3f5a72..00000000 --- a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml.cs b/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml.cs deleted file mode 100644 index 04d77cde..00000000 --- a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System; -using System.Diagnostics; -using System.ComponentModel; -using System.Threading.Tasks; -using CommunityToolkit.Mvvm.Messaging; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Input; -using Microsoft.UI.Xaml.Navigation; -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.Calendar; -using Wino.Mail.Views.Abstract; -using Wino.Messaging.Client.Calendar; -using Windows.System; - -namespace Wino.Mail.WinUI.Views.Calendar; - -public sealed partial class CalendarAppShell : CalendarAppShellAbstract, - IRecipient -{ - private const string STATE_HorizontalCalendar = "HorizontalCalendar"; - private const string STATE_VerticalCalendar = "VerticalCalendar"; - private bool _isSynchronizingVisibleDateRangeCalendar; - - public Frame GetShellFrame() => InnerShellFrame; - - public CalendarAppShell() - { - InitializeComponent(); - - ViewModel.PropertyChanged += ViewModelPropertyChanged; - ManageCalendarDisplayType(ViewModel.StatePersistenceService.CalendarDisplayType); - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - UpdateNavigationPaneLayout(navigationView.DisplayMode); - SynchronizeVisibleDateRangeCalendar(); - } - - private void ManageCalendarDisplayType(Core.Domain.Enums.CalendarDisplayType displayType) - { - if (displayType == Core.Domain.Enums.CalendarDisplayType.Month) - { - VisualStateManager.GoToState(this, STATE_VerticalCalendar, false); - } - else - { - VisualStateManager.GoToState(this, STATE_HorizontalCalendar, false); - } - } - - private void PreviousDateClicked(object sender, RoutedEventArgs e) - => ViewModel.PreviousDateRangeCommand.Execute(null); - - private void NextDateClicked(object sender, RoutedEventArgs e) - => ViewModel.NextDateRangeCommand.Execute(null); - - private async void NewCalendarEventNavigationItemTapped(object sender, TappedRoutedEventArgs e) - { - e.Handled = true; - await InvokeNewCalendarEventAsync(); - } - - private void VisibleDateRangeCalendarViewSelectedDatesChanged(CalendarView sender, CalendarViewSelectedDatesChangedEventArgs args) - { - if (_isSynchronizingVisibleDateRangeCalendar) - return; - - DateTimeOffset? interactedDate = null; - - if (args.AddedDates.Count > 0) - { - interactedDate = args.AddedDates[0]; - } - else if (args.RemovedDates.Count > 0) - { - interactedDate = args.RemovedDates[0]; - } - - if (interactedDate is null) - return; - - var clickedArgs = new CalendarViewDayClickedEventArgs(interactedDate.Value.DateTime); - - if (ViewModel.DateClickedCommand.CanExecute(clickedArgs)) - { - ViewModel.DateClickedCommand.Execute(clickedArgs); - } - } - - private async void NewCalendarEventNavigationItemKeyDown(object sender, KeyRoutedEventArgs e) - { - if (e.Key is not (VirtualKey.Enter or VirtualKey.Space)) - return; - - e.Handled = true; - await InvokeNewCalendarEventAsync(); - } - - private async void NavigationViewItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) - { - if (args.InvokedItemContainer is FrameworkElement { DataContext: IMenuItem menuItem }) - { - await ViewModel.HandleNavigationItemInvokedAsync(menuItem); - } - } - - private void NavigationViewDisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) - => UpdateNavigationPaneLayout(args.DisplayMode); - - private void NavigationPaneOpened(NavigationView sender, object args) - => UpdateNavigationPaneLayout(sender.DisplayMode); - - private void NavigationPaneClosed(NavigationView sender, object args) - => UpdateNavigationPaneLayout(sender.DisplayMode); - - private Task InvokeNewCalendarEventAsync() - => ViewModel.HandleNavigationItemInvokedAsync(new NewCalendarEventMenuItem()); - - private void UpdateNavigationPaneLayout(NavigationViewDisplayMode displayMode) - { - var paneContentVisibility = displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen - ? Visibility.Visible - : Visibility.Collapsed; - - PaneCustomContent.Visibility = paneContentVisibility; - - Debug.WriteLine($"NavigationView display mode changed to {displayMode}. Pane custom content visibility set to {paneContentVisibility}."); - } - - public void Receive(CalendarDisplayTypeChangedMessage message) - { - ManageCalendarDisplayType(message.NewDisplayType); - SynchronizeVisibleDateRangeCalendar(); - } - - private void ViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (e.PropertyName is nameof(ViewModel.CurrentVisibleRange) or nameof(ViewModel.VisibleDateRangeText)) - { - SynchronizeVisibleDateRangeCalendar(); - } - } - - protected override void OnNavigatedFrom(NavigationEventArgs e) - { - base.OnNavigatedFrom(e); - - InnerShellFrame.BackStack.Clear(); - InnerShellFrame.ForwardStack.Clear(); - - if (InnerShellFrame.Content is IDisposable disposableContent) - { - disposableContent.Dispose(); - } - - Bindings.StopTracking(); - } - - protected override void RegisterRecipients() - { - base.RegisterRecipients(); - - WeakReferenceMessenger.Default.Register(this); - } - - protected override void UnregisterRecipients() - { - base.UnregisterRecipients(); - - WeakReferenceMessenger.Default.Unregister(this); - } - - 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 shortcutService = WinoApplication.Current.Services.GetRequiredService(); - var shortcut = await shortcutService.GetShortcutForKeyAsync(WinoApplicationMode.Calendar, 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.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 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() - }; - } - - private void SynchronizeVisibleDateRangeCalendar() - { - if (!DispatcherQueue.HasThreadAccess) - { - var enqueued = DispatcherQueue.TryEnqueue(SynchronizeVisibleDateRangeCalendar); - - if (!enqueued) - throw new InvalidOperationException("Could not marshal visible date range calendar synchronization onto the UI thread."); - - return; - } - - _isSynchronizingVisibleDateRangeCalendar = true; - - try - { - VisibleDateRangeCalendarView.SelectedDates.Clear(); - - var currentRange = ViewModel.CurrentVisibleRange; - if (currentRange == null) - return; - - foreach (var date in currentRange.Dates) - { - VisibleDateRangeCalendarView.SelectedDates.Add(new DateTimeOffset(date.ToDateTime(TimeOnly.MinValue))); - } - - VisibleDateRangeCalendarView.SetDisplayDate(new DateTimeOffset(currentRange.AnchorDate.ToDateTime(TimeOnly.MinValue))); - } - finally - { - _isSynchronizingVisibleDateRangeCalendar = false; - } - } -} diff --git a/Wino.Mail.WinUI/Views/WinoAppShell.xaml b/Wino.Mail.WinUI/Views/WinoAppShell.xaml index 9abeecca..5ee54cb0 100644 --- a/Wino.Mail.WinUI/Views/WinoAppShell.xaml +++ b/Wino.Mail.WinUI/Views/WinoAppShell.xaml @@ -568,27 +568,14 @@ Text="{x:Bind domain:Translator.CalendarEventCompose_NewEventButton, Mode=OneTime}" /> - - - - - - - + Margin="12,0" + HorizontalAlignment="Stretch" + SelectedDatesChanged="VisibleDateRangeCalendarViewSelectedDatesChanged" + SelectionMode="Multiple" + Style="{StaticResource WinoCalendarViewStyle}" /> dayOfWeek switch + { + DayOfWeek.Sunday => Windows.Globalization.DayOfWeek.Sunday, + DayOfWeek.Monday => Windows.Globalization.DayOfWeek.Monday, + DayOfWeek.Tuesday => Windows.Globalization.DayOfWeek.Tuesday, + DayOfWeek.Wednesday => Windows.Globalization.DayOfWeek.Wednesday, + DayOfWeek.Thursday => Windows.Globalization.DayOfWeek.Thursday, + DayOfWeek.Friday => Windows.Globalization.DayOfWeek.Friday, + DayOfWeek.Saturday => Windows.Globalization.DayOfWeek.Saturday, + _ => Windows.Globalization.DayOfWeek.Monday + }; + private void ViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(ViewModel.SelectedMenuItem) || !ViewModel.CurrentClient.HandlesNavigationSelection)