607 lines
22 KiB
C#
607 lines
22 KiB
C#
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.Api.Contracts.Ai;
|
|
using Wino.Mail.ViewModels.Data;
|
|
using Wino.Messaging.Client.Navigation;
|
|
using Wino.Messaging.UI;
|
|
|
|
namespace Wino.Core.ViewModels;
|
|
|
|
public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
|
|
IRecipient<WinoAccountProfileUpdatedMessage>,
|
|
IRecipient<WinoAccountProfileDeletedMessage>,
|
|
IRecipient<WinoAccountAddOnPurchasedMessage>
|
|
{
|
|
private const string BuyAiPackUrl = "https://example.com/wino-ai-pack";
|
|
|
|
private readonly INativeAppService _nativeAppService;
|
|
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 readonly IWinoAccountProfileService _profileService;
|
|
private readonly IMailDialogService _dialogService;
|
|
private bool _isInitializingSettings;
|
|
private bool _isAppearanceSelectionPaused;
|
|
|
|
public string GitHubUrl => AppUrls.GitHub;
|
|
public string PaypalUrl => AppUrls.Paypal;
|
|
public string WebsiteUrl => AppUrls.Website;
|
|
public string PrivacyPolicyUrl => AppUrls.PrivacyPolicy;
|
|
|
|
public ObservableCollection<SettingsNavigationItemInfo> SearchSuggestions { get; } = [];
|
|
public ObservableCollection<IAccountProviderDetailViewModel> Accounts { get; } = [];
|
|
public ObservableCollection<AppColorViewModel> Colors { get; } = [];
|
|
|
|
public List<ElementThemeContainer> 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;
|
|
|
|
[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<AppLanguageModel> 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; }
|
|
|
|
// Wino Account hero card properties
|
|
|
|
[ObservableProperty]
|
|
public partial bool IsWinoAccountBusy { get; set; }
|
|
|
|
[ObservableProperty]
|
|
[NotifyPropertyChangedFor(nameof(IsWinoAccountSignedOut))]
|
|
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
|
|
public partial bool IsWinoAccountSignedIn { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial string WinoAccountEmail { get; set; } = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
public partial string WinoAccountStatusText { get; set; } = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
|
|
public partial bool HasAiPack { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial string AiPackStateText { get; set; } = Translator.WinoAccount_Management_AiPackInactive;
|
|
|
|
[ObservableProperty]
|
|
public partial string AiUsageSummary { get; set; } = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
public partial string AiBillingPeriodSummary { get; set; } = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
public partial double AiUsagePercent { get; set; }
|
|
|
|
public bool IsWinoAccountSignedOut => !IsWinoAccountSignedIn;
|
|
public bool CanShowAiUsage => HasAiPack;
|
|
public bool CanShowBuyAiPack => IsWinoAccountSignedIn && !HasAiPack;
|
|
|
|
public SettingOptionsPageViewModel(INativeAppService nativeAppService,
|
|
IAccountService accountService,
|
|
IMimeStorageService mimeStorageService,
|
|
IStoreRatingService storeRatingService,
|
|
ITranslationService translationService,
|
|
INewThemeService newThemeService,
|
|
IPreferencesService preferencesService,
|
|
IProviderService providerService,
|
|
IWinoAccountProfileService profileService,
|
|
IMailDialogService dialogService)
|
|
{
|
|
_nativeAppService = nativeAppService;
|
|
_accountService = accountService;
|
|
_mimeStorageService = mimeStorageService;
|
|
_storeRatingService = storeRatingService;
|
|
_translationService = translationService;
|
|
_newThemeService = newThemeService;
|
|
_preferencesService = preferencesService;
|
|
_providerService = providerService;
|
|
_profileService = profileService;
|
|
_dialogService = dialogService;
|
|
}
|
|
|
|
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();
|
|
_ = LoadWinoAccountAsync();
|
|
}
|
|
|
|
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(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) ?? []).ToList();
|
|
var count = accounts.Count;
|
|
Dictionary<Guid, long> 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 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<IAccountProviderDetailViewModel> CreateAccountItems(List<MailAccount> 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<IAccountProviderDetailViewModel>();
|
|
|
|
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);
|
|
}
|
|
|
|
// Wino Account message recipients
|
|
|
|
protected override void RegisterRecipients()
|
|
{
|
|
base.RegisterRecipients();
|
|
|
|
Messenger.Register<WinoAccountProfileUpdatedMessage>(this);
|
|
Messenger.Register<WinoAccountProfileDeletedMessage>(this);
|
|
Messenger.Register<WinoAccountAddOnPurchasedMessage>(this);
|
|
}
|
|
|
|
protected override void UnregisterRecipients()
|
|
{
|
|
base.UnregisterRecipients();
|
|
|
|
Messenger.Unregister<WinoAccountProfileUpdatedMessage>(this);
|
|
Messenger.Unregister<WinoAccountProfileDeletedMessage>(this);
|
|
Messenger.Unregister<WinoAccountAddOnPurchasedMessage>(this);
|
|
}
|
|
|
|
public void Receive(WinoAccountProfileUpdatedMessage message)
|
|
=> _ = LoadWinoAccountAsync();
|
|
|
|
public void Receive(WinoAccountProfileDeletedMessage message)
|
|
=> _ = ResetWinoAccountStateAsync();
|
|
|
|
public void Receive(WinoAccountAddOnPurchasedMessage message)
|
|
=> _ = LoadWinoAccountAsync();
|
|
|
|
// Wino Account hero card commands and helpers
|
|
|
|
[RelayCommand]
|
|
private async Task WinoAccountRegisterAsync()
|
|
{
|
|
var account = await _dialogService.ShowWinoAccountRegistrationDialogAsync();
|
|
if (account == null) return;
|
|
|
|
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
string.Format(Translator.WinoAccount_RegisterSuccessMessage, account.Email),
|
|
InfoBarMessageType.Success);
|
|
await LoadWinoAccountAsync();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task WinoAccountSignInAsync()
|
|
{
|
|
var account = await _dialogService.ShowWinoAccountLoginDialogAsync();
|
|
if (account == null) return;
|
|
|
|
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
string.Format(Translator.WinoAccount_LoginSuccessMessage, account.Email),
|
|
InfoBarMessageType.Success);
|
|
await LoadWinoAccountAsync();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task WinoAccountSignOutAsync()
|
|
{
|
|
var account = await _profileService.GetActiveAccountAsync().ConfigureAwait(false);
|
|
if (account == null) return;
|
|
|
|
await _profileService.SignOutAsync().ConfigureAwait(false);
|
|
|
|
_dialogService.InfoBarMessage(Translator.GeneralTitle_Info,
|
|
string.Format(Translator.WinoAccount_SignOut_SuccessMessage, account.Email),
|
|
InfoBarMessageType.Success);
|
|
await ResetWinoAccountStateAsync();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task OpenBuyAiPackPageAsync() => await _nativeAppService.LaunchUriAsync(new Uri(BuyAiPackUrl));
|
|
|
|
[RelayCommand]
|
|
private void NavigateToWinoAccountManagement()
|
|
=> NavigateSubDetail(WinoPage.WinoAccountManagementPage);
|
|
|
|
private async Task LoadWinoAccountAsync()
|
|
{
|
|
await ExecuteUIThread(() => IsWinoAccountBusy = true);
|
|
|
|
try
|
|
{
|
|
var account = await _profileService.GetAuthenticatedAccountAsync().ConfigureAwait(false);
|
|
if (account == null)
|
|
{
|
|
await ResetWinoAccountStateAsync();
|
|
return;
|
|
}
|
|
|
|
var currentUserResponse = await _profileService.GetCurrentUserAsync().ConfigureAwait(false);
|
|
var aiStatusResponse = await _profileService.GetAiStatusAsync().ConfigureAwait(false);
|
|
|
|
var resolvedEmail = currentUserResponse.IsSuccess && currentUserResponse.Result != null
|
|
? currentUserResponse.Result.Email
|
|
: account.Email;
|
|
|
|
var resolvedStatus = currentUserResponse.IsSuccess && currentUserResponse.Result != null
|
|
? currentUserResponse.Result.AccountStatus
|
|
: account.AccountStatus;
|
|
|
|
await ExecuteUIThread(() =>
|
|
{
|
|
IsWinoAccountSignedIn = true;
|
|
WinoAccountEmail = resolvedEmail;
|
|
WinoAccountStatusText = string.Format(Translator.WinoAccount_Management_StatusLabel, resolvedStatus);
|
|
});
|
|
|
|
UpdateAiPackState(aiStatusResponse.IsSuccess ? aiStatusResponse.Result : null);
|
|
}
|
|
catch
|
|
{
|
|
await ResetWinoAccountStateAsync();
|
|
}
|
|
finally
|
|
{
|
|
await ExecuteUIThread(() => IsWinoAccountBusy = false);
|
|
}
|
|
}
|
|
|
|
private async Task ResetWinoAccountStateAsync()
|
|
{
|
|
await ExecuteUIThread(() =>
|
|
{
|
|
IsWinoAccountSignedIn = false;
|
|
WinoAccountEmail = string.Empty;
|
|
WinoAccountStatusText = string.Empty;
|
|
HasAiPack = false;
|
|
AiPackStateText = Translator.WinoAccount_Management_AiPackInactive;
|
|
AiUsageSummary = string.Empty;
|
|
AiBillingPeriodSummary = string.Empty;
|
|
AiUsagePercent = 0;
|
|
});
|
|
}
|
|
|
|
private void UpdateAiPackState(AiStatusResultDto aiStatus)
|
|
{
|
|
var hasAiPack = aiStatus?.HasAiPack == true;
|
|
var usageText = Translator.WinoAccount_Management_AiPackUnknownUsage;
|
|
var billingText = string.Empty;
|
|
var usagePercent = 0d;
|
|
|
|
if (hasAiPack && aiStatus?.Used is int used && aiStatus.MonthlyLimit is int limit && aiStatus.Remaining is int remaining)
|
|
{
|
|
usageText = string.Format(Translator.WinoAccount_Management_AiPackUsage, used, limit, remaining);
|
|
usagePercent = limit > 0 ? (double)used / limit * 100 : 0;
|
|
}
|
|
|
|
if (hasAiPack && aiStatus?.CurrentPeriodStartUtc is DateTimeOffset periodStart && aiStatus.CurrentPeriodEndUtc is DateTimeOffset periodEnd)
|
|
{
|
|
billingText = string.Format(Translator.WinoAccount_Management_AiPackBillingPeriod, periodStart.LocalDateTime, periodEnd.LocalDateTime);
|
|
}
|
|
|
|
_ = ExecuteUIThread(() =>
|
|
{
|
|
HasAiPack = hasAiPack;
|
|
AiPackStateText = hasAiPack
|
|
? Translator.WinoAccount_Management_AiPackActive
|
|
: Translator.WinoAccount_Management_AiPackInactive;
|
|
AiUsageSummary = hasAiPack ? usageText : string.Empty;
|
|
AiBillingPeriodSummary = hasAiPack ? billingText : string.Empty;
|
|
AiUsagePercent = usagePercent;
|
|
});
|
|
}
|
|
|
|
[RelayCommand]
|
|
public void NavigateSubDetail(object type)
|
|
{
|
|
if (type is WinoPage pageType)
|
|
{
|
|
var pageInfo = SettingsNavigationInfoProvider.GetInfo(pageType, AccountSummaryText);
|
|
Messenger.Send(new BreadcrumbNavigationRequested(pageInfo.Title, pageType));
|
|
}
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task NavigateExternalAsync(object target)
|
|
{
|
|
if (target is not string stringTarget || string.IsNullOrWhiteSpace(stringTarget))
|
|
return;
|
|
|
|
if (stringTarget == "Store")
|
|
{
|
|
await _storeRatingService.LaunchStorePageForReviewAsync();
|
|
return;
|
|
}
|
|
|
|
await _nativeAppService.LaunchUriAsync(new Uri(stringTarget));
|
|
}
|
|
}
|