Files
PalladiumWallet/src/App/Views/MainView.axaml
T

1116 lines
76 KiB
XML
Raw Normal View History

<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:PalladiumWallet.App.ViewModels"
xmlns:net="using:PalladiumWallet.Core.Net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="620"
x:Class="PalladiumWallet.App.Views.MainView"
x:DataType="vm:MainWindowViewModel">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<UserControl.Styles>
<!-- Su desktop gli overlay card sono centrati con dimensione massima;
su mobile il default (stretch, nessun margine) occupa tutta la schermata. -->
<Style Selector="Border.desktop-overlay">
<Setter Property="MaxWidth" Value="540"/>
<Setter Property="MaxHeight" Value="540"/>
<Setter Property="Margin" Value="16"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="CornerRadius" Value="8"/>
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,*,Auto" Background="{DynamicResource AppBackgroundBrush}">
<!-- ============ MENU (stile Electrum) ============ -->
<Menu Grid.Row="0" IsVisible="{Binding IsDesktop}">
<MenuItem Header="{Binding Loc[menu.file]}">
<MenuItem Header="{Binding Loc[menu.file.new]}" Command="{Binding NewWalletCommand}"/>
<MenuItem Header="{Binding Loc[menu.file.open]}" Click="OnOpenWalletFileClick"
IsVisible="{Binding IsDesktop}"/>
<Separator/>
<MenuItem Header="{Binding Loc[menu.file.close]}" Command="{Binding CloseWalletCommand}"
IsEnabled="{Binding IsWalletOpen}"/>
</MenuItem>
<MenuItem Header="{Binding Loc[menu.settings]}"
Command="{Binding OpenSettingsCommand}"/>
<MenuItem Header="{Binding Loc[menu.help]}"
Command="{Binding OpenHelpCommand}"/>
</Menu>
<!-- Pulsanti Settings/Help mobile-only (il menu è nascosto su mobile) -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="8"
HorizontalAlignment="Right" Margin="8,4"
IsVisible="{Binding IsMobile}">
<Button Content="{Binding Loc[menu.settings]}" Command="{Binding OpenSettingsCommand}"/>
<Button Content="{Binding Loc[menu.help]}" Command="{Binding OpenHelpCommand}"/>
</StackPanel>
<!-- ============ WIZARD DI SETUP (§15): un passo alla volta ============ -->
<ScrollViewer Grid.Row="1" IsVisible="{Binding IsSetupVisible}">
<StackPanel MaxWidth="560" Margin="24,40" Spacing="18"
HorizontalAlignment="Center">
<TextBlock Text="Palladium Wallet" FontSize="28" FontWeight="Bold"
HorizontalAlignment="Center"/>
<!-- Passo 0 (primo avvio): dove salvare i dati -->
<StackPanel IsVisible="{Binding IsStepDataLocation}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.data.title]}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Loc[wiz.data.info]}" TextWrapping="Wrap" Foreground="{DynamicResource TextSecondaryBrush}"/>
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[wiz.data.default]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<SelectableTextBlock Text="{Binding DefaultDataPath}"
FontFamily="monospace" FontSize="13" TextWrapping="Wrap"/>
</StackPanel>
<Button Content="{Binding Loc[wiz.data.usedefault]}" FontSize="16" Classes="accent"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Command="{Binding UseDefaultDataLocationCommand}"/>
<Button Content="{Binding Loc[wiz.data.choose]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Click="OnChooseDataFolderClick"/>
</StackPanel>
<!-- Passo 1: scelta iniziale -->
<StackPanel IsVisible="{Binding IsStepStart}" Spacing="12">
<Button Content="{Binding Loc[wiz.open.btn]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
IsVisible="{Binding WalletFileExists}"
Command="{Binding WizardStartOpenCommand}"/>
<Button Content="{Binding Loc[wiz.new.btn]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Command="{Binding WizardStartNewCommand}"/>
<Button Content="{Binding Loc[wiz.restore.btn]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Command="{Binding WizardStartRestoreCommand}"/>
<Button Content="{Binding Loc[wiz.importxkey.btn]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Command="{Binding WizardStartImportXkeyCommand}"/>
<Button Content="{Binding Loc[wiz.importwif.btn]}" FontSize="16"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
Command="{Binding WizardStartImportWifCommand}"/>
</StackPanel>
<!-- Passo: scelta del wallet (più file presenti) -->
<StackPanel IsVisible="{Binding IsStepChooseWallet}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.choose.title]}" FontSize="18" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding WalletList}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:WalletFileEntry">
<Button Content="{Binding Name}" FontFamily="monospace"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Left"
Margin="0,0,0,6"
Command="{Binding $parent[ItemsControl].((vm:MainWindowViewModel)DataContext).ChooseWalletCommand}"
CommandParameter="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
</StackPanel>
<!-- Passo: password del wallet esistente -->
<StackPanel IsVisible="{Binding IsStepOpen}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.open.title]}" FontSize="18" FontWeight="Bold"/>
<TextBox PlaceholderText="{Binding Loc[wiz.open.placeholder]}"
PasswordChar="●" Text="{Binding PasswordInput}"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.open.ok]}" Classes="accent"
Command="{Binding OpenExistingCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: mostra il nuovo seed -->
<StackPanel IsVisible="{Binding IsStepShowSeed}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.seed.title]}" FontSize="18" FontWeight="Bold"/>
<Border BorderBrush="{DynamicResource SystemAccentColor}" BorderThickness="1"
CornerRadius="6" Padding="14">
<SelectableTextBlock Text="{Binding MnemonicInput}"
FontFamily="monospace" FontSize="16" TextWrapping="Wrap"/>
</Border>
<TextBlock Foreground="{DynamicResource WarningBrush}" TextWrapping="Wrap"
Text="{Binding Loc[wiz.seed.warning]}"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.seed.next]}" Classes="accent"
Command="{Binding WizardNextFromShowSeedCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: conferma del seed -->
<StackPanel IsVisible="{Binding IsStepConfirmSeed}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.confirm.title]}" FontSize="18" FontWeight="Bold"/>
<TextBox PlaceholderText="{Binding Loc[wiz.confirm.placeholder]}"
AcceptsReturn="False" Text="{Binding ConfirmMnemonicInput}"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromConfirmSeedCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: inserimento seed (ripristino) -->
<StackPanel IsVisible="{Binding IsStepWords}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.words.title]}" FontSize="18" FontWeight="Bold"/>
<TextBox PlaceholderText="{Binding Loc[wiz.words.placeholder]}"
AcceptsReturn="False" Text="{Binding MnemonicInput}"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromWordsCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: passphrase opzionale -->
<StackPanel IsVisible="{Binding IsStepPassphrase}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.passphrase.title]}" FontSize="18" FontWeight="Bold"/>
<TextBox PlaceholderText="{Binding Loc[wiz.passphrase.placeholder]}"
Text="{Binding PassphraseInput}"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromPassphraseCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: import xpub/xprv estesa (SLIP-132) -->
<StackPanel IsVisible="{Binding IsStepImportXkey}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.importxkey.title]}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Loc[wiz.importxkey.hint]}" TextWrapping="Wrap" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBox PlaceholderText="{Binding Loc[wiz.importxkey.placeholder]}"
Text="{Binding ImportXkeyInput}" AcceptsReturn="False"/>
<TextBlock Text="{Binding ImportXkeyDetectedKind}"
IsVisible="{Binding ImportXkeyDetectedKind, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
Foreground="{DynamicResource SuccessBrush}" FontSize="12"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromImportXkeyCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: import chiave WIF singola -->
<StackPanel IsVisible="{Binding IsStepImportWif}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.importwif.title]}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Loc[wiz.importwif.hint]}" TextWrapping="Wrap" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBox PlaceholderText="{Binding Loc[wiz.importwif.placeholder]}"
Text="{Binding ImportWifInput}" AcceptsReturn="True" Height="80"/>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromImportWifCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo: scelta del tipo di script/indirizzi -->
<StackPanel IsVisible="{Binding IsStepScriptType}" Spacing="12">
<TextBlock Text="{Binding Loc[wiz.scripttype.title]}" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding Loc[wiz.scripttype.hint]}" TextWrapping="Wrap" Foreground="{DynamicResource TextSecondaryBrush}"/>
<RadioButton GroupName="ScriptType"
IsChecked="{Binding IsLegacySelected, Mode=OneWay}"
Command="{Binding SelectLegacyCommand}">
<StackPanel Spacing="2">
<TextBlock Text="Legacy (P2PKH)" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Loc[wiz.scripttype.legacy.desc]}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"/>
</StackPanel>
</RadioButton>
<RadioButton GroupName="ScriptType"
IsChecked="{Binding IsWrappedSegwitSelected, Mode=OneWay}"
Command="{Binding SelectWrappedSegwitCommand}">
<StackPanel Spacing="2">
<TextBlock Text="Wrapped SegWit (P2SH-P2WPKH)" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Loc[wiz.scripttype.wrapped.desc]}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"/>
</StackPanel>
</RadioButton>
<RadioButton GroupName="ScriptType"
IsChecked="{Binding IsNativeSegwitSelected, Mode=OneWay}"
Command="{Binding SelectNativeSegwitCommand}">
<StackPanel Spacing="2">
<TextBlock Text="Native SegWit (P2WPKH)" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Loc[wiz.scripttype.native.desc]}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"/>
</StackPanel>
</RadioButton>
<RadioButton GroupName="ScriptType"
IsChecked="{Binding IsTaprootSelected, Mode=OneWay}"
Command="{Binding SelectTaprootCommand}">
<StackPanel Spacing="2">
<TextBlock Text="Taproot (P2TR)" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Loc[wiz.scripttype.taproot.desc]}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"/>
</StackPanel>
</RadioButton>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.next]}" Classes="accent"
Command="{Binding WizardNextFromScriptTypeCommand}"/>
</StackPanel>
</StackPanel>
<!-- Passo finale: nome + password del file (cifratura, stile Electrum) -->
<StackPanel IsVisible="{Binding IsStepPassword}" Spacing="16">
<TextBlock Text="{Binding Loc[wiz.password.title]}" FontSize="18" FontWeight="Bold"/>
<!-- Sezione nome: bordo distinto dal gruppo password -->
<Border BorderBrush="{DynamicResource SystemAccentColor}"
BorderThickness="0,0,0,0"
Background="{DynamicResource SurfaceAltBrush}"
CornerRadius="6" Padding="12,10">
<StackPanel Spacing="6">
<TextBlock Text="{Binding Loc[wiz.name.label]}"
FontWeight="SemiBold" FontSize="13"/>
<TextBox PlaceholderText="{Binding Loc[wiz.name.placeholder]}"
Text="{Binding WalletNameInput}"/>
</StackPanel>
</Border>
<!-- Separatore visivo -->
<Separator Margin="0,0"/>
<!-- Sezione cifratura -->
<StackPanel Spacing="8">
<TextBox PlaceholderText="{Binding Loc[wiz.password.placeholder]}"
PasswordChar="●" Text="{Binding PasswordInput}"/>
<TextBox PlaceholderText="{Binding Loc[wiz.password.confirm]}"
PasswordChar="●" Text="{Binding ConfirmPasswordInput}"/>
<CheckBox Content="{Binding Loc[wiz.password.encrypt]}"
IsChecked="{Binding EncryptWallet}"/>
<TextBlock Text="{Binding Loc[wiz.password.encrypt.hint]}"
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" TextWrapping="Wrap"
IsVisible="{Binding !EncryptWallet}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[wiz.back]}" Command="{Binding WizardBackCommand}"/>
<Button Content="{Binding Loc[wiz.password.create]}" Classes="accent"
Command="{Binding CreateOrRestoreCommand}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
<!-- ============ PANNELLO WALLET ============ -->
<Grid Grid.Row="1" RowDefinitions="Auto,*" IsVisible="{Binding IsWalletOpen}" Margin="16">
<!-- Testata: card del saldo. Connetti/sincronizza è automatico; chiudi
wallet è in File. Lo stato connessione è nella barra in basso. -->
<Border Grid.Row="0" Classes="balance-hero" Margin="0,0,0,16">
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.balance]}" Classes="label on-hero"/>
<TextBlock Text="{Binding BalanceText}" Classes="amount"/>
<TextBlock Text="{Binding UnconfirmedText}" Foreground="#FCD34D"
TextWrapping="Wrap"
IsVisible="{Binding UnconfirmedText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<TextBlock Text="{Binding NetworkInfo}" Classes="on-hero" FontSize="12"
Margin="0,2,0,0"/>
</StackPanel>
</Border>
<!-- Tab: Storico / Invia / Ricevi / Indirizzi / Contatti -->
<TabControl Grid.Row="1"
SelectedIndex="{Binding SelectedTabIndex}"
TabStripPlacement="Top">
<TabControl.Styles>
<Style Selector="TabStrip">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{DynamicResource SurfaceBrush}"/>
<Setter Property="ItemsPanel">
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</Setter>
</Style>
<Style Selector="TabItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="4,8"/>
</Style>
</TabControl.Styles>
<!-- 1. Storico -->
<TabItem>
<TabItem.Header>
<StackPanel Spacing="2" HorizontalAlignment="Center">
<Viewbox Width="22" Height="22" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{Binding $parent[TabItem].Foreground}"
Data="M7,5H21V7H7V5M7,13V11H21V13H7M4,4.5A1.5,1.5 0 0,1 5.5,6A1.5,1.5 0 0,1 4,7.5A1.5,1.5 0 0,1 2.5,6A1.5,1.5 0 0,1 4,4.5M4,10.5A1.5,1.5 0 0,1 5.5,12A1.5,1.5 0 0,1 4,13.5A1.5,1.5 0 0,1 2.5,12A1.5,1.5 0 0,1 4,10.5M7,19V17H21V19H7M4,16.5A1.5,1.5 0 0,1 5.5,18A1.5,1.5 0 0,1 4,19.5A1.5,1.5 0 0,1 2.5,18A1.5,1.5 0 0,1 4,16.5Z"/>
</Canvas>
</Viewbox>
<TextBlock Text="{Binding Loc[tab.history]}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<Grid RowDefinitions="Auto,*" Margin="4">
<TextBlock Grid.Row="0" Text="{Binding Loc[history.hint]}"
IsVisible="{Binding IsDesktop}"
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="11" Margin="6,2"/>
<ListBox Grid.Row="1" ItemsSource="{Binding History}"
DoubleTapped="OnHistoryRowDoubleTapped">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:HistoryRow">
<Panel Cursor="Hand">
<!-- Desktop: 4 colonne fisse -->
<Grid ColumnDefinitions="90,160,*,70"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Conferma}" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Column="1" Text="{Binding Importo}" FontFamily="monospace"/>
<TextBlock Grid.Column="2" Text="{Binding Txid}"
FontFamily="monospace" FontSize="12"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="3" Text="{Binding Verificata}" Foreground="{DynamicResource SuccessBrush}"/>
</Grid>
<!-- Mobile: card verticale -->
<StackPanel Spacing="2"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsMobile}">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="{Binding Importo}"
FontFamily="monospace" FontWeight="SemiBold"/>
<TextBlock Grid.Column="1" Text="{Binding Verificata}"
Foreground="{DynamicResource SuccessBrush}" FontSize="11"/>
</Grid>
<TextBlock Text="{Binding Conferma}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="11"/>
<TextBlock Text="{Binding Txid}" FontFamily="monospace" FontSize="11"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Panel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</TabItem>
<!-- 2. Invia -->
<TabItem>
<TabItem.Header>
<StackPanel Spacing="2" HorizontalAlignment="Center">
<Viewbox Width="22" Height="22" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{Binding $parent[TabItem].Foreground}"
Data="M2,21L23,12L2,3V10L17,12L2,14V21Z"/>
</Canvas>
</Viewbox>
<TextBlock Text="{Binding Loc[tab.send]}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<StackPanel Spacing="10" Margin="8" MaxWidth="640" HorizontalAlignment="Left">
<!-- Contatto rapido -->
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="{Binding Loc[send.from.contact]}" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding Contacts}"
SelectedItem="{Binding SendToContact}"
PlaceholderText="{Binding Loc[send.contact.hint]}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="vm:ContactEntry">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0"
PlaceholderText="{Binding Loc[send.to]}" Text="{Binding SendTo}"
FontFamily="monospace"/>
<Button Grid.Column="1" Margin="6,0,0,0" Padding="8,6"
IsVisible="{Binding IsMobile}"
Command="{Binding ScanQrCommand}"
ToolTip.Tip="{Binding Loc[send.scan]}">
<Viewbox Width="22" Height="22">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource SystemBaseHighColor}"
Data="M20,5H16.83L15,3H9L7.17,5H4A2,2 0 0,0 2,7V19A2,2 0 0,0 4,21H20A2,2 0 0,0 22,19V7A2,2 0 0,0 20,5M20,19H4V7H8.05L9.88,5H14.12L15.95,7H20V19M12,8A5,5 0 0,0 7,13A5,5 0 0,0 12,18A5,5 0 0,0 17,13A5,5 0 0,0 12,8M12,16A3,3 0 0,1 9,13A3,3 0 0,1 12,10A3,3 0 0,1 15,13A3,3 0 0,1 12,16Z"/>
</Canvas>
</Viewbox>
</Button>
</Grid>
<!-- Desktop: riga amount + fee in 4 colonne -->
<Grid ColumnDefinitions="*,Auto,Auto,Auto" IsVisible="{Binding IsDesktop}">
<TextBox Grid.Column="0" PlaceholderText="{Binding Loc[send.amount]}"
Text="{Binding SendAmount}" IsEnabled="{Binding !SendAll}"/>
<TextBlock Grid.Column="1" Text="{Binding UnitLabel}"
VerticalAlignment="Center" Margin="6,0" Foreground="{DynamicResource TextSecondaryBrush}"/>
<CheckBox Grid.Column="2" Content="{Binding Loc[send.all]}" Margin="10,0"
IsChecked="{Binding SendAll}"/>
<StackPanel Grid.Column="3" Orientation="Horizontal" Spacing="6">
<TextBlock Text="{Binding Loc[send.feerate]}" VerticalAlignment="Center"/>
<TextBox Text="{Binding SendFeeRate}" MinWidth="60"/>
</StackPanel>
</Grid>
<!-- Mobile: amount e fee su righe separate -->
<StackPanel Spacing="6" IsVisible="{Binding IsMobile}">
<Grid ColumnDefinitions="*,Auto,Auto">
<TextBox Grid.Column="0" PlaceholderText="{Binding Loc[send.amount]}"
Text="{Binding SendAmount}" IsEnabled="{Binding !SendAll}"/>
<TextBlock Grid.Column="1" Text="{Binding UnitLabel}"
VerticalAlignment="Center" Margin="6,0" Foreground="{DynamicResource TextSecondaryBrush}"/>
<CheckBox Grid.Column="2" Content="{Binding Loc[send.all]}" Margin="6,0"
IsChecked="{Binding SendAll}"/>
</Grid>
<StackPanel Orientation="Horizontal" Spacing="6">
<TextBlock Text="{Binding Loc[send.feerate]}" VerticalAlignment="Center"/>
<TextBox Text="{Binding SendFeeRate}" MinWidth="60"/>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding Loc[send.prepare]}" Command="{Binding PrepareSendCommand}"/>
<Button Content="{Binding Loc[send.confirm]}" Classes="accent"
Command="{Binding ConfirmSendCommand}"
IsEnabled="{Binding HasPendingSend}"/>
</StackPanel>
<SelectableTextBlock Text="{Binding SendPreview}" TextWrapping="Wrap"
FontSize="13"/>
</StackPanel>
</TabItem>
<!-- 3. Ricevi -->
<TabItem>
<TabItem.Header>
<StackPanel Spacing="2" HorizontalAlignment="Center">
<Viewbox Width="22" Height="22" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{Binding $parent[TabItem].Foreground}"
Data="M2,12H4V17H20V12H22V17A2,2 0 0,1 20,19H4A2,2 0 0,1 2,17V12M12,15L17,10L15.59,8.58L13,11.17V2H11V11.17L8.41,8.59L7,10L12,15Z"/>
</Canvas>
</Viewbox>
<TextBlock Text="{Binding Loc[tab.receive]}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<StackPanel Spacing="10" Margin="8">
<TextBlock Text="{Binding Loc[receive.next]}"/>
<!-- Desktop: indirizzo + copia su una riga -->
<StackPanel Orientation="Horizontal" Spacing="8" IsVisible="{Binding IsDesktop}">
<SelectableTextBlock Text="{Binding ReceiveAddress}"
FontFamily="monospace" FontSize="16"
VerticalAlignment="Center"/>
<Button Content="{Binding Loc[receive.copy]}"
Click="OnCopyReceiveAddressClick"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Mobile: indirizzo su riga intera + copia sotto -->
<StackPanel Spacing="6" IsVisible="{Binding IsMobile}">
<SelectableTextBlock Text="{Binding ReceiveAddress}"
FontFamily="monospace" FontSize="13"
TextWrapping="Wrap"/>
<Button Content="{Binding Loc[receive.copy]}"
Click="OnCopyReceiveAddressClick"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"/>
</StackPanel>
<Border Background="White" Padding="12" CornerRadius="6"
HorizontalAlignment="Center"
IsVisible="{Binding ReceiveQr, Converter={x:Static ObjectConverters.IsNotNull}}">
<Image Source="{Binding ReceiveQr}" Width="220" Height="220"
RenderOptions.BitmapInterpolationMode="None"/>
</Border>
<TextBlock Text="{Binding Loc[receive.hint]}"
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
</TabItem>
<!-- 4. Indirizzi -->
<TabItem>
<TabItem.Header>
<StackPanel Spacing="2" HorizontalAlignment="Center">
<Viewbox Width="22" Height="22" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{Binding $parent[TabItem].Foreground}"
Data="M21,18V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5A2,2 0 0,1 5,3H19A2,2 0 0,1 21,5V6H12C10.89,6 10,6.9 10,8V16A2,2 0 0,0 12,18H21M12,16H22V8H12V16M16,13.5A1.5,1.5 0 0,1 14.5,12A1.5,1.5 0 0,1 16,10.5A1.5,1.5 0 0,1 17.5,12A1.5,1.5 0 0,1 16,13.5Z"/>
</Canvas>
</Viewbox>
<TextBlock Text="{Binding Loc[tab.addresses]}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<Grid RowDefinitions="Auto,*" Margin="4">
<!-- Intestazione colonne — solo desktop -->
<Grid Grid.Row="0" ColumnDefinitions="90,60,*,140,60" Margin="12,4"
IsVisible="{Binding IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Loc[addr.type]}" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Text="{Binding Loc[addr.index]}" FontWeight="Bold"/>
<TextBlock Grid.Column="2" Text="{Binding Loc[addr.address]}" FontWeight="Bold"/>
<TextBlock Grid.Column="3" Text="{Binding Loc[addr.balance]}" FontWeight="Bold"/>
<TextBlock Grid.Column="4" Text="Tx" FontWeight="Bold"/>
</Grid>
<ListBox Grid.Row="1" ItemsSource="{Binding Addresses}"
SelectedItem="{Binding SelectedAddressRow}"
x:Name="AddressesListBox"
Tapped="OnAddressListTapped"
PointerPressed="OnAddressListPointerPressed">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:AddressRow">
<Panel>
<!-- Desktop: 5 colonne fisse -->
<Grid ColumnDefinitions="90,60,*,140,60"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Tipo}" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Column="1" Text="{Binding Indice}" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Column="2" Text="{Binding Indirizzo}"
FontFamily="monospace" FontSize="13"/>
<TextBlock Grid.Column="3" Text="{Binding Saldo}" FontFamily="monospace"/>
<TextBlock Grid.Column="4" Text="{Binding NumTx}" Foreground="{DynamicResource TextSecondaryBrush}"/>
</Grid>
<!-- Mobile: card verticale -->
<StackPanel Spacing="1" Margin="0,3"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsMobile}">
<TextBlock Text="{Binding Indirizzo}"
FontFamily="monospace" FontSize="12"
TextTrimming="CharacterEllipsis"/>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="{Binding Tipo}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="11"/>
<TextBlock Text="{Binding Indice}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="11"/>
<TextBlock Text="{Binding Saldo}" FontFamily="monospace" FontSize="11"/>
<TextBlock Text="{Binding NumTx}" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="11"/>
</StackPanel>
</StackPanel>
</Panel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</TabItem>
<!-- 5. Contatti -->
<TabItem>
<TabItem.Header>
<StackPanel Spacing="2" HorizontalAlignment="Center">
<Viewbox Width="22" Height="22" HorizontalAlignment="Center">
<Canvas Width="24" Height="24">
<Path Fill="{Binding $parent[TabItem].Foreground}"
Data="M16,13C15.71,13 15.38,13 15.03,13.05C16.19,13.89 17,15 17,16.5V19H23V16.5C23,14.17 18.33,13 16,13M8,13C5.67,13 1,14.17 1,16.5V19H15V16.5C15,14.17 10.33,13 8,13M8,11A3,3 0 0,0 11,8A3,3 0 0,0 8,5A3,3 0 0,0 5,8A3,3 0 0,0 8,11M16,11A3,3 0 0,0 19,8A3,3 0 0,0 16,5C15.71,5 15.42,5.03 15.14,5.09C15.68,5.95 16,6.94 16,8C16,9.06 15.68,10.05 15.14,10.91C15.42,10.97 15.71,11 16,11Z"/>
</Canvas>
</Viewbox>
<TextBlock Text="{Binding Loc[tab.contacts]}" FontSize="12"
HorizontalAlignment="Center"/>
</StackPanel>
</TabItem.Header>
<Grid RowDefinitions="Auto,*,Auto,Auto" Margin="4">
<!-- Intestazioni colonne — solo desktop -->
<Grid Grid.Row="0" ColumnDefinitions="180,*" Margin="12,4"
IsVisible="{Binding IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Loc[contacts.name]}" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Text="{Binding Loc[contacts.address]}" FontWeight="Bold"/>
</Grid>
<!-- Lista contatti -->
<ListBox Grid.Row="1" ItemsSource="{Binding Contacts}"
SelectedItem="{Binding SelectedContactInList}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:ContactEntry">
<Panel>
<!-- Desktop: 2 colonne -->
<Grid ColumnDefinitions="180,*"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Name}"
VerticalAlignment="Center"/>
<SelectableTextBlock Grid.Column="1" Text="{Binding Address}"
FontFamily="monospace" FontSize="12"
VerticalAlignment="Center"/>
</Grid>
<!-- Mobile: card verticale -->
<StackPanel Spacing="1" Margin="0,3"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsMobile}">
2026-06-15 10:58:39 +02:00
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" FontSize="13"
TextTrimming="CharacterEllipsis"/>
<SelectableTextBlock Text="{Binding Address}"
FontFamily="monospace" FontSize="11"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Panel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- Pulsante rimuovi selezionato -->
<Button Grid.Row="2" Content="{Binding Loc[contacts.remove]}"
Command="{Binding RemoveSelectedContactCommand}"
IsEnabled="{Binding SelectedContactInList, Converter={x:Static ObjectConverters.IsNotNull}}"
Margin="0,6,0,0"/>
<!-- Form aggiungi contatto — Desktop: 3 colonne -->
<Grid Grid.Row="3" ColumnDefinitions="180,*,Auto" Margin="0,8,0,0"
IsVisible="{Binding IsDesktop}">
<TextBox Grid.Column="0" PlaceholderText="{Binding Loc[contacts.name.ph]}"
Text="{Binding NewContactName}" Margin="0,0,6,0"/>
<TextBox Grid.Column="1" PlaceholderText="{Binding Loc[contacts.address.ph]}"
Text="{Binding NewContactAddress}" FontFamily="monospace"
Margin="0,0,6,0"/>
<Button Grid.Column="2" Content="{Binding Loc[contacts.add]}"
Command="{Binding AddContactCommand}"/>
</Grid>
<!-- Form aggiungi contatto — Mobile: verticale -->
<StackPanel Grid.Row="3" Spacing="6" Margin="0,8,0,0"
IsVisible="{Binding IsMobile}">
<TextBox PlaceholderText="{Binding Loc[contacts.name.ph]}"
Text="{Binding NewContactName}"/>
<TextBox PlaceholderText="{Binding Loc[contacts.address.ph]}"
Text="{Binding NewContactAddress}" FontFamily="monospace"/>
<Button Content="{Binding Loc[contacts.add]}"
Command="{Binding AddContactCommand}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"/>
</StackPanel>
</Grid>
</TabItem>
</TabControl>
</Grid>
<!-- Barra di stato: messaggio a sinistra, stato connessione a destra.
Lo stato connessione è cliccabile e apre le impostazioni del server. -->
<Border Grid.Row="2" Background="{DynamicResource SurfaceBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="0,1,0,0"
Padding="12,7">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="{Binding StatusMessage}" FontSize="12"
TextWrapping="Wrap" VerticalAlignment="Center"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6"
Margin="12,0,0,0" VerticalAlignment="Center"
Cursor="Hand" Background="Transparent"
ToolTip.Tip="{Binding Loc[server.title]}"
Tapped="OnConnectionStatusTapped">
<Ellipse Width="10" Height="10" Fill="{DynamicResource SuccessBrush}" VerticalAlignment="Center"
IsVisible="{Binding IsConnected}"/>
<Ellipse Width="10" Height="10" Fill="{DynamicResource DangerBrush}" VerticalAlignment="Center"
IsVisible="{Binding !IsConnected}"/>
<TextBlock Text="{Binding ConnectionStatus}" FontSize="12"
Foreground="{DynamicResource SystemAccentColor}"
VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Border>
<!-- ============ OVERLAY DETTAGLIO INDIRIZZO ============ -->
<!-- Overlay in-app invece di una Window separata: apertura/chiusura
istantanee (niente create/destroy di una top-level window). -->
<Border Grid.Row="0" Grid.RowSpan="3"
Background="{DynamicResource ScrimBrush}"
Tapped="OnAddressOverlayBackdropTapped"
IsVisible="{Binding AddressInfo, Converter={x:Static ObjectConverters.IsNotNull}}">
<Border Background="{DynamicResource OverlayCardBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
MaxWidth="540" Margin="16"
HorizontalAlignment="Center" VerticalAlignment="Center"
DataContext="{Binding AddressInfo}">
<ScrollViewer MaxHeight="640">
<StackPanel Margin="24" Spacing="16">
<TextBlock Text="{Binding Loc[addr.info.title]}"
FontSize="18" FontWeight="Bold"/>
<!-- Indirizzo -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.address]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<SelectableTextBlock Text="{Binding Address}"
FontFamily="monospace" FontSize="13"
TextWrapping="Wrap"/>
</StackPanel>
<!-- Derivation path -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.derivpath]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<SelectableTextBlock Text="{Binding DerivPath}"
FontFamily="monospace" FontSize="13"/>
</StackPanel>
<!-- Chiave pubblica -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.pubkey]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<SelectableTextBlock Text="{Binding PubKey}"
FontFamily="monospace" FontSize="12"
TextWrapping="Wrap"/>
</StackPanel>
<!-- Chiave privata (solo se disponibile) -->
<StackPanel Spacing="4" IsVisible="{Binding HasPrivKey}">
<TextBlock Text="{Binding Loc[addr.privkey]}" FontSize="11" Foreground="{DynamicResource DangerBrush}"/>
<SelectableTextBlock Text="{Binding PrivKey}"
FontFamily="monospace" FontSize="12"
Foreground="{DynamicResource DangerBrush}"
TextWrapping="Wrap"/>
</StackPanel>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Command="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).CloseAddressInfoCommand}"/>
</StackPanel>
</ScrollViewer>
</Border>
</Border>
<!-- ============ OVERLAY DETTAGLIO TRANSAZIONE ============ -->
<!-- Overlay in-app (come indirizzo): appare subito con lo spinner, i dati
arrivano dal server in background; chiusura istantanea. -->
<Border Grid.Row="0" Grid.RowSpan="3"
Background="{DynamicResource ScrimBrush}"
Tapped="OnTxDetailsOverlayBackdropTapped"
IsVisible="{Binding IsTxDetailsOpen}">
<Border Background="{DynamicResource OverlayCardBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
MaxWidth="540" MaxHeight="600" Margin="16" Padding="0"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Panel Margin="24">
<!-- Caricamento -->
<StackPanel IsVisible="{Binding IsTxDetailsLoading}"
HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="14">
<ProgressBar IsIndeterminate="True" Width="220"/>
<TextBlock Text="{Binding Loc[tx.loading]}" Foreground="{DynamicResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
</StackPanel>
<!-- Contenuto (IsVisible sul contenitore esterno, così resta
legato al VM principale; il DataContext interno è TxDetails) -->
<Grid IsVisible="{Binding !IsTxDetailsLoading}">
<DockPanel DataContext="{Binding TxDetails}">
<TextBlock DockPanel.Dock="Top" Text="{Binding Loc[tx.title]}"
FontSize="18" FontWeight="Bold" Margin="0,0,0,12"/>
<Button DockPanel.Dock="Bottom" Content="{Binding Loc[tx.close]}"
HorizontalAlignment="Right" Margin="0,12,0,0"
Command="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).CloseTransactionDetailsCommand}"/>
<ScrollViewer>
<StackPanel Spacing="14">
<Grid ColumnDefinitions="170,*" RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/><RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.status]}"/>
<SelectableTextBlock Grid.Row="0" Grid.Column="1" FontSize="13" TextWrapping="Wrap" Text="{Binding StatusText}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.date]}"/>
<SelectableTextBlock Grid.Row="1" Grid.Column="1" FontSize="13" Text="{Binding DateText}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding CounterpartyHeader}"/>
<SelectableTextBlock Grid.Row="2" Grid.Column="1" FontSize="13" FontFamily="monospace" TextWrapping="Wrap" Text="{Binding CounterpartyText}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding AmountHeader}"/>
<SelectableTextBlock Grid.Row="3" Grid.Column="1" FontSize="13" FontFamily="monospace" Text="{Binding AmountText}"/>
<TextBlock Grid.Row="4" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.fee]}"/>
<SelectableTextBlock Grid.Row="4" Grid.Column="1" FontSize="13" FontFamily="monospace" Text="{Binding FeeText}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.feerate]}"/>
<SelectableTextBlock Grid.Row="5" Grid.Column="1" FontSize="13" FontFamily="monospace" Text="{Binding FeeRateText}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.net]}"/>
<SelectableTextBlock Grid.Row="6" Grid.Column="1" FontSize="13" FontFamily="monospace" FontWeight="Bold" Text="{Binding NetText}"/>
<TextBlock Grid.Row="7" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.id]}"/>
<SelectableTextBlock Grid.Row="7" Grid.Column="1" FontSize="12" FontFamily="monospace" TextWrapping="Wrap" Text="{Binding Txid}"/>
<TextBlock Grid.Row="8" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.size.total]}"/>
<SelectableTextBlock Grid.Row="8" Grid.Column="1" FontSize="13" Text="{Binding TotalSizeText}"/>
<TextBlock Grid.Row="9" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.size.virtual]}"/>
<SelectableTextBlock Grid.Row="9" Grid.Column="1" FontSize="13" Text="{Binding VirtualSizeText}"/>
<TextBlock Grid.Row="10" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.rbf]}"/>
<SelectableTextBlock Grid.Row="10" Grid.Column="1" FontSize="13" Text="{Binding RbfText}"/>
<TextBlock Grid.Row="11" Grid.Column="0" Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12" Text="{Binding Loc[tx.verified]}"/>
<SelectableTextBlock Grid.Row="11" Grid.Column="1" FontSize="13" Foreground="{DynamicResource SuccessBrush}" Text="{Binding VerifiedText}"/>
</Grid>
<TextBlock Text="{Binding Loc[tx.inputs]}" FontWeight="Bold" Margin="0,4,0,0"/>
<ItemsControl ItemsSource="{Binding Inputs}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:TxIoRow">
<Grid ColumnDefinitions="170,*,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding Position}"
FontFamily="monospace" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Column="1" Text="{Binding Address}"
FontFamily="monospace" FontSize="11" TextTrimming="CharacterEllipsis"
Foreground="{Binding IsMine, Converter={x:Static vm:MineColorConverter.Instance}}"/>
<TextBlock Grid.Column="2" Text="{Binding Amount}"
FontFamily="monospace" FontSize="11" Margin="8,0,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="{Binding Loc[tx.outputs]}" FontWeight="Bold" Margin="0,4,0,0"/>
<ItemsControl ItemsSource="{Binding Outputs}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:TxIoRow">
<Grid ColumnDefinitions="60,*,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding Position}"
FontFamily="monospace" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Column="1" Text="{Binding Address}"
FontFamily="monospace" FontSize="11" TextTrimming="CharacterEllipsis"
Foreground="{Binding IsMine, Converter={x:Static vm:MineColorConverter.Instance}}"/>
<TextBlock Grid.Column="2" Text="{Binding Amount}"
FontFamily="monospace" FontSize="11" Margin="8,0,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Grid>
</Panel>
</Border>
</Border>
<!-- ============ OVERLAY IMPOSTAZIONI SERVER ============ -->
<!-- Stesso pattern dell'overlay indirizzo: apertura/chiusura istantanee.
Accessibile da Impostazioni → Server. -->
<Border Grid.Row="0" Grid.RowSpan="3"
Background="{DynamicResource ScrimBrush}"
Tapped="OnServerOverlayBackdropTapped"
IsVisible="{Binding IsServerSettingsOpen}">
<Border Background="{DynamicResource OverlayCardBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1"
Classes.desktop-overlay="{Binding IsDesktop}">
<ScrollViewer>
<StackPanel Margin="24" Spacing="14">
<TextBlock Text="{Binding Loc[server.title]}"
FontSize="18" FontWeight="Bold"/>
<!-- Host + porta — Desktop: 3 colonne -->
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="Auto,Auto"
IsVisible="{Binding IsDesktop}">
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Loc[server.host]}"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Loc[server.port]}"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}" Margin="10,0,0,0" Width="90"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="TLS"
FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}" Margin="10,0,0,0"/>
<TextBox Grid.Row="1" Grid.Column="0" Text="{Binding ServerHost}"
FontFamily="monospace" Margin="0,2,0,0"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ServerPort}"
FontFamily="monospace" Width="90" Margin="10,2,0,0"/>
<CheckBox Grid.Row="1" Grid.Column="2" IsChecked="{Binding UseSsl}"
Margin="10,2,0,0" VerticalAlignment="Center"/>
</Grid>
<!-- Host + porta — Mobile: verticale, font più grandi -->
<StackPanel Spacing="10" IsVisible="{Binding IsMobile}">
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[server.host]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBox Text="{Binding ServerHost}" FontFamily="monospace" FontSize="15"/>
</StackPanel>
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="{Binding Loc[server.port]}" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/>
<TextBox Text="{Binding ServerPort}" FontFamily="monospace" FontSize="15"/>
</StackPanel>
<StackPanel Grid.Column="1" Spacing="4" Margin="20,0,0,0"
VerticalAlignment="Center">
<TextBlock Text="TLS" FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"
HorizontalAlignment="Center"/>
<CheckBox IsChecked="{Binding UseSsl}"
HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</StackPanel>
<!-- Azioni — Desktop: in riga -->
<StackPanel Orientation="Horizontal" Spacing="8" IsVisible="{Binding IsDesktop}">
<Button Content="{Binding Loc[wallet.connect]}" Classes="accent"
Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}"/>
<Button Content="{Binding Loc[wallet.discover]}"
Command="{Binding DiscoverServersCommand}"/>
<Button Content="{Binding Loc[wallet.resetcert]}"
Command="{Binding ResetCertificatesCommand}"/>
</StackPanel>
<!-- Azioni — Mobile: in colonna -->
<StackPanel Spacing="6" IsVisible="{Binding IsMobile}">
<Button Content="{Binding Loc[wallet.connect]}" Classes="accent"
Command="{Binding ConnectAndSyncCommand}" IsEnabled="{Binding !IsSyncing}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
<Button Content="{Binding Loc[wallet.discover]}"
Command="{Binding DiscoverServersCommand}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
<Button Content="{Binding Loc[wallet.resetcert]}"
Command="{Binding ResetCertificatesCommand}"
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
</StackPanel>
<!-- Stato connessione -->
<StackPanel Orientation="Horizontal" Spacing="6">
<Ellipse Width="10" Height="10" Fill="{DynamicResource SuccessBrush}" VerticalAlignment="Center"
IsVisible="{Binding IsConnected}"/>
<Ellipse Width="10" Height="10" Fill="{DynamicResource DangerBrush}" VerticalAlignment="Center"
IsVisible="{Binding !IsConnected}"/>
<TextBlock Text="{Binding ConnectionStatus}" Foreground="{DynamicResource TextSecondaryBrush}"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Server conosciuti: clicca per riempire host/porta -->
<TextBlock Text="{Binding Loc[server.known]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<ListBox ItemsSource="{Binding KnownServers}"
SelectedItem="{Binding SelectedKnownServer}"
MaxHeight="300">
<ListBox.Styles>
<Style Selector="ListBox:empty">
<Setter Property="Template">
<ControlTemplate>
<TextBlock Text="{Binding Loc[server.empty]}"
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"
TextWrapping="Wrap" Margin="8"/>
</ControlTemplate>
</Setter>
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="net:KnownServer">
<Panel>
<!-- Desktop: host + porte in 2 colonne -->
<Grid ColumnDefinitions="*,Auto"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsDesktop}">
<TextBlock Grid.Column="0" Text="{Binding Host}"
FontFamily="monospace" FontSize="13"
VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"
VerticalAlignment="Center">
<Run Text="tcp "/><Run Text="{Binding TcpPort}"/>
<Run Text=" ssl "/><Run Text="{Binding SslPort}"/>
</TextBlock>
</Grid>
<!-- Mobile: host sopra, porte sotto -->
<StackPanel Spacing="2" Margin="0,4"
IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsMobile}">
<TextBlock Text="{Binding Host}"
FontFamily="monospace" FontSize="15"
TextTrimming="CharacterEllipsis"/>
<StackPanel Orientation="Horizontal" Spacing="16">
<TextBlock FontSize="12" Foreground="{DynamicResource TextSecondaryBrush}">
<Run Text="tcp "/><Run Text="{Binding TcpPort}"/>
</TextBlock>
<TextBlock FontSize="12" Foreground="{DynamicResource TextSecondaryBrush}">
<Run Text="ssl "/><Run Text="{Binding SslPort}"/>
</TextBlock>
</StackPanel>
</StackPanel>
</Panel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Command="{Binding CloseServerSettingsCommand}"/>
</StackPanel>
</ScrollViewer>
</Border>
</Border>
<!-- ============ OVERLAY IMPOSTAZIONI ============ -->
<!-- In-app invece dei sottomenu annidati: niente popup OS lenti su WSLg. -->
<Border Grid.Row="0" Grid.RowSpan="3"
Background="{DynamicResource ScrimBrush}"
Tapped="OnSettingsOverlayBackdropTapped"
IsVisible="{Binding IsSettingsOpen}">
<Border Background="{DynamicResource OverlayCardBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
MaxWidth="440" Margin="16"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ScrollViewer MaxHeight="640">
<StackPanel Margin="24" Spacing="16">
<TextBlock Text="{Binding Loc[settings.title]}"
FontSize="18" FontWeight="Bold"/>
<!-- Lingua -->
<StackPanel Spacing="6">
<TextBlock Text="{Binding Loc[settings.language]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<WrapPanel>
<RadioButton GroupName="lang" Content="Italiano" Margin="0,0,14,4"
IsChecked="{Binding IsLangIt, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="it"/>
<RadioButton GroupName="lang" Content="English" Margin="0,0,14,4"
IsChecked="{Binding IsLangEn, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="en"/>
<RadioButton GroupName="lang" Content="Español" Margin="0,0,14,4"
IsChecked="{Binding IsLangEs, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="es"/>
<RadioButton GroupName="lang" Content="Français" Margin="0,0,14,4"
IsChecked="{Binding IsLangFr, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="fr"/>
<RadioButton GroupName="lang" Content="Português" Margin="0,0,14,4"
IsChecked="{Binding IsLangPt, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="pt"/>
<RadioButton GroupName="lang" Content="Deutsch" Margin="0,0,14,4"
IsChecked="{Binding IsLangDe, Mode=OneWay}"
Command="{Binding SetLanguageCommand}" CommandParameter="de"/>
</WrapPanel>
</StackPanel>
<!-- Unità -->
<StackPanel Spacing="6">
<TextBlock Text="{Binding Loc[settings.unit]}" FontSize="11" Foreground="{DynamicResource TextSecondaryBrush}"/>
<WrapPanel>
<RadioButton GroupName="unit" Content="PLM" Margin="0,0,14,4"
IsChecked="{Binding IsUnitPlm, Mode=OneWay}"
Command="{Binding SetUnitCommand}" CommandParameter="PLM"/>
<RadioButton GroupName="unit" Content="mPLM" Margin="0,0,14,4"
IsChecked="{Binding IsUnitMilli, Mode=OneWay}"
Command="{Binding SetUnitCommand}" CommandParameter="mPLM"/>
<RadioButton GroupName="unit" Content="µPLM" Margin="0,0,14,4"
IsChecked="{Binding IsUnitMicro, Mode=OneWay}"
Command="{Binding SetUnitCommand}" CommandParameter="µPLM"/>
<RadioButton GroupName="unit" Content="sat" Margin="0,0,14,4"
IsChecked="{Binding IsUnitSat, Mode=OneWay}"
Command="{Binding SetUnitCommand}" CommandParameter="sat"/>
</WrapPanel>
</StackPanel>
<!-- Server di indicizzazione (configurabile anche prima di aprire un wallet) -->
<Button Content="{Binding Loc[settings.server]}"
HorizontalAlignment="Left"
Command="{Binding OpenServerSettingsCommand}"/>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Command="{Binding CloseSettingsCommand}"/>
</StackPanel>
</ScrollViewer>
</Border>
</Border>
<!-- ============ OVERLAY HELP / INFORMAZIONI ============ -->
<!-- Stesso pattern dell'overlay impostazioni: apertura/chiusura istantanee. -->
<Border Grid.Row="0" Grid.RowSpan="3"
Background="{DynamicResource ScrimBrush}"
Tapped="OnHelpOverlayBackdropTapped"
IsVisible="{Binding IsHelpOpen}">
<Border Background="{DynamicResource OverlayCardBrush}"
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
MaxWidth="440" Margin="16"
HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Margin="24" Spacing="16">
<TextBlock Text="{Binding Loc[help.title]}"
FontSize="18" FontWeight="Bold"/>
<StackPanel Spacing="4">
<TextBlock Text="Palladium Wallet" FontSize="16" FontWeight="Bold"/>
<TextBlock Text="{Binding WindowTitle}" FontSize="12" Foreground="{DynamicResource TextSecondaryBrush}"/>
</StackPanel>
<TextBlock Text="{Binding Loc[help.info]}" TextWrapping="Wrap"/>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Command="{Binding CloseHelpCommand}"/>
</StackPanel>
</Border>
</Border>
</Grid>
</UserControl>