Files
Clario/Clario/Views/SettingsView.axaml

531 lines
30 KiB
XML

<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Clario.ViewModels"
mc:Ignorable="d" d:DesignWidth="1180" d:DesignHeight="800"
x:Class="Clario.Views.SettingsView"
x:DataType="vm:SettingsViewModel">
<Design.DataContext>
<vm:SettingsViewModel />
</Design.DataContext>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel Margin="32,28,32,48"
Spacing="0"
MaxWidth="720">
<!-- ── Page header ─────────────────────────── -->
<StackPanel Margin="0,0,0,28">
<TextBlock Text="Settings"
FontSize="26"
FontWeight="Bold"
Foreground="{DynamicResource TextPrimary}" />
<TextBlock Text="Manage your account and preferences"
FontSize="13"
Foreground="{DynamicResource TextMuted}"
Margin="0,4,0,0" />
</StackPanel>
<!-- ── Global success / error banner ─────────── -->
<Border Background="{DynamicResource IconBgGreen}"
BorderBrush="{DynamicResource AccentGreen}"
BorderThickness="1"
CornerRadius="12"
Padding="14,10"
Margin="0,0,0,14"
IsVisible="{Binding HasSuccess}">
<Grid ColumnDefinitions="Auto,*">
<Svg Grid.Column="0"
Path="../Assets/Icons/circle-check.svg"
Width="14" Height="14"
Css="{DynamicResource SvgGreen}"
VerticalAlignment="Center"
Margin="0,0,10,0" />
<TextBlock Grid.Column="1"
Text="{Binding SuccessMessage}"
FontSize="13"
Foreground="{DynamicResource AccentGreen}"
VerticalAlignment="Center" />
</Grid>
</Border>
<Border Background="{DynamicResource BadgeBgRed}"
BorderBrush="{DynamicResource AccentRed}"
BorderThickness="1"
CornerRadius="12"
Padding="14,10"
Margin="0,0,0,14"
IsVisible="{Binding HasError}">
<Grid ColumnDefinitions="Auto,*">
<Svg Grid.Column="0"
Path="../Assets/Icons/circle-alert.svg"
Width="14" Height="14"
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }"
VerticalAlignment="Center"
Margin="0,0,10,0" />
<TextBlock Grid.Column="1"
Text="{Binding ErrorMessage}"
FontSize="13"
Foreground="{DynamicResource AccentRed}"
VerticalAlignment="Center"
TextWrapping="Wrap" />
</Grid>
</Border>
<!-- ══════════════════════════════════════════════
SECTION: Profile
══════════════════════════════════════════════ -->
<TextBlock Text="PROFILE"
Classes="label"
Margin="0,0,0,10" />
<Border Background="{DynamicResource BgSurface}"
BorderBrush="{DynamicResource BorderSubtle}"
BorderThickness="1"
CornerRadius="16"
Padding="22"
Margin="0,0,0,24">
<StackPanel Spacing="20">
<!-- Avatar -->
<Grid ColumnDefinitions="Auto,*">
<StackPanel Grid.Column="0"
Spacing="8"
Margin="0,0,20,0">
<!-- Avatar circle -->
<Panel Width="80" Height="80"
HorizontalAlignment="Center">
<!-- Image (if has avatar) -->
<Border CornerRadius="40"
ClipToBounds="True"
Width="80" Height="80"
IsVisible="{Binding HasAvatar}">
<Image Source="{Binding AvatarImage}"
Stretch="UniformToFill" />
</Border>
<!-- Initials fallback -->
<Border CornerRadius="40"
Width="80" Height="80"
Background="{DynamicResource BorderAccent}"
IsVisible="{Binding !HasAvatar}">
<TextBlock Text="{Binding DisplayName[0]}"
FontSize="28"
FontWeight="Bold"
Foreground="{DynamicResource AccentBlue}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<!-- Upload spinner overlay -->
<Border CornerRadius="40"
Width="80" Height="80"
Background="#80000000"
IsVisible="{Binding IsUploadingAvatar}">
<TextBlock Text="..."
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</Panel>
<!-- Avatar actions -->
<StackPanel Spacing="4">
<Button Classes="base"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="0,7"
FontSize="12"
IsEnabled="{Binding !IsUploadingAvatar}"
Command="{Binding UploadAvatarCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Svg Path="../Assets/Icons/upload.svg"
Width="12" Height="12"
Css="{DynamicResource SvgMuted}" />
<TextBlock Text="Upload" FontSize="12" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Background="Transparent"
BorderThickness="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="0,4"
FontSize="11"
Foreground="{DynamicResource AccentRed}"
IsVisible="{Binding HasAvatar}"
IsEnabled="{Binding !IsUploadingAvatar}"
Command="{Binding RemoveAvatarCommand}"
Content="Remove" />
</StackPanel>
</StackPanel>
<!-- Profile fields -->
<StackPanel Grid.Column="1" Spacing="16">
<!-- Display name -->
<StackPanel Spacing="6">
<TextBlock Text="DISPLAY NAME" Classes="label" />
<TextBox Text="{Binding DisplayName, Mode=TwoWay}"
Watermark="Your name"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
<!-- Currency + Theme -->
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="6">
<TextBlock Text="CURRENCY" Classes="label" />
<ComboBox ItemsSource="{Binding Currencies}"
SelectedItem="{Binding SelectedCurrency, Mode=TwoWay}"
HorizontalAlignment="Stretch"
Padding="10,8"
FontSize="13" />
</StackPanel>
<StackPanel Grid.Column="2" Spacing="6">
<TextBlock Text="THEME" Classes="label" />
<ComboBox ItemsSource="{Binding ThemeLabels}"
SelectedIndex="{Binding SelectedThemeIndex, Mode=TwoWay}"
HorizontalAlignment="Stretch"
Padding="10,8"
FontSize="13" />
</StackPanel>
</Grid>
<!-- Language -->
<StackPanel Spacing="6">
<TextBlock Text="LANGUAGE" Classes="label" />
<ComboBox ItemsSource="{Binding LanguageLabels}"
SelectedIndex="{Binding SelectedLanguageIndex, Mode=TwoWay}"
HorizontalAlignment="Stretch"
Padding="10,8"
FontSize="13" />
</StackPanel>
</StackPanel>
</Grid>
<Separator />
<!-- Save button -->
<Button Classes="accented"
HorizontalAlignment="Right"
Padding="20,9"
IsEnabled="{Binding !IsSaving}"
Command="{Binding SaveProfileCommand}">
<StackPanel Orientation="Horizontal" Spacing="8">
<Svg Path="../Assets/Icons/check.svg"
Width="13" Height="13"
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #0D0F14; }" />
<Panel>
<TextBlock Text="{Binding IsSaving, Converter={StaticResource BoolToStringConverter}, ConverterParameter='Saving...|Save Changes'}"
FontSize="13"
FontWeight="SemiBold"
Foreground="{DynamicResource BgBase}"
VerticalAlignment="Center" />
</Panel>
</StackPanel>
</Button>
</StackPanel>
</Border>
<!-- ══════════════════════════════════════════════
SECTION: Account Security
══════════════════════════════════════════════ -->
<TextBlock Text="ACCOUNT &amp; SECURITY"
Classes="label"
Margin="0,0,0,10" />
<Border Background="{DynamicResource BgSurface}"
BorderBrush="{DynamicResource BorderSubtle}"
BorderThickness="1"
CornerRadius="16"
Padding="0"
Margin="0,0,0,24">
<StackPanel Spacing="0">
<!-- ── Email row ───────────────────────────── -->
<Border BorderBrush="{DynamicResource BorderSubtle}"
BorderThickness="0,0,0,1"
Padding="20,0">
<Panel>
<!-- Normal email display -->
<Grid IsVisible="{Binding !IsChangingEmail}"
ColumnDefinitions="*,Auto"
MinHeight="58">
<StackPanel Grid.Column="0"
VerticalAlignment="Center"
Spacing="2">
<TextBlock Text="EMAIL ADDRESS"
Classes="label" />
<TextBlock Text="{Binding MaskedEmail}"
FontSize="13"
Foreground="{DynamicResource TextPrimary}"
FontWeight="SemiBold" />
</StackPanel>
<Button Grid.Column="1"
Background="Transparent"
BorderThickness="0"
Padding="0"
Cursor="Hand"
VerticalAlignment="Center"
Command="{Binding StartChangeEmailCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Svg Path="../Assets/Icons/pencil.svg"
Width="13" Height="13"
Css="{DynamicResource SvgMuted}" />
<TextBlock Text="Change"
FontSize="12"
Foreground="{DynamicResource AccentBlue}" />
</StackPanel>
</Button>
</Grid>
<!-- Change email form -->
<StackPanel IsVisible="{Binding IsChangingEmail}"
Spacing="12"
Margin="0,16,0,16">
<TextBlock Text="CHANGE EMAIL ADDRESS"
Classes="label" />
<!-- Email success / error -->
<Border Background="{DynamicResource IconBgGreen}"
BorderBrush="{DynamicResource AccentGreen}"
BorderThickness="1"
CornerRadius="10"
Padding="12,8"
IsVisible="{Binding HasEmailSuccess}">
<TextBlock Text="{Binding EmailSuccessMessage}"
FontSize="12"
Foreground="{DynamicResource AccentGreen}"
TextWrapping="Wrap" />
</Border>
<Border Background="{DynamicResource BadgeBgRed}"
BorderBrush="{DynamicResource AccentRed}"
BorderThickness="1"
CornerRadius="10"
Padding="12,8"
IsVisible="{Binding HasEmailError}">
<TextBlock Text="{Binding EmailErrorMessage}"
FontSize="12"
Foreground="{DynamicResource AccentRed}"
TextWrapping="Wrap" />
</Border>
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="6">
<TextBlock Text="NEW EMAIL" Classes="label" />
<TextBox Text="{Binding NewEmail, Mode=TwoWay}"
Watermark="new@email.com"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
<StackPanel Grid.Column="2" Spacing="6">
<TextBlock Text="CONFIRM WITH PASSWORD" Classes="label" />
<TextBox Text="{Binding EmailConfirmPassword, Mode=TwoWay}"
Watermark="Current password"
PasswordChar="•"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal"
Spacing="8"
HorizontalAlignment="Right">
<Button Classes="base"
Padding="16,8"
FontSize="13"
Content="Cancel"
Command="{Binding CancelChangeEmailCommand}" />
<Button Classes="accented"
Padding="16,8"
IsEnabled="{Binding !IsSaving}"
Command="{Binding ConfirmChangeEmailCommand}">
<TextBlock Text="Update Email"
FontSize="13"
FontWeight="SemiBold"
Foreground="{DynamicResource BgBase}" />
</Button>
</StackPanel>
</StackPanel>
</Panel>
</Border>
<!-- ── Password row ───────────────────────── -->
<Border Padding="20,0">
<!-- Normal password display -->
<Panel>
<Grid IsVisible="{Binding !IsChangingPassword}"
ColumnDefinitions="*,Auto"
MinHeight="58">
<StackPanel Grid.Column="0"
VerticalAlignment="Center"
Spacing="2">
<TextBlock Text="PASSWORD"
Classes="label" />
<TextBlock Text="••••••••••••"
FontSize="16"
Foreground="{DynamicResource TextMuted}"
LetterSpacing="2" />
</StackPanel>
<Button Grid.Column="1"
Background="Transparent"
BorderThickness="0"
Padding="0"
Cursor="Hand"
VerticalAlignment="Center"
Command="{Binding StartChangePasswordCommand}">
<StackPanel Orientation="Horizontal" Spacing="6">
<Svg Path="../Assets/Icons/pencil.svg"
Width="13" Height="13"
Css="{DynamicResource SvgMuted}" />
<TextBlock Text="Change"
FontSize="12"
Foreground="{DynamicResource AccentBlue}" />
</StackPanel>
</Button>
</Grid>
<!-- Change password form -->
<StackPanel IsVisible="{Binding IsChangingPassword}"
Spacing="12"
Margin="0,16,0,16">
<TextBlock Text="CHANGE PASSWORD" Classes="label" />
<!-- Password success / error -->
<Border Background="{DynamicResource IconBgGreen}"
BorderBrush="{DynamicResource AccentGreen}"
BorderThickness="1"
CornerRadius="10"
Padding="12,8"
IsVisible="{Binding HasPasswordSuccess}">
<TextBlock Text="{Binding PasswordSuccessMessage}"
FontSize="12"
Foreground="{DynamicResource AccentGreen}"
TextWrapping="Wrap" />
</Border>
<Border Background="{DynamicResource BadgeBgRed}"
BorderBrush="{DynamicResource AccentRed}"
BorderThickness="1"
CornerRadius="10"
Padding="12,8"
IsVisible="{Binding HasPasswordError}">
<TextBlock Text="{Binding PasswordErrorMessage}"
FontSize="12"
Foreground="{DynamicResource AccentRed}"
TextWrapping="Wrap" />
</Border>
<StackPanel Spacing="6">
<TextBlock Text="CURRENT PASSWORD" Classes="label" />
<TextBox Text="{Binding CurrentPassword, Mode=TwoWay}"
Watermark="Enter current password"
PasswordChar="•"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
<Grid ColumnDefinitions="*,16,*">
<StackPanel Grid.Column="0" Spacing="6">
<TextBlock Text="NEW PASSWORD" Classes="label" />
<TextBox Text="{Binding NewPassword, Mode=TwoWay}"
Watermark="Min. 8 characters"
PasswordChar="•"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
<StackPanel Grid.Column="2" Spacing="6">
<TextBlock Text="CONFIRM NEW PASSWORD" Classes="label" />
<TextBox Text="{Binding ConfirmNewPassword, Mode=TwoWay}"
Watermark="Repeat new password"
PasswordChar="•"
FontSize="13"
Height="38"
Padding="12,0"
VerticalContentAlignment="Center" />
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal"
Spacing="8"
HorizontalAlignment="Right">
<Button Classes="base"
Padding="16,8"
FontSize="13"
Content="Cancel"
Command="{Binding CancelChangePasswordCommand}" />
<Button Classes="accented"
Padding="16,8"
IsEnabled="{Binding !IsSaving}"
Command="{Binding ConfirmChangePasswordCommand}">
<TextBlock Text="Update Password"
FontSize="13"
FontWeight="SemiBold"
Foreground="{DynamicResource BgBase}" />
</Button>
</StackPanel>
</StackPanel>
</Panel>
</Border>
</StackPanel>
</Border>
<!-- ══════════════════════════════════════════════
SECTION: Danger zone
══════════════════════════════════════════════ -->
<TextBlock Text="SESSION"
Classes="label"
Margin="0,0,0,10" />
<Border Background="{DynamicResource BgSurface}"
BorderBrush="{DynamicResource BorderSubtle}"
BorderThickness="1"
CornerRadius="16"
Padding="20">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"
VerticalAlignment="Center"
Spacing="2">
<TextBlock Text="Sign Out"
FontSize="14"
FontWeight="SemiBold"
Foreground="{DynamicResource TextPrimary}" />
<TextBlock Text="You will be returned to the login screen."
FontSize="12"
Foreground="{DynamicResource TextMuted}" />
</StackPanel>
<Button Grid.Column="1"
Background="#2A0D0D"
BorderBrush="#3A1515"
BorderThickness="1"
CornerRadius="{DynamicResource RadiusControl}"
Padding="16,9"
Command="{Binding SignOutCommand}">
<StackPanel Orientation="Horizontal" Spacing="8">
<Svg Path="../Assets/Icons/log-out.svg"
Width="13" Height="13"
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
<TextBlock Text="Sign Out"
FontSize="13"
FontWeight="SemiBold"
Foreground="#FF5E5E"
VerticalAlignment="Center" />
</StackPanel>
</Button>
</Grid>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>