From bf331dfeb3b54bd8d3421995a79b2395429c5257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Tue, 10 Mar 2026 16:50:16 +0100 Subject: [PATCH] Better shell --- .../CalendarAppShellViewModel.cs | 63 +- Wino.Core.Domain/Enums/WinoApplicationMode.cs | 3 +- .../Translations/en_US/resources.json | 1 + .../Data/KeyboardShortcutViewModel.cs | 1 + .../AppPreferencesPageViewModel.cs | 3 +- Wino.Mail.ViewModels/MailAppShellViewModel.cs | 41 - .../Activation/AppModeActivationResolver.cs | 19 +- Wino.Mail.WinUI/App.xaml | 1 + Wino.Mail.WinUI/App.xaml.cs | 7 +- .../AppModeFooterSwitcherControl.xaml | 30 + .../AppModeFooterSwitcherControl.xaml.cs | 75 ++ .../Calendar/CalendarItemControl.xaml | 2 +- .../Controls/UpdateNotesFlipViewControl.xaml | 12 +- .../Dialogs/AccountPickerDialog.xaml | 4 +- .../Dialogs/AccountReorderDialog.xaml | 8 +- .../Dialogs/ContactEditDialog.xaml | 4 +- .../Dialogs/CreateAccountAliasDialog.xaml | 4 +- .../Dialogs/CustomThemeBuilderDialog.xaml | 4 +- Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml | 10 +- Wino.Mail.WinUI/Dialogs/PrintDialog.xaml | 4 +- .../SystemFolderConfigurationDialog.xaml | 2 +- Wino.Mail.WinUI/MailAppShell.xaml | 5 +- Wino.Mail.WinUI/Services/NavigationService.cs | 70 +- Wino.Mail.WinUI/ShellWindow.xaml | 24 +- Wino.Mail.WinUI/ShellWindow.xaml.cs | 41 +- .../CalendarShellNavigationViewStyle.xaml | 890 ++++++++++++++++++ .../Abstract/ContactsAppShellAbstract.cs | 9 + .../Views/AccountSetupProgressPage.xaml | 8 +- .../Calendar/CalendarAccountSettingsPage.xaml | 16 +- .../Views/Calendar/CalendarAppShell.xaml | 218 ++--- .../Views/Calendar/CalendarAppShell.xaml.cs | 37 + .../Calendar/CalendarEventComposePage.xaml | 4 +- .../Views/Calendar/CalendarPage.xaml | 2 +- .../Views/Calendar/EventDetailsPage.xaml | 6 +- .../Views/Contacts/ContactsAppShell.xaml | 46 + .../Views/Contacts/ContactsAppShell.xaml.cs | 38 + .../Views/Settings/ContactsPage.xaml | 2 +- .../Settings/CreateEmailTemplatePage.xaml | 12 +- .../Views/Settings/EmailTemplatesPage.xaml | 2 +- .../Views/Settings/PersonalizationPage.xaml | 9 +- .../Views/Settings/StoragePage.xaml | 9 +- Wino.Mail.WinUI/Views/WelcomeHostPage.xaml | 4 +- Wino.Mail.WinUI/Wino.Mail.WinUI.csproj | 6 + 43 files changed, 1416 insertions(+), 340 deletions(-) create mode 100644 Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml create mode 100644 Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml.cs create mode 100644 Wino.Mail.WinUI/Styles/CalendarShellNavigationViewStyle.xaml create mode 100644 Wino.Mail.WinUI/Views/Abstract/ContactsAppShellAbstract.cs create mode 100644 Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml create mode 100644 Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml.cs diff --git a/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs b/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs index 8930f74b..42789c62 100644 --- a/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs +++ b/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs @@ -16,6 +16,7 @@ using Wino.Core.Domain.Collections; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Extensions; using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.MenuItems; using Wino.Core.Domain.Models.Calendar; using Wino.Core.Domain.Models; using Wino.Core.Domain.Models.Navigation; @@ -40,6 +41,9 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, public IAccountCalendarStateService AccountCalendarStateService { get; } public INavigationService NavigationService { get; } + public MenuItemCollection MenuItems { get; private set; } + public MenuItemCollection FooterItems { get; private set; } + [ObservableProperty] private int _selectedMenuItemIndex = -1; @@ -71,6 +75,11 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, [ObservableProperty] private bool isStoreUpdateItemVisible; + private readonly ManageAccountsMenuItem _manageAccountsMenuItem = new(); + private readonly SettingsItem _settingsItem = new(); + private readonly StoreUpdateMenuItem _storeUpdateMenuItem = new(); + private readonly NewMailMenuItem _newEventMenuItem = new(); + // For updating account calendars asynchronously. private SemaphoreSlim _accountCalendarUpdateSemaphoreSlim = new(1); @@ -106,6 +115,9 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, base.OnDispatcherAssigned(); AccountCalendarStateService.Dispatcher = Dispatcher; + MenuItems = new MenuItemCollection(Dispatcher); + FooterItems = new MenuItemCollection(Dispatcher); + MenuItems.Add(_newEventMenuItem); _ = RefreshFooterItemsAsync(false); } @@ -183,11 +195,9 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, private async Task RefreshFooterItemsAsync(bool showNotification) { - await _storeUpdateService.RefreshAvailabilityAsync(showNotification).ConfigureAwait(false); - await ExecuteUIThread(() => { - IsStoreUpdateItemVisible = _storeUpdateService.HasAvailableUpdate && PreferencesService.IsStoreUpdateNotificationsEnabled; + FooterItems.Clear(); }); } @@ -263,26 +273,7 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, _navigationDate = null; } - partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue) - { - if (newValue < 0) - return; - - if (newValue == 0) - { - NavigationService.Navigate(WinoPage.ManageAccountsPage); - } - else if (newValue == 1) - { - NavigationService.Navigate(WinoPage.SettingsPage); - } - else if (IsStoreUpdateItemVisible && newValue == 2) - { - _ = StartStoreUpdateAsync(); - } - - SelectedMenuItemIndex = -1; - } + partial void OnSelectedMenuItemIndexChanged(int oldValue, int newValue) { } [RelayCommand] private async Task Sync() @@ -353,6 +344,25 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, [RelayCommand] public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage); + public async Task HandleNavigationItemInvokedAsync(IMenuItem menuItem) + { + switch (menuItem) + { + case NewMailMenuItem: + await NewEventAsync().ConfigureAwait(false); + break; + case ManageAccountsMenuItem: + NavigationService.Navigate(WinoPage.ManageAccountsPage); + break; + case SettingsItem: + NavigationService.Navigate(WinoPage.SettingsPage); + break; + case StoreUpdateMenuItem: + await StartStoreUpdateAsync().ConfigureAwait(false); + break; + } + } + [RelayCommand] private async Task NewEventAsync() { @@ -521,12 +531,15 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, return new DateTime(dominantKey.Year, dominantKey.Month, 1).ToString("Y", cultureInfo); } - partial void OnHighlightedDateRangeChanged(DateRange value) => UpdateDateNavigationHeaderItems(); + partial void OnHighlightedDateRangeChanged(DateRange value) + { + UpdateDateNavigationHeaderItems(); + } public async void Receive(CalendarEnableStatusChangedMessage message) => await ExecuteUIThread(() => IsCalendarEnabled = message.IsEnabled); - public void Receive(NavigateManageAccountsRequested message) => SelectedMenuItemIndex = 0; + public void Receive(NavigateManageAccountsRequested message) => NavigationService.Navigate(WinoPage.ManageAccountsPage); public void Receive(CalendarDisplayTypeChangedMessage message) { diff --git a/Wino.Core.Domain/Enums/WinoApplicationMode.cs b/Wino.Core.Domain/Enums/WinoApplicationMode.cs index 3c51ece4..bee901db 100644 --- a/Wino.Core.Domain/Enums/WinoApplicationMode.cs +++ b/Wino.Core.Domain/Enums/WinoApplicationMode.cs @@ -3,5 +3,6 @@ public enum WinoApplicationMode { Mail, - Calendar + Calendar, + Contacts } diff --git a/Wino.Core.Domain/Translations/en_US/resources.json b/Wino.Core.Domain/Translations/en_US/resources.json index 8d87609c..08a75252 100644 --- a/Wino.Core.Domain/Translations/en_US/resources.json +++ b/Wino.Core.Domain/Translations/en_US/resources.json @@ -952,6 +952,7 @@ "SystemFolderConfigSetupSuccess_Title": "System Folders Setup", "SystemTrayMenu_ShowWino": "Open Wino Mail", "SystemTrayMenu_ShowWinoCalendar": "Open Wino Calendar", + "SystemTrayMenu_ShowWinoContacts": "Open Wino Contacts", "SystemTrayMenu_ExitWino": "Exit", "TestingImapConnectionMessage": "Testing server connection...", "TitleBarServerDisconnectedButton_Description": "Wino is disconnected from the network. Click reconnect to restore connection.", diff --git a/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs b/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs index 6ee4e1cb..e664a701 100644 --- a/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs +++ b/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs @@ -43,6 +43,7 @@ public partial class KeyboardShortcutViewModel : ObservableObject { WinoApplicationMode.Mail => Translator.KeyboardShortcuts_ModeMail, WinoApplicationMode.Calendar => Translator.KeyboardShortcuts_ModeCalendar, + WinoApplicationMode.Contacts => Translator.ContactsPage_Title, _ => Mode.ToString() }; diff --git a/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs b/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs index 76b292eb..5c0ab298 100644 --- a/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs +++ b/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs @@ -83,7 +83,8 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel ApplicationModes = [ Translator.SettingsAppPreferences_ApplicationMode_Mail, - Translator.SettingsAppPreferences_ApplicationMode_Calendar + Translator.SettingsAppPreferences_ApplicationMode_Calendar, + Translator.ContactsPage_Title ]; SelectedDefaultSearchMode = SearchModes[(int)PreferencesService.DefaultSearchMode]; diff --git a/Wino.Mail.ViewModels/MailAppShellViewModel.cs b/Wino.Mail.ViewModels/MailAppShellViewModel.cs index 7580c175..277377d2 100644 --- a/Wino.Mail.ViewModels/MailAppShellViewModel.cs +++ b/Wino.Mail.ViewModels/MailAppShellViewModel.cs @@ -149,30 +149,9 @@ public partial class MailAppShellViewModel : MailBaseViewModel, private async Task CreateFooterItemsAsync(bool showNotification = false) { - await _storeUpdateService.RefreshAvailabilityAsync(showNotification).ConfigureAwait(false); - await ExecuteUIThread(() => { - // TODO: Selected footer item container still remains selected after re-creation. - // To reproduce, go settings and change the language. - - foreach (var item in FooterItems) - { - item.IsExpanded = false; - item.IsSelected = false; - } - FooterItems.Clear(); - - FooterItems.Add(ContactsMenuItem); - FooterItems.Add(ManageAccountsMenuItem); - - if (_storeUpdateService.HasAvailableUpdate && PreferencesService.IsStoreUpdateNotificationsEnabled) - { - FooterItems.Add(StoreUpdateMenuItem); - } - - FooterItems.Add(SettingsItem); }); } @@ -669,26 +648,6 @@ public partial class MailAppShellViewModel : MailBaseViewModel, // Don't navigate to merged account if it's already selected. Preserve user's already selected folder. await ChangeLoadedAccountAsync(clickedMergedAccountMenuItem, true); } - else if (clickedMenuItem is StoreUpdateMenuItem) - { - await _storeUpdateService.StartUpdateAsync().ConfigureAwait(false); - await CreateFooterItemsAsync().ConfigureAwait(false); - } - else if (clickedMenuItem is SettingsItem) - { - NavigationService.Navigate(WinoPage.SettingsPage, parameter, NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType.None); - UpdateWindowTitle(Translator.MenuSettings); - } - else if (clickedMenuItem is ManageAccountsMenuItem) - { - NavigationService.Navigate(WinoPage.ManageAccountsPage, parameter, NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType.None); - UpdateWindowTitle(Translator.MenuManageAccounts); - } - else if (clickedMenuItem is ContactsMenuItem) - { - NavigationService.Navigate(WinoPage.ContactsPage, parameter, NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType.None); - UpdateWindowTitle(Translator.ContactsPage_Title); - } else if (clickedMenuItem is IAccountMenuItem clickedAccountMenuItem) { // Changing loaded account. diff --git a/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs b/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs index ca84b5e1..9a617203 100644 --- a/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs +++ b/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs @@ -43,6 +43,16 @@ internal static class AppModeActivationResolver return true; } + if (Contains(value, "wino-contacts") || + Contains(value, "--mode=contacts") || + Contains(value, "mode=contacts") || + Contains(value, "contactsapp") || + EqualsToken(value, "contacts")) + { + mode = WinoApplicationMode.Contacts; + return true; + } + if (Contains(value, "wino-mail") || Contains(value, "--mode=mail") || Contains(value, "mode=mail") || @@ -63,7 +73,10 @@ internal static class AppModeActivationResolver => string.Equals(source.Trim(), token, StringComparison.OrdinalIgnoreCase); private static WinoApplicationMode GetOpposite(WinoApplicationMode defaultMode) - => defaultMode == WinoApplicationMode.Mail - ? WinoApplicationMode.Calendar - : WinoApplicationMode.Mail; + => defaultMode switch + { + WinoApplicationMode.Mail => WinoApplicationMode.Calendar, + WinoApplicationMode.Calendar => WinoApplicationMode.Mail, + _ => WinoApplicationMode.Mail + }; } diff --git a/Wino.Mail.WinUI/App.xaml b/Wino.Mail.WinUI/App.xaml index c9a30e23..ddc385cd 100644 --- a/Wino.Mail.WinUI/App.xaml +++ b/Wino.Mail.WinUI/App.xaml @@ -26,6 +26,7 @@ + diff --git a/Wino.Mail.WinUI/App.xaml.cs b/Wino.Mail.WinUI/App.xaml.cs index 25eec544..c920308f 100644 --- a/Wino.Mail.WinUI/App.xaml.cs +++ b/Wino.Mail.WinUI/App.xaml.cs @@ -954,7 +954,12 @@ public partial class App : WinoApplication, } private static string GetModeLaunchArgument(WinoApplicationMode mode) - => mode == WinoApplicationMode.Calendar ? "--mode=calendar" : "--mode=mail"; + => mode switch + { + WinoApplicationMode.Calendar => "--mode=calendar", + WinoApplicationMode.Contacts => "--mode=contacts", + _ => "--mode=mail" + }; private static string AppendLaunchArgument(string? launchArguments, string launchArgument) { diff --git a/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml b/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml new file mode 100644 index 00000000..14b7381a --- /dev/null +++ b/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml.cs b/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml.cs new file mode 100644 index 00000000..07ae3ecb --- /dev/null +++ b/Wino.Mail.WinUI/Controls/AppModeFooterSwitcherControl.xaml.cs @@ -0,0 +1,75 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; + +namespace Wino.Mail.WinUI.Controls; + +public sealed partial class AppModeFooterSwitcherControl : UserControl +{ + private readonly IStatePersistanceService _statePersistenceService; + private readonly INavigationService _navigationService; + private bool _isUpdatingSelection; + + public AppModeFooterSwitcherControl() + { + _statePersistenceService = WinoApplication.Current.Services.GetRequiredService(); + _navigationService = WinoApplication.Current.Services.GetRequiredService(); + + InitializeComponent(); + + Loaded += ControlLoaded; + Unloaded += ControlUnloaded; + } + + private void ControlLoaded(object sender, RoutedEventArgs e) + { + _statePersistenceService.StatePropertyChanged += StatePropertyChanged; + UpdateSelection(_statePersistenceService.ApplicationMode); + } + + private void ControlUnloaded(object sender, RoutedEventArgs e) + { + _statePersistenceService.StatePropertyChanged -= StatePropertyChanged; + } + + private void StatePropertyChanged(object? sender, string propertyName) + { + if (propertyName != nameof(IStatePersistanceService.ApplicationMode)) + return; + + DispatcherQueue.TryEnqueue(() => UpdateSelection(_statePersistenceService.ApplicationMode)); + } + + private void ModeSegmentedControlSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (_isUpdatingSelection) + return; + + var selectedMode = ModeSegmentedControl.SelectedIndex switch + { + 1 => WinoApplicationMode.Calendar, + 2 => WinoApplicationMode.Contacts, + _ => WinoApplicationMode.Mail + }; + + if (selectedMode == _statePersistenceService.ApplicationMode) + return; + + _navigationService.ChangeApplicationMode(selectedMode); + } + + private void UpdateSelection(WinoApplicationMode mode) + { + _isUpdatingSelection = true; + ModeSegmentedControl.SelectedIndex = mode switch + { + WinoApplicationMode.Calendar => 1, + WinoApplicationMode.Contacts => 2, + _ => 0 + }; + _isUpdatingSelection = false; + } +} diff --git a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml index 64ce0b93..86ed725b 100644 --- a/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml +++ b/Wino.Mail.WinUI/Controls/Calendar/CalendarItemControl.xaml @@ -80,9 +80,9 @@ - + - + @@ -44,7 +40,7 @@ x:Name="FlipViewPager" Grid.Row="1" HorizontalAlignment="Center" - SelectedPageIndex="0" - SelectedIndexChanged="OnPipsPagerSelectedIndexChanged" /> + SelectedIndexChanged="OnPipsPagerSelectedIndexChanged" + SelectedPageIndex="0" /> diff --git a/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml index 7f687443..a7011a04 100644 --- a/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml +++ b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml @@ -30,9 +30,7 @@ - + diff --git a/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml index a5054555..16fbea2e 100644 --- a/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml +++ b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml @@ -49,9 +49,7 @@ Grid.Column="2" VerticalAlignment="Center" Spacing="2"> - + - + + CornerRadius="6"> diff --git a/Wino.Mail.WinUI/Dialogs/CreateAccountAliasDialog.xaml b/Wino.Mail.WinUI/Dialogs/CreateAccountAliasDialog.xaml index cb597444..02f2efe1 100644 --- a/Wino.Mail.WinUI/Dialogs/CreateAccountAliasDialog.xaml +++ b/Wino.Mail.WinUI/Dialogs/CreateAccountAliasDialog.xaml @@ -19,9 +19,7 @@ - + + Background="{ThemeResource SystemAccentColor}" + CornerRadius="4" /> diff --git a/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml index 7bbb0911..4555e190 100644 --- a/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml +++ b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml @@ -46,15 +46,13 @@ - + Visibility="Collapsed"> + + CornerRadius="6"> diff --git a/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml index cc5d2ec2..8160a698 100644 --- a/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml +++ b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml @@ -94,9 +94,9 @@ diff --git a/Wino.Mail.WinUI/MailAppShell.xaml b/Wino.Mail.WinUI/MailAppShell.xaml index 26a68ea0..abf075a3 100644 --- a/Wino.Mail.WinUI/MailAppShell.xaml +++ b/Wino.Mail.WinUI/MailAppShell.xaml @@ -375,9 +375,7 @@ @@ -402,11 +399,11 @@ Grid.Row="1" Grid.ColumnSpan="3" Margin="-1,-1,0,0" + Style="{StaticResource CalendarShellNavigationViewStyle}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" AlwaysShowHeader="True" DisplayModeChanged="NavigationViewDisplayModeChanged" - FooterMenuItemsSource="{x:Bind ViewModel.FooterItems, Mode=OneWay}" IsBackButtonVisible="Collapsed" IsPaneOpen="{x:Bind ViewModel.PreferencesService.IsNavigationPaneOpened, Mode=TwoWay}" IsPaneToggleButtonVisible="False" diff --git a/Wino.Mail.WinUI/Services/NavigationService.cs b/Wino.Mail.WinUI/Services/NavigationService.cs index 5a0a1abb..d1e9ebf0 100644 --- a/Wino.Mail.WinUI/Services/NavigationService.cs +++ b/Wino.Mail.WinUI/Services/NavigationService.cs @@ -19,10 +19,12 @@ using Wino.Mail.WinUI.Views.Calendar; using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Mails; using Wino.Messaging.Client.Navigation; +using Wino.Mail.WinUI.Views.Contacts; using Wino.Views; using Wino.Views.Account; using Wino.Views.Mail; using Wino.Views.Settings; +using Microsoft.UI.Xaml.Media.Animation; namespace Wino.Services; @@ -58,6 +60,11 @@ public class NavigationService : NavigationServiceBase, INavigationService WinoPage.CalendarEventComposePage ]; + private static readonly WinoPage[] ContactsOnlyPages = + [ + WinoPage.ContactsPage + ]; + public NavigationService(IStatePersistanceService statePersistanceService, IDispatcher dispatcher, IWinoWindowManager windowManager) { _statePersistanceService = statePersistanceService; @@ -184,15 +191,20 @@ public class NavigationService : NavigationServiceBase, INavigationService if (coreFrame == null) return false; + var currentMode = _statePersistanceService.ApplicationMode; + // Update the application mode in state persistence service _statePersistanceService.ApplicationMode = mode; - _statePersistanceService.AppModeTitle = mode == WinoApplicationMode.Calendar - ? "Wino Calendar" - : "Wino Mail"; + _statePersistanceService.AppModeTitle = GetApplicationModeTitle(mode); - var targetPageType = mode == WinoApplicationMode.Mail ? typeof(MailAppShell) : typeof(CalendarAppShell); + var targetPageType = mode switch + { + WinoApplicationMode.Calendar => typeof(CalendarAppShell), + WinoApplicationMode.Contacts => typeof(ContactsAppShell), + _ => typeof(MailAppShell) + }; var currentPageType = coreFrame.Content?.GetType(); - var transitionInfo = GetNavigationTransitionInfo(NavigationTransitionType.DrillIn); + var transitionInfo = GetApplicationModeTransitionInfo(currentMode, mode); // If already on the target page, do nothing if (currentPageType == targetPageType) @@ -241,12 +253,7 @@ public class NavigationService : NavigationServiceBase, INavigationService var currentApplicationMode = _statePersistanceService.ApplicationMode; - if (currentApplicationMode == WinoApplicationMode.Calendar && IsMailOnlyPage(page)) - { - return false; - } - - if (currentApplicationMode == WinoApplicationMode.Mail && IsCalendarOnlyPage(page)) + if (!IsPageAllowedInMode(currentApplicationMode, page)) { return false; } @@ -368,6 +375,47 @@ public class NavigationService : NavigationServiceBase, INavigationService private static bool IsCalendarOnlyPage(WinoPage page) => CalendarOnlyPages.Contains(page); + private static bool IsContactsOnlyPage(WinoPage page) + => ContactsOnlyPages.Contains(page); + + private static bool IsPageAllowedInMode(WinoApplicationMode mode, WinoPage page) + => mode switch + { + WinoApplicationMode.Mail => !IsCalendarOnlyPage(page) && !IsContactsOnlyPage(page), + WinoApplicationMode.Calendar => !IsMailOnlyPage(page) && !IsContactsOnlyPage(page), + WinoApplicationMode.Contacts => !IsMailOnlyPage(page) && !IsCalendarOnlyPage(page), + _ => true + }; + + private static string GetApplicationModeTitle(WinoApplicationMode mode) + => mode switch + { + WinoApplicationMode.Calendar => "Wino Calendar", + WinoApplicationMode.Contacts => "Wino Contacts", + _ => "Wino Mail" + }; + + private static NavigationTransitionInfo GetApplicationModeTransitionInfo(WinoApplicationMode currentMode, WinoApplicationMode targetMode) + { + var slideEffect = IsNextMode(currentMode, targetMode) + ? SlideNavigationTransitionEffect.FromRight + : SlideNavigationTransitionEffect.FromLeft; + + return new SlideNavigationTransitionInfo + { + Effect = slideEffect + }; + } + + private static bool IsNextMode(WinoApplicationMode currentMode, WinoApplicationMode targetMode) + => currentMode switch + { + WinoApplicationMode.Mail => targetMode == WinoApplicationMode.Calendar, + WinoApplicationMode.Calendar => targetMode == WinoApplicationMode.Contacts, + WinoApplicationMode.Contacts => targetMode == WinoApplicationMode.Mail, + _ => false + }; + private static LoadCalendarMessage CreateLoadCalendarMessage(CalendarPageNavigationArgs args) { var targetDate = args.RequestDefaultNavigation diff --git a/Wino.Mail.WinUI/ShellWindow.xaml b/Wino.Mail.WinUI/ShellWindow.xaml index 1410cf3f..3ca32d25 100644 --- a/Wino.Mail.WinUI/ShellWindow.xaml +++ b/Wino.Mail.WinUI/ShellWindow.xaml @@ -3,7 +3,6 @@ x:Class="Wino.Mail.WinUI.ShellWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:coreControls="using:Wino.Mail.WinUI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:domain="using:Wino.Core.Domain" @@ -38,7 +37,6 @@ Subtitle="{x:Bind StatePersistanceService.CoreWindowTitle, Mode=OneWay}"> - - - - - - - - - - - - - - @@ -130,13 +109,14 @@ + diff --git a/Wino.Mail.WinUI/ShellWindow.xaml.cs b/Wino.Mail.WinUI/ShellWindow.xaml.cs index b458ce28..fec3a812 100644 --- a/Wino.Mail.WinUI/ShellWindow.xaml.cs +++ b/Wino.Mail.WinUI/ShellWindow.xaml.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using System.Windows.Input; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using CommunityToolkit.WinUI.Controls; using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -37,12 +36,12 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, public ICommand ShowWinoCommand { get; set; } public ICommand ShowWinoCalendarCommand { get; set; } + public ICommand ShowWinoContactsCommand { get; set; } + public ICommand RestoreCurrentModeCommand { get; set; } public ICommand ExitWinoCommand { get; set; } public ObservableCollection SyncActionItems { get; } = new(); private bool _calendarReminderServerStartAttempted; - private bool _isApplyingActivationMode; - private WinoApplicationMode _currentMode = WinoApplicationMode.Mail; public ShellWindow() { @@ -65,6 +64,8 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, ShowWinoCommand = new RelayCommand(() => RestoreAndSwitchMode(WinoApplicationMode.Mail)); ShowWinoCalendarCommand = new RelayCommand(() => RestoreAndSwitchMode(WinoApplicationMode.Calendar)); + ShowWinoContactsCommand = new RelayCommand(() => RestoreAndSwitchMode(WinoApplicationMode.Contacts)); + RestoreCurrentModeCommand = new RelayCommand(() => RestoreAndSwitchMode(StatePersistanceService.ApplicationMode)); ExitWinoCommand = new RelayCommand(ForceClose); this.SetIcon("Assets/Wino_Icon.ico"); @@ -116,13 +117,6 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, public void HandleAppActivation(string? launchArguments, string? tileId = null, string? appId = null) { var targetMode = AppModeActivationResolver.Resolve(launchArguments, tileId, appId, PreferencesService.DefaultApplicationMode); - _currentMode = targetMode; - - _isApplyingActivationMode = true; - AppModeSegmentedControl.SelectedIndex = targetMode == WinoApplicationMode.Mail ? 0 : 1; - _isApplyingActivationMode = false; - - StatePersistanceService.AppModeTitle = GetAppModeTitle(targetMode); NavigationService.ChangeApplicationMode(targetMode); } @@ -312,13 +306,6 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, private void RestoreAndSwitchMode(WinoApplicationMode mode) { - _currentMode = mode; - - _isApplyingActivationMode = true; - AppModeSegmentedControl.SelectedIndex = mode == WinoApplicationMode.Mail ? 0 : 1; - _isApplyingActivationMode = false; - - StatePersistanceService.AppModeTitle = GetAppModeTitle(mode); NavigationService.ChangeApplicationMode(mode); RestoreFromTray(); } @@ -358,24 +345,4 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, WeakReferenceMessenger.Default.Unregister(this); } - private void SegmentedChanged(object sender, SelectionChangedEventArgs e) - { - if (_isApplyingActivationMode || sender is not Segmented segmentedControl) - return; - - var selectedMode = segmentedControl.SelectedIndex == 1 - ? WinoApplicationMode.Calendar - : WinoApplicationMode.Mail; - - if (selectedMode == _currentMode) - return; - - _currentMode = selectedMode; - NavigationService.ChangeApplicationMode(selectedMode); - } - - private static string GetAppModeTitle(WinoApplicationMode mode) - => mode == WinoApplicationMode.Calendar - ? "Wino Calendar" - : "Wino Mail"; } diff --git a/Wino.Mail.WinUI/Styles/CalendarShellNavigationViewStyle.xaml b/Wino.Mail.WinUI/Styles/CalendarShellNavigationViewStyle.xaml new file mode 100644 index 00000000..71a7e421 --- /dev/null +++ b/Wino.Mail.WinUI/Styles/CalendarShellNavigationViewStyle.xaml @@ -0,0 +1,890 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/Abstract/ContactsAppShellAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/ContactsAppShellAbstract.cs new file mode 100644 index 00000000..d10d33b0 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/ContactsAppShellAbstract.cs @@ -0,0 +1,9 @@ +namespace Wino.Mail.WinUI.Views.Abstract; + +public abstract class ContactsAppShellAbstract : BasePage +{ + protected ContactsAppShellAbstract() + { + NavigationCacheMode = Microsoft.UI.Xaml.Navigation.NavigationCacheMode.Enabled; + } +} diff --git a/Wino.Mail.WinUI/Views/AccountSetupProgressPage.xaml b/Wino.Mail.WinUI/Views/AccountSetupProgressPage.xaml index 73c2d3ec..d5d9c006 100644 --- a/Wino.Mail.WinUI/Views/AccountSetupProgressPage.xaml +++ b/Wino.Mail.WinUI/Views/AccountSetupProgressPage.xaml @@ -103,9 +103,7 @@ Severity="Success" /> - + -