diff --git a/AGENTS.md b/AGENTS.md index f1324382..fe235e7a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -143,7 +143,7 @@ private string searchQuery = string.Empty; - In ViewModels, update all UI-bound properties/collections via `ExecuteUIThread(...)` (especially after awaited calls and any use of `ConfigureAwait(false)`). - In `EventDetailsPageViewModel.LoadAttendeesAsync`, never mutate `CurrentEvent.Attendees` outside `ExecuteUIThread(...)`. - Never create pure C# controls or controls that heavily manipulate UI structure from `.cs` files. Define controls in XAML and keep UI composition in XAML. -- For XAML-backed controls and pages, wire framework events like `Loaded`, `Unloaded`, and input events from XAML, not by subscribing in constructors in `.xaml.cs`. +- Never subscribe to framework events like `Loaded`, `Unloaded`, or input events from constructors in `.xaml.cs` for XAML-backed controls and pages; wire them directly in XAML instead. diff --git a/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs b/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs index 15609ec5..9b98cc15 100644 --- a/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs +++ b/Wino.Calendar.ViewModels/CalendarAppShellViewModel.cs @@ -85,7 +85,6 @@ 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 NewCalendarEventMenuItem _newEventMenuItem = new(); @@ -378,9 +377,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, ForceNavigateCalendarDate(); } - [RelayCommand] - public void ManageAccounts() => NavigationService.Navigate(WinoPage.AccountManagementPage); - public async Task HandleNavigationItemInvokedAsync(IMenuItem menuItem) { switch (menuItem) @@ -388,9 +384,6 @@ public partial class CalendarAppShellViewModel : CalendarBaseViewModel, case NewMailMenuItem: await NewEventAsync().ConfigureAwait(false); break; - case ManageAccountsMenuItem: - NavigationService.Navigate(WinoPage.ManageAccountsPage); - break; case SettingsItem: NavigationService.Navigate(WinoPage.SettingsPage); break; diff --git a/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs index 2c544e59..fa10bc7e 100644 --- a/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs +++ b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs @@ -44,11 +44,6 @@ public interface IStatePersistanceService : INotifyPropertyChanged /// bool IsEventDetailsVisible { get; set; } - /// - /// Whether ManageAccountsPage has navigated to a sub-page and can go back. - /// - bool IsManageAccountsNavigating { get; set; } - /// /// Whether SettingsPage has navigated to a sub-page and can go back. /// diff --git a/Wino.Core.Domain/MenuItems/ManageAccountsMenuItem.cs b/Wino.Core.Domain/MenuItems/ManageAccountsMenuItem.cs deleted file mode 100644 index 147501b2..00000000 --- a/Wino.Core.Domain/MenuItems/ManageAccountsMenuItem.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Wino.Core.Domain.MenuItems; - -public class ManageAccountsMenuItem : MenuItemBase { } diff --git a/Wino.Core.Domain/MenuItems/MenuItemBase.cs b/Wino.Core.Domain/MenuItems/MenuItemBase.cs index eaf53f82..db4958de 100644 --- a/Wino.Core.Domain/MenuItems/MenuItemBase.cs +++ b/Wino.Core.Domain/MenuItems/MenuItemBase.cs @@ -8,10 +8,10 @@ namespace Wino.Core.Domain.MenuItems; public partial class MenuItemBase : ObservableObject, IMenuItem { [ObservableProperty] - private bool _isExpanded; + public partial bool IsExpanded { get; set; } [ObservableProperty] - private bool _isSelected; + public partial bool IsSelected { get; set; } public IMenuItem ParentMenuItem { get; } @@ -46,7 +46,7 @@ public partial class MenuItemBase : ObservableObject, IMenuItem public partial class MenuItemBase : MenuItemBase { [ObservableProperty] - private T _parameter; + public partial T Parameter { get; set; } public MenuItemBase(T parameter, Guid? entityId, IMenuItem parentMenuItem = null) : base(entityId, parentMenuItem) => Parameter = parameter; } @@ -54,7 +54,7 @@ public partial class MenuItemBase : MenuItemBase public partial class MenuItemBase : MenuItemBase { [ObservableProperty] - private bool _isChildSelected; + public partial bool IsChildSelected { get; set; } protected MenuItemBase(TValue parameter, Guid? entityId, IMenuItem parentMenuItem = null) : base(parameter, entityId, parentMenuItem) { } diff --git a/Wino.Core.Domain/MenuItems/NewContactMenuItem.cs b/Wino.Core.Domain/MenuItems/NewContactMenuItem.cs new file mode 100644 index 00000000..24d09bc0 --- /dev/null +++ b/Wino.Core.Domain/MenuItems/NewContactMenuItem.cs @@ -0,0 +1,3 @@ +namespace Wino.Core.Domain.MenuItems; + +public sealed class NewContactMenuItem : MenuItemBase { } diff --git a/Wino.Core.Domain/Translations/en_US/resources.json b/Wino.Core.Domain/Translations/en_US/resources.json index 8d87609c..97f7e975 100644 --- a/Wino.Core.Domain/Translations/en_US/resources.json +++ b/Wino.Core.Domain/Translations/en_US/resources.json @@ -793,7 +793,7 @@ "SettingsMailSpacing_Description": "Adjust the spacing for listing mails.", "SettingsMailSpacing_Title": "Mail Spacing", "SettingsManageAccountSettings_Description": "Notifications, signatures, synchronization and other settings per account.", - "SettingsManageAccountSettings_Title": "Manage Account Settings", + "SettingsManageAccountSettings_Title": "Manage Accounts", "SettingsManageAliases_Description": "See e-mail aliases assigned for this account, update or delete them.", "SettingsManageAliases_Title": "Aliases", "SettingsEditAccountDetails_Title": "Edit Account Details", @@ -1060,6 +1060,9 @@ "ContactsPage_EmptyState": "No contacts to display", "ContactsPage_AddFirstContact": "Add your first contact", "ContactsPage_ContactsCountSuffix": "contacts", + "ContactsPane_NewContact": "New Contact", + "ContactsPane_DescriptionTitle": "Manage your contacts", + "ContactsPane_DescriptionBody": "Create contacts, rename them, update profile pictures, and keep saved details organized in one place.", "ContactEditDialog_AddTitle": "Add Contact", "ContactInfoBar_ContactAdded": "Contact added successfully.", "ContactInfoBar_ContactUpdated": "Contact updated successfully.", diff --git a/Wino.Mail.ViewModels/ContactsPageViewModel.cs b/Wino.Mail.ViewModels/ContactsPageViewModel.cs index 4e883ef8..f08e4ac6 100644 --- a/Wino.Mail.ViewModels/ContactsPageViewModel.cs +++ b/Wino.Mail.ViewModels/ContactsPageViewModel.cs @@ -7,16 +7,19 @@ using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Navigation; using Wino.Mail.ViewModels.Data; +using Wino.Messaging.Client.Contacts; namespace Wino.Mail.ViewModels; -public partial class ContactsPageViewModel : MailBaseViewModel +public partial class ContactsPageViewModel : MailBaseViewModel, + IRecipient { private const int ContactPageSize = 50; @@ -97,6 +100,9 @@ public partial class ContactsPageViewModel : MailBaseViewModel private async void ContactsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => await ExecuteUIThread(() => { OnPropertyChanged(nameof(IsEmpty)); }); + void IRecipient.Receive(NewContactRequested message) + => _ = AddContactAsync(); + [RelayCommand] private async Task ReloadContactsAsync() { @@ -219,6 +225,20 @@ public partial class ContactsPageViewModel : MailBaseViewModel } } + protected override void RegisterRecipients() + { + base.RegisterRecipients(); + + Messenger.Register(this); + } + + protected override void UnregisterRecipients() + { + base.UnregisterRecipients(); + + Messenger.Unregister(this); + } + [RelayCommand] private async Task EditContactAsync(AccountContactViewModel contactViewModel) { diff --git a/Wino.Mail.ViewModels/MailAppShellViewModel.cs b/Wino.Mail.ViewModels/MailAppShellViewModel.cs index 20ea5ad2..fc668429 100644 --- a/Wino.Mail.ViewModels/MailAppShellViewModel.cs +++ b/Wino.Mail.ViewModels/MailAppShellViewModel.cs @@ -54,7 +54,6 @@ public partial class MailAppShellViewModel : MailBaseViewModel, public MenuItemCollection MenuItems { get; set; } private readonly SettingsItem SettingsItem = new SettingsItem(); - private readonly ManageAccountsMenuItem ManageAccountsMenuItem = new ManageAccountsMenuItem(); private readonly ContactsMenuItem ContactsMenuItem = new ContactsMenuItem(); private readonly StoreUpdateMenuItem StoreUpdateMenuItem = new StoreUpdateMenuItem(); @@ -820,7 +819,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel, if (isManageAccountClicked) { - SelectedMenuItem = ManageAccountsMenuItem; + NavigationService.Navigate(WinoPage.SettingsPage, WinoPage.ManageAccountsPage); } return; diff --git a/Wino.Mail.WinUI/App.xaml.cs b/Wino.Mail.WinUI/App.xaml.cs index fa39fb6f..06bb04cf 100644 --- a/Wino.Mail.WinUI/App.xaml.cs +++ b/Wino.Mail.WinUI/App.xaml.cs @@ -561,7 +561,7 @@ public partial class App : WinoApplication, public Task OpenManageAccountsFromWelcomeAsync() { Services.GetRequiredService() - .Navigate(WinoPage.ManageAccountsPage, null, NavigationReferenceFrame.ShellFrame, NavigationTransitionType.DrillIn); + .Navigate(WinoPage.SettingsPage, WinoPage.ManageAccountsPage, NavigationReferenceFrame.ShellFrame, NavigationTransitionType.DrillIn); return Task.CompletedTask; } diff --git a/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs index 97167fbf..030026c5 100644 --- a/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs +++ b/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs @@ -8,7 +8,6 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector { public DataTemplate MenuItemTemplate { get; set; } = null!; public DataTemplate ContactsMenuItemTemplate { get; set; } = null!; - public DataTemplate AccountManagementTemplate { get; set; } = null!; public DataTemplate ClickableAccountMenuTemplate { get; set; } = null!; public DataTemplate MergedAccountTemplate { get; set; } = null!; public DataTemplate MergedAccountFolderTemplate { get; set; } = null!; @@ -21,6 +20,7 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector public DataTemplate CreateNewFolderTemplate { get; set; } = null!; public DataTemplate SeperatorTemplate { get; set; } = null!; public DataTemplate NewMailTemplate { get; set; } = null!; + public DataTemplate NewContactTemplate { get; set; } = null!; public DataTemplate CalendarNewEventTemplate { get; set; } = null!; public DataTemplate CategoryItemsTemplate { get; set; } = null!; public DataTemplate FixAuthenticationIssueTemplate { get; set; } = null!; @@ -30,6 +30,8 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector { if (item is NewCalendarEventMenuItem) return CalendarNewEventTemplate; + else if (item is NewContactMenuItem) + return NewContactTemplate; else if (item is NewMailMenuItem) return NewMailTemplate; else if (item is ContactsMenuItem) @@ -43,8 +45,6 @@ public partial class NavigationMenuTemplateSelector : DataTemplateSelector else if (item is AccountMenuItem) // Merged inbox account menu items must be nested. return ClickableAccountMenuTemplate; - else if (item is ManageAccountsMenuItem) - return AccountManagementTemplate; else if (item is RateMenuItem) return RatingItemTemplate; else if (item is MergedAccountMenuItem) diff --git a/Wino.Mail.WinUI/Services/NavigationService.cs b/Wino.Mail.WinUI/Services/NavigationService.cs index 1a1fde0d..10e63b43 100644 --- a/Wino.Mail.WinUI/Services/NavigationService.cs +++ b/Wino.Mail.WinUI/Services/NavigationService.cs @@ -106,7 +106,7 @@ public class NavigationService : NavigationServiceBase, INavigationService WinoPage.AccountDetailsPage => typeof(AccountDetailsPage), WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage), WinoPage.AccountManagementPage => typeof(AccountManagementPage), - WinoPage.ManageAccountsPage => typeof(ManageAccountsPage), + WinoPage.ManageAccountsPage => typeof(AccountManagementPage), WinoPage.SignatureManagementPage => typeof(SignatureManagementPage), WinoPage.AboutPage => typeof(AboutPage), WinoPage.PersonalizationPage => typeof(PersonalizationPage), @@ -237,6 +237,11 @@ public class NavigationService : NavigationServiceBase, INavigationService NavigationReferenceFrame frame = NavigationReferenceFrame.InnerShellFrame, NavigationTransitionType transition = NavigationTransitionType.None) { + if (page is WinoPage.ManageAccountsPage or WinoPage.AccountManagementPage) + { + return NavigateInternal(WinoPage.SettingsPage, WinoPage.ManageAccountsPage, frame, transition); + } + var pageType = GetPageType(page); if (pageType == null) return false; @@ -441,11 +446,8 @@ public class NavigationService : NavigationServiceBase, INavigationService private void GoBackInternal(Core.Domain.Enums.NavigationTransitionEffect slideEffect = Core.Domain.Enums.NavigationTransitionEffect.FromRight) { - // Check if we're navigating within ManageAccountsPage (applies to both modes) - // Check if we're navigating within SettingsPage (applies to both modes) - if (_statePersistanceService.IsManageAccountsNavigating || _statePersistanceService.IsSettingsNavigating) + if (_statePersistanceService.IsSettingsNavigating) { - // Send message to ManageAccountsPage to go back within its AccountPagesFrame WeakReferenceMessenger.Default.Send(new BackBreadcrumNavigationRequested(slideEffect)); return; } diff --git a/Wino.Mail.WinUI/Services/StatePersistenceService.cs b/Wino.Mail.WinUI/Services/StatePersistenceService.cs index 23ce4466..67db9961 100644 --- a/Wino.Mail.WinUI/Services/StatePersistenceService.cs +++ b/Wino.Mail.WinUI/Services/StatePersistenceService.cs @@ -34,8 +34,8 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic public bool IsBackButtonVisible => ApplicationMode == WinoApplicationMode.Mail - ? (IsReadingMail && IsReaderNarrowed) || IsManageAccountsNavigating || IsSettingsNavigating - : IsEventDetailsVisible || IsManageAccountsNavigating || IsSettingsNavigating; + ? (IsReadingMail && IsReaderNarrowed) || IsSettingsNavigating + : IsEventDetailsVisible || IsSettingsNavigating; private WinoApplicationMode applicationMode = WinoApplicationMode.Mail; @@ -68,20 +68,6 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic } } - private bool isManageAccountsNavigating; - - public bool IsManageAccountsNavigating - { - get => isManageAccountsNavigating; - set - { - if (SetProperty(ref isManageAccountsNavigating, value)) - { - OnPropertyChanged(nameof(IsBackButtonVisible)); - } - } - } - private bool isSettingsNavigating; public bool IsSettingsNavigating diff --git a/Wino.Mail.WinUI/Styles/DataTemplates.xaml b/Wino.Mail.WinUI/Styles/DataTemplates.xaml index dd622a9e..d914a61a 100644 --- a/Wino.Mail.WinUI/Styles/DataTemplates.xaml +++ b/Wino.Mail.WinUI/Styles/DataTemplates.xaml @@ -26,15 +26,6 @@ - - - - - - - - - diff --git a/Wino.Mail.WinUI/ViewModels/ContactsShellClient.cs b/Wino.Mail.WinUI/ViewModels/ContactsShellClient.cs index f17cefd0..ef73e0c3 100644 --- a/Wino.Mail.WinUI/ViewModels/ContactsShellClient.cs +++ b/Wino.Mail.WinUI/ViewModels/ContactsShellClient.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Messaging; using Wino.Core.Domain; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; @@ -6,11 +7,14 @@ using Wino.Core.Domain.MenuItems; using Wino.Core.Domain.Models; using Wino.Core.Domain.Models.Navigation; using Wino.Core.ViewModels; +using Wino.Messaging.Client.Contacts; namespace Wino.Mail.WinUI.ViewModels; public sealed class ContactsShellClient(INavigationService navigationService) : CoreBaseViewModel, IShellClient { + private readonly NewContactMenuItem _newContactMenuItem = new(); + public WinoApplicationMode Mode => WinoApplicationMode.Contacts; public MenuItemCollection? MenuItems { get; private set; } public object? SelectedMenuItem { get; set; } @@ -20,6 +24,11 @@ public sealed class ContactsShellClient(INavigationService navigationService) : { base.OnDispatcherAssigned(); MenuItems ??= new MenuItemCollection(Dispatcher); + + if (MenuItems.Count == 0) + { + MenuItems.Add(_newContactMenuItem); + } } public void Activate(ShellModeActivationContext activationContext) @@ -33,7 +42,15 @@ public sealed class ContactsShellClient(INavigationService navigationService) : OnNavigatedFrom(NavigationMode.New, null!); } - public Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem) => Task.CompletedTask; + public Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem) + { + if (menuItem is NewContactMenuItem) + { + WeakReferenceMessenger.Default.Send(new NewContactRequested()); + } + + return Task.CompletedTask; + } public Task HandleNavigationSelectionChangedAsync(IMenuItem? menuItem) => Task.CompletedTask; } diff --git a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml b/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml index 550f2b14..7335a0eb 100644 --- a/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml +++ b/Wino.Mail.WinUI/Views/Calendar/CalendarAppShell.xaml @@ -39,15 +39,6 @@ - - - - - - - - - diff --git a/Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml b/Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml index 338640f7..1c86542d 100644 --- a/Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml +++ b/Wino.Mail.WinUI/Views/Contacts/ContactsAppShell.xaml @@ -5,14 +5,16 @@ xmlns:abstract="using:Wino.Mail.WinUI.Views.Abstract" xmlns:coreControls="using:Wino.Mail.WinUI.Controls" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"> - - + + ScrollViewer.VerticalScrollBarVisibility="Hidden" + Style="{StaticResource CalendarShellNavigationViewStyle}"> @@ -15,38 +12,6 @@ - - - - - - - - - - - - - - - - - - - - - + HorizontalAlignment="Stretch" /> diff --git a/Wino.Mail.WinUI/Views/ManageAccountsPage.xaml.cs b/Wino.Mail.WinUI/Views/ManageAccountsPage.xaml.cs index 20ef8f9e..f1545fc8 100644 --- a/Wino.Mail.WinUI/Views/ManageAccountsPage.xaml.cs +++ b/Wino.Mail.WinUI/Views/ManageAccountsPage.xaml.cs @@ -1,136 +1,12 @@ -using System.Collections.ObjectModel; -using System.Linq; -using CommunityToolkit.Mvvm.Messaging; -using Microsoft.UI.Xaml.Media.Animation; -using Microsoft.UI.Xaml.Navigation; using Wino.Core.Domain; -using Wino.Core.Domain.Enums; -using Wino.Helpers; -using Wino.Mail.ViewModels.Data; using Wino.Mail.WinUI.Views.Abstract; -using Wino.Messaging.Client.Navigation; -using Wino.Messaging.UI; namespace Wino.Views; -public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract, - IRecipient, - IRecipient, - IRecipient, - IRecipient +public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract { - public ObservableCollection PageHistory { get; set; } = new ObservableCollection(); - - public ManageAccountsPage() { InitializeComponent(); } - - protected override void OnNavigatedTo(NavigationEventArgs e) - { - base.OnNavigatedTo(e); - - // Re-register message handlers after base.OnNavigatedTo unregisters all handlers - WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); - WeakReferenceMessenger.Default.Register(this); - - // Register for frame navigation events to track back button visibility - AccountPagesFrame.Navigated -= AccountPagesFrameNavigated; - AccountPagesFrame.Navigated += AccountPagesFrameNavigated; - - var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuManageAccounts, WinoPage.AccountManagementPage); - PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true, backStackDepth: AccountPagesFrame.BackStack.Count + 1)); - - var accountManagementPageType = ViewModel.NavigationService.GetPageType(WinoPage.AccountManagementPage); - - AccountPagesFrame.Navigate(accountManagementPageType, null, new SuppressNavigationTransitionInfo()); - UpdateWindowTitle(); - } - - protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) - { - // Explicitly unregister our message handlers before base.OnNavigatingFrom calls UnregisterAll - WeakReferenceMessenger.Default.Unregister(this); - WeakReferenceMessenger.Default.Unregister(this); - WeakReferenceMessenger.Default.Unregister(this); - WeakReferenceMessenger.Default.Unregister(this); - - // Unregister frame navigation event - AccountPagesFrame.Navigated -= AccountPagesFrameNavigated; - - // Reset navigation state when leaving ManageAccountsPage - ViewModel.StatePersistenceService.IsManageAccountsNavigating = false; - - base.OnNavigatingFrom(e); - } - - void IRecipient.Receive(BreadcrumbNavigationRequested message) - { - BreadcrumbNavigationHelper.Navigate(AccountPagesFrame, PageHistory, message, ViewModel.NavigationService.GetPageType); - UpdateWindowTitle(); - } - - private void AccountPagesFrameNavigated(object sender, NavigationEventArgs e) - { - // Update back button visibility based on whether we can go back within the frame - ViewModel.StatePersistenceService.IsManageAccountsNavigating = AccountPagesFrame.CanGoBack; - } - - private void GoBackFrame(Core.Domain.Enums.NavigationTransitionEffect slideEffect) - { - if (!BreadcrumbNavigationHelper.GoBack(AccountPagesFrame, PageHistory, slideEffect)) - return; - - ViewModel.StatePersistenceService.IsManageAccountsNavigating = AccountPagesFrame.CanGoBack; - UpdateWindowTitle(); - } - - private void BreadItemClicked(Microsoft.UI.Xaml.Controls.BreadcrumbBar sender, Microsoft.UI.Xaml.Controls.BreadcrumbBarItemClickedEventArgs args) - { - if (!BreadcrumbNavigationHelper.NavigateTo(AccountPagesFrame, PageHistory, args.Index)) - return; - - ViewModel.StatePersistenceService.IsManageAccountsNavigating = AccountPagesFrame.CanGoBack; - UpdateWindowTitle(); - } - - public void Receive(BackBreadcrumNavigationRequested message) - { - GoBackFrame(message.SlideEffect); - } - - public void Receive(AccountUpdatedMessage message) - { - var activePage = PageHistory.FirstOrDefault(a => a.Request.PageType == WinoPage.AccountDetailsPage); - - if (activePage == null) return; - - DispatcherQueue.TryEnqueue(() => - { - activePage.Title = message.Account.Name; - UpdateWindowTitle(); - }); - } - - public void Receive(MergedInboxRenamed message) - { - // TODO: Find better way to retrieve page history from the stack for the merged account. - var activePage = PageHistory.LastOrDefault(); - - if (activePage == null) return; - - activePage.Title = message.NewName; - UpdateWindowTitle(); - } - - private void UpdateWindowTitle() - { - var activeTitle = PageHistory.LastOrDefault()?.Title; - ViewModel.StatePersistenceService.CoreWindowTitle = string.IsNullOrWhiteSpace(activeTitle) - ? Translator.MenuManageAccounts - : activeTitle; - } } diff --git a/Wino.Mail.WinUI/Views/Settings/ContactsPage.xaml b/Wino.Mail.WinUI/Views/Settings/ContactsPage.xaml index 7ac7e478..cd4190c7 100644 --- a/Wino.Mail.WinUI/Views/Settings/ContactsPage.xaml +++ b/Wino.Mail.WinUI/Views/Settings/ContactsPage.xaml @@ -106,11 +106,6 @@ - - - - - - - diff --git a/Wino.Mail.WinUI/Views/SettingsPage.xaml.cs b/Wino.Mail.WinUI/Views/SettingsPage.xaml.cs index 9f861d82..4bf25b17 100644 --- a/Wino.Mail.WinUI/Views/SettingsPage.xaml.cs +++ b/Wino.Mail.WinUI/Views/SettingsPage.xaml.cs @@ -8,6 +8,7 @@ using Wino.Core.Domain.Enums; using Wino.Helpers; using Wino.Mail.ViewModels.Data; using Wino.Messaging.Client.Navigation; +using Wino.Messaging.UI; using Wino.Views.Abstract; using Wino.Views.Settings; @@ -15,7 +16,9 @@ namespace Wino.Views; public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient, - IRecipient + IRecipient, + IRecipient, + IRecipient { public ObservableCollection PageHistory { get; set; } = []; @@ -45,20 +48,20 @@ public sealed partial class SettingsPage : SettingsPageAbstract, switch (parameterPage) { case WinoPage.AppPreferencesPage: - WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsAppPreferences_Title, WinoPage.AppPreferencesPage)); + NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.SettingsAppPreferences_Title, WinoPage.AppPreferencesPage)); break; case WinoPage.PersonalizationPage: - WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsPersonalization_Title, WinoPage.PersonalizationPage)); + NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.SettingsPersonalization_Title, WinoPage.PersonalizationPage)); break; case WinoPage.StoragePage: - WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsStorage_Title, WinoPage.StoragePage)); + NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.SettingsStorage_Title, WinoPage.StoragePage)); break; case WinoPage.EmailTemplatesPage: - WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsEmailTemplates_Title, WinoPage.EmailTemplatesPage)); + NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.SettingsEmailTemplates_Title, WinoPage.EmailTemplatesPage)); break; case WinoPage.ManageAccountsPage: case WinoPage.AccountManagementPage: - WeakReferenceMessenger.Default.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage)); + NavigateBreadcrumb(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage)); break; } } @@ -77,6 +80,14 @@ public sealed partial class SettingsPage : SettingsPageAbstract, if (settingsHeader == null) return; settingsHeader.Title = Translator.MenuSettings; + var manageAccountsEntry = PageHistory.FirstOrDefault(a => + a.Request.PageType == WinoPage.ManageAccountsPage || a.Request.PageType == WinoPage.AccountManagementPage); + + if (manageAccountsEntry != null) + { + manageAccountsEntry.Title = Translator.SettingsManageAccountSettings_Title; + } + UpdateWindowTitle(); } @@ -97,6 +108,8 @@ public sealed partial class SettingsPage : SettingsPageAbstract, WeakReferenceMessenger.Default.Register(this); WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); + WeakReferenceMessenger.Default.Register(this); } protected override void UnregisterRecipients() @@ -105,12 +118,13 @@ public sealed partial class SettingsPage : SettingsPageAbstract, WeakReferenceMessenger.Default.Unregister(this); WeakReferenceMessenger.Default.Unregister(this); + WeakReferenceMessenger.Default.Unregister(this); + WeakReferenceMessenger.Default.Unregister(this); } void IRecipient.Receive(BreadcrumbNavigationRequested message) { - BreadcrumbNavigationHelper.Navigate(SettingsFrame, PageHistory, message, ViewModel.NavigationService.GetPageType); - UpdateWindowTitle(); + NavigateBreadcrumb(message); } private void SettingsFrameNavigated(object sender, NavigationEventArgs e) @@ -142,6 +156,42 @@ public sealed partial class SettingsPage : SettingsPageAbstract, GoBackFrame(message.SlideEffect); } + public void Receive(AccountUpdatedMessage message) + { + var activePage = PageHistory.LastOrDefault(a => a.Request.PageType == WinoPage.AccountDetailsPage); + + if (activePage == null) + return; + + DispatcherQueue.TryEnqueue(() => + { + activePage.Title = message.Account.Name; + UpdateWindowTitle(); + }); + } + + public void Receive(MergedInboxRenamed message) + { + var activePage = PageHistory.LastOrDefault(a => a.Request.PageType == WinoPage.MergedAccountDetailsPage); + + if (activePage == null) + return; + + DispatcherQueue.TryEnqueue(() => + { + activePage.Title = message.NewName; + UpdateWindowTitle(); + }); + } + + private void NavigateBreadcrumb(BreadcrumbNavigationRequested message) + { + if (!BreadcrumbNavigationHelper.Navigate(SettingsFrame, PageHistory, message, ViewModel.NavigationService.GetPageType)) + return; + + UpdateWindowTitle(); + } + private void UpdateWindowTitle() { var activeTitle = PageHistory.LastOrDefault()?.Title; diff --git a/Wino.Mail.WinUI/Views/WinoAppShell.xaml b/Wino.Mail.WinUI/Views/WinoAppShell.xaml index 2e1f78fd..32c5c10d 100644 --- a/Wino.Mail.WinUI/Views/WinoAppShell.xaml +++ b/Wino.Mail.WinUI/Views/WinoAppShell.xaml @@ -394,6 +394,23 @@ + + + + + + + + + - - - - + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/WinoAppShell.xaml.cs b/Wino.Mail.WinUI/Views/WinoAppShell.xaml.cs index df834607..39dab9ea 100644 --- a/Wino.Mail.WinUI/Views/WinoAppShell.xaml.cs +++ b/Wino.Mail.WinUI/Views/WinoAppShell.xaml.cs @@ -157,7 +157,6 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract, private void ResetShellModeNavigationState() { - ViewModel.StatePersistenceService.IsManageAccountsNavigating = false; ViewModel.StatePersistenceService.IsSettingsNavigating = false; InnerShellFrame.BackStack.Clear(); InnerShellFrame.ForwardStack.Clear(); @@ -187,7 +186,7 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract, if (ViewModel.IsCalendarMode) { - ViewModel.StatePersistenceService.CoreWindowTitle = ViewModel.StatePersistenceService.AppModeTitle; + ViewModel.StatePersistenceService.CoreWindowTitle = string.Empty; return; } @@ -490,16 +489,29 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract, private void UpdateNavigationPaneLayout(NavigationViewDisplayMode displayMode) { - if (ViewModel.IsCalendarMode) + if (displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen) { - PaneCustomContent.Visibility = displayMode == NavigationViewDisplayMode.Expanded && navigationView.IsPaneOpen - ? Visibility.Visible - : Visibility.Collapsed; + if (ViewModel.IsCalendarMode) + { + PaneCustomContent.Visibility = Visibility.Visible; + CalendarPaneContent.Visibility = Visibility.Visible; + ContactsPaneContent.Visibility = Visibility.Collapsed; + InnerShellFrame.Margin = new Thickness(0); + return; + } - InnerShellFrame.Margin = new Thickness(0); - return; + if (ViewModel.IsContactsMode) + { + PaneCustomContent.Visibility = Visibility.Visible; + CalendarPaneContent.Visibility = Visibility.Collapsed; + ContactsPaneContent.Visibility = Visibility.Visible; + InnerShellFrame.Margin = new Thickness(0); + return; + } } + CalendarPaneContent.Visibility = Visibility.Collapsed; + ContactsPaneContent.Visibility = Visibility.Collapsed; PaneCustomContent.Visibility = Visibility.Collapsed; InnerShellFrame.Margin = displayMode == NavigationViewDisplayMode.Minimal ? new Thickness(7, 0, 0, 0) diff --git a/Wino.Messages/Client/Contacts/NewContactRequested.cs b/Wino.Messages/Client/Contacts/NewContactRequested.cs new file mode 100644 index 00000000..2d451cf2 --- /dev/null +++ b/Wino.Messages/Client/Contacts/NewContactRequested.cs @@ -0,0 +1,3 @@ +namespace Wino.Messaging.Client.Contacts; + +public record NewContactRequested;