New management page.

This commit is contained in:
Burak Kaan Köse
2026-03-18 10:25:07 +01:00
parent aee32228c2
commit bac291587d
4 changed files with 368 additions and 60 deletions
@@ -857,11 +857,15 @@
"SettingsSearch_KeyboardShortcuts_Keywords": "shortcut;shortcuts;hotkey;hotkeys;keyboard;keys", "SettingsSearch_KeyboardShortcuts_Keywords": "shortcut;shortcuts;hotkey;hotkeys;keyboard;keys",
"SettingsSearch_WinoAccount_Keywords": "winoaccount;account;accounts;wino", "SettingsSearch_WinoAccount_Keywords": "winoaccount;account;accounts;wino",
"WinoAccount_Management_Description": "Manage your Wino Account, AI Pack access, and synchronized settings.", "WinoAccount_Management_Description": "Manage your Wino Account, AI Pack access, and synchronized settings.",
"WinoAccount_Management_SignedOutTitle": "Sign in to Wino Account", "WinoAccount_Management_SignedOutTitle": "Sign in to Wino Mail",
"WinoAccount_Management_SignedOutDescription": "Sign in or create a Wino Account to sync your settings and manage Wino add-ons.", "WinoAccount_Management_SignedOutDescription": "Sign in or create an account to sync your email, access AI features, and manage your settings across devices.",
"WinoAccount_Management_ProfileSectionHeader": "Profile",
"WinoAccount_Management_AiPackSectionHeader": "AI Pack",
"WinoAccount_Management_DataSectionHeader": "Data",
"WinoAccount_Management_AccountActionsSectionHeader": "Account actions",
"WinoAccount_Management_AccountCardTitle": "Account", "WinoAccount_Management_AccountCardTitle": "Account",
"WinoAccount_Management_AccountCardDescription": "Your Wino Account email address and current account state.", "WinoAccount_Management_AccountCardDescription": "Your Wino Account email address and current account state.",
"WinoAccount_Management_AiPackCardTitle": "Wino AI Pack", "WinoAccount_Management_AiPackCardTitle": "AI Pack",
"WinoAccount_Management_AiPackCardDescription": "See whether Wino AI Pack is active and how much usage is left.", "WinoAccount_Management_AiPackCardDescription": "See whether Wino AI Pack is active and how much usage is left.",
"WinoAccount_Management_AiPackActive": "AI Pack is active", "WinoAccount_Management_AiPackActive": "AI Pack is active",
"WinoAccount_Management_AiPackInactive": "AI Pack is not active", "WinoAccount_Management_AiPackInactive": "AI Pack is not active",
@@ -869,6 +873,24 @@
"WinoAccount_Management_AiPackBillingPeriod": "Billing period: {0:d} - {1:d}", "WinoAccount_Management_AiPackBillingPeriod": "Billing period: {0:d} - {1:d}",
"WinoAccount_Management_AiPackUnknownUsage": "Usage details are not available yet.", "WinoAccount_Management_AiPackUnknownUsage": "Usage details are not available yet.",
"WinoAccount_Management_AiPackBuyDescription": "Buy Wino AI Pack to translate, rewrite or summarize emails with AI.", "WinoAccount_Management_AiPackBuyDescription": "Buy Wino AI Pack to translate, rewrite or summarize emails with AI.",
"WinoAccount_Management_AiPackPromoTitle": "Unlock AI Pack",
"WinoAccount_Management_AiPackPromoDescription": "Supercharge your email workflow with AI-powered tools. Translate messages into 50+ languages, rewrite for clarity and tone, and get instant summaries of long threads.",
"WinoAccount_Management_AiPackPromoPrice": "$4.99 / mo",
"WinoAccount_Management_AiPackPromoRequests": "1,000 requests",
"WinoAccount_Management_AiPackGetButton": "Get AI Pack",
"WinoAccount_Management_AiPackSubscriptionActive": "Your subscription is active",
"WinoAccount_Management_AiPackRenews": "Renews {0:d}",
"WinoAccount_Management_AiPackRequestsUsed": "Requests used this month",
"WinoAccount_Management_AiPackResets": "Resets {0:d}",
"WinoAccount_Management_AiPackFeatureTranslate": "Translate",
"WinoAccount_Management_AiPackFeatureRewrite": "Rewrite",
"WinoAccount_Management_AiPackFeatureSummarize": "Summarize",
"WinoAccount_Management_ImportSettingsTitle": "Import settings",
"WinoAccount_Management_ImportSettingsDescription": "Restore your preferences from cloud.",
"WinoAccount_Management_ExportSettingsTitle": "Export settings",
"WinoAccount_Management_ExportSettingsDescription": "Save your preferences to cloud.",
"WinoAccount_Management_SignOutTitle": "Sign out",
"WinoAccount_Management_SignOutDescription": "Sign out of your account on this device",
"WinoAccount_Management_SettingsCardTitle": "Settings sync", "WinoAccount_Management_SettingsCardTitle": "Settings sync",
"WinoAccount_Management_SettingsCardDescription": "Export your current settings to your Wino Account or import them back on this device.", "WinoAccount_Management_SettingsCardDescription": "Export your current settings to your Wino Account or import them back on this device.",
"WinoAccount_Management_StatusLabel": "Status: {0}", "WinoAccount_Management_StatusLabel": "Status: {0}",
@@ -108,7 +108,6 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel,
public partial string WinoAccountStatusText { get; set; } = string.Empty; public partial string WinoAccountStatusText { get; set; } = string.Empty;
[ObservableProperty] [ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanShowAiUsage))]
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))] [NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
public partial bool HasAiPack { get; set; } public partial bool HasAiPack { get; set; }
@@ -23,6 +23,7 @@ namespace Wino.Core.ViewModels;
public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
{ {
private const string BuyAiPackUrl = "https://example.com/wino-ai-pack"; private const string BuyAiPackUrl = "https://example.com/wino-ai-pack";
private const string ManageAiPackUrl = "https://example.com/wino-ai-pack/manage";
private readonly IWinoAccountProfileService _profileService; private readonly IWinoAccountProfileService _profileService;
private readonly IWinoAccountApiClient _apiClient; private readonly IWinoAccountApiClient _apiClient;
@@ -38,6 +39,12 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
[NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))] [NotifyPropertyChangedFor(nameof(CanShowBuyAiPack))]
public partial bool IsSignedIn { get; set; } public partial bool IsSignedIn { get; set; }
[ObservableProperty]
public partial string AccountDisplayName { get; set; } = string.Empty;
[ObservableProperty]
public partial string AccountInitials { get; set; } = string.Empty;
[ObservableProperty] [ObservableProperty]
public partial string AccountEmail { get; set; } = string.Empty; public partial string AccountEmail { get; set; } = string.Empty;
@@ -58,6 +65,21 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
[ObservableProperty] [ObservableProperty]
public partial string AiBillingPeriodSummary { get; set; } = string.Empty; public partial string AiBillingPeriodSummary { get; set; } = string.Empty;
[ObservableProperty]
public partial string AiPackRenewalText { get; set; } = string.Empty;
[ObservableProperty]
public partial int AiUsageCount { get; set; }
[ObservableProperty]
public partial int AiUsageLimit { get; set; } = 1;
[ObservableProperty]
public partial double AiUsagePercentage { get; set; }
[ObservableProperty]
public partial string AiUsageResetText { get; set; } = string.Empty;
public bool IsSignedOut => !IsSignedIn; public bool IsSignedOut => !IsSignedIn;
public bool CanShowAiUsage => HasAiPack; public bool CanShowAiUsage => HasAiPack;
public bool CanShowBuyAiPack => IsSignedIn && !HasAiPack; public bool CanShowBuyAiPack => IsSignedIn && !HasAiPack;
@@ -137,6 +159,9 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
[RelayCommand] [RelayCommand]
private async Task OpenBuyPageAsync() => await _nativeAppService.LaunchUriAsync(new Uri(BuyAiPackUrl)); private async Task OpenBuyPageAsync() => await _nativeAppService.LaunchUriAsync(new Uri(BuyAiPackUrl));
[RelayCommand]
private async Task ManageAiPackAsync() => await _nativeAppService.LaunchUriAsync(new Uri(ManageAiPackUrl));
[RelayCommand] [RelayCommand]
private async Task ExportSettingsAsync() private async Task ExportSettingsAsync()
{ {
@@ -289,6 +314,8 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
{ {
IsSignedIn = true; IsSignedIn = true;
AccountEmail = resolvedUser.Email; AccountEmail = resolvedUser.Email;
AccountDisplayName = ExtractDisplayName(resolvedUser.Email);
AccountInitials = ExtractInitials(resolvedUser.Email);
AccountStatusText = string.Format(Translator.WinoAccount_Management_StatusLabel, resolvedUser.AccountStatus); AccountStatusText = string.Format(Translator.WinoAccount_Management_StatusLabel, resolvedUser.AccountStatus);
}); });
@@ -319,12 +346,19 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
await ExecuteUIThread(() => await ExecuteUIThread(() =>
{ {
IsSignedIn = false; IsSignedIn = false;
AccountDisplayName = string.Empty;
AccountInitials = string.Empty;
AccountEmail = string.Empty; AccountEmail = string.Empty;
AccountStatusText = string.Empty; AccountStatusText = string.Empty;
HasAiPack = false; HasAiPack = false;
AiPackStateText = Translator.WinoAccount_Management_AiPackInactive; AiPackStateText = Translator.WinoAccount_Management_AiPackInactive;
AiUsageSummary = string.Empty; AiUsageSummary = string.Empty;
AiBillingPeriodSummary = string.Empty; AiBillingPeriodSummary = string.Empty;
AiPackRenewalText = string.Empty;
AiUsageCount = 0;
AiUsageLimit = 1;
AiUsagePercentage = 0;
AiUsageResetText = string.Empty;
}); });
} }
@@ -358,15 +392,25 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
var hasAiPack = aiStatus?.HasAiPack == true; var hasAiPack = aiStatus?.HasAiPack == true;
var usageText = Translator.WinoAccount_Management_AiPackUnknownUsage; var usageText = Translator.WinoAccount_Management_AiPackUnknownUsage;
var billingText = string.Empty; var billingText = string.Empty;
var renewalText = string.Empty;
var usageCount = 0;
var usageLimit = 1;
var usagePercentage = 0d;
var resetText = string.Empty;
if (hasAiPack && aiStatus?.Used is int used && aiStatus.MonthlyLimit is int limit && aiStatus.Remaining is int remaining) 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); usageText = string.Format(Translator.WinoAccount_Management_AiPackUsage, used, limit, remaining);
usageCount = used;
usageLimit = limit > 0 ? limit : 1;
usagePercentage = (double)used / usageLimit * 100;
} }
if (hasAiPack && aiStatus?.CurrentPeriodStartUtc is DateTimeOffset periodStart && aiStatus.CurrentPeriodEndUtc is DateTimeOffset periodEnd) if (hasAiPack && aiStatus?.CurrentPeriodStartUtc is DateTimeOffset periodStart && aiStatus.CurrentPeriodEndUtc is DateTimeOffset periodEnd)
{ {
billingText = string.Format(Translator.WinoAccount_Management_AiPackBillingPeriod, periodStart.LocalDateTime, periodEnd.LocalDateTime); billingText = string.Format(Translator.WinoAccount_Management_AiPackBillingPeriod, periodStart.LocalDateTime, periodEnd.LocalDateTime);
renewalText = string.Format(Translator.WinoAccount_Management_AiPackRenews, periodEnd.LocalDateTime);
resetText = string.Format(Translator.WinoAccount_Management_AiPackResets, periodEnd.LocalDateTime);
} }
_ = ExecuteUIThread(() => _ = ExecuteUIThread(() =>
@@ -377,9 +421,36 @@ public partial class WinoAccountManagementPageViewModel : CoreBaseViewModel
: Translator.WinoAccount_Management_AiPackInactive; : Translator.WinoAccount_Management_AiPackInactive;
AiUsageSummary = hasAiPack ? usageText : string.Empty; AiUsageSummary = hasAiPack ? usageText : string.Empty;
AiBillingPeriodSummary = hasAiPack ? billingText : string.Empty; AiBillingPeriodSummary = hasAiPack ? billingText : string.Empty;
AiPackRenewalText = hasAiPack ? renewalText : string.Empty;
AiUsageCount = usageCount;
AiUsageLimit = usageLimit;
AiUsagePercentage = usagePercentage;
AiUsageResetText = hasAiPack ? resetText : string.Empty;
}); });
} }
private static string ExtractDisplayName(string email)
{
if (string.IsNullOrWhiteSpace(email))
return string.Empty;
var atIndex = email.IndexOf('@');
var localPart = atIndex > 0 ? email[..atIndex] : email;
if (localPart.Length == 0)
return string.Empty;
return char.ToUpper(localPart[0], CultureInfo.CurrentCulture) + localPart[1..];
}
private static string ExtractInitials(string email)
{
var displayName = ExtractDisplayName(email);
return displayName.Length > 0
? displayName[..1].ToUpper(CultureInfo.CurrentCulture)
: string.Empty;
}
private Dictionary<string, object?> CollectPreferencesSnapshot() private Dictionary<string, object?> CollectPreferencesSnapshot()
{ {
var settings = new Dictionary<string, object?>(StringComparer.Ordinal); var settings = new Dictionary<string, object?>(StringComparer.Ordinal);
@@ -12,12 +12,8 @@
<ScrollViewer> <ScrollViewer>
<StackPanel Spacing="{StaticResource SettingsCardSpacing}"> <StackPanel Spacing="{StaticResource SettingsCardSpacing}">
<TextBlock
Margin="0,0,0,8"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_Description}" />
<!-- Busy indicator -->
<StackPanel <StackPanel
x:Name="BusyPanel" x:Name="BusyPanel"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -30,76 +26,296 @@
<TextBlock HorizontalAlignment="Center" Text="{x:Bind domain:Translator.Busy}" /> <TextBlock HorizontalAlignment="Center" Text="{x:Bind domain:Translator.Busy}" />
</StackPanel> </StackPanel>
<!-- ══════════════════════════════════════ -->
<!-- SIGNED-OUT VIEW -->
<!-- ══════════════════════════════════════ -->
<StackPanel <StackPanel
x:Name="SignedOutPanel" x:Name="SignedOutPanel"
x:Load="{x:Bind ViewModel.IsSignedOut, Mode=OneWay}" x:Load="{x:Bind ViewModel.IsSignedOut, Mode=OneWay}"
Spacing="{StaticResource SettingsCardSpacing}"> Spacing="{StaticResource SettingsCardSpacing}">
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_SignedOutDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_SignedOutTitle}">
<controls:SettingsCard.HeaderIcon> <StackPanel
<SymbolIcon Symbol="Contact" /> Padding="0,40,0,40"
</controls:SettingsCard.HeaderIcon> HorizontalAlignment="Center"
<StackPanel Orientation="Horizontal" Spacing="12"> Spacing="16">
<!-- App logo -->
<Image
Width="64"
Height="64"
HorizontalAlignment="Center"
Source="ms-appx:///Assets/AppEntries/MailAssets/Square150x150Logo.scale-100.png" />
<!-- Title -->
<TextBlock
HorizontalAlignment="Center"
FontSize="20"
FontWeight="SemiBold"
Text="{x:Bind domain:Translator.WinoAccount_Management_SignedOutTitle}" />
<!-- Description -->
<TextBlock
MaxWidth="360"
HorizontalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_SignedOutDescription}"
TextAlignment="Center"
TextWrapping="WrapWholeWords" />
<!-- Action buttons -->
<StackPanel
HorizontalAlignment="Center"
Orientation="Horizontal"
Spacing="12">
<Button
Command="{x:Bind ViewModel.SignInCommand}"
Content="{x:Bind domain:Translator.Buttons_SignIn}"
Style="{StaticResource AccentButtonStyle}" />
<Button Command="{x:Bind ViewModel.RegisterCommand}" Content="{x:Bind domain:Translator.Buttons_CreateAccount}" /> <Button Command="{x:Bind ViewModel.RegisterCommand}" Content="{x:Bind domain:Translator.Buttons_CreateAccount}" />
<Button Command="{x:Bind ViewModel.SignInCommand}" Content="{x:Bind domain:Translator.Buttons_SignIn}" />
</StackPanel> </StackPanel>
</controls:SettingsCard> </StackPanel>
</StackPanel> </StackPanel>
<!-- ══════════════════════════════════════ -->
<!-- SIGNED-IN VIEW -->
<!-- ══════════════════════════════════════ -->
<StackPanel <StackPanel
x:Name="SignedInPanel" x:Name="SignedInPanel"
x:Load="{x:Bind ViewModel.IsSignedIn, Mode=OneWay}" x:Load="{x:Bind ViewModel.IsSignedIn, Mode=OneWay}"
Spacing="{StaticResource SettingsCardSpacing}"> Spacing="{StaticResource SettingsCardSpacing}">
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_AccountCardDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_AccountCardTitle}">
<controls:SettingsCard.HeaderIcon> <!-- ─── Profile section ─── -->
<SymbolIcon Symbol="Contact" /> <TextBlock
</controls:SettingsCard.HeaderIcon> Margin="0,0,0,4"
<StackPanel Spacing="8"> Style="{StaticResource BodyStrongTextBlockStyle}"
<TextBlock FontWeight="SemiBold" Text="{x:Bind ViewModel.AccountEmail, Mode=OneWay}" /> Text="{x:Bind domain:Translator.WinoAccount_Management_ProfileSectionHeader}" />
<TextBlock Text="{x:Bind ViewModel.AccountStatusText, Mode=OneWay}" />
<Button <controls:SettingsCard>
HorizontalAlignment="Left" <controls:SettingsCard.Header>
Command="{x:Bind ViewModel.SignOutCommand}" <StackPanel Orientation="Horizontal" Spacing="12">
Content="{x:Bind domain:Translator.WinoAccount_SignOutButton_Action}" /> <PersonPicture
</StackPanel> Width="40"
Height="40"
Initials="{x:Bind ViewModel.AccountInitials, Mode=OneWay}" />
<StackPanel VerticalAlignment="Center" Spacing="2">
<TextBlock FontWeight="SemiBold" Text="{x:Bind ViewModel.AccountDisplayName, Mode=OneWay}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.AccountEmail, Mode=OneWay}" />
</StackPanel>
</StackPanel>
</controls:SettingsCard.Header>
<Border
Padding="12,4"
Background="{ThemeResource SystemFillColorSuccessBackgroundBrush}"
CornerRadius="12">
<TextBlock
Foreground="{ThemeResource SystemFillColorSuccessBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.AccountStatusText, Mode=OneWay}" />
</Border>
</controls:SettingsCard> </controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_AiPackCardDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_AiPackCardTitle}"> <!-- ─── AI Pack section ─── -->
<TextBlock
Margin="0,12,0,4"
Style="{StaticResource BodyStrongTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackSectionHeader}" />
<StackPanel Spacing="8"> <!-- AI Pack promo (no AI Pack) -->
<TextBlock FontWeight="SemiBold" Text="{x:Bind ViewModel.AiPackStateText, Mode=OneWay}" /> <controls:SettingsCard
<TextBlock x:Name="AiPackPromoCard"
x:Name="CanShowAITextBlock" x:Load="{x:Bind ViewModel.CanShowBuyAiPack, Mode=OneWay}"
x:Load="{x:Bind ViewModel.CanShowAiUsage, Mode=OneWay}" Description="{x:Bind domain:Translator.WinoAccount_Management_AiPackPromoDescription}">
Text="{x:Bind ViewModel.AiUsageSummary, Mode=OneWay}" <controls:SettingsCard.HeaderIcon>
TextWrapping="WrapWholeWords" /> <FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE945;" />
<TextBlock </controls:SettingsCard.HeaderIcon>
x:Name="BillingBlock" <controls:SettingsCard.Header>
x:Load="{x:Bind ViewModel.CanShowAiUsage, Mode=OneWay}" <StackPanel Spacing="8">
Foreground="{ThemeResource TextFillColorSecondaryBrush}" <StackPanel Orientation="Horizontal" Spacing="8">
Text="{x:Bind ViewModel.AiBillingPeriodSummary, Mode=OneWay}" <TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackPromoTitle}" />
TextWrapping="WrapWholeWords" /> <Border
<TextBlock Padding="8,2"
x:Name="CanBuyAIPack" Background="{ThemeResource SystemAccentColor}"
x:Load="{x:Bind ViewModel.CanShowBuyAiPack, Mode=OneWay}" CornerRadius="4">
Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackBuyDescription}" <TextBlock
TextWrapping="WrapWholeWords" /> FontSize="10"
<Button FontWeight="Bold"
x:Name="OpenBuyPageButton" Foreground="White"
HorizontalAlignment="Left" Text="PRO" />
x:Load="{x:Bind ViewModel.CanShowBuyAiPack, Mode=OneWay}" </Border>
Command="{x:Bind ViewModel.OpenBuyPageCommand}" </StackPanel>
Content="{x:Bind domain:Translator.Buttons_Purchase}" /> <TextBlock
</StackPanel> MaxWidth="400"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackPromoDescription}"
TextWrapping="WrapWholeWords" />
<StackPanel Orientation="Horizontal" Spacing="16">
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xE8C1;" />
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackFeatureTranslate}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xE70F;" />
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackFeatureRewrite}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="4">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="12"
Glyph="&#xE8FD;" />
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackFeatureSummarize}" />
</StackPanel>
</StackPanel>
<StackPanel
Margin="0,4,0,0"
Orientation="Horizontal"
Spacing="12">
<Button
Command="{x:Bind ViewModel.OpenBuyPageCommand}"
Content="{x:Bind domain:Translator.WinoAccount_Management_AiPackGetButton}"
Style="{StaticResource AccentButtonStyle}" />
<TextBlock
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}">
<Run Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackPromoPrice}" />
<Run Text=" · " />
<Run Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackPromoRequests}" />
</TextBlock>
</StackPanel>
</StackPanel>
</controls:SettingsCard.Header>
</controls:SettingsCard> </controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_SettingsCardDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_SettingsCardTitle}"> <!-- AI Pack active: subscription info -->
<controls:SettingsExpander
x:Name="AiPackActiveCard"
x:Load="{x:Bind ViewModel.HasAiPack, Mode=OneWay}"
IsExpanded="True">
<controls:SettingsExpander.HeaderIcon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE945;" />
</controls:SettingsExpander.HeaderIcon>
<controls:SettingsExpander.Header>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackCardTitle}" />
<Border
Padding="8,2"
Background="{ThemeResource SystemAccentColor}"
CornerRadius="4">
<TextBlock
FontSize="10"
FontWeight="Bold"
Foreground="White"
Text="PRO" />
</Border>
</StackPanel>
</controls:SettingsExpander.Header>
<controls:SettingsExpander.Description>
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackSubscriptionActive}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text=" · " />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.AiPackRenewalText, Mode=OneWay}" />
</StackPanel>
</controls:SettingsExpander.Description>
<HyperlinkButton Command="{x:Bind ViewModel.ManageAiPackCommand}" Content="{x:Bind domain:Translator.Buttons_Manage}" />
<controls:SettingsExpander.Items>
<!-- AI Pack active: usage bar -->
<controls:SettingsCard x:Name="AiPackUsageCard" HorizontalContentAlignment="Stretch">
<controls:SettingsCard.Header>
<StackPanel MinWidth="400" Spacing="8">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock
FontSize="24"
FontWeight="Bold"
Text="{x:Bind ViewModel.AiUsageCount, Mode=OneWay}" />
<TextBlock
Margin="0,0,0,2"
VerticalAlignment="Bottom"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}">
<Run Text="/ " />
<Run Text="{x:Bind ViewModel.AiUsageLimit, Mode=OneWay}" />
</TextBlock>
</StackPanel>
<ProgressBar
Height="8"
Maximum="100"
Value="{x:Bind ViewModel.AiUsagePercentage, Mode=OneWay}" />
<Grid>
<TextBlock
HorizontalAlignment="Left"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_AiPackRequestsUsed}" />
<TextBlock
HorizontalAlignment="Right"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind ViewModel.AiUsageResetText, Mode=OneWay}" />
</Grid>
</StackPanel>
</controls:SettingsCard.Header>
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<!-- ─── Data section ─── -->
<TextBlock
Margin="0,12,0,4"
Style="{StaticResource BodyStrongTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_DataSectionHeader}" />
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_ImportSettingsDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_ImportSettingsTitle}">
<controls:SettingsCard.HeaderIcon> <controls:SettingsCard.HeaderIcon>
<SymbolIcon Symbol="Sync" /> <FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE896;" />
</controls:SettingsCard.HeaderIcon>
<Button Command="{x:Bind ViewModel.ImportSettingsCommand}" Content="{x:Bind domain:Translator.Buttons_Browse}" />
</controls:SettingsCard>
<controls:SettingsCard Description="{x:Bind domain:Translator.WinoAccount_Management_ExportSettingsDescription}" Header="{x:Bind domain:Translator.WinoAccount_Management_ExportSettingsTitle}">
<controls:SettingsCard.HeaderIcon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE898;" />
</controls:SettingsCard.HeaderIcon>
<Button Command="{x:Bind ViewModel.ExportSettingsCommand}" Content="{x:Bind domain:Translator.Buttons_Export}" />
</controls:SettingsCard>
<!-- ─── Account actions section ─── -->
<TextBlock
Margin="0,12,0,4"
Style="{StaticResource BodyStrongTextBlockStyle}"
Text="{x:Bind domain:Translator.WinoAccount_Management_AccountActionsSectionHeader}" />
<controls:SettingsCard
Command="{x:Bind ViewModel.SignOutCommand}"
Description="{x:Bind domain:Translator.WinoAccount_Management_SignOutDescription}"
Header="{x:Bind domain:Translator.WinoAccount_Management_SignOutTitle}"
IsClickEnabled="True">
<controls:SettingsCard.HeaderIcon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xF3B1;" />
</controls:SettingsCard.HeaderIcon> </controls:SettingsCard.HeaderIcon>
<StackPanel Orientation="Horizontal" Spacing="12">
<Button Command="{x:Bind ViewModel.ExportSettingsCommand}" Content="{x:Bind domain:Translator.Buttons_Export}" />
<Button Command="{x:Bind ViewModel.ImportSettingsCommand}" Content="{x:Bind domain:Translator.Buttons_Import}" />
</StackPanel>
</controls:SettingsCard> </controls:SettingsCard>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>