using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using Wino.Core.Domain; using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Navigation; using Wino.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; public partial class SettingOptionsPageViewModel : CoreBaseViewModel { private readonly INativeAppService _nativeAppService; private readonly IAccountService _accountService; private readonly IMimeStorageService _mimeStorageService; private readonly ITranslationService _translationService; private readonly INewThemeService _newThemeService; private readonly IPreferencesService _preferencesService; private readonly IProviderService _providerService; private bool _isInitializingSettings; private bool _isAppearanceSelectionPaused; public string WebsiteUrl => AppUrls.Website; public string PrivacyPolicyUrl => AppUrls.PrivacyPolicy; public ObservableCollection SearchSuggestions { get; } = []; public ObservableCollection Accounts { get; } = []; public ObservableCollection Colors { get; } = []; public List ElementThemes { get; } = [ new(ApplicationElementTheme.Default, Translator.ElementTheme_Default), new(ApplicationElementTheme.Light, Translator.ElementTheme_Light), new(ApplicationElementTheme.Dark, Translator.ElementTheme_Dark), ]; public bool HasAccounts => Accounts.Count > 0; [ObservableProperty] public partial string VersionText { get; set; } = string.Empty; [ObservableProperty] public partial string AccountSummaryText { get; set; } = string.Empty; [ObservableProperty] public partial int AccountCount { get; set; } [ObservableProperty] public partial string StorageSummaryText { get; set; } = string.Empty; [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, ITranslationService translationService, INewThemeService newThemeService, IPreferencesService preferencesService, IProviderService providerService) { _nativeAppService = nativeAppService; _accountService = accountService; _mimeStorageService = mimeStorageService; _translationService = translationService; _newThemeService = newThemeService; _preferencesService = preferencesService; _providerService = providerService; } public override void OnNavigatedTo(NavigationMode mode, object parameters) { base.OnNavigatedTo(mode, parameters); VersionText = string.Format("{0}{1}", Translator.SettingsAboutVersion, _nativeAppService.GetFullAppVersion()); SearchQuery = string.Empty; SearchSuggestions.Clear(); StorageSummaryText = Translator.SettingsHome_StorageLoading; InitializeQuickSettings(); _ = LoadDashboardAsync(); } public void UpdateSearchSuggestions(string query) { SearchQuery = query; SearchSuggestions.Clear(); foreach (var result in SettingsNavigationInfoProvider.Search(query, AccountSummaryText).Take(6)) { SearchSuggestions.Add(result); } } public SettingsNavigationItemInfo GetBestSearchSuggestion(string query) => SettingsNavigationInfoProvider.Search(query, AccountSummaryText).FirstOrDefault(); public void NavigateToSetting(SettingsNavigationItemInfo item) { if (item?.PageType is WinoPage pageType) { NavigateSubDetail(pageType); } } 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(GetAccountDetailsTitle(accountDetails.Account), 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, ProviderSelectionNavigationContext.CreateForSettingsAddAccount())); } public void NavigateToManageAccounts() { Messenger.Send(new BreadcrumbNavigationRequested(Translator.SettingsManageAccountSettings_Title, WinoPage.ManageAccountsPage)); } private async Task LoadDashboardAsync() { 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()); if (!string.IsNullOrWhiteSpace(SearchQuery)) { UpdateSearchSuggestions(SearchQuery); } }); } private static string GetAccountDetailsTitle(MailAccount account) => !string.IsNullOrWhiteSpace(account?.Address) ? string.Format(Translator.SettingsAccountDetails_NavigationTitle, account.Address) : account?.Name ?? Translator.AccountDetailsPage_Title; private void InitializeQuickSettings() { _isInitializingSettings = true; InitializeColors(); InitializeLanguageOptions(); InitializeAppearanceOptions(); _isInitializingSettings = false; } private void InitializeColors() { Colors.Clear(); foreach (var color in AccentColorProvider.GetAvailableColors()) { Colors.Add(new AppColorViewModel(color)); } UseAccentColor = _preferencesService.IsCustomAccentColorEnabled; SelectedAppColor = Colors.FirstOrDefault(color => color.Hex == _preferencesService.CustomAccentColorHex) ?? Colors.FirstOrDefault(); } private void InitializeLanguageOptions() { AvailableLanguages = _translationService.GetAvailableLanguages(); SelectedLanguage = AvailableLanguages.FirstOrDefault(language => language.Language == _preferencesService.CurrentLanguage) ?? AvailableLanguages.FirstOrDefault(); } private void InitializeAppearanceOptions() { SelectedElementTheme = ElementThemes.FirstOrDefault(theme => theme.Theme == _preferencesService.ApplicationTheme) ?? ElementThemes[0]; } partial void OnSelectedLanguageChanged(AppLanguageModel value) { if (_isInitializingSettings || value == null) return; _ = _translationService.InitializeLanguageAsync(value.Language); } partial void OnSelectedElementThemeChanged(ElementThemeContainer value) { if (_isInitializingSettings || value == null) return; _preferencesService.ApplicationTheme = value.Theme; } partial void OnSelectedAppColorChanged(AppColorViewModel value) { if (_isInitializingSettings || _isAppearanceSelectionPaused || value == null) return; _preferencesService.CustomAccentColorHex = value.Hex; if (UseAccentColor) { _newThemeService.ApplyCustomAccentColor(value.Color); } } partial void OnUseAccentColorChanged(bool value) { if (_isInitializingSettings) return; _preferencesService.IsCustomAccentColorEnabled = value; _isAppearanceSelectionPaused = true; try { if (value && SelectedAppColor != null) { _newThemeService.ApplyCustomAccentColor(SelectedAppColor.Color); } else { _newThemeService.ResetAccentColor(); } } finally { _isAppearanceSelectionPaused = false; } } [RelayCommand] private Task NavigateExternalAsync(string url) { if (string.IsNullOrWhiteSpace(url)) return Task.CompletedTask; return _nativeAppService.LaunchUriAsync(new Uri(url)); } private static List CreateAccountItems(List accounts) { return AccountProviderDetailViewModelFactory.CreateAccountItems(accounts); } }