All checks were successful
Build Linux / build (push) Successful in 1m8s
- Primary account determines app-wide reference currency; all totals, charts, and summaries convert to it automatically using live rates - Transactions show both converted and original amounts for cross-currency accounts; IsMultiCurrency recalculates on primary currency change - Exchange rates fetched live on account save and broadcast via RatesRefreshed so all views update without a restart - Account create/edit/delete with currency, icon, color, and primary toggle - Budget create/edit/delete; savings goal dialog - Settings view: display name, avatar upload, theme, language - Removed currency selector from Settings (follows primary account) - Fixed account list sort: primary first, then oldest CreatedAt, per group - Fixed total balance overlap in dashboard accounts card
375 lines
21 KiB
XML
375 lines
21 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"
|
|
xmlns:cc="clr-namespace:Clario.CustomControls"
|
|
xmlns:behaviors="clr-namespace:Clario.Behaviors"
|
|
mc:Ignorable="d"
|
|
x:Class="Clario.Views.AccountFormView"
|
|
x:DataType="vm:AccountFormViewModel"
|
|
x:Name="AccountFormRoot">
|
|
<Design.DataContext>
|
|
<vm:AccountFormViewModel />
|
|
</Design.DataContext>
|
|
|
|
<!-- ── Dim overlay ───────────────────────── -->
|
|
<Grid>
|
|
<Border Background="#70000000" />
|
|
|
|
<!-- ── Modal card ────────────────────────── -->
|
|
<Border HorizontalAlignment="Center"
|
|
VerticalAlignment="Center"
|
|
Background="{DynamicResource BgSurface}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="18"
|
|
Padding="28"
|
|
Width="460"
|
|
BoxShadow="0 24 72 0 #60000000">
|
|
<StackPanel Spacing="0">
|
|
|
|
<!-- ── Header ──────────────────────── -->
|
|
<Grid ColumnDefinitions="Auto,*,Auto" Margin="0,0,0,24">
|
|
<Border Grid.Column="0"
|
|
CornerRadius="10"
|
|
Width="42" Height="42"
|
|
Margin="0,0,14,0">
|
|
<Border.Background>
|
|
<SolidColorBrush
|
|
Color="{Binding SelectedColor, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
|
Opacity="0.15" />
|
|
</Border.Background>
|
|
<Svg Path="{Binding SelectedIcon, Converter={StaticResource SvgPathFromName}}"
|
|
Width="18" Height="18"
|
|
Css="{Binding SelectedColor, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
|
</Border>
|
|
<StackPanel Grid.Column="1" VerticalAlignment="Center" Spacing="2">
|
|
<TextBlock Text="{Binding FormTitle}"
|
|
FontSize="16"
|
|
FontWeight="Bold"
|
|
Foreground="{DynamicResource TextPrimary}" />
|
|
<TextBlock Text="{Binding FormSubtitle}"
|
|
FontSize="11"
|
|
Foreground="{DynamicResource TextMuted}" />
|
|
</StackPanel>
|
|
<Button Grid.Column="2"
|
|
Background="Transparent"
|
|
BorderThickness="0"
|
|
Padding="6"
|
|
VerticalAlignment="Top"
|
|
Cursor="Hand"
|
|
Command="{Binding CancelCommand}">
|
|
<Svg Path="../Assets/Icons/x.svg"
|
|
Width="15" Height="15"
|
|
Css="{DynamicResource SvgMuted}" />
|
|
</Button>
|
|
</Grid>
|
|
|
|
<!-- ── Name ──────────────────────── -->
|
|
<TextBlock Text="NAME" Classes="label" Margin="0,0,0,6" />
|
|
<TextBox Text="{Binding Name, Mode=TwoWay}"
|
|
Watermark="e.g. Main Checking"
|
|
FontSize="13"
|
|
Height="38"
|
|
Padding="12,0"
|
|
VerticalContentAlignment="Center"
|
|
Margin="0,0,0,16" />
|
|
|
|
<!-- ── Type ─────────────────────────── -->
|
|
<TextBlock Text="TYPE" Classes="label" Margin="0,0,0,6" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Margin="0,0,0,16">
|
|
<ComboBox ItemsSource="{Binding AccountTypes}"
|
|
SelectedItem="{Binding SelectedType, Mode=TwoWay}"
|
|
Background="Transparent"
|
|
BorderThickness="0"
|
|
Padding="12,10"
|
|
FontSize="13"
|
|
HorizontalAlignment="Stretch" />
|
|
</Border>
|
|
|
|
<!-- ── Institution + Mask ──────────── -->
|
|
<Grid ColumnDefinitions="*,14,*" Margin="0,0,0,16">
|
|
<!-- Institution -->
|
|
<StackPanel Grid.Column="0" Spacing="6">
|
|
<TextBlock Text="INSTITUTION (OPTIONAL)" Classes="label" />
|
|
<TextBox Text="{Binding Institution, Mode=TwoWay}"
|
|
Watermark="e.g. Chase"
|
|
FontSize="13"
|
|
Height="38"
|
|
Padding="12,0"
|
|
VerticalContentAlignment="Center" />
|
|
</StackPanel>
|
|
|
|
<!-- Mask -->
|
|
<StackPanel Grid.Column="2" Spacing="6">
|
|
<TextBlock Text="LAST 4 DIGITS (OPTIONAL)" Classes="label" />
|
|
<TextBox Text="{Binding Mask, Mode=TwoWay}"
|
|
Watermark="e.g. 1234"
|
|
FontSize="13"
|
|
Height="38"
|
|
Padding="12,0"
|
|
MaxLength="4"
|
|
VerticalContentAlignment="Center">
|
|
<Interaction.Behaviors>
|
|
<behaviors:NumericInputBehavior />
|
|
</Interaction.Behaviors>
|
|
</TextBox>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<!-- ── Opening Balance + Currency ──────────── -->
|
|
<Grid ColumnDefinitions="*,14,*" Margin="0,0,0,16">
|
|
<!-- Opening Balance -->
|
|
<StackPanel Grid.Column="0" Spacing="6">
|
|
<TextBlock Text="OPENING BALANCE" Classes="label" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Padding="12,0">
|
|
<Grid ColumnDefinitions="Auto,*">
|
|
<TextBlock Grid.Column="0"
|
|
Text="$"
|
|
FontSize="13"
|
|
Foreground="{DynamicResource TextMuted}"
|
|
VerticalAlignment="Center"
|
|
Margin="0,0,6,0" />
|
|
<TextBox Grid.Column="1"
|
|
Classes="ghost"
|
|
Text="{Binding OpeningBalance, Mode=TwoWay}"
|
|
Watermark="0.00"
|
|
FontSize="13"
|
|
Foreground="{DynamicResource TextPrimary}"
|
|
Height="38"
|
|
Padding="0"
|
|
VerticalContentAlignment="Center">
|
|
<Interaction.Behaviors>
|
|
<behaviors:NumericInputBehavior />
|
|
</Interaction.Behaviors>
|
|
</TextBox>
|
|
</Grid>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<!-- Currency -->
|
|
<StackPanel Grid.Column="2" Spacing="6">
|
|
<TextBlock Text="CURRENCY" Classes="label" />
|
|
<TextBox Text="{Binding CurrencySearch, Mode=TwoWay}"
|
|
Watermark="Search..."
|
|
FontSize="12"
|
|
Height="32"
|
|
Padding="10,0"
|
|
VerticalContentAlignment="Center" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Padding="8">
|
|
<ScrollViewer MaxHeight="100"
|
|
HorizontalScrollBarVisibility="Disabled"
|
|
VerticalScrollBarVisibility="Auto">
|
|
<ItemsControl ItemsSource="{Binding FilteredCurrencies}">
|
|
<ItemsControl.ItemsPanel>
|
|
<ItemsPanelTemplate>
|
|
<UniformGrid Columns="4" />
|
|
</ItemsPanelTemplate>
|
|
</ItemsControl.ItemsPanel>
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<Button Classes="nav"
|
|
Content="{Binding}"
|
|
Margin="2"
|
|
Padding="8,4"
|
|
CornerRadius="6"
|
|
FontSize="12"
|
|
Command="{Binding DataContext.SetCurrencyCommand, ElementName=AccountFormRoot}"
|
|
CommandParameter="{Binding}">
|
|
<Classes.accented>
|
|
<MultiBinding Converter="{StaticResource EqualValueConverter}">
|
|
<Binding Path="." />
|
|
<Binding Path="DataContext.Currency" ElementName="AccountFormRoot" />
|
|
</MultiBinding>
|
|
</Classes.accented>
|
|
</Button>
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</ScrollViewer>
|
|
</Border>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<!-- ── Credit Limit (if type is credit) ──────────── -->
|
|
<StackPanel Spacing="6" Margin="0,0,0,16" IsVisible="{Binding IsCredit}">
|
|
<TextBlock Text="CREDIT LIMIT (OPTIONAL)" Classes="label" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Padding="12,0">
|
|
<Grid ColumnDefinitions="Auto,*">
|
|
<TextBlock Grid.Column="0"
|
|
Text="$"
|
|
FontSize="13"
|
|
Foreground="{DynamicResource TextMuted}"
|
|
VerticalAlignment="Center"
|
|
Margin="0,0,6,0" />
|
|
<TextBox Grid.Column="1"
|
|
Classes="ghost"
|
|
Text="{Binding CreditLimit, Mode=TwoWay}"
|
|
Watermark="0.00"
|
|
FontSize="13"
|
|
Foreground="{DynamicResource TextPrimary}"
|
|
Height="38"
|
|
Padding="0"
|
|
VerticalContentAlignment="Center">
|
|
<Interaction.Behaviors>
|
|
<behaviors:NumericInputBehavior />
|
|
</Interaction.Behaviors>
|
|
</TextBox>
|
|
</Grid>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<!-- ── Opened At ──────────────────────── -->
|
|
<TextBlock Text="OPENED ON (OPTIONAL)" Classes="label" Margin="0,0,0,6" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Margin="0,0,0,16">
|
|
<cc:DateRangePicker Classes="ghost"
|
|
SelectionMode="SingleDate"
|
|
SelectedDates="{Binding OpenedAtDates}"
|
|
HorizontalAlignment="Stretch"
|
|
Padding="12,10" />
|
|
</Border>
|
|
|
|
<!-- ── Icon + Color ──────────── -->
|
|
<Grid ColumnDefinitions="*,14,*" Margin="0,0,0,16">
|
|
<!-- Icon -->
|
|
<StackPanel Grid.Column="0" Spacing="6">
|
|
<TextBlock Text="ICON" Classes="label" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}">
|
|
<Grid ColumnDefinitions="Auto,*">
|
|
<Border Grid.Column="0"
|
|
CornerRadius="7"
|
|
Width="30" Height="30"
|
|
Margin="8,0,0,0"
|
|
VerticalAlignment="Center">
|
|
<Border.Background>
|
|
<SolidColorBrush
|
|
Color="{Binding SelectedColor, Converter={StaticResource HexToColorConverter}, ConverterParameter=color}"
|
|
Opacity="0.15" />
|
|
</Border.Background>
|
|
<Svg Path="{Binding SelectedIcon, Converter={StaticResource SvgPathFromName}}"
|
|
Width="14" Height="14"
|
|
Css="{Binding SelectedColor, Converter={StaticResource HexToColorConverter}, ConverterParameter=css}" />
|
|
</Border>
|
|
<ComboBox Grid.Column="1"
|
|
ItemsSource="{Binding Icons}"
|
|
SelectedItem="{Binding SelectedIcon, Mode=TwoWay}"
|
|
Background="Transparent"
|
|
BorderThickness="0"
|
|
Padding="8,10"
|
|
FontSize="13"
|
|
HorizontalAlignment="Stretch" />
|
|
</Grid>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<!-- Color -->
|
|
<StackPanel Grid.Column="2" Spacing="6">
|
|
<TextBlock Text="COLOR" Classes="label" />
|
|
<Border Background="{DynamicResource BgBase}"
|
|
BorderBrush="{DynamicResource BorderSubtle}"
|
|
BorderThickness="1"
|
|
CornerRadius="{DynamicResource RadiusControl}"
|
|
Height="40"
|
|
MaxWidth="194">
|
|
<ColorPicker
|
|
Color="{Binding SelectedColor,Converter={StaticResource HexToColorConverter},ConverterParameter=color}" Width="194" Height="40"
|
|
CornerRadius="{DynamicResource RadiusControl}" IsAlphaEnabled="False" IsAlphaVisible="False" IsColorPaletteVisible="False"
|
|
IsAccentColorsVisible="False">
|
|
</ColorPicker>
|
|
</Border>
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<!-- ── Primary account toggle ──────────── -->
|
|
<Grid ColumnDefinitions="*,Auto" Margin="0,0,0,16">
|
|
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="2">
|
|
<TextBlock Text="PRIMARY ACCOUNT" Classes="label" />
|
|
<TextBlock Text="Sets this account's currency as the reference currency"
|
|
FontSize="11"
|
|
Foreground="{DynamicResource TextMuted}"
|
|
TextWrapping="Wrap" />
|
|
</StackPanel>
|
|
<ToggleSwitch Grid.Column="1"
|
|
IsChecked="{Binding IsPrimary, Mode=TwoWay}"
|
|
OffContent=""
|
|
OnContent=""
|
|
VerticalAlignment="Center" />
|
|
</Grid>
|
|
|
|
<!-- ── Validation error ─────────────── -->
|
|
<Border Background="{DynamicResource BadgeBgRed}"
|
|
BorderBrush="{DynamicResource AccentRed}"
|
|
BorderThickness="1"
|
|
CornerRadius="10"
|
|
Padding="12,8"
|
|
Margin="0,0,0,16"
|
|
IsVisible="{Binding HasError}">
|
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
|
<Svg Path="../Assets/Icons/circle-alert.svg"
|
|
Width="13" Height="13"
|
|
Css="path, circle, rect, ellipse, line, polyline, polygon, text, use { stroke: #FF5E5E; }" />
|
|
<TextBlock Text="{Binding ErrorMessage}"
|
|
FontSize="12"
|
|
Foreground="{DynamicResource AccentRed}"
|
|
VerticalAlignment="Center" />
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<!-- ── Actions ──────────────────────── -->
|
|
<UniformGrid Rows="1">
|
|
<Button Classes="base"
|
|
Margin="0,0,6,0"
|
|
Padding="0,11"
|
|
HorizontalAlignment="Stretch"
|
|
HorizontalContentAlignment="Center"
|
|
FontSize="13"
|
|
Content="Cancel"
|
|
Command="{Binding CancelCommand}" />
|
|
<Button Classes="accented"
|
|
Margin="6,0,0,0"
|
|
Padding="0,11"
|
|
HorizontalAlignment="Stretch"
|
|
HorizontalContentAlignment="Center"
|
|
IsEnabled="{Binding IsValid}"
|
|
Command="{Binding SaveCommand}">
|
|
<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; }" />
|
|
<TextBlock Text="{Binding SaveButtonLabel}"
|
|
FontSize="13"
|
|
FontWeight="SemiBold"
|
|
Foreground="{DynamicResource BgBase}"
|
|
VerticalAlignment="Center" />
|
|
</StackPanel>
|
|
</Button>
|
|
</UniformGrid>
|
|
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
</UserControl> |