Settings page and manage accounts navigation options.

This commit is contained in:
Burak Kaan Köse
2026-01-06 17:23:58 +01:00
parent 7cc201f423
commit f105c2f8f0
29 changed files with 874 additions and 197 deletions
@@ -0,0 +1,135 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar;
namespace Wino.Calendar.ViewModels;
/// <summary>
/// ViewModel for managing calendar account settings.
/// </summary>
public partial class CalendarAccountSettingsPageViewModel : CalendarBaseViewModel
{
private readonly ICalendarService _calendarService;
private readonly IAccountService _accountService;
[ObservableProperty]
public partial MailAccount Account { get; set; }
[ObservableProperty]
public partial AccountCalendar AccountCalendar { get; set; }
[ObservableProperty]
public partial string AccountColorHex { get; set; } = "#0078D4";
[ObservableProperty]
public partial bool IsSyncEnabled { get; set; }
[ObservableProperty]
public partial bool IsPrimaryCalendar { get; set; }
public ObservableCollection<ShowAsOption> ShowAsOptions { get; } = new ObservableCollection<ShowAsOption>();
[ObservableProperty]
public partial ShowAsOption SelectedDefaultShowAsOption { get; set; }
public CalendarAccountSettingsPageViewModel(ICalendarService calendarService, IAccountService accountService)
{
_calendarService = calendarService;
_accountService = accountService;
// Initialize ShowAs options
ShowAsOptions.Add(new ShowAsOption(CalendarItemShowAs.Free));
ShowAsOptions.Add(new ShowAsOption(CalendarItemShowAs.Tentative));
ShowAsOptions.Add(new ShowAsOption(CalendarItemShowAs.Busy));
ShowAsOptions.Add(new ShowAsOption(CalendarItemShowAs.OutOfOffice));
ShowAsOptions.Add(new ShowAsOption(CalendarItemShowAs.WorkingElsewhere));
}
public override async void OnNavigatedTo(NavigationMode mode, object parameters)
{
base.OnNavigatedTo(mode, parameters);
if (parameters is not Guid accountId)
return;
// Load account
Account = await _accountService.GetAccountAsync(accountId);
if (Account == null)
return;
// Load first primary calendar for this account
var calendars = await _calendarService.GetAccountCalendarsAsync(accountId);
AccountCalendar = calendars.FirstOrDefault(c => c.IsPrimary) ?? calendars.FirstOrDefault();
if (AccountCalendar == null)
return;
// Initialize properties from AccountCalendar
AccountColorHex = AccountCalendar.BackgroundColorHex ?? "#0078D4";
IsSyncEnabled = AccountCalendar.IsExtended;
IsPrimaryCalendar = AccountCalendar.IsPrimary;
// TODO: Default ShowAs is not stored in AccountCalendar yet, defaulting to Busy
SelectedDefaultShowAsOption = ShowAsOptions[2]; // Busy
}
partial void OnAccountColorHexChanged(string value)
{
if (AccountCalendar != null && !string.IsNullOrEmpty(value))
{
AccountCalendar.BackgroundColorHex = value;
SaveChangesAsync();
}
}
partial void OnIsSyncEnabledChanged(bool value)
{
if (AccountCalendar != null)
{
AccountCalendar.IsExtended = value;
SaveChangesAsync();
}
}
partial void OnIsPrimaryCalendarChanged(bool value)
{
if (AccountCalendar != null)
{
AccountCalendar.IsPrimary = value;
SaveChangesAsync();
}
}
partial void OnSelectedDefaultShowAsOptionChanged(ShowAsOption value)
{
// TODO: Default ShowAs should be stored in AccountCalendar or account preferences
// For now, this is just a placeholder as the property doesn't exist yet
if (value != null)
{
// Future: Store value.ShowAs somewhere
}
}
private async void SaveChangesAsync()
{
if (AccountCalendar == null)
return;
await _calendarService.UpdateAccountCalendarAsync(AccountCalendar);
// Send message to update UI
Messenger.Send(new CalendarListUpdated(AccountCalendar));
}
}
@@ -1,13 +1,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging; 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.Interfaces;
using Wino.Core.Domain.Translations; using Wino.Core.Domain.Translations;
using Wino.Core.ViewModels; using Wino.Core.ViewModels;
using Wino.Messaging.Client.Calendar; using Wino.Messaging.Client.Calendar;
using Wino.Messaging.Client.Navigation;
namespace Wino.Calendar.ViewModels; namespace Wino.Calendar.ViewModels;
@@ -45,13 +52,17 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
public IPreferencesService PreferencesService { get; } public IPreferencesService PreferencesService { get; }
private readonly ICalendarService _calendarService; private readonly ICalendarService _calendarService;
private readonly IAccountService _accountService;
public ObservableCollection<MailAccount> Accounts { get; } = new ObservableCollection<MailAccount>();
private readonly bool _isLoaded = false; private readonly bool _isLoaded = false;
public CalendarSettingsPageViewModel(IPreferencesService preferencesService, ICalendarService calendarService) public CalendarSettingsPageViewModel(IPreferencesService preferencesService, ICalendarService calendarService, IAccountService accountService)
{ {
PreferencesService = preferencesService; PreferencesService = preferencesService;
_calendarService = calendarService; _calendarService = calendarService;
_accountService = accountService;
var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage); var currentLanguageLanguageCode = WinoTranslationDictionary.GetLanguageFileNameRelativePath(preferencesService.CurrentLanguage);
@@ -98,6 +109,34 @@ public partial class CalendarSettingsPageViewModel : CalendarBaseViewModel
} }
_isLoaded = true; _isLoaded = true;
// Load accounts with calendar support
LoadAccountsAsync();
}
private async void LoadAccountsAsync()
{
var accounts = await _accountService.GetAccountsAsync();
await Dispatcher.ExecuteOnUIThread(() =>
{
Accounts.Clear();
foreach (var account in accounts)
{
Accounts.Add(account);
}
});
}
[RelayCommand]
private void NavigateToAccountSettings(MailAccount account)
{
if (account == null) return;
Messenger.Send(new BreadcrumbNavigationRequested(
string.Format(Translator.CalendarAccountSettings_Description, account.Name),
WinoPage.CalendarAccountSettingsPage,
account.Id));
} }
partial void OnCellHourHeightChanged(double oldValue, double newValue) => SaveSettings(); partial void OnCellHourHeightChanged(double oldValue, double newValue) => SaveSettings();
+1 -1
View File
@@ -30,7 +30,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
}; };
} }
public void GoBack() public void GoBack(Core.Domain.Enums.SlideNavigationTransitionEffect slideEffect = Core.Domain.Enums.SlideNavigationTransitionEffect.FromRight)
{ {
if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage) if (Window.Current.Content is Frame appFrame && appFrame.Content is AppShell shellPage)
{ {
@@ -0,0 +1,27 @@
namespace Wino.Core.Domain.Enums;
/// <summary>
/// Specifies the animation effect to use during a slide navigation transition.
/// </summary>
public enum NavigationTransitionEffect
{
/// <summary>
/// The navigation transition effect starts from the left edge of the frame.
/// </summary>
FromLeft,
/// <summary>
/// The navigation transition effect starts from the right edge of the frame.
/// </summary>
FromRight,
/// <summary>
/// The navigation transition effect starts from the top edge of the frame.
/// </summary>
FromTop,
/// <summary>
/// The navigation transition effect starts from the bottom edge of the frame.
/// </summary>
FromBottom
}
+1
View File
@@ -30,6 +30,7 @@ public enum WinoPage
KeyboardShortcutsPage, KeyboardShortcutsPage,
CalendarPage, CalendarPage,
CalendarSettingsPage, CalendarSettingsPage,
CalendarAccountSettingsPage,
EventDetailsPage, EventDetailsPage,
SignatureAndEncryptionPage SignatureAndEncryptionPage
} }
@@ -39,6 +39,16 @@ public interface IStatePersistanceService : INotifyPropertyChanged
/// </summary> /// </summary>
bool IsEventDetailsVisible { get; set; } bool IsEventDetailsVisible { get; set; }
/// <summary>
/// Whether ManageAccountsPage has navigated to a sub-page and can go back.
/// </summary>
bool IsManageAccountsNavigating { get; set; }
/// <summary>
/// Whether SettingsPage has navigated to a sub-page and can go back.
/// </summary>
bool IsSettingsNavigating { get; set; }
/// <summary> /// <summary>
/// Setting: Opened pane length for the navigation view. /// Setting: Opened pane length for the navigation view.
/// </summary> /// </summary>
@@ -13,5 +13,5 @@ public interface INavigationService
Type GetPageType(WinoPage winoPage); Type GetPageType(WinoPage winoPage);
bool ChangeApplicationMode(WinoApplicationMode mode); bool ChangeApplicationMode(WinoApplicationMode mode);
void GoBack(); void GoBack(NavigationTransitionEffect slideEffect = NavigationTransitionEffect.FromRight);
} }
@@ -26,6 +26,10 @@
"AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.", "AccountDetailsPage_Description": "Change the name of the account in Wino and set desired sender name.",
"AccountDetailsPage_ColorPicker_Title": "Account color", "AccountDetailsPage_ColorPicker_Title": "Account color",
"AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.", "AccountDetailsPage_ColorPicker_Description": "Assign a new account color to colorize its symbol in the list.",
"AccountDetailsPage_TabGeneral": "General",
"AccountDetailsPage_TabMail": "Mail",
"AccountDetailsPage_TabCalendar": "Calendar",
"AccountDetailsPage_CalendarListDescription": "Select a calendar to configure its settings",
"AddHyperlink": "Add", "AddHyperlink": "Add",
"AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization", "AppCloseBackgroundSynchronizationWarningTitle": "Background Synchronization",
"AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.", "AppCloseStartupLaunchDisabledWarningMessageFirstLine": "Application has not been set to launch on Windows startup.",
@@ -861,5 +865,15 @@
"ContactSelection_SelectAll": "Select All", "ContactSelection_SelectAll": "Select All",
"ContactSelection_Clear": "Clear Selection", "ContactSelection_Clear": "Clear Selection",
"ContactsPage_EmptyState": "No contacts to display", "ContactsPage_EmptyState": "No contacts to display",
"ContactsPage_AddFirstContact": "Add your first contact" "ContactsPage_AddFirstContact": "Add your first contact",
"CalendarAccountSettings_Title": "Calendar Account Settings",
"CalendarAccountSettings_Description": "Manage calendar settings for {0}",
"CalendarAccountSettings_AccountColor": "Account Color",
"CalendarAccountSettings_AccountColorDescription": "Change the display color for this calendar account",
"CalendarAccountSettings_SyncEnabled": "Enable Synchronization",
"CalendarAccountSettings_SyncEnabledDescription": "Enable or disable calendar synchronization for this account",
"CalendarAccountSettings_DefaultShowAs": "Default Show As Status",
"CalendarAccountSettings_DefaultShowAsDescription": "Default availability status for new events created with this account",
"CalendarAccountSettings_PrimaryCalendar": "Primary Calendar",
"CalendarAccountSettings_PrimaryCalendarDescription": "Mark this calendar as the primary calendar for the account"
} }
@@ -4,10 +4,12 @@ namespace Wino.Core.ViewModels;
public class ManageAccountsPagePageViewModel : CoreBaseViewModel public class ManageAccountsPagePageViewModel : CoreBaseViewModel
{ {
public ManageAccountsPagePageViewModel(INavigationService navigationService) public ManageAccountsPagePageViewModel(INavigationService navigationService, IStatePersistanceService statePersistenceService)
{ {
NavigationService = navigationService; NavigationService = navigationService;
StatePersistenceService = statePersistenceService;
} }
public INavigationService NavigationService { get; } public INavigationService NavigationService { get; }
public IStatePersistanceService StatePersistenceService { get; }
} }
@@ -4,10 +4,12 @@ namespace Wino.Core.ViewModels;
public class SettingsPageViewModel : CoreBaseViewModel public class SettingsPageViewModel : CoreBaseViewModel
{ {
public SettingsPageViewModel(INavigationService navigationService) public SettingsPageViewModel(INavigationService navigationService, IStatePersistanceService statePersistenceService)
{ {
NavigationService = navigationService; NavigationService = navigationService;
StatePersistenceService = statePersistenceService;
} }
public INavigationService NavigationService { get; } public INavigationService NavigationService { get; }
public IStatePersistanceService StatePersistenceService { get; }
} }
@@ -1,17 +1,21 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using Wino.Core.Domain; using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.Navigation; using Wino.Core.Domain.Models.Navigation;
using Wino.Core.Services; using Wino.Core.Services;
using Wino.Messaging.Client.Calendar;
using Wino.Messaging.Client.Navigation; using Wino.Messaging.Client.Navigation;
namespace Wino.Mail.ViewModels; namespace Wino.Mail.ViewModels;
@@ -21,11 +25,17 @@ public partial class AccountDetailsPageViewModel : MailBaseViewModel
private readonly IMailDialogService _dialogService; private readonly IMailDialogService _dialogService;
private readonly IAccountService _accountService; private readonly IAccountService _accountService;
private readonly IFolderService _folderService; private readonly IFolderService _folderService;
private readonly ICalendarService _calendarService;
private bool isLoaded = false; private bool isLoaded = false;
public MailAccount Account { get; set; } public MailAccount Account { get; set; }
public ObservableCollection<IMailItemFolder> CurrentFolders { get; set; } = []; public ObservableCollection<IMailItemFolder> CurrentFolders { get; set; } = [];
public ObservableCollection<AccountCalendar> AccountCalendars { get; set; } = [];
[ObservableProperty]
public partial int SelectedTabIndex { get; set; } = 1; // Default to Mail tab
// Mail-related properties
[ObservableProperty] [ObservableProperty]
private bool isFocusedInboxEnabled; private bool isFocusedInboxEnabled;
@@ -49,11 +59,13 @@ public partial class AccountDetailsPageViewModel : MailBaseViewModel
public AccountDetailsPageViewModel(IMailDialogService dialogService, public AccountDetailsPageViewModel(IMailDialogService dialogService,
IAccountService accountService, IAccountService accountService,
IFolderService folderService) IFolderService folderService,
ICalendarService calendarService)
{ {
_dialogService = dialogService; _dialogService = dialogService;
_accountService = accountService; _accountService = accountService;
_folderService = folderService; _folderService = folderService;
_calendarService = calendarService;
} }
[RelayCommand] [RelayCommand]
@@ -127,10 +139,33 @@ public partial class AccountDetailsPageViewModel : MailBaseViewModel
CurrentFolders.Add(folder); CurrentFolders.Add(folder);
} }
// Load calendar list
await LoadAccountCalendarsAsync();
isLoaded = true; isLoaded = true;
} }
} }
private async Task LoadAccountCalendarsAsync()
{
var calendars = await _calendarService.GetAccountCalendarsAsync(Account.Id);
AccountCalendars.Clear();
foreach (var calendar in calendars)
{
AccountCalendars.Add(calendar);
}
}
[RelayCommand]
private void CalendarItemClicked(AccountCalendar calendar)
{
if (calendar == null) return;
// Navigate to calendar settings page with breadcrumb
Messenger.Send(new BreadcrumbNavigationRequested(calendar.Name, WinoPage.CalendarAccountSettingsPage, calendar));
}
protected override async void OnPropertyChanged(PropertyChangedEventArgs e) protected override async void OnPropertyChanged(PropertyChangedEventArgs e)
{ {
base.OnPropertyChanged(e); base.OnPropertyChanged(e);
+1
View File
@@ -95,6 +95,7 @@ public partial class App : WinoApplication,
services.AddTransient(typeof(CalendarPageViewModel)); services.AddTransient(typeof(CalendarPageViewModel));
services.AddTransient(typeof(CalendarSettingsPageViewModel)); services.AddTransient(typeof(CalendarSettingsPageViewModel));
services.AddTransient(typeof(CalendarAccountSettingsPageViewModel));
services.AddTransient(typeof(EventDetailsPageViewModel)); services.AddTransient(typeof(EventDetailsPageViewModel));
} }
+1
View File
@@ -42,6 +42,7 @@ public static class XamlHelpers
public static Visibility ReverseBoolToVisibilityConverter(bool value) => value ? Visibility.Collapsed : Visibility.Visible; public static Visibility ReverseBoolToVisibilityConverter(bool value) => value ? Visibility.Collapsed : Visibility.Visible;
public static Visibility ReverseVisibilityConverter(Visibility visibility) => visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible; public static Visibility ReverseVisibilityConverter(Visibility visibility) => visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
public static bool ReverseBoolConverter(bool value) => !value; public static bool ReverseBoolConverter(bool value) => !value;
public static bool AreEqual(int value1, int value2) => value1 == value2;
public static bool ShouldDisplayPreview(string text) => text == null ? false : text.Any(x => char.IsLetter(x)); public static bool ShouldDisplayPreview(string text) => text == null ? false : text.Any(x => char.IsLetter(x));
public static bool CountToBooleanConverter(int value) => value > 0; public static bool CountToBooleanConverter(int value) => value > 0;
public static bool ObjectEquals(object obj1, object obj2) => object.Equals(obj1, obj2); public static bool ObjectEquals(object obj1, object obj2) => object.Equals(obj1, obj2);
@@ -8,7 +8,7 @@ namespace Wino.Selectors;
/// <summary> /// <summary>
/// DataTemplateSelector that selects the appropriate stripe template based on CalendarItemShowAs status. /// DataTemplateSelector that selects the appropriate stripe template based on CalendarItemShowAs status.
/// </summary> /// </summary>
public class CalendarItemShowAsStripeTemplateSelector : DataTemplateSelector public partial class CalendarItemShowAsStripeTemplateSelector : DataTemplateSelector
{ {
public DataTemplate FreeTemplate { get; set; } public DataTemplate FreeTemplate { get; set; }
public DataTemplate TentativeTemplate { get; set; } public DataTemplate TentativeTemplate { get; set; }
+12 -1
View File
@@ -15,6 +15,7 @@ using Wino.Mail.WinUI.Interfaces;
using Wino.Mail.WinUI.Services; using Wino.Mail.WinUI.Services;
using Wino.Mail.WinUI.Views.Calendar; using Wino.Mail.WinUI.Views.Calendar;
using Wino.Messaging.Client.Mails; using Wino.Messaging.Client.Mails;
using Wino.Messaging.Client.Navigation;
using Wino.Views; using Wino.Views;
using Wino.Views.Account; using Wino.Views.Account;
using Wino.Views.Mail; using Wino.Views.Mail;
@@ -68,6 +69,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
WinoPage.CalendarPage => typeof(CalendarPage), WinoPage.CalendarPage => typeof(CalendarPage),
WinoPage.EventDetailsPage => typeof(EventDetailsPage), WinoPage.EventDetailsPage => typeof(EventDetailsPage),
WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage), WinoPage.CalendarSettingsPage => typeof(CalendarSettingsPage),
WinoPage.CalendarAccountSettingsPage => typeof(CalendarAccountSettingsPage),
_ => null, _ => null,
}; };
} }
@@ -208,8 +210,17 @@ public class NavigationService : NavigationServiceBase, INavigationService
return false; return false;
} }
public void GoBack() public void GoBack(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)
{
// Send message to ManageAccountsPage to go back within its AccountPagesFrame
WeakReferenceMessenger.Default.Send(new BackBreadcrumNavigationRequested(slideEffect));
return;
}
if (_statePersistanceService.ApplicationMode == WinoApplicationMode.Calendar) if (_statePersistanceService.ApplicationMode == WinoApplicationMode.Calendar)
{ {
var innerShellFrame = GetCoreFrame(NavigationReferenceFrame.InnerShellFrame); var innerShellFrame = GetCoreFrame(NavigationReferenceFrame.InnerShellFrame);
@@ -32,8 +32,8 @@ public class StatePersistenceService : ObservableObject, IStatePersistanceServic
public bool IsBackButtonVisible => public bool IsBackButtonVisible =>
ApplicationMode == WinoApplicationMode.Mail ApplicationMode == WinoApplicationMode.Mail
? IsReadingMail && IsReaderNarrowed ? (IsReadingMail && IsReaderNarrowed) || IsManageAccountsNavigating || IsSettingsNavigating
: IsEventDetailsVisible; : IsEventDetailsVisible || IsManageAccountsNavigating || IsSettingsNavigating;
private WinoApplicationMode applicationMode = WinoApplicationMode.Mail; private WinoApplicationMode applicationMode = WinoApplicationMode.Mail;
@@ -66,6 +66,34 @@ 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
{
get => isSettingsNavigating;
set
{
if (SetProperty(ref isSettingsNavigating, value))
{
OnPropertyChanged(nameof(IsBackButtonVisible));
}
}
}
private bool isReadingMail; private bool isReadingMail;
public bool IsReadingMail public bool IsReadingMail
@@ -0,0 +1,6 @@
using Wino.Calendar.ViewModels;
using Wino.Mail.WinUI.Views.Abstract;
namespace Wino.Mail.WinUI.Views.Abstract;
public abstract class CalendarAccountSettingsPageAbstract : BasePage<CalendarAccountSettingsPageViewModel> { }
@@ -3,6 +3,7 @@
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:abstract="using:Wino.Views.Abstract" xmlns:abstract="using:Wino.Views.Abstract"
xmlns:calendar="using:Wino.Core.Domain.Entities.Calendar"
xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:controls1="using:Wino.Controls" xmlns:controls1="using:Wino.Controls"
xmlns:coreControls="using:Wino.Mail.WinUI.Controls" xmlns:coreControls="using:Wino.Mail.WinUI.Controls"
@@ -15,7 +16,8 @@
xmlns:local="using:Wino.Views" xmlns:local="using:Wino.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
x:Name="root" xmlns:ui="using:CommunityToolkit.WinUI"
x:Name="PageRoot"
mc:Ignorable="d"> mc:Ignorable="d">
<Page.Resources> <Page.Resources>
@@ -69,6 +71,27 @@
</Page.Resources> </Page.Resources>
<ScrollViewer> <ScrollViewer>
<Grid RowSpacing="12">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<SelectorBar x:Name="TabSelector" SelectionChanged="OnTabSelectionChanged">
<SelectorBarItem Icon="Contact" Text="{x:Bind domain:Translator.AccountDetailsPage_TabGeneral, Mode=OneTime}" />
<SelectorBarItem Icon="Mail" Text="{x:Bind domain:Translator.AccountDetailsPage_TabMail, Mode=OneTime}" />
<SelectorBarItem Text="{x:Bind domain:Translator.AccountDetailsPage_TabCalendar, Mode=OneTime}">
<SelectorBarItem.Icon>
<FontIcon Glyph="&#xE163;" />
</SelectorBarItem.Icon>
</SelectorBarItem>
</SelectorBar>
<!-- General Settings Panel -->
<Grid
x:Name="GeneralSettingsPanel"
Grid.Row="1"
Visibility="Collapsed">
<StackPanel Spacing="4"> <StackPanel Spacing="4">
<StackPanel.ChildrenTransitions> <StackPanel.ChildrenTransitions>
<TransitionCollection> <TransitionCollection>
@@ -86,6 +109,36 @@
</controls:SettingsCard.HeaderIcon> </controls:SettingsCard.HeaderIcon>
</controls:SettingsCard> </controls:SettingsCard>
<controls:SettingsCard
ActionIcon="{x:Null}"
ActionIconToolTip="{x:Bind domain:Translator.SettingsDeleteAccount_Title}"
Command="{x:Bind ViewModel.DeleteAccountCommand}"
Description="{x:Bind domain:Translator.SettingsDeleteAccount_Description}"
Header="{x:Bind domain:Translator.SettingsDeleteAccount_Title}">
<Button
Background="Red"
Command="{x:Bind ViewModel.DeleteAccountCommand}"
Content="{x:Bind domain:Translator.Buttons_Delete}" />
<controls:SettingsCard.HeaderIcon>
<SymbolIcon Symbol="Delete" />
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
</StackPanel>
</Grid>
<!-- Mail Settings Panel -->
<Grid
x:Name="MailSettingsPanel"
Grid.Row="1"
Visibility="Collapsed">
<StackPanel Spacing="4">
<StackPanel.ChildrenTransitions>
<TransitionCollection>
<RepositionThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</StackPanel.ChildrenTransitions>
<controls:SettingsCard <controls:SettingsCard
Command="{x:Bind ViewModel.EditAliasesCommand}" Command="{x:Bind ViewModel.EditAliasesCommand}"
Description="{x:Bind domain:Translator.SettingsManageAliases_Description}" Description="{x:Bind domain:Translator.SettingsManageAliases_Description}"
@@ -233,22 +286,79 @@
<ToggleSwitch IsOn="{x:Bind ViewModel.IsAppendMessageSettinEnabled, Mode=TwoWay}" /> <ToggleSwitch IsOn="{x:Bind ViewModel.IsAppendMessageSettinEnabled, Mode=TwoWay}" />
</controls:SettingsCard> </controls:SettingsCard>
<controls:SettingsCard
Margin="0,-4,0,0"
ActionIcon="{x:Null}"
ActionIconToolTip="{x:Bind domain:Translator.SettingsDeleteAccount_Title}"
Command="{x:Bind ViewModel.DeleteAccountCommand}"
Description="{x:Bind domain:Translator.SettingsDeleteAccount_Description}"
Header="{x:Bind domain:Translator.SettingsDeleteAccount_Title}">
<Button
Background="Red"
Command="{x:Bind ViewModel.DeleteAccountCommand}"
Content="{x:Bind domain:Translator.Buttons_Delete}" />
<controls:SettingsCard.HeaderIcon>
<SymbolIcon Symbol="Delete" />
</controls:SettingsCard.HeaderIcon>
</controls:SettingsCard>
</StackPanel> </StackPanel>
</Grid>
<!-- Calendar Settings Panel -->
<Grid
x:Name="CalendarSettingsPanel"
Grid.Row="1"
Visibility="Collapsed">
<StackPanel MaxWidth="900" Spacing="12">
<!-- Calendars List -->
<ItemsControl ItemsSource="{x:Bind ViewModel.AccountCalendars, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="calendar:AccountCalendar">
<controls:SettingsCard
Margin="0,0,0,4"
ActionIcon="{ui:FontIcon Glyph=&#xE974;}"
Click="CalendarItemClicked"
CommandParameter="{x:Bind}"
Description="{x:Bind TimeZone, Mode=OneWay}"
Header="{x:Bind Name, Mode=OneWay}"
IsClickEnabled="True">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE163;" />
</controls:SettingsCard.HeaderIcon>
<Border
Width="32"
Height="32"
Background="{x:Bind BackgroundColorHex, Mode=OneWay}"
CornerRadius="4" />
</controls:SettingsCard>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="TabStates">
<VisualState x:Name="GeneralTab">
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.AreEqual(ViewModel.SelectedTabIndex, 0), Mode=OneWay}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="GeneralSettingsPanel.Visibility" Value="Visible" />
<Setter Target="MailSettingsPanel.Visibility" Value="Collapsed" />
<Setter Target="CalendarSettingsPanel.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="MailTab">
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.AreEqual(ViewModel.SelectedTabIndex, 1), Mode=OneWay}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="GeneralSettingsPanel.Visibility" Value="Collapsed" />
<Setter Target="MailSettingsPanel.Visibility" Value="Visible" />
<Setter Target="CalendarSettingsPanel.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="CalendarTab">
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:XamlHelpers.AreEqual(ViewModel.SelectedTabIndex, 2), Mode=OneWay}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="GeneralSettingsPanel.Visibility" Value="Collapsed" />
<Setter Target="MailSettingsPanel.Visibility" Value="Collapsed" />
<Setter Target="CalendarSettingsPanel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ScrollViewer> </ScrollViewer>
</abstract:AccountDetailsPageAbstract> </abstract:AccountDetailsPageAbstract>
@@ -1,4 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Wino.Core.Domain.Entities.Calendar;
using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.Folders;
using Wino.Views.Abstract; using Wino.Views.Abstract;
@@ -9,9 +12,16 @@ public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
public AccountDetailsPage() public AccountDetailsPage()
{ {
InitializeComponent(); InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
} }
private async void SyncFolderToggled(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) private void OnTabSelectionChanged(SelectorBar sender, SelectorBarSelectionChangedEventArgs e)
{
ViewModel.SelectedTabIndex = TabSelector.SelectedItem == null ? 1 : TabSelector.Items.IndexOf(TabSelector.SelectedItem);
}
private async void SyncFolderToggled(object sender, RoutedEventArgs e)
{ {
if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder) if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder)
{ {
@@ -19,11 +29,30 @@ public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
} }
} }
private async void UnreadBadgeCheckboxToggled(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) private async void UnreadBadgeCheckboxToggled(object sender, RoutedEventArgs e)
{ {
if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder) if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder)
{ {
await ViewModel.FolderShowUnreadToggled(folder, checkBox.IsChecked.GetValueOrDefault()); await ViewModel.FolderShowUnreadToggled(folder, checkBox.IsChecked.GetValueOrDefault());
} }
} }
private void CalendarItemClicked(object sender, RoutedEventArgs e)
{
if (sender is CommunityToolkit.WinUI.Controls.SettingsCard settingsCard && settingsCard.CommandParameter is AccountCalendar calendar)
{
ViewModel.CalendarItemClickedCommand?.Execute(calendar);
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode == NavigationMode.New)
{
// Set initial tab to Mail (index 1)
TabSelector.SelectedItem = TabSelector.Items[1];
}
}
} }
@@ -230,7 +230,6 @@
<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 M 18.125 9.443359 C 18.125 9.866537 18.040363 10.263672 17.871094 10.634766 C 17.701822 11.005859 17.473957 11.329753 17.1875 11.606445 C 16.901041 11.883139 16.56901 12.101237 16.191406 12.260742 C 15.813802 12.420248 15.416666 12.5 15 12.5 C 14.563802 12.5 14.1569 12.41862 13.779297 12.255859 C 13.401691 12.0931 13.071288 11.870117 12.788086 11.586914 C 12.504882 11.303711 12.2819 10.973308 12.119141 10.595703 C 11.95638 10.2181 11.875 9.811198 11.875 9.375 C 11.875 8.938803 11.95638 8.531901 12.119141 8.154297 C 12.2819 7.776693 12.504882 7.446289 12.788086 7.163086 C 13.071288 6.879883 13.401691 6.656901 13.779297 6.494141 C 14.1569 6.331381 14.563802 6.25 15 6.25 C 15.449218 6.25 15.864257 6.333008 16.245117 6.499023 C 16.625977 6.665039 16.956379 6.892904 17.236328 7.182617 C 17.516275 7.472331 17.734375 7.810873 17.890625 8.198242 C 18.046875 8.585612 18.125 9.000651 18.125 9.443359 Z M 20 16.25 C 20 16.666666 19.926758 17.049154 19.780273 17.397461 C 19.633789 17.745768 19.435221 18.058268 19.18457 18.334961 C 18.933918 18.611654 18.642578 18.854166 18.310547 19.0625 C 17.978516 19.270834 17.626953 19.444986 17.255859 19.584961 C 16.884766 19.724936 16.505533 19.829102 16.118164 19.897461 C 15.730794 19.96582 15.358072 20 15 20 C 14.654947 20 14.291992 19.96582 13.911133 19.897461 C 13.530273 19.829102 13.154297 19.726562 12.783203 19.589844 C 12.412109 19.453125 12.058919 19.282227 11.723633 19.077148 C 11.388346 18.87207 11.092122 18.632812 10.834961 18.359375 C 10.577799 18.085938 10.374349 17.779947 10.224609 17.441406 C 10.074869 17.102865 10 16.731771 10 16.328125 L 10 15.78125 C 10 15.501303 10.052083 15.237631 10.15625 14.990234 C 10.260416 14.742839 10.405273 14.526367 10.59082 14.34082 C 10.776367 14.155273 10.991211 14.010417 11.235352 13.90625 C 11.479492 13.802084 11.744791 13.75 12.03125 13.75 L 17.96875 13.75 C 18.248697 13.75 18.512369 13.803711 18.759766 13.911133 C 19.00716 14.018555 19.222004 14.163412 19.404297 14.345703 C 19.586588 14.527995 19.731445 14.742839 19.838867 14.990234 C 19.946289 15.237631 20 15.501303 20 15.78125 Z " /> <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 M 18.125 9.443359 C 18.125 9.866537 18.040363 10.263672 17.871094 10.634766 C 17.701822 11.005859 17.473957 11.329753 17.1875 11.606445 C 16.901041 11.883139 16.56901 12.101237 16.191406 12.260742 C 15.813802 12.420248 15.416666 12.5 15 12.5 C 14.563802 12.5 14.1569 12.41862 13.779297 12.255859 C 13.401691 12.0931 13.071288 11.870117 12.788086 11.586914 C 12.504882 11.303711 12.2819 10.973308 12.119141 10.595703 C 11.95638 10.2181 11.875 9.811198 11.875 9.375 C 11.875 8.938803 11.95638 8.531901 12.119141 8.154297 C 12.2819 7.776693 12.504882 7.446289 12.788086 7.163086 C 13.071288 6.879883 13.401691 6.656901 13.779297 6.494141 C 14.1569 6.331381 14.563802 6.25 15 6.25 C 15.449218 6.25 15.864257 6.333008 16.245117 6.499023 C 16.625977 6.665039 16.956379 6.892904 17.236328 7.182617 C 17.516275 7.472331 17.734375 7.810873 17.890625 8.198242 C 18.046875 8.585612 18.125 9.000651 18.125 9.443359 Z M 20 16.25 C 20 16.666666 19.926758 17.049154 19.780273 17.397461 C 19.633789 17.745768 19.435221 18.058268 19.18457 18.334961 C 18.933918 18.611654 18.642578 18.854166 18.310547 19.0625 C 17.978516 19.270834 17.626953 19.444986 17.255859 19.584961 C 16.884766 19.724936 16.505533 19.829102 16.118164 19.897461 C 15.730794 19.96582 15.358072 20 15 20 C 14.654947 20 14.291992 19.96582 13.911133 19.897461 C 13.530273 19.829102 13.154297 19.726562 12.783203 19.589844 C 12.412109 19.453125 12.058919 19.282227 11.723633 19.077148 C 11.388346 18.87207 11.092122 18.632812 10.834961 18.359375 C 10.577799 18.085938 10.374349 17.779947 10.224609 17.441406 C 10.074869 17.102865 10 16.731771 10 16.328125 L 10 15.78125 C 10 15.501303 10.052083 15.237631 10.15625 14.990234 C 10.260416 14.742839 10.405273 14.526367 10.59082 14.34082 C 10.776367 14.155273 10.991211 14.010417 11.235352 13.90625 C 11.479492 13.802084 11.744791 13.75 12.03125 13.75 L 17.96875 13.75 C 18.248697 13.75 18.512369 13.803711 18.759766 13.911133 C 19.00716 14.018555 19.222004 14.163412 19.404297 14.345703 C 19.586588 14.527995 19.731445 14.742839 19.838867 14.990234 C 19.946289 15.237631 20 15.501303 20 15.78125 Z " />
</winuiControls:SettingsCard.HeaderIcon> </winuiControls:SettingsCard.HeaderIcon>
</winuiControls:SettingsCard> </winuiControls:SettingsCard>
<winuiControls:SettingsCard <winuiControls:SettingsCard
Command="{x:Bind ViewModel.ReorderAccountsCommand}" Command="{x:Bind ViewModel.ReorderAccountsCommand}"
Description="{x:Bind domain:Translator.SettingsReorderAccounts_Description}" Description="{x:Bind domain:Translator.SettingsReorderAccounts_Description}"
@@ -1,6 +1,5 @@
using CommunityToolkit.WinUI.Controls; using CommunityToolkit.WinUI.Controls;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Navigation;
using Wino.Core.ViewModels.Data; using Wino.Core.ViewModels.Data;
using Wino.Mail.ViewModels.Data; using Wino.Mail.ViewModels.Data;
using Wino.Views.Abstract; using Wino.Views.Abstract;
@@ -12,8 +11,6 @@ public sealed partial class AccountManagementPage : AccountManagementPageAbstrac
public AccountManagementPage() public AccountManagementPage()
{ {
InitializeComponent(); InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
} }
private void EditMergedAccounts_Click(object sender, RoutedEventArgs e) private void EditMergedAccounts_Click(object sender, RoutedEventArgs e)
@@ -0,0 +1,86 @@
<abstract:CalendarAccountSettingsPageAbstract
x:Class="Wino.Mail.WinUI.Views.Calendar.CalendarAccountSettingsPage"
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:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Style="{StaticResource PageStyle}"
mc:Ignorable="d">
<Grid Padding="20" RowSpacing="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Page Header -->
<StackPanel Grid.Row="0" Spacing="4">
<TextBlock
Style="{StaticResource TitleTextBlockStyle}"
Text="{x:Bind domain:Translator.CalendarAccountSettings_Title, Mode=OneTime}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind ViewModel.Account.Name, Mode=OneWay}"
TextWrapping="Wrap" />
</StackPanel>
<!-- Settings Cards -->
<ScrollViewer Grid.Row="1">
<StackPanel MaxWidth="900" Spacing="4">
<!-- Account Color -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_AccountColorDescription, Mode=OneTime}"
Header="{x:Bind domain:Translator.CalendarAccountSettings_AccountColor, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE790;" />
</controls:SettingsCard.HeaderIcon>
<Border
Width="40"
Height="40"
Background="{x:Bind ViewModel.AccountColorHex, Mode=OneWay}"
CornerRadius="4" />
</controls:SettingsCard>
<!-- Enable Synchronization -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_SyncEnabledDescription, Mode=OneTime}"
Header="{x:Bind domain:Translator.CalendarAccountSettings_SyncEnabled, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE895;" />
</controls:SettingsCard.HeaderIcon>
<ToggleSwitch IsOn="{x:Bind ViewModel.IsSyncEnabled, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Primary Calendar -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendarDescription, Mode=OneTime}"
Header="{x:Bind domain:Translator.CalendarAccountSettings_PrimaryCalendar, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE735;" />
</controls:SettingsCard.HeaderIcon>
<ToggleSwitch IsOn="{x:Bind ViewModel.IsPrimaryCalendar, Mode=TwoWay}" />
</controls:SettingsCard>
<!-- Default Show As Status -->
<controls:SettingsCard
Description="{x:Bind domain:Translator.CalendarAccountSettings_DefaultShowAsDescription, Mode=OneTime}"
Header="{x:Bind domain:Translator.CalendarAccountSettings_DefaultShowAs, Mode=OneTime}">
<controls:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE163;" />
</controls:SettingsCard.HeaderIcon>
<ComboBox
MinWidth="150"
DisplayMemberPath="DisplayText"
ItemsSource="{x:Bind ViewModel.ShowAsOptions, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.SelectedDefaultShowAsOption, Mode=TwoWay}" />
</controls:SettingsCard>
</StackPanel>
</ScrollViewer>
</Grid>
</abstract:CalendarAccountSettingsPageAbstract>
@@ -0,0 +1,11 @@
using Wino.Mail.WinUI.Views.Abstract;
namespace Wino.Mail.WinUI.Views.Calendar;
public sealed partial class CalendarAccountSettingsPage : CalendarAccountSettingsPageAbstract
{
public CalendarAccountSettingsPage()
{
InitializeComponent();
}
}
@@ -7,8 +7,10 @@
xmlns:controls1="using:Microsoft.UI.Xaml.Controls" xmlns:controls1="using:Microsoft.UI.Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain" xmlns:domain="using:Wino.Core.Domain"
xmlns:entities="using:Wino.Core.Domain.Entities.Shared"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkitExt="using:CommunityToolkit.WinUI" xmlns:toolkitExt="using:CommunityToolkit.WinUI"
x:Name="Root"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
@@ -178,7 +180,52 @@
</controls:SettingsCard> </controls:SettingsCard>
</controls:SettingsExpander.Items> </controls:SettingsExpander.Items>
</controls:SettingsExpander> </controls:SettingsExpander>
<!-- Calendar Accounts -->
<!--<controls:SettingsExpander
Description="Manage calendar settings for each account"
Header="Calendar Accounts"
IsExpanded="True">
<controls:SettingsExpander.HeaderIcon>
<FontIcon Glyph="&#xE77B;" />
</controls:SettingsExpander.HeaderIcon>
<controls:SettingsExpander.Items>
<controls:SettingsCard
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ContentAlignment="Vertical">
<ItemsControl ItemsSource="{x:Bind ViewModel.Accounts, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="entities:MailAccount">
<Button
Padding="12,8"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Command="{Binding ElementName=Root, Path=ViewModel.NavigateToAccountSettingsCommand}"
CommandParameter="{x:Bind}"
Style="{StaticResource SubtleButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="12">
<FontIcon FontSize="20" Glyph="&#xE8D8;" />
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{x:Bind Name}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Address}" />
</StackPanel>
<FontIcon
Margin="0,0,8,0"
HorizontalAlignment="Right"
FontSize="12"
Glyph="&#xE76C;" />
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>-->
<!-- Default reminder --> <!-- Default reminder -->
<controls:SettingsCard Description="Set a default reminder for all new calendar events." Header="Default reminder"> <controls:SettingsCard Description="Set a default reminder for all new calendar events." Header="Default reminder">
<controls:SettingsCard.HeaderIcon> <controls:SettingsCard.HeaderIcon>
@@ -43,7 +43,10 @@
</winuiControls:BreadcrumbBar.ItemTemplate> </winuiControls:BreadcrumbBar.ItemTemplate>
</winuiControls:BreadcrumbBar> </winuiControls:BreadcrumbBar>
<Frame x:Name="AccountPagesFrame" Grid.Row="1" /> <Frame
x:Name="AccountPagesFrame"
Grid.Row="1"
Navigated="AccountPagesFrameNavigated" />
</Grid> </Grid>
</Border> </Border>
</abstract:ManageAccountsPageAbstract> </abstract:ManageAccountsPageAbstract>
@@ -6,8 +6,8 @@ using Microsoft.UI.Xaml.Navigation;
using MoreLinq; using MoreLinq;
using Wino.Core.Domain; using Wino.Core.Domain;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Mail.WinUI.Views.Abstract;
using Wino.Mail.ViewModels.Data; using Wino.Mail.ViewModels.Data;
using Wino.Mail.WinUI.Views.Abstract;
using Wino.Messaging.Client.Navigation; using Wino.Messaging.Client.Navigation;
using Wino.Messaging.UI; using Wino.Messaging.UI;
@@ -37,6 +37,10 @@ public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract,
WeakReferenceMessenger.Default.Register<MergedInboxRenamed>(this); WeakReferenceMessenger.Default.Register<MergedInboxRenamed>(this);
WeakReferenceMessenger.Default.Register<AccountUpdatedMessage>(this); WeakReferenceMessenger.Default.Register<AccountUpdatedMessage>(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); var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuManageAccounts, WinoPage.AccountManagementPage);
PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true)); PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true));
@@ -53,6 +57,12 @@ public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract,
WeakReferenceMessenger.Default.Unregister<MergedInboxRenamed>(this); WeakReferenceMessenger.Default.Unregister<MergedInboxRenamed>(this);
WeakReferenceMessenger.Default.Unregister<AccountUpdatedMessage>(this); WeakReferenceMessenger.Default.Unregister<AccountUpdatedMessage>(this);
// Unregister frame navigation event
AccountPagesFrame.Navigated -= AccountPagesFrameNavigated;
// Reset navigation state when leaving ManageAccountsPage
ViewModel.StatePersistenceService.IsManageAccountsNavigating = false;
base.OnNavigatingFrom(e); base.OnNavigatingFrom(e);
} }
@@ -62,20 +72,42 @@ public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract,
if (pageType == null) return; if (pageType == null) return;
AccountPagesFrame.Navigate(pageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); AccountPagesFrame.Navigate(pageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = Microsoft.UI.Xaml.Media.Animation.SlideNavigationTransitionEffect.FromRight });
PageHistory.ForEach(a => a.IsActive = false); PageHistory.ForEach(a => a.IsActive = false);
PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true)); PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true));
} }
private void GoBackFrame() 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 (AccountPagesFrame.CanGoBack) if (AccountPagesFrame.CanGoBack)
{ {
PageHistory.RemoveAt(PageHistory.Count - 1); PageHistory.RemoveAt(PageHistory.Count - 1);
AccountPagesFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); var winuiEffect = slideEffect switch
{
Core.Domain.Enums.NavigationTransitionEffect.FromLeft => Microsoft.UI.Xaml.Media.Animation.SlideNavigationTransitionEffect.FromLeft,
_ => Microsoft.UI.Xaml.Media.Animation.SlideNavigationTransitionEffect.FromRight,
};
AccountPagesFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = winuiEffect });
// Set the new last item as active
if (PageHistory.Count > 0)
{
PageHistory.ForEach(a => a.IsActive = false);
PageHistory[PageHistory.Count - 1].IsActive = true;
}
// Update back button visibility after navigation
ViewModel.StatePersistenceService.IsManageAccountsNavigating = AccountPagesFrame.CanGoBack;
} }
} }
@@ -83,17 +115,16 @@ public sealed partial class ManageAccountsPage : ManageAccountsPageAbstract,
{ {
var clickedPageHistory = PageHistory[args.Index]; var clickedPageHistory = PageHistory[args.Index];
// Trigger GoBack repeatedly until we reach the clicked breadcrumb item
while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory) while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory)
{ {
AccountPagesFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); ViewModel.NavigationService.GoBack();
PageHistory.RemoveAt(PageHistory.Count - 1);
PageHistory[PageHistory.Count - 1].IsActive = true;
} }
} }
public void Receive(BackBreadcrumNavigationRequested message) public void Receive(BackBreadcrumNavigationRequested message)
{ {
GoBackFrame(); GoBackFrame(message.SlideEffect);
} }
public void Receive(AccountUpdatedMessage message) public void Receive(AccountUpdatedMessage message)
@@ -43,7 +43,7 @@
Text="{x:Bind ViewModel.SenderName, Mode=TwoWay}" /> Text="{x:Bind ViewModel.SenderName, Mode=TwoWay}" />
</controls:SettingsCard> </controls:SettingsCard>
<controls:SettingsCard HorizontalContentAlignment="Stretch" Header="{x:Bind domain:Translator.Buttons_Save}"> <controls:SettingsCard HorizontalContentAlignment="Stretch">
<Button <Button
Command="{x:Bind ViewModel.SaveChangesCommand}" Command="{x:Bind ViewModel.SaveChangesCommand}"
Content="{x:Bind domain:Translator.Buttons_Save}" Content="{x:Bind domain:Translator.Buttons_Save}"
+55 -6
View File
@@ -1,9 +1,9 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using MoreLinq;
using Microsoft.UI.Xaml.Media.Animation; using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Navigation; using Microsoft.UI.Xaml.Navigation;
using MoreLinq;
using Wino.Core.Domain; using Wino.Core.Domain;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Mail.ViewModels.Data; using Wino.Mail.ViewModels.Data;
@@ -13,7 +13,9 @@ using Wino.Views.Settings;
namespace Wino.Views; namespace Wino.Views;
public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<BreadcrumbNavigationRequested> public sealed partial class SettingsPage : SettingsPageAbstract,
IRecipient<BreadcrumbNavigationRequested>,
IRecipient<BackBreadcrumNavigationRequested>
{ {
public ObservableCollection<BreadcrumbNavigationItemViewModel> PageHistory { get; set; } = []; public ObservableCollection<BreadcrumbNavigationItemViewModel> PageHistory { get; set; } = [];
@@ -26,6 +28,10 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
{ {
base.OnNavigatedTo(e); base.OnNavigatedTo(e);
// Register for frame navigation events to track back button visibility
SettingsFrame.Navigated -= SettingsFrameNavigated;
SettingsFrame.Navigated += SettingsFrameNavigated;
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo()); SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage); var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage);
@@ -60,6 +66,12 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{ {
// Unregister frame navigation event
SettingsFrame.Navigated -= SettingsFrameNavigated;
// Reset navigation state when leaving SettingsPage
ViewModel.StatePersistenceService.IsSettingsNavigating = false;
base.OnNavigatingFrom(e); base.OnNavigatingFrom(e);
} }
@@ -68,6 +80,7 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
base.RegisterRecipients(); base.RegisterRecipients();
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this); WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
WeakReferenceMessenger.Default.Register<BackBreadcrumNavigationRequested>(this);
} }
protected override void UnregisterRecipients() protected override void UnregisterRecipients()
@@ -75,6 +88,7 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
base.UnregisterRecipients(); base.UnregisterRecipients();
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this); WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
WeakReferenceMessenger.Default.Unregister<BackBreadcrumNavigationRequested>(this);
} }
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message) void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
@@ -90,16 +104,51 @@ public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<Brea
PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true)); PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true));
} }
private void SettingsFrameNavigated(object sender, NavigationEventArgs e)
{
// Update back button visibility based on whether we can go back within the frame
ViewModel.StatePersistenceService.IsSettingsNavigating = SettingsFrame.CanGoBack;
}
private void GoBackFrame(Core.Domain.Enums.NavigationTransitionEffect slideEffect)
{
if (SettingsFrame.CanGoBack)
{
PageHistory.RemoveAt(PageHistory.Count - 1);
var winuiEffect = slideEffect switch
{
Core.Domain.Enums.NavigationTransitionEffect.FromLeft => Microsoft.UI.Xaml.Media.Animation.SlideNavigationTransitionEffect.FromLeft,
_ => Microsoft.UI.Xaml.Media.Animation.SlideNavigationTransitionEffect.FromRight,
};
SettingsFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = winuiEffect });
// Set the new last item as active
if (PageHistory.Count > 0)
{
PageHistory.ForEach(a => a.IsActive = false);
PageHistory[PageHistory.Count - 1].IsActive = true;
}
// Update back button visibility after navigation
ViewModel.StatePersistenceService.IsSettingsNavigating = SettingsFrame.CanGoBack;
}
}
private void BreadItemClicked(Microsoft.UI.Xaml.Controls.BreadcrumbBar sender, Microsoft.UI.Xaml.Controls.BreadcrumbBarItemClickedEventArgs args) private void BreadItemClicked(Microsoft.UI.Xaml.Controls.BreadcrumbBar sender, Microsoft.UI.Xaml.Controls.BreadcrumbBarItemClickedEventArgs args)
{ {
var clickedPageHistory = PageHistory[args.Index]; var clickedPageHistory = PageHistory[args.Index];
var activeIndex = PageHistory.IndexOf(PageHistory.FirstOrDefault(a => a.IsActive));
// Trigger GoBack repeatedly until we reach the clicked breadcrumb item
while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory) while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory)
{ {
SettingsFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); ViewModel.NavigationService.GoBack();
PageHistory.RemoveAt(PageHistory.Count - 1);
PageHistory[PageHistory.Count - 1].IsActive = true;
} }
} }
public void Receive(BackBreadcrumNavigationRequested message)
{
GoBackFrame(message.SlideEffect);
}
} }
@@ -1,6 +1,9 @@
namespace Wino.Messaging.Client.Navigation; using Wino.Core.Domain.Enums;
namespace Wino.Messaging.Client.Navigation;
/// <summary> /// <summary>
/// When back navigation is requested for breadcrumb pages. /// When back navigation is requested for breadcrumb pages.
/// </summary> /// </summary>
public record BackBreadcrumNavigationRequested { } /// <param name="SlideEffect">The slide animation effect to use during navigation.</param>
public record BackBreadcrumNavigationRequested(NavigationTransitionEffect SlideEffect = NavigationTransitionEffect.FromRight);