From 33672ab0aae2cf5ace4760803ad3b9e076cc6924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sun, 22 Feb 2026 17:55:57 +0100 Subject: [PATCH] Local draft resent and default app mode settings. --- .../Interfaces/IPreferencesService.cs | 5 + .../Translations/en_US/resources.json | 6 + Wino.Core/Requests/Mail/CreateDraftRequest.cs | 5 +- .../AppPreferencesPageViewModel.cs | 22 +++ Wino.Mail.ViewModels/ComposePageViewModel.cs | 156 ++++++++++++++++-- .../Activation/AppModeActivationResolver.cs | 4 +- Wino.Mail.WinUI/App.xaml.cs | 16 +- .../Services/PreferencesService.cs | 13 ++ Wino.Mail.WinUI/ShellWindow.xaml.cs | 2 +- Wino.Mail.WinUI/Views/Mail/ComposePage.xaml | 14 +- .../Views/Mail/MailListPage.xaml.cs | 9 +- .../Views/Settings/AppPreferencesPage.xaml | 7 + 12 files changed, 229 insertions(+), 30 deletions(-) diff --git a/Wino.Core.Domain/Interfaces/IPreferencesService.cs b/Wino.Core.Domain/Interfaces/IPreferencesService.cs index 490244db..a207136c 100644 --- a/Wino.Core.Domain/Interfaces/IPreferencesService.cs +++ b/Wino.Core.Domain/Interfaces/IPreferencesService.cs @@ -52,6 +52,11 @@ public interface IPreferencesService : INotifyPropertyChanged /// int EmailSyncIntervalMinutes { get; set; } + /// + /// Setting: Default application mode to open when activation does not specify one. + /// + WinoApplicationMode DefaultApplicationMode { get; set; } + #endregion #region Mail diff --git a/Wino.Core.Domain/Translations/en_US/resources.json b/Wino.Core.Domain/Translations/en_US/resources.json index 15012aa4..ba2f5ee1 100644 --- a/Wino.Core.Domain/Translations/en_US/resources.json +++ b/Wino.Core.Domain/Translations/en_US/resources.json @@ -77,6 +77,7 @@ "Buttons_Save": "Save", "Buttons_SaveConfiguration": "Save Configuration", "Buttons_Send": "Send", + "Buttons_SendToServer": "Send to server", "Buttons_Share": "Share", "Buttons_SignIn": "Sign In", "Buttons_Sync": "Synchronize", @@ -619,6 +620,10 @@ "SettingsAppPreferences_SearchMode_Local": "Local", "SettingsAppPreferences_SearchMode_Online": "Online", "SettingsAppPreferences_SearchMode_Title": "Default search mode", + "SettingsAppPreferences_ApplicationMode_Title": "Default application mode", + "SettingsAppPreferences_ApplicationMode_Description": "Choose which mode Wino opens in when no activation type explicitly sets it.", + "SettingsAppPreferences_ApplicationMode_Mail": "Mail", + "SettingsAppPreferences_ApplicationMode_Calendar": "Calendar", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Description": "Wino Mail will keep running in the background. You will be notified as new mails arrive.", "SettingsAppPreferences_ServerBackgroundingMode_Invisible_Title": "Run in the background", "SettingsAppPreferences_ServerBackgroundingMode_MinimizeTray_Description": "Wino Mail will keep running on the system tray. Available to launch by clicking on an icon. You will be notified as new mails arrive.", @@ -915,6 +920,7 @@ "Composer_CcBcc": "Cc & Bcc", "Composer_EnableSmimeSignature": "Enable/disable S/MIME signature", "Composer_EnableSmimeEncryption": "Enable/disable S/MIME encryption", + "Composer_LocalDraftSyncInfo": "This draft is local only. Wino failed to send it to your mail server. Click to retry sending it to the server.", "Composer_CertificateExpires": "Expires on: ", "Composer_SmimeSignature": "S/MIME Signature", "Composer_SmimeEncryption": "S/MIME Encryption", diff --git a/Wino.Core/Requests/Mail/CreateDraftRequest.cs b/Wino.Core/Requests/Mail/CreateDraftRequest.cs index 569f9f25..7477673f 100644 --- a/Wino.Core/Requests/Mail/CreateDraftRequest.cs +++ b/Wino.Core/Requests/Mail/CreateDraftRequest.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using CommunityToolkit.Mvvm.Messaging; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Requests; -using Wino.Messaging.UI; namespace Wino.Core.Requests.Mail; @@ -24,6 +22,7 @@ public record CreateDraftRequest(DraftPreparationRequest DraftPreperationRequest public override void RevertUIChanges() { - WeakReferenceMessenger.Default.Send(new MailRemovedMessage(Item)); + // Keep local draft intact when create-draft synchronization fails. + // This allows users to retry sending the local draft to the server. } } diff --git a/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs b/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs index c460db6e..76b292eb 100644 --- a/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs +++ b/Wino.Mail.ViewModels/AppPreferencesPageViewModel.cs @@ -16,6 +16,9 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel [ObservableProperty] public partial List SearchModes { get; set; } + [ObservableProperty] + public partial List ApplicationModes { get; set; } + [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsStartupBehaviorDisabled))] [NotifyPropertyChangedFor(nameof(IsStartupBehaviorEnabled))] @@ -48,6 +51,18 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel } } + private string _selectedDefaultApplicationMode; + public string SelectedDefaultApplicationMode + { + get => _selectedDefaultApplicationMode; + set + { + SetProperty(ref _selectedDefaultApplicationMode, value); + + PreferencesService.DefaultApplicationMode = (WinoApplicationMode)ApplicationModes.IndexOf(value); + } + } + private readonly IMailDialogService _dialogService; private readonly IStartupBehaviorService _startupBehaviorService; @@ -65,7 +80,14 @@ public partial class AppPreferencesPageViewModel : MailBaseViewModel Translator.SettingsAppPreferences_SearchMode_Online ]; + ApplicationModes = + [ + Translator.SettingsAppPreferences_ApplicationMode_Mail, + Translator.SettingsAppPreferences_ApplicationMode_Calendar + ]; + SelectedDefaultSearchMode = SearchModes[(int)PreferencesService.DefaultSearchMode]; + SelectedDefaultApplicationMode = ApplicationModes[(int)PreferencesService.DefaultApplicationMode]; EmailSyncIntervalMinutes = PreferencesService.EmailSyncIntervalMinutes; } diff --git a/Wino.Mail.ViewModels/ComposePageViewModel.cs b/Wino.Mail.ViewModels/ComposePageViewModel.cs index 471c5f9b..538e4e2a 100644 --- a/Wino.Mail.ViewModels/ComposePageViewModel.cs +++ b/Wino.Mail.ViewModels/ComposePageViewModel.cs @@ -15,6 +15,7 @@ using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Exceptions; +using Wino.Core.Domain.Extensions; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Navigation; @@ -23,11 +24,15 @@ using Wino.Core.Services; using Wino.Mail.ViewModels.Data; using Wino.Mail.ViewModels.Messages; using Wino.Messaging.Client.Mails; +using Wino.Messaging.UI; namespace Wino.Mail.ViewModels; public partial class ComposePageViewModel : MailBaseViewModel, - IRecipient + IRecipient, + IRecipient, + IRecipient, + IRecipient { public Func> GetHTMLBodyFunction; @@ -36,9 +41,11 @@ public partial class ComposePageViewModel : MailBaseViewModel, private bool isUpdatingMimeBlocked = false; private bool canSendMail => ComposingAccount != null && !IsLocalDraft && CurrentMimeMessage != null && !IsDraftBusy; + private bool canSendLocalDraftToServer => ComposingAccount != null && IsLocalDraft && CurrentMimeMessage != null && !IsDraftBusy && !IsRetryingSendToServer; [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] [NotifyCanExecuteChangedFor(nameof(SendCommand))] + [NotifyCanExecuteChangedFor(nameof(SendToServerCommand))] [ObservableProperty] private MimeMessage currentMimeMessage = null; @@ -50,15 +57,24 @@ public partial class ComposePageViewModel : MailBaseViewModel, [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsLocalDraft))] + [NotifyPropertyChangedFor(nameof(ShouldShowSendToServerButton))] + [NotifyPropertyChangedFor(nameof(ShouldShowSendButton))] [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] [NotifyCanExecuteChangedFor(nameof(SendCommand))] + [NotifyCanExecuteChangedFor(nameof(SendToServerCommand))] public partial MailItemViewModel CurrentMailDraftItem { get; set; } [ObservableProperty] + [NotifyPropertyChangedFor(nameof(ShouldShowSendToServerButton))] [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] [NotifyCanExecuteChangedFor(nameof(SendCommand))] + [NotifyCanExecuteChangedFor(nameof(SendToServerCommand))] public partial bool IsDraftBusy { get; set; } + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(SendToServerCommand))] + public partial bool IsRetryingSendToServer { get; set; } + [ObservableProperty] public partial bool IsImportanceSelected { get; set; } @@ -74,6 +90,7 @@ public partial class ComposePageViewModel : MailBaseViewModel, [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(DiscardCommand))] [NotifyCanExecuteChangedFor(nameof(SendCommand))] + [NotifyCanExecuteChangedFor(nameof(SendToServerCommand))] public partial MailAccount ComposingAccount { get; set; } [ObservableProperty] @@ -103,6 +120,8 @@ public partial class ComposePageViewModel : MailBaseViewModel, public ObservableCollection ToItems { get; set; } = []; public ObservableCollection CCItems { get; set; } = []; public ObservableCollection BCCItems { get; set; } = []; + public bool ShouldShowSendToServerButton => IsLocalDraft && !IsDraftBusy; + public bool ShouldShowSendButton => !IsLocalDraft; #endregion @@ -325,6 +344,48 @@ public partial class ComposePageViewModel : MailBaseViewModel, await _worker.ExecuteAsync(draftSendPreparationRequest); } + [RelayCommand(CanExecute = nameof(canSendLocalDraftToServer))] + private async Task SendToServerAsync() + { + if (CurrentMailDraftItem?.MailCopy == null || ComposingAccount == null || CurrentMimeMessage == null) + return; + + try + { + await ExecuteUIThread(() => + { + IsRetryingSendToServer = true; + IsDraftBusy = true; + NotifyComposeActionStateChanged(); + }); + + await UpdateMimeChangesAsync().ConfigureAwait(false); + + var localDraftCopy = CurrentMailDraftItem.MailCopy; + var draftPreparationRequest = new DraftPreparationRequest( + localDraftCopy.AssignedAccount ?? ComposingAccount, + localDraftCopy, + CurrentMimeMessage.GetBase64MimeMessage(), + DraftCreationReason.Empty); + + await _worker.ExecuteAsync(draftPreparationRequest).ConfigureAwait(false); + } + catch (Exception ex) + { + _dialogService.InfoBarMessage(Translator.Info_RequestCreationFailedTitle, ex.Message, InfoBarMessageType.Error); + } + finally + { + await ExecuteUIThread(() => + { + IsRetryingSendToServer = false; + }); + + await UpdatePendingOperationStateAsync().ConfigureAwait(false); + NotifyComposeActionStateChanged(); + } + } + public async Task UpdateMimeChangesAsync() { if (isUpdatingMimeBlocked || CurrentMimeMessage == null || ComposingAccount == null || CurrentMailDraftItem == null) return; @@ -424,13 +485,13 @@ public partial class ComposePageViewModel : MailBaseViewModel, } } - public override void OnNavigatedFrom(NavigationMode mode, object parameters) - { - base.OnNavigatedFrom(mode, parameters); + //public override void OnNavigatedFrom(NavigationMode mode, object parameters) + //{ + // base.OnNavigatedFrom(mode, parameters); - /// Do not put any code here. - /// Make sure to use Page's OnNavigatedTo instead. - } + // /// Do not put any code here. + // /// Make sure to use Page's OnNavigatedTo instead. + //} public override async void OnNavigatedTo(NavigationMode mode, object parameters) { @@ -461,11 +522,38 @@ public partial class ComposePageViewModel : MailBaseViewModel, await TryPrepareComposeAsync(true); } + public async void Receive(SynchronizationActionsAdded message) + { + if (!ShouldTrackDraftSynchronizationState(message.AccountId)) + return; + + await UpdatePendingOperationStateAsync().ConfigureAwait(false); + } + + public async void Receive(SynchronizationActionsCompleted message) + { + if (!ShouldTrackDraftSynchronizationState(message.AccountId)) + return; + + await UpdatePendingOperationStateAsync().ConfigureAwait(false); + } + + public async void Receive(AccountSynchronizerStateChanged message) + { + if (message.NewState != AccountSynchronizerState.Idle || !ShouldTrackDraftSynchronizationState(message.AccountId)) + return; + + await UpdatePendingOperationStateAsync().ConfigureAwait(false); + } + protected override void RegisterRecipients() { base.RegisterRecipients(); Messenger.Register(this); + Messenger.Register(this); + Messenger.Register(this); + Messenger.Register(this); } protected override void UnregisterRecipients() @@ -473,6 +561,9 @@ public partial class ComposePageViewModel : MailBaseViewModel, base.UnregisterRecipients(); Messenger.Unregister(this); + Messenger.Unregister(this); + Messenger.Unregister(this); + Messenger.Unregister(this); } private async Task InitializeComposerAccountAsync() @@ -514,19 +605,31 @@ public partial class ComposePageViewModel : MailBaseViewModel, private async Task UpdatePendingOperationStateAsync() { - IsDraftBusy = false; + var hasPendingOperation = false; if (CurrentMailDraftItem?.MailCopy == null || !CurrentMailDraftItem.MailCopy.IsDraft) + { + await ExecuteUIThread(() => + { + IsDraftBusy = false; + NotifyComposeActionStateChanged(); + }); return; + } var accountId = CurrentMailDraftItem.MailCopy.AssignedAccount?.Id ?? Guid.Empty; - if (accountId == Guid.Empty) - return; + if (accountId != Guid.Empty) + { + var synchronizer = await SynchronizationManager.Instance.GetSynchronizerAsync(accountId).ConfigureAwait(false); + hasPendingOperation = synchronizer?.HasPendingOperation(CurrentMailDraftItem.MailCopy.UniqueId) ?? false; + } - var synchronizer = await SynchronizationManager.Instance.GetSynchronizerAsync(accountId).ConfigureAwait(false); - - IsDraftBusy = synchronizer?.HasPendingOperation(CurrentMailDraftItem.MailCopy.UniqueId) ?? false; + await ExecuteUIThread(() => + { + IsDraftBusy = hasPendingOperation; + NotifyComposeActionStateChanged(); + }); } private async Task TryPrepareComposeAsync(bool downloadIfNeeded) @@ -706,11 +809,32 @@ public partial class ComposePageViewModel : MailBaseViewModel, await ExecuteUIThread(async () => { CurrentMailDraftItem.UpdateFrom(updatedMail); - DiscardCommand.NotifyCanExecuteChanged(); - SendCommand.NotifyCanExecuteChanged(); - await UpdatePendingOperationStateAsync(); + NotifyComposeActionStateChanged(); }); } } + + private void NotifyComposeActionStateChanged() + { + OnPropertyChanged(nameof(IsLocalDraft)); + OnPropertyChanged(nameof(ShouldShowSendToServerButton)); + OnPropertyChanged(nameof(ShouldShowSendButton)); + + DiscardCommand.NotifyCanExecuteChanged(); + SendCommand.NotifyCanExecuteChanged(); + SendToServerCommand.NotifyCanExecuteChanged(); + } + + private bool ShouldTrackDraftSynchronizationState(Guid accountId) + { + if (accountId == Guid.Empty) + return false; + + var currentDraftAccountId = CurrentMailDraftItem?.MailCopy?.AssignedAccount?.Id + ?? ComposingAccount?.Id + ?? Guid.Empty; + + return currentDraftAccountId != Guid.Empty && currentDraftAccountId == accountId; + } } diff --git a/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs b/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs index 670b93dc..2a234df8 100644 --- a/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs +++ b/Wino.Mail.WinUI/Activation/AppModeActivationResolver.cs @@ -5,7 +5,7 @@ namespace Wino.Mail.WinUI.Activation; internal static class AppModeActivationResolver { - public static WinoApplicationMode Resolve(string? launchArguments, string? tileId, string? appId) + public static WinoApplicationMode Resolve(string? launchArguments, string? tileId, string? appId, WinoApplicationMode defaultMode = WinoApplicationMode.Mail) { if (TryResolveFromText(launchArguments, out var mode)) return mode; @@ -16,7 +16,7 @@ internal static class AppModeActivationResolver if (TryResolveFromText(appId, out mode)) return mode; - return WinoApplicationMode.Mail; + return defaultMode; } private static bool TryResolveFromText(string? value, out WinoApplicationMode mode) diff --git a/Wino.Mail.WinUI/App.xaml.cs b/Wino.Mail.WinUI/App.xaml.cs index 7c816bea..df7a1f1f 100644 --- a/Wino.Mail.WinUI/App.xaml.cs +++ b/Wino.Mail.WinUI/App.xaml.cs @@ -198,7 +198,10 @@ public partial class App : WinoApplication, if (activationArgs.Kind == ExtendedActivationKind.AppNotification) return true; - var launchMode = AppModeActivationResolver.Resolve(args?.Arguments, GetCurrentLaunchTileId(), Environment.CommandLine); + var launchMode = AppModeActivationResolver.Resolve(args?.Arguments, + GetCurrentLaunchTileId(), + Environment.CommandLine, + _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail); bool shouldRegister = launchMode == WinoApplicationMode.Mail; if (!shouldRegister) @@ -313,6 +316,7 @@ public partial class App : WinoApplication, { // Pass null for args since we're handling toast navigation await CreateAndActivateWindow(null!); + navigationService.ChangeApplicationMode(Core.Domain.Enums.WinoApplicationMode.Mail); } else { @@ -453,7 +457,7 @@ public partial class App : WinoApplication, return; } - if (TryResolveActivationMode(activationArgs, out var activationMode)) + if (TryResolveActivationMode(activationArgs, _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail, out var activationMode)) { shellWindow.HandleAppActivation(GetModeLaunchArgument(activationMode)); return; @@ -684,7 +688,7 @@ public partial class App : WinoApplication, { shellWindow.HandleAppActivation(launchArgs.Arguments, launchArgs.TileId); } - else if (TryResolveActivationMode(args, out var redirectedMode)) + else if (TryResolveActivationMode(args, _preferencesService?.DefaultApplicationMode ?? WinoApplicationMode.Mail, out var redirectedMode)) { shellWindow.HandleAppActivation(GetModeLaunchArgument(redirectedMode)); } @@ -700,9 +704,9 @@ public partial class App : WinoApplication, private static string GetModeLaunchArgument(WinoApplicationMode mode) => mode == WinoApplicationMode.Calendar ? "--mode=calendar" : "--mode=mail"; - private static bool TryResolveActivationMode(AppActivationArguments activationArgs, out WinoApplicationMode mode) + private static bool TryResolveActivationMode(AppActivationArguments activationArgs, WinoApplicationMode defaultMode, out WinoApplicationMode mode) { - mode = WinoApplicationMode.Mail; + mode = defaultMode; if (activationArgs.Kind == ExtendedActivationKind.Protocol && activationArgs.Data is IProtocolActivatedEventArgs protocolArgs) @@ -746,7 +750,7 @@ public partial class App : WinoApplication, if (activationArgs.Kind == ExtendedActivationKind.Launch && activationArgs.Data is ILaunchActivatedEventArgs launchArgs) { - mode = AppModeActivationResolver.Resolve(launchArgs.Arguments, launchArgs.TileId, null); + mode = AppModeActivationResolver.Resolve(launchArgs.Arguments, launchArgs.TileId, null, defaultMode); return true; } diff --git a/Wino.Mail.WinUI/Services/PreferencesService.cs b/Wino.Mail.WinUI/Services/PreferencesService.cs index 8b930750..bbdc8c1f 100644 --- a/Wino.Mail.WinUI/Services/PreferencesService.cs +++ b/Wino.Mail.WinUI/Services/PreferencesService.cs @@ -290,6 +290,19 @@ public class PreferencesService(IConfigurationService configurationService) : Ob set => SetPropertyAndSave(nameof(EmailSyncIntervalMinutes), value); } + public WinoApplicationMode DefaultApplicationMode + { + get + { + var configuredMode = _configurationService.Get(nameof(DefaultApplicationMode), WinoApplicationMode.Mail); + + return Enum.IsDefined(typeof(WinoApplicationMode), configuredMode) + ? configuredMode + : WinoApplicationMode.Mail; + } + set => SaveProperty(propertyName: nameof(DefaultApplicationMode), value); + } + public CalendarSettings GetCurrentCalendarSettings() { var workingDays = GetDaysBetween(WorkingDayStart, WorkingDayEnd); diff --git a/Wino.Mail.WinUI/ShellWindow.xaml.cs b/Wino.Mail.WinUI/ShellWindow.xaml.cs index bb355e1f..7a114807 100644 --- a/Wino.Mail.WinUI/ShellWindow.xaml.cs +++ b/Wino.Mail.WinUI/ShellWindow.xaml.cs @@ -111,7 +111,7 @@ 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); + var targetMode = AppModeActivationResolver.Resolve(launchArguments, tileId, appId, PreferencesService.DefaultApplicationMode); _currentMode = targetMode; _isApplyingActivationMode = true; diff --git a/Wino.Mail.WinUI/Views/Mail/ComposePage.xaml b/Wino.Mail.WinUI/Views/Mail/ComposePage.xaml index 45c9b62a..7b87f701 100644 --- a/Wino.Mail.WinUI/Views/Mail/ComposePage.xaml +++ b/Wino.Mail.WinUI/Views/Mail/ComposePage.xaml @@ -227,11 +227,23 @@ - + + + + + + diff --git a/Wino.Mail.WinUI/Views/Mail/MailListPage.xaml.cs b/Wino.Mail.WinUI/Views/Mail/MailListPage.xaml.cs index 7e956ab7..c01df587 100644 --- a/Wino.Mail.WinUI/Views/Mail/MailListPage.xaml.cs +++ b/Wino.Mail.WinUI/Views/Mail/MailListPage.xaml.cs @@ -280,7 +280,14 @@ public sealed partial class MailListPage : MailListPageAbstract, // No active mail item. Go to empty page. if (message.SelectedMailItemViewModel == null) { - WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested()); + if (IsRenderingPageActive()) + { + WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested()); + } + + // Ensure rendering frame actually navigates away from Compose/Rendering pages. + // Otherwise those pages keep their messenger registrations alive. + ViewModel.NavigationService.Navigate(WinoPage.IdlePage, null, NavigationReferenceFrame.RenderingFrame, NavigationTransitionType.DrillIn); } else { diff --git a/Wino.Mail.WinUI/Views/Settings/AppPreferencesPage.xaml b/Wino.Mail.WinUI/Views/Settings/AppPreferencesPage.xaml index ff3c57e1..298401b5 100644 --- a/Wino.Mail.WinUI/Views/Settings/AppPreferencesPage.xaml +++ b/Wino.Mail.WinUI/Views/Settings/AppPreferencesPage.xaml @@ -30,6 +30,13 @@ + + + + + + +