From 45142e6953b4cf15e80e00b403910d5b31798910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Sat, 14 Mar 2026 21:03:52 +0100 Subject: [PATCH] Settings home refactoring. --- .../Interfaces/IStatePersistenceService.cs | 1 + .../SettingOptionsPageViewModel.cs | 258 ++++++++++++++++- .../Collections/WinoMailCollectionTests.cs | 72 +++++ .../Collections/WinoMailCollection.cs | 150 +++++++--- .../MessageListPageViewModel.cs | 66 +++-- Wino.Mail.WinUI/Views/SettingOptionsPage.xaml | 264 +++++++++--------- .../Views/SettingOptionsPage.xaml.cs | 26 +- .../Views/Settings/MessageListPage.xaml | 26 ++ .../Views/Settings/PersonalizationPage.xaml | 31 -- Wino.Mail.WinUI/Views/SettingsPage.xaml | 2 +- 10 files changed, 660 insertions(+), 236 deletions(-) diff --git a/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs index 4f8031d6..12e0be84 100644 --- a/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs +++ b/Wino.Core.Domain/Interfaces/IStatePersistenceService.cs @@ -74,4 +74,5 @@ public interface IStatePersistanceService : INotifyPropertyChanged /// Setting: Calendar display count for the day view. /// int DayDisplayCount { get; set; } + } diff --git a/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs b/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs index 6abc8c6d..e49f98fe 100644 --- a/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs +++ b/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs @@ -7,11 +7,16 @@ 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.Core.Domain.Models.Personalization; using Wino.Core.Domain.Models.Settings; +using Wino.Core.Domain.Models.Translations; using Wino.Core.Extensions; +using Wino.Core.ViewModels.Data; +using Wino.Mail.ViewModels.Data; using Wino.Messaging.Client.Navigation; namespace Wino.Core.ViewModels; @@ -22,6 +27,12 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel private readonly IAccountService _accountService; private readonly IMimeStorageService _mimeStorageService; private readonly IStoreRatingService _storeRatingService; + private readonly ITranslationService _translationService; + private readonly INewThemeService _newThemeService; + private readonly IPreferencesService _preferencesService; + private readonly IProviderService _providerService; + private bool _isInitializingSettings; + private bool _isAppearanceSelectionPaused; public string GitHubUrl => AppUrls.GitHub; public string PaypalUrl => AppUrls.Paypal; @@ -29,6 +40,17 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel public string PrivacyPolicyUrl => AppUrls.PrivacyPolicy; public ObservableCollection SearchSuggestions { get; } = []; + public ObservableCollection Accounts { get; } = []; + public ObservableCollection Colors { get; } = []; + + public List ElementThemes { get; } = + [ + new(ApplicationElementTheme.Light, Translator.ElementTheme_Light), + new(ApplicationElementTheme.Dark, Translator.ElementTheme_Dark), + new(ApplicationElementTheme.Default, Translator.ElementTheme_Default), + ]; + + public bool HasAccounts => Accounts.Count > 0; [ObservableProperty] public partial string VersionText { get; set; } = string.Empty; @@ -45,15 +67,38 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel [ObservableProperty] public partial string SearchQuery { get; set; } = string.Empty; + [ObservableProperty] + public partial List AvailableLanguages { get; set; } = []; + + [ObservableProperty] + public partial AppLanguageModel SelectedLanguage { get; set; } + + [ObservableProperty] + public partial ElementThemeContainer SelectedElementTheme { get; set; } + + [ObservableProperty] + public partial AppColorViewModel SelectedAppColor { get; set; } + + [ObservableProperty] + public partial bool UseAccentColor { get; set; } + public SettingOptionsPageViewModel(INativeAppService nativeAppService, - IAccountService accountService, - IMimeStorageService mimeStorageService, - IStoreRatingService storeRatingService) + IAccountService accountService, + IMimeStorageService mimeStorageService, + IStoreRatingService storeRatingService, + ITranslationService translationService, + INewThemeService newThemeService, + IPreferencesService preferencesService, + IProviderService providerService) { _nativeAppService = nativeAppService; _accountService = accountService; _mimeStorageService = mimeStorageService; _storeRatingService = storeRatingService; + _translationService = translationService; + _newThemeService = newThemeService; + _preferencesService = preferencesService; + _providerService = providerService; } public override void OnNavigatedTo(NavigationMode mode, object parameters) @@ -64,6 +109,7 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel SearchQuery = string.Empty; SearchSuggestions.Clear(); StorageSummaryText = Translator.SettingsHome_StorageLoading; + InitializeQuickSettings(); _ = LoadDashboardAsync(); } @@ -91,19 +137,54 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel } } + public void NavigateToAccount(IAccountProviderDetailViewModel account) + { + if (account == null) + { + return; + } + + Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage)); + + switch (account) + { + case AccountProviderDetailViewModel accountDetails: + Messenger.Send(new BreadcrumbNavigationRequested(accountDetails.Account.Name, WinoPage.AccountDetailsPage, accountDetails.Account.Id)); + break; + case MergedAccountProviderDetailViewModel mergedAccount: + Messenger.Send(new BreadcrumbNavigationRequested(mergedAccount.MergedInbox.Name, WinoPage.MergedAccountDetailsPage, mergedAccount)); + break; + } + } + + public void NavigateToAddAccount() + { + Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage)); + Messenger.Send(new BreadcrumbNavigationRequested(Translator.WelcomeWizard_Step2Title, WinoPage.ProviderSelectionPage)); + } + private async Task LoadDashboardAsync() { - var accounts = await _accountService.GetAccountsAsync().ConfigureAwait(false) ?? []; + var accounts = (await _accountService.GetAccountsAsync().ConfigureAwait(false) ?? []).ToList(); var count = accounts.Count; Dictionary storageSizeMap = count == 0 ? [] : await _mimeStorageService.GetAccountsMimeStorageSizesAsync(accounts.Select(account => account.Id)).ConfigureAwait(false); var totalStorageBytes = storageSizeMap.Values.Sum(); + var groupedAccountItems = CreateAccountItems(accounts); await ExecuteUIThread(() => { AccountCount = count; AccountSummaryText = string.Format(Translator.SettingsOptions_AccountsSummary, count); + Accounts.Clear(); + + foreach (var account in groupedAccountItems) + { + Accounts.Add(account); + } + + OnPropertyChanged(nameof(HasAccounts)); StorageSummaryText = totalStorageBytes == 0 ? Translator.SettingsHome_StorageEmptySummary : string.Format(Translator.SettingsStorage_TotalUsage, totalStorageBytes.GetBytesReadable()); @@ -115,6 +196,175 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel }); } + private void InitializeQuickSettings() + { + _isInitializingSettings = true; + InitializeColors(); + InitializeLanguageOptions(); + InitializeAppearanceOptions(); + _isInitializingSettings = false; + } + + private void InitializeLanguageOptions() + { + AvailableLanguages = _translationService.GetAvailableLanguages(); + SelectedLanguage = AvailableLanguages.FirstOrDefault(language => language.Language == _preferencesService.CurrentLanguage) + ?? AvailableLanguages.FirstOrDefault(); + } + + private void InitializeColors() + { + Colors.Clear(); + + foreach (var color in _newThemeService.GetAvailableAccountColors().Distinct(StringComparer.OrdinalIgnoreCase)) + { + Colors.Add(new AppColorViewModel(color)); + } + + var systemAccentColor = _newThemeService.GetSystemAccentColorHex(); + + if (Colors.All(color => !string.Equals(color.Hex, systemAccentColor, StringComparison.OrdinalIgnoreCase))) + { + Colors.Add(new AppColorViewModel(systemAccentColor, true)); + } + else + { + var matchingAccentColor = Colors.First(color => string.Equals(color.Hex, systemAccentColor, StringComparison.OrdinalIgnoreCase)); + Colors.Remove(matchingAccentColor); + Colors.Add(new AppColorViewModel(systemAccentColor, true)); + } + } + + private void InitializeAppearanceOptions() + { + _isAppearanceSelectionPaused = true; + + var currentAccentColor = _newThemeService.AccentColor; + + if (!string.IsNullOrWhiteSpace(currentAccentColor) && + Colors.All(color => !string.Equals(color.Hex, currentAccentColor, StringComparison.OrdinalIgnoreCase))) + { + Colors.Insert(0, new AppColorViewModel(currentAccentColor)); + } + + SelectedElementTheme = ElementThemes.FirstOrDefault(theme => theme.NativeTheme == _newThemeService.RootTheme) + ?? ElementThemes.LastOrDefault(); + + if (string.IsNullOrWhiteSpace(currentAccentColor)) + { + SelectedAppColor = Colors.LastOrDefault(color => color.IsAccentColor) ?? Colors.LastOrDefault(); + UseAccentColor = true; + } + else + { + SelectedAppColor = Colors.FirstOrDefault(color => string.Equals(color.Hex, currentAccentColor, StringComparison.OrdinalIgnoreCase)) + ?? Colors.FirstOrDefault(); + UseAccentColor = SelectedAppColor?.IsAccentColor == true; + } + + _isAppearanceSelectionPaused = false; + } + + private List CreateAccountItems(List accounts) + { + var groupedAccounts = accounts + .OrderBy(account => account.MergedInboxId == null ? 1 : 0) + .ThenBy(account => account.Order) + .ThenBy(account => account.Name) + .GroupBy(account => account.MergedInboxId); + var accountItems = new List(); + + foreach (var accountGroup in groupedAccounts) + { + if (accountGroup.Key == null) + { + accountItems.AddRange(accountGroup.Select(CreateAccountProviderDetails)); + continue; + } + + var mergedInbox = accountGroup.First().MergedInbox; + var holdingAccounts = accountGroup + .Select(CreateAccountProviderDetails) + .ToList(); + var mergedAccount = new MergedAccountProviderDetailViewModel(mergedInbox, holdingAccounts) + { + ProviderDetail = holdingAccounts.FirstOrDefault()?.ProviderDetail + }; + + accountItems.Add(mergedAccount); + } + + return accountItems; + } + + private AccountProviderDetailViewModel CreateAccountProviderDetails(MailAccount account) + { + var provider = _providerService.GetProviderDetail(account.ProviderType); + return new AccountProviderDetailViewModel(provider, account); + } + + partial void OnSelectedLanguageChanged(AppLanguageModel value) + { + if (_isInitializingSettings || value == null) + { + return; + } + + _ = ApplyLanguageAsync(value); + } + + partial void OnSelectedElementThemeChanged(ElementThemeContainer value) + { + if (_isInitializingSettings || value == null) + { + return; + } + + _newThemeService.RootTheme = value.NativeTheme; + } + + partial void OnSelectedAppColorChanged(AppColorViewModel value) + { + if (_isInitializingSettings || _isAppearanceSelectionPaused || value == null) + { + return; + } + + _isAppearanceSelectionPaused = true; + UseAccentColor = value.IsAccentColor; + _isAppearanceSelectionPaused = false; + + _newThemeService.AccentColor = value.Hex; + } + + partial void OnUseAccentColorChanged(bool value) + { + if (_isInitializingSettings || _isAppearanceSelectionPaused || Colors.Count == 0) + { + return; + } + + var accentColor = Colors.LastOrDefault(color => color.IsAccentColor); + var fallbackColor = Colors.FirstOrDefault(color => !color.IsAccentColor) ?? Colors.FirstOrDefault(); + var targetColor = value ? accentColor : SelectedAppColor?.IsAccentColor == true ? fallbackColor : SelectedAppColor; + + if (targetColor == null || ReferenceEquals(targetColor, SelectedAppColor)) + { + return; + } + + _isAppearanceSelectionPaused = true; + SelectedAppColor = targetColor; + _isAppearanceSelectionPaused = false; + + _newThemeService.AccentColor = targetColor.Hex; + } + + private async Task ApplyLanguageAsync(AppLanguageModel language) + { + await _translationService.InitializeLanguageAsync(language.Language); + } + [RelayCommand] public void NavigateSubDetail(object type) { diff --git a/Wino.Mail.ViewModels.Tests/Collections/WinoMailCollectionTests.cs b/Wino.Mail.ViewModels.Tests/Collections/WinoMailCollectionTests.cs index 23ae4817..3c13879b 100644 --- a/Wino.Mail.ViewModels.Tests/Collections/WinoMailCollectionTests.cs +++ b/Wino.Mail.ViewModels.Tests/Collections/WinoMailCollectionTests.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Wino.Core.Domain.Entities.Mail; +using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Mail.ViewModels.Collections; using Wino.Mail.ViewModels.Data; @@ -112,6 +113,48 @@ public class WinoMailCollectionTests threadItems.Should().Contain(item => item.ThreadId == "thread-c" && item.EmailCount == 2); } + [Fact] + public async Task UpdateMailCopy_ShouldMergeExistingSingles_WhenThreadIdChangesToMatch() + { + var sut = CreateCollection(); + var first = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow.AddMinutes(-1)); + var second = CreateMailCopy(threadId: string.Empty, creationDate: DateTime.UtcNow); + + await sut.AddAsync(first); + await sut.AddAsync(second); + + var updatedSecond = CloneMailCopy(second); + updatedSecond.ThreadId = "shared-thread"; + + await sut.UpdateMailCopy(updatedSecond, MailUpdateSource.Server, MailCopyChangeFlags.ThreadId); + + var items = FlattenItems(sut); + var threadItem = items.Should().ContainSingle().Which.Should().BeOfType().Subject; + threadItem.EmailCount.Should().Be(2); + threadItem.GetContainingIds().Should().BeEquivalentTo([first.UniqueId, second.UniqueId]); + } + + [Fact] + public async Task AddAsync_ShouldThreadWithUpdatedItem_WhenThreadIdWasSetByPriorUpdate() + { + var sut = CreateCollection(); + var existing = CreateMailCopy(threadId: string.Empty, creationDate: DateTime.UtcNow.AddMinutes(-1)); + var incoming = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow); + + await sut.AddAsync(existing); + + var updatedExisting = CloneMailCopy(existing); + updatedExisting.ThreadId = "shared-thread"; + + await sut.UpdateMailCopy(updatedExisting, MailUpdateSource.Server, MailCopyChangeFlags.ThreadId); + await sut.AddAsync(incoming); + + var items = FlattenItems(sut); + var threadItem = items.Should().ContainSingle().Which.Should().BeOfType().Subject; + threadItem.EmailCount.Should().Be(2); + threadItem.GetContainingIds().Should().BeEquivalentTo([existing.UniqueId, incoming.UniqueId]); + } + private static WinoMailCollection CreateCollection() => new() { CoreDispatcher = new ImmediateDispatcher() @@ -146,6 +189,35 @@ public class WinoMailCollectionTests FolderId = Guid.NewGuid() }; + private static MailCopy CloneMailCopy(MailCopy source) + => new() + { + UniqueId = source.UniqueId, + Id = source.Id, + FolderId = source.FolderId, + ThreadId = source.ThreadId, + MessageId = source.MessageId, + References = source.References, + InReplyTo = source.InReplyTo, + FromName = source.FromName, + FromAddress = source.FromAddress, + Subject = source.Subject, + PreviewText = source.PreviewText, + CreationDate = source.CreationDate, + Importance = source.Importance, + IsRead = source.IsRead, + IsFlagged = source.IsFlagged, + IsFocused = source.IsFocused, + HasAttachments = source.HasAttachments, + ItemType = source.ItemType, + DraftId = source.DraftId, + IsDraft = source.IsDraft, + FileId = source.FileId, + SenderContact = source.SenderContact, + AssignedAccount = source.AssignedAccount, + AssignedFolder = source.AssignedFolder + }; + private sealed class ImmediateDispatcher : IDispatcher { public Task ExecuteOnUIThread(Action action) diff --git a/Wino.Mail.ViewModels/Collections/WinoMailCollection.cs b/Wino.Mail.ViewModels/Collections/WinoMailCollection.cs index 2b378ecb..2d4f804a 100644 --- a/Wino.Mail.ViewModels/Collections/WinoMailCollection.cs +++ b/Wino.Mail.ViewModels/Collections/WinoMailCollection.cs @@ -213,14 +213,37 @@ public class WinoMailCollection : ObservableRecipient, IRecipient @@ -380,7 +403,8 @@ public class WinoMailCollection : ObservableRecipient, IRecipient { - existingItem.UpdateFrom(updatedItem); + updatedContainer.ItemViewModel.IsSelected = isSelected; + updatedContainer.ItemViewModel.IsBusy = isBusy; + }); + } + + private async Task UpdateExistingItemAsync(MailItemContainer itemContainer, + MailCopy updatedItem, + MailUpdateSource mailUpdateSource = MailUpdateSource.Server, + MailCopyChangeFlags changeHint = MailCopyChangeFlags.None) + { + if (itemContainer?.ItemViewModel == null) + { + return; + } + + var existingItem = itemContainer.ItemViewModel; + var threadOwner = itemContainer.ThreadViewModel as IMailListItem ?? existingItem; + var wasSelected = existingItem.IsSelected; + MailCopyChangeFlags appliedChanges = MailCopyChangeFlags.None; + + await ExecuteUIThread(() => + { + UpdateUniqueIdHashes(existingItem, false); + UpdateThreadIdCache(threadOwner, false); + + itemContainer.ThreadViewModel?.SuspendChildPropertyNotifications(); + + try + { + appliedChanges = existingItem.UpdateFrom(updatedItem, changeHint); + } + finally + { + itemContainer.ThreadViewModel?.ResumeChildPropertyNotifications(); + } + + existingItem.IsBusy = mailUpdateSource == MailUpdateSource.ClientUpdated; + + UpdateUniqueIdHashes(existingItem, true); + UpdateThreadIdCache(threadOwner, true); + + if (itemContainer.ThreadViewModel != null) + { + _uniqueIdToThreadMap[existingItem.MailCopy.UniqueId] = itemContainer.ThreadViewModel; + } + else + { + _uniqueIdToThreadMap.TryRemove(existingItem.MailCopy.UniqueId, out _); + } }); - UpdateUniqueIdHashes(existingItem, true); + if ((appliedChanges & MailCopyChangeFlags.ThreadId) != 0) + { + await ReinsertUpdatedItemAsync(updatedItem, wasSelected, existingItem.IsBusy); + return; + } + + if (itemContainer.ThreadViewModel != null && appliedChanges != MailCopyChangeFlags.None) + { + await ExecuteUIThread(() => + { + itemContainer.ThreadViewModel.NotifyMailItemUpdated(existingItem, appliedChanges); + }); + } } /// @@ -755,45 +846,14 @@ public class WinoMailCollection : ObservableRecipient, IRecipient public Task UpdateMailCopy(MailCopy updatedMailCopy, MailUpdateSource mailUpdateSource, MailCopyChangeFlags changedProperties = MailCopyChangeFlags.None) { - return ExecuteUIThread(() => + var itemContainer = GetMailItemContainer(updatedMailCopy.UniqueId); + + if (itemContainer?.ItemViewModel == null) { - var itemContainer = GetMailItemContainer(updatedMailCopy.UniqueId); + return Task.CompletedTask; + } - if (itemContainer == null) return; - MailCopyChangeFlags appliedChanges = MailCopyChangeFlags.None; - - if (itemContainer.ItemViewModel != null) - { - UpdateUniqueIdHashes(itemContainer.ItemViewModel, false); - - itemContainer.ThreadViewModel?.SuspendChildPropertyNotifications(); - - try - { - appliedChanges = itemContainer.ItemViewModel.UpdateFrom(updatedMailCopy, changedProperties); - } - finally - { - itemContainer.ThreadViewModel?.ResumeChildPropertyNotifications(); - } - - // Mark the item view model as busy until the network operation is completed. - itemContainer.ItemViewModel.IsBusy = mailUpdateSource == MailUpdateSource.ClientUpdated; - - UpdateUniqueIdHashes(itemContainer.ItemViewModel, true); - - // Keep thread membership cache in sync for items rendered inside thread containers. - if (itemContainer.ThreadViewModel != null) - { - _uniqueIdToThreadMap[itemContainer.ItemViewModel.MailCopy.UniqueId] = itemContainer.ThreadViewModel; - } - } - - if (itemContainer.ThreadViewModel != null && appliedChanges != MailCopyChangeFlags.None) - { - itemContainer.ThreadViewModel.NotifyMailItemUpdated(itemContainer.ItemViewModel, appliedChanges); - } - }); + return UpdateExistingItemAsync(itemContainer, updatedMailCopy, mailUpdateSource, changedProperties); } public MailItemViewModel GetFirst() => AllItems.ElementAtOrDefault(0); diff --git a/Wino.Mail.ViewModels/MessageListPageViewModel.cs b/Wino.Mail.ViewModels/MessageListPageViewModel.cs index b1bf22bb..2a381093 100644 --- a/Wino.Mail.ViewModels/MessageListPageViewModel.cs +++ b/Wino.Mail.ViewModels/MessageListPageViewModel.cs @@ -12,22 +12,8 @@ public partial class MessageListPageViewModel : MailBaseViewModel { public IPreferencesService PreferencesService { get; } private readonly IThumbnailService _thumbnailService; - - private int selectedMarkAsOptionIndex; - public int SelectedMarkAsOptionIndex - { - get => selectedMarkAsOptionIndex; - set - { - if (SetProperty(ref selectedMarkAsOptionIndex, value)) - { - if (value >= 0) - { - PreferencesService.MarkAsPreference = (MailMarkAsOption)Enum.GetValues().GetValue(value); - } - } - } - } + private readonly IStatePersistanceService _statePersistenceService; + private readonly IDialogServiceBase _dialogService; private readonly List availableHoverActions = [ @@ -38,6 +24,13 @@ public partial class MessageListPageViewModel : MailBaseViewModel MailOperation.MoveToJunk ]; + private readonly List availableMailSpacingOptions = + [ + MailListDisplayMode.Compact, + MailListDisplayMode.Medium, + MailListDisplayMode.Spacious + ]; + public List AvailableHoverActionsTranslations { get; set; } = [ Translator.HoverActionOption_Archive, @@ -47,6 +40,32 @@ public partial class MessageListPageViewModel : MailBaseViewModel Translator.HoverActionOption_MoveJunk ]; + private int selectedMarkAsOptionIndex; + public int SelectedMarkAsOptionIndex + { + get => selectedMarkAsOptionIndex; + set + { + if (SetProperty(ref selectedMarkAsOptionIndex, value) && value >= 0) + { + PreferencesService.MarkAsPreference = (MailMarkAsOption)Enum.GetValues().GetValue(value); + } + } + } + + private int selectedMailSpacingIndex; + public int SelectedMailSpacingIndex + { + get => selectedMailSpacingIndex; + set + { + if (SetProperty(ref selectedMailSpacingIndex, value) && value >= 0 && value < availableMailSpacingOptions.Count) + { + PreferencesService.MailItemDisplayMode = availableMailSpacingOptions[value]; + } + } + } + #region Properties private int leftHoverActionIndex; public int LeftHoverActionIndex @@ -88,13 +107,19 @@ public partial class MessageListPageViewModel : MailBaseViewModel } #endregion - public MessageListPageViewModel(IPreferencesService preferencesService, IThumbnailService thumbnailService) + public MessageListPageViewModel(IPreferencesService preferencesService, + IThumbnailService thumbnailService, + IStatePersistanceService statePersistenceService, + IDialogServiceBase dialogService) { PreferencesService = preferencesService; _thumbnailService = thumbnailService; + _statePersistenceService = statePersistenceService; + _dialogService = dialogService; leftHoverActionIndex = availableHoverActions.IndexOf(PreferencesService.LeftHoverAction); centerHoverActionIndex = availableHoverActions.IndexOf(PreferencesService.CenterHoverAction); rightHoverActionIndex = availableHoverActions.IndexOf(PreferencesService.RightHoverAction); + selectedMailSpacingIndex = availableMailSpacingOptions.IndexOf(PreferencesService.MailItemDisplayMode); SelectedMarkAsOptionIndex = Array.IndexOf(Enum.GetValues(), PreferencesService.MarkAsPreference); } @@ -103,4 +128,11 @@ public partial class MessageListPageViewModel : MailBaseViewModel { await _thumbnailService.ClearCache(); } + + [RelayCommand] + private void ResetMailListPaneLength() + { + _statePersistenceService.MailListPaneLength = 420; + _dialogService.InfoBarMessage(Translator.GeneralTitle_Info, Translator.Info_MailListSizeResetSuccessMessage, InfoBarMessageType.Success); + } } diff --git a/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml b/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml index c7254768..acc7fbe7 100644 --- a/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml +++ b/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml @@ -3,15 +3,75 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:abstract="using:Wino.Views.Abstract" + xmlns:controls="using:CommunityToolkit.WinUI.Controls" + xmlns:coreControls="using:Wino.Mail.WinUI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:domain="using:Wino.Core.Domain" xmlns:enums="using:Wino.Core.Domain.Enums" + xmlns:helpers="using:Wino.Helpers" + xmlns:mailViewModelData="using:Wino.Mail.ViewModels.Data" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:personalization="using:Wino.Core.Domain.Models.Personalization" + xmlns:selectors="using:Wino.Selectors" xmlns:settingsModels="using:Wino.Core.Domain.Models.Settings" + xmlns:translations="using:Wino.Core.Domain.Models.Translations" + xmlns:viewModelData="using:Wino.Core.ViewModels.Data" x:Name="root" Title="{x:Bind domain:Translator.SettingsHome_Title}" mc:Ignorable="d"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -20,57 +80,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml.cs b/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml.cs index 9171c91e..7f1db1ce 100644 --- a/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml.cs +++ b/Wino.Mail.WinUI/Views/SettingOptionsPage.xaml.cs @@ -1,7 +1,10 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; +using CommunityToolkit.WinUI.Controls; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Models.Settings; +using Wino.Core.ViewModels.Data; +using Wino.Mail.ViewModels.Data; using Wino.Views.Abstract; namespace Wino.Views.Settings; @@ -17,7 +20,7 @@ public sealed partial class SettingOptionsPage : SettingOptionsPageAbstract { WinoPage? page = sender switch { - Button button when button.Tag is WinoPage p => p, + FrameworkElement element when element.Tag is WinoPage p => p, _ => null }; @@ -27,6 +30,27 @@ public sealed partial class SettingOptionsPage : SettingOptionsPageAbstract } } + private void AccountSettingClicked(object sender, RoutedEventArgs e) + { + if (sender is SettingsCard settingsCard && settingsCard.CommandParameter is AccountProviderDetailViewModel account) + { + ViewModel.NavigateToAccount(account); + } + } + + private void MergedAccountSettingClicked(object sender, RoutedEventArgs e) + { + if (sender is SettingsCard settingsCard && settingsCard.CommandParameter is MergedAccountProviderDetailViewModel account) + { + ViewModel.NavigateToAccount(account); + } + } + + private void AddAccountSettingClicked(object sender, RoutedEventArgs e) + { + ViewModel.NavigateToAddAccount(); + } + private void SettingsSearchTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) { if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput || string.IsNullOrWhiteSpace(sender.Text)) diff --git a/Wino.Mail.WinUI/Views/Settings/MessageListPage.xaml b/Wino.Mail.WinUI/Views/Settings/MessageListPage.xaml index fe0050d0..b28f7818 100644 --- a/Wino.Mail.WinUI/Views/Settings/MessageListPage.xaml +++ b/Wino.Mail.WinUI/Views/Settings/MessageListPage.xaml @@ -18,6 +18,32 @@ + + + + + + + + + + + + + + + + + + + + + + +