Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 96b6a7e291 | |||
| b13b66160c | |||
| 9744619eb4 |
@@ -60,6 +60,19 @@ public sealed class Loc
|
|||||||
"Portefeuille SPV pour la cryptomonnaie Palladium (PLM).",
|
"Portefeuille SPV pour la cryptomonnaie Palladium (PLM).",
|
||||||
"Carteira SPV para a criptomoeda Palladium (PLM).",
|
"Carteira SPV para a criptomoeda Palladium (PLM).",
|
||||||
"SPV-Wallet für die Kryptowährung Palladium (PLM)."],
|
"SPV-Wallet für die Kryptowährung Palladium (PLM)."],
|
||||||
|
["help.tab.info"] = ["Info", "Info", "Info", "Info", "Info", "Info"],
|
||||||
|
["help.tab.donate"] = ["Dona", "Donate", "Donar", "Faire un don", "Doar", "Spenden"],
|
||||||
|
["donate.desc"] = [
|
||||||
|
"Se questo wallet ti è utile, considera una piccola donazione allo sviluppatore.",
|
||||||
|
"If you find this wallet useful, consider a small donation to the developer.",
|
||||||
|
"Si esta wallet te resulta útil, considera una pequeña donación al desarrollador.",
|
||||||
|
"Si ce portefeuille vous est utile, envisagez un petit don au développeur.",
|
||||||
|
"Se esta carteira é útil para você, considere uma pequena doação ao desenvolvedor.",
|
||||||
|
"Wenn Ihnen dieses Wallet nützlich ist, erwägen Sie eine kleine Spende an den Entwickler."],
|
||||||
|
["donate.dev.address"] = ["Indirizzo sviluppatore", "Developer address", "Dirección del desarrollador", "Adresse du développeur", "Endereço do desenvolvedor", "Entwickleradresse"],
|
||||||
|
["donate.amount"] = ["Importo donazione", "Donation amount", "Monto de donación", "Montant du don", "Valor da doação", "Spendenbetrag"],
|
||||||
|
["donate.prepare"] = ["Prepara donazione", "Prepare donation", "Preparar donación", "Préparer le don", "Preparar doação", "Spende vorbereiten"],
|
||||||
|
["donate.confirm"] = ["Conferma e invia", "Confirm and send", "Confirmar y enviar", "Confirmer et envoyer", "Confirmar e enviar", "Bestätigen und senden"],
|
||||||
["settings.unit.short"] = ["Unità", "Unit", "Unidad", "Unité", "Unidade", "Einheit"],
|
["settings.unit.short"] = ["Unità", "Unit", "Unidad", "Unité", "Unidade", "Einheit"],
|
||||||
|
|
||||||
// Wizard
|
// Wizard
|
||||||
|
|||||||
@@ -117,6 +117,11 @@
|
|||||||
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
<Setter Property="TextElement.Foreground" Value="{DynamicResource PrimaryBrush}"/>
|
<Setter Property="TextElement.Foreground" Value="{DynamicResource PrimaryBrush}"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- Push tab header content up so the 2px selection indicator (drawn at Panel bottom)
|
||||||
|
does not overlap the text label. -->
|
||||||
|
<Style Selector="TabItem /template/ ContentPresenter#PART_ContentPresenter">
|
||||||
|
<Setter Property="Margin" Value="0,0,0,4"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<!-- ===== Reusable classes ===== -->
|
<!-- ===== Reusable classes ===== -->
|
||||||
<!-- Card: elevated surface with a subtle border and soft corners -->
|
<!-- Card: elevated surface with a subtle border and soft corners -->
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using NBitcoin;
|
||||||
|
using PalladiumWallet.Core.Chain;
|
||||||
|
using PalladiumWallet.Core.Net;
|
||||||
|
using PalladiumWallet.Core.Wallet;
|
||||||
|
|
||||||
|
namespace PalladiumWallet.App.ViewModels;
|
||||||
|
|
||||||
|
public partial class MainWindowViewModel
|
||||||
|
{
|
||||||
|
public const string DevAddress = "plm1qdq3gu2zvg9lyr8gxd6yln4wavc5tlp8prmvfay";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string donateAmount = "";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string donatePreview = "";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool hasPendingDonate;
|
||||||
|
|
||||||
|
private BuiltTransaction? _pendingDonate;
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task PrepareDonate()
|
||||||
|
{
|
||||||
|
_pendingDonate = null;
|
||||||
|
HasPendingDonate = false;
|
||||||
|
|
||||||
|
if (_account is null || _doc?.Cache is null || _lastTransactions is null)
|
||||||
|
{
|
||||||
|
DonatePreview = "Sincronizza prima di inviare.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var destination = BitcoinAddress.Create(DevAddress, PalladiumNetworks.For(Net));
|
||||||
|
if (!CoinAmount.TryParseIn(DonateAmount.Trim(), _config.Unit, out var amount) || amount <= 0)
|
||||||
|
{
|
||||||
|
DonatePreview = "Importo non valido.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!decimal.TryParse(SendFeeRate, System.Globalization.NumberStyles.Any,
|
||||||
|
System.Globalization.CultureInfo.InvariantCulture, out var feeRate) || feeRate <= 0)
|
||||||
|
feeRate = 1m;
|
||||||
|
|
||||||
|
_pendingDonate = new TransactionFactory(_account).Build(
|
||||||
|
_doc.Cache.Utxos, _lastTransactions, destination, amount, feeRate,
|
||||||
|
_doc.Cache.NextChangeIndex, sendAll: false);
|
||||||
|
|
||||||
|
DonatePreview = $"txid {_pendingDonate.Txid[..16]}… · " +
|
||||||
|
$"fee {Fmt(_pendingDonate.Fee.Satoshi)} " +
|
||||||
|
$"({_pendingDonate.Transaction.GetVirtualSize()} vB)" +
|
||||||
|
(_pendingDonate.Signed ? "" : " · watch-only");
|
||||||
|
HasPendingDonate = _pendingDonate.Signed;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_pendingDonate = null;
|
||||||
|
HasPendingDonate = false;
|
||||||
|
DonatePreview = $"Errore: {ex.Message}";
|
||||||
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task ConfirmDonate()
|
||||||
|
{
|
||||||
|
if (_pendingDonate is null || _client is null)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var txid = await _client.BroadcastAsync(_pendingDonate.ToHex());
|
||||||
|
DonatePreview = $"Grazie! txid: {txid}";
|
||||||
|
DonateAmount = "";
|
||||||
|
_pendingDonate = null;
|
||||||
|
HasPendingDonate = false;
|
||||||
|
await ConnectAndSync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
DonatePreview = $"Errore broadcast: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetDonate()
|
||||||
|
{
|
||||||
|
DonateAmount = "";
|
||||||
|
DonatePreview = "";
|
||||||
|
HasPendingDonate = false;
|
||||||
|
_pendingDonate = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,5 +70,5 @@ public partial class MainWindowViewModel
|
|||||||
private void OpenHelp() => IsHelpOpen = true;
|
private void OpenHelp() => IsHelpOpen = true;
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void CloseHelp() => IsHelpOpen = false;
|
private void CloseHelp() { IsHelpOpen = false; ResetDonate(); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
public bool IsMobile => !IsDesktop;
|
public bool IsMobile => !IsDesktop;
|
||||||
|
|
||||||
|
// Tab bar sizing: compact on mobile so all 5 tabs fit in one row.
|
||||||
|
public double TabIconSize => IsMobile ? 20 : 24;
|
||||||
|
public double TabFontSize => IsMobile ? 10 : 13;
|
||||||
|
public double TabSpacing => IsMobile ? 4 : 4;
|
||||||
|
|
||||||
public string UnitLabel => _config.Unit;
|
public string UnitLabel => _config.Unit;
|
||||||
public AppConfig CurrentConfig => _config;
|
public AppConfig CurrentConfig => _config;
|
||||||
|
|
||||||
|
|||||||
+194
-65
@@ -324,7 +324,7 @@
|
|||||||
<Setter Property="Background" Value="{DynamicResource SurfaceBrush}"/>
|
<Setter Property="Background" Value="{DynamicResource SurfaceBrush}"/>
|
||||||
<Setter Property="ItemsPanel">
|
<Setter Property="ItemsPanel">
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<UniformGrid Rows="1"/>
|
<UniformGrid Rows="1" Columns="5"/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
@@ -332,22 +332,25 @@
|
|||||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||||
<Setter Property="Padding" Value="8,14"/>
|
<Setter Property="Padding" Value="8,12"/>
|
||||||
<Setter Property="MinWidth" Value="80"/>
|
|
||||||
</Style>
|
</Style>
|
||||||
</TabControl.Styles>
|
</TabControl.Styles>
|
||||||
|
|
||||||
<!-- 1. History -->
|
<!-- 1. History -->
|
||||||
<TabItem>
|
<TabItem>
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
<StackPanel Spacing="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabSpacing}"
|
||||||
<Viewbox Width="24" Height="24" HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
|
<Viewbox Width="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
Height="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
<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"/>
|
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>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Text="{Binding Loc[tab.history]}" FontSize="13"
|
<TextBlock Text="{Binding Loc[tab.history]}"
|
||||||
|
FontSize="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabFontSize}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
@@ -393,14 +396,18 @@
|
|||||||
<!-- 2. Send -->
|
<!-- 2. Send -->
|
||||||
<TabItem>
|
<TabItem>
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
<StackPanel Spacing="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabSpacing}"
|
||||||
<Viewbox Width="24" Height="24" HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
|
<Viewbox Width="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
Height="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
||||||
Data="M2,21L23,12L2,3V10L17,12L2,14V21Z"/>
|
Data="M2,21L23,12L2,3V10L17,12L2,14V21Z"/>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Text="{Binding Loc[tab.send]}" FontSize="13"
|
<TextBlock Text="{Binding Loc[tab.send]}"
|
||||||
|
FontSize="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabFontSize}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
@@ -496,34 +503,41 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- ── MOBILE: vertical stack ── -->
|
<!-- ── MOBILE: vertical stack ── -->
|
||||||
<StackPanel IsVisible="{Binding IsMobile}" Spacing="14">
|
<StackPanel IsVisible="{Binding IsMobile}" Spacing="12">
|
||||||
<Border Classes="card" Padding="20,16">
|
|
||||||
<StackPanel Spacing="12">
|
<!-- Recipient card with labelled inputs -->
|
||||||
|
<Border Classes="card" Padding="20,18">
|
||||||
|
<StackPanel Spacing="14">
|
||||||
<TextBlock Text="{Binding Loc[send.sect.recipient]}" Classes="section"/>
|
<TextBlock Text="{Binding Loc[send.sect.recipient]}" Classes="section"/>
|
||||||
<Grid ColumnDefinitions="Auto,*">
|
<!-- Contact picker -->
|
||||||
<TextBlock Grid.Column="0" Text="{Binding Loc[send.from.contact]}"
|
<StackPanel Spacing="4">
|
||||||
VerticalAlignment="Center" Margin="0,0,10,0"
|
<TextBlock Text="{Binding Loc[send.from.contact]}" Classes="label"/>
|
||||||
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="13"/>
|
<ComboBox HorizontalAlignment="Stretch"
|
||||||
<ComboBox Grid.Column="1" HorizontalAlignment="Stretch"
|
|
||||||
ItemsSource="{Binding Contacts}"
|
ItemsSource="{Binding Contacts}"
|
||||||
SelectedItem="{Binding SendToContact}"
|
SelectedItem="{Binding SendToContact}"
|
||||||
PlaceholderText="{Binding Loc[send.contact.hint]}">
|
PlaceholderText="{Binding Loc[send.contact.hint]}"
|
||||||
|
MinHeight="48">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:ContactEntry">
|
<DataTemplate x:DataType="vm:ContactEntry">
|
||||||
<TextBlock Text="{Binding Name}"/>
|
<TextBlock Text="{Binding Name}" FontSize="15"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ComboBox.ItemTemplate>
|
</ComboBox.ItemTemplate>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</StackPanel>
|
||||||
|
<!-- Address + QR scan button -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="{Binding Loc[send.to]}" Classes="label"/>
|
||||||
<Grid ColumnDefinitions="*,Auto">
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
<TextBox Grid.Column="0"
|
<TextBox Grid.Column="0"
|
||||||
PlaceholderText="{Binding Loc[send.to]}"
|
PlaceholderText="{Binding Loc[send.to]}"
|
||||||
Text="{Binding SendTo}"
|
Text="{Binding SendTo}"
|
||||||
FontFamily="monospace"/>
|
FontFamily="monospace" FontSize="15"
|
||||||
<Button Grid.Column="1" Margin="8,0,0,0" Padding="10,6"
|
MinHeight="48"/>
|
||||||
|
<Button Grid.Column="1" Margin="8,0,0,0"
|
||||||
|
Width="52" Height="48"
|
||||||
Command="{Binding ScanQrCommand}"
|
Command="{Binding ScanQrCommand}"
|
||||||
ToolTip.Tip="{Binding Loc[send.scan]}">
|
ToolTip.Tip="{Binding Loc[send.scan]}">
|
||||||
<Viewbox Width="20" Height="20">
|
<Viewbox Width="22" Height="22">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{DynamicResource SystemBaseHighColor}"
|
<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"/>
|
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"/>
|
||||||
@@ -532,26 +546,44 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Classes="card" Padding="20,16">
|
|
||||||
<StackPanel Spacing="12">
|
<!-- Amount & fee card with labelled inputs -->
|
||||||
|
<Border Classes="card" Padding="20,18">
|
||||||
|
<StackPanel Spacing="14">
|
||||||
<TextBlock Text="{Binding Loc[send.sect.amount]}" Classes="section"/>
|
<TextBlock Text="{Binding Loc[send.sect.amount]}" Classes="section"/>
|
||||||
<Grid ColumnDefinitions="*,Auto,Auto">
|
<!-- Amount field -->
|
||||||
<TextBox Grid.Column="0" PlaceholderText="0.00000000"
|
<StackPanel Spacing="4">
|
||||||
Text="{Binding SendAmount}" IsEnabled="{Binding !SendAll}"
|
<TextBlock Text="{Binding Loc[send.amount]}" Classes="label"/>
|
||||||
FontFamily="monospace"/>
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
|
<TextBox Grid.Column="0"
|
||||||
|
PlaceholderText="0.00000000"
|
||||||
|
Text="{Binding SendAmount}"
|
||||||
|
IsEnabled="{Binding !SendAll}"
|
||||||
|
FontFamily="monospace" FontSize="16"
|
||||||
|
MinHeight="48"/>
|
||||||
<TextBlock Grid.Column="1" Text="{Binding UnitLabel}"
|
<TextBlock Grid.Column="1" Text="{Binding UnitLabel}"
|
||||||
VerticalAlignment="Center" Margin="8,0,0,0"
|
VerticalAlignment="Center" Margin="12,0,0,0"
|
||||||
|
FontWeight="Medium"
|
||||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
<CheckBox Grid.Column="2" Content="{Binding Loc[send.all]}"
|
|
||||||
IsChecked="{Binding SendAll}" Margin="10,0,0,0"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
</StackPanel>
|
||||||
<TextBlock Text="{Binding Loc[send.feerate]}" VerticalAlignment="Center" Classes="label"/>
|
<!-- Send-all toggle -->
|
||||||
<TextBox Text="{Binding SendFeeRate}" MinWidth="80" FontFamily="monospace"/>
|
<CheckBox Content="{Binding Loc[send.all]}"
|
||||||
|
IsChecked="{Binding SendAll}"
|
||||||
|
MinHeight="44" FontSize="14"/>
|
||||||
|
<!-- Fee rate field -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="{Binding Loc[send.feerate]}" Classes="label"/>
|
||||||
|
<TextBox Text="{Binding SendFeeRate}"
|
||||||
|
FontFamily="monospace" FontSize="15"
|
||||||
|
MinHeight="48" HorizontalAlignment="Stretch"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- Summary card -->
|
||||||
<Border Classes="card" Padding="20,16"
|
<Border Classes="card" Padding="20,16"
|
||||||
IsVisible="{Binding SendPreview, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
IsVisible="{Binding SendPreview, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||||
<StackPanel Spacing="8">
|
<StackPanel Spacing="8">
|
||||||
@@ -561,15 +593,19 @@
|
|||||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Grid ColumnDefinitions="*,*" ColumnSpacing="12">
|
|
||||||
<Button Grid.Column="0" Content="{Binding Loc[send.prepare]}"
|
<!-- Action buttons: primary (Confirm) prominent, secondary below -->
|
||||||
Command="{Binding PrepareSendCommand}"
|
<Button Content="{Binding Loc[send.confirm]}" Classes="accent"
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
|
|
||||||
<Button Grid.Column="1" Content="{Binding Loc[send.confirm]}" Classes="accent"
|
|
||||||
Command="{Binding ConfirmSendCommand}"
|
Command="{Binding ConfirmSendCommand}"
|
||||||
IsEnabled="{Binding HasPendingSend}"
|
IsEnabled="{Binding HasPendingSend}"
|
||||||
|
MinHeight="52"
|
||||||
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"
|
||||||
|
FontSize="15"/>
|
||||||
|
<Button Content="{Binding Loc[send.prepare]}"
|
||||||
|
Command="{Binding PrepareSendCommand}"
|
||||||
|
MinHeight="48"
|
||||||
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
|
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"/>
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</Panel>
|
</Panel>
|
||||||
@@ -579,14 +615,18 @@
|
|||||||
<!-- 3. Receive -->
|
<!-- 3. Receive -->
|
||||||
<TabItem>
|
<TabItem>
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
<StackPanel Spacing="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabSpacing}"
|
||||||
<Viewbox Width="24" Height="24" HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
|
<Viewbox Width="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
Height="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
<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"/>
|
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>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Text="{Binding Loc[tab.receive]}" FontSize="13"
|
<TextBlock Text="{Binding Loc[tab.receive]}"
|
||||||
|
FontSize="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabFontSize}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
@@ -635,39 +675,49 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- ── MOBILE: vertical stack ── -->
|
<!-- ── MOBILE: vertical stack ── -->
|
||||||
<StackPanel IsVisible="{Binding IsMobile}" Spacing="14">
|
<StackPanel IsVisible="{Binding IsMobile}" Spacing="12">
|
||||||
<Border Classes="card" Padding="24,20"
|
|
||||||
|
<!-- QR card: full-width, centered with generous padding -->
|
||||||
|
<Border Classes="card" Padding="24,22"
|
||||||
IsVisible="{Binding ReceiveQr, Converter={x:Static ObjectConverters.IsNotNull}}">
|
IsVisible="{Binding ReceiveQr, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<StackPanel Spacing="18" HorizontalAlignment="Center">
|
<StackPanel Spacing="16" HorizontalAlignment="Center">
|
||||||
<TextBlock Text="{Binding Loc[receive.next]}" Classes="label"
|
<TextBlock Text="{Binding Loc[receive.next]}" Classes="label"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center" FontSize="13"/>
|
||||||
<Border Background="White" Padding="14" CornerRadius="10"
|
<Border Background="White" Padding="16" CornerRadius="12"
|
||||||
HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
<Image Source="{Binding ReceiveQr}" Width="200" Height="200"
|
<Image Source="{Binding ReceiveQr}" Width="220" Height="220"
|
||||||
RenderOptions.BitmapInterpolationMode="None"/>
|
RenderOptions.BitmapInterpolationMode="None"/>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Classes="card" Padding="20,18">
|
|
||||||
<StackPanel Spacing="12">
|
<!-- Address card: label + monospace box + big Copy button -->
|
||||||
|
<Border Classes="card" Padding="20,20">
|
||||||
|
<StackPanel Spacing="14">
|
||||||
<TextBlock Text="{Binding Loc[receive.your.address]}" Classes="section"/>
|
<TextBlock Text="{Binding Loc[receive.your.address]}" Classes="section"/>
|
||||||
<Border Background="{DynamicResource SurfaceAltBrush}"
|
<Border Background="{DynamicResource SurfaceAltBrush}"
|
||||||
CornerRadius="8" Padding="14,10">
|
CornerRadius="8" Padding="16,12">
|
||||||
<SelectableTextBlock Text="{Binding ReceiveAddress}"
|
<SelectableTextBlock Text="{Binding ReceiveAddress}"
|
||||||
FontFamily="monospace" FontSize="13"
|
FontFamily="monospace" FontSize="14"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"
|
||||||
|
LineHeight="22"/>
|
||||||
</Border>
|
</Border>
|
||||||
<Button Content="{Binding Loc[receive.copy]}" Classes="accent"
|
<Button Content="{Binding Loc[receive.copy]}" Classes="accent"
|
||||||
Click="OnCopyReceiveAddressClick"
|
Click="OnCopyReceiveAddressClick"
|
||||||
|
MinHeight="52"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Center"/>
|
HorizontalContentAlignment="Center"
|
||||||
|
FontSize="15"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- Hint -->
|
||||||
<TextBlock Text="{Binding Loc[receive.hint]}"
|
<TextBlock Text="{Binding Loc[receive.hint]}"
|
||||||
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"
|
Foreground="{DynamicResource TextSecondaryBrush}" FontSize="12"
|
||||||
TextWrapping="Wrap" TextAlignment="Center" Margin="4,0"/>
|
TextWrapping="Wrap" TextAlignment="Center" Margin="4,0"/>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</Panel>
|
</Panel>
|
||||||
@@ -677,14 +727,18 @@
|
|||||||
<!-- 4. Addresses -->
|
<!-- 4. Addresses -->
|
||||||
<TabItem>
|
<TabItem>
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
<StackPanel Spacing="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabSpacing}"
|
||||||
<Viewbox Width="24" Height="24" HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
|
<Viewbox Width="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
Height="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
<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"/>
|
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>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Text="{Binding Loc[tab.addresses]}" FontSize="13"
|
<TextBlock Text="{Binding Loc[tab.addresses]}"
|
||||||
|
FontSize="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabFontSize}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
@@ -739,14 +793,18 @@
|
|||||||
<!-- 5. Contacts -->
|
<!-- 5. Contacts -->
|
||||||
<TabItem>
|
<TabItem>
|
||||||
<TabItem.Header>
|
<TabItem.Header>
|
||||||
<StackPanel Spacing="4" HorizontalAlignment="Center">
|
<StackPanel Spacing="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabSpacing}"
|
||||||
<Viewbox Width="24" Height="24" HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
|
<Viewbox Width="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
Height="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabIconSize}"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{Binding $parent[TabItem].Foreground}"
|
<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"/>
|
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>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
<TextBlock Text="{Binding Loc[tab.contacts]}" FontSize="13"
|
<TextBlock Text="{Binding Loc[tab.contacts]}"
|
||||||
|
FontSize="{Binding $parent[TabControl].((vm:MainWindowViewModel)DataContext).TabFontSize}"
|
||||||
HorizontalAlignment="Center"/>
|
HorizontalAlignment="Center"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem.Header>
|
</TabItem.Header>
|
||||||
@@ -1315,17 +1373,88 @@
|
|||||||
<Border Background="{DynamicResource OverlayCardBrush}"
|
<Border Background="{DynamicResource OverlayCardBrush}"
|
||||||
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
|
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
|
||||||
MaxWidth="440" Margin="16"
|
MaxWidth="440" Margin="16"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||||
<StackPanel Margin="24" Spacing="16">
|
<StackPanel Margin="24" Spacing="16">
|
||||||
<TextBlock Text="{Binding Loc[help.title]}"
|
<TextBlock Text="{Binding Loc[help.title]}"
|
||||||
FontSize="18" FontWeight="Bold"/>
|
FontSize="18" FontWeight="Bold"/>
|
||||||
|
|
||||||
|
<!-- Fixed height so the overlay never resizes when switching tabs. -->
|
||||||
|
<TabControl Height="320">
|
||||||
|
<!-- Tab: Info -->
|
||||||
|
<TabItem Header="{Binding Loc[help.tab.info]}">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<StackPanel Spacing="12" Margin="0,12,0,0">
|
||||||
<StackPanel Spacing="4">
|
<StackPanel Spacing="4">
|
||||||
<TextBlock Text="Palladium Wallet" FontSize="16" FontWeight="Bold"/>
|
<TextBlock Text="Palladium Wallet" FontSize="16" FontWeight="Bold"/>
|
||||||
<TextBlock Text="{Binding WindowTitle}" FontSize="12" Foreground="{DynamicResource TextSecondaryBrush}"/>
|
<TextBlock Text="{Binding WindowTitle}" FontSize="12"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Text="{Binding Loc[help.info]}" TextWrapping="Wrap"/>
|
||||||
|
<Border BorderBrush="{DynamicResource BorderSubtleBrush}"
|
||||||
|
BorderThickness="0,1,0,0" Margin="0,4,0,0"/>
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="© 2026 Davide Grilli — MIT License"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
<TextBlock Text="Built with .NET 10 · Avalonia 12 · NBitcoin"
|
||||||
|
FontSize="11"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<!-- Tab: Donate -->
|
||||||
|
<TabItem Header="{Binding Loc[help.tab.donate]}">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<StackPanel Spacing="12" Margin="0,12,0,0">
|
||||||
|
<TextBlock Text="{Binding Loc[donate.desc]}" TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
|
||||||
|
<!-- Dev address (read-only) -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="{Binding Loc[donate.dev.address]}" FontSize="11"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
<SelectableTextBlock Text="{x:Static vm:MainWindowViewModel.DevAddress}"
|
||||||
|
FontFamily="monospace" FontSize="11"
|
||||||
|
TextWrapping="Wrap"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock Text="{Binding Loc[help.info]}" TextWrapping="Wrap"/>
|
<!-- Amount input -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="{Binding Loc[donate.amount]}" FontSize="11"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
|
<TextBox Grid.Column="0"
|
||||||
|
Text="{Binding DonateAmount}"
|
||||||
|
PlaceholderText="{Binding UnitLabel}"/>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding UnitLabel}"
|
||||||
|
VerticalAlignment="Center" Margin="8,0,0,0"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Preview -->
|
||||||
|
<SelectableTextBlock Text="{Binding DonatePreview}"
|
||||||
|
IsVisible="{Binding DonatePreview,
|
||||||
|
Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||||
|
FontFamily="monospace" FontSize="11"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right">
|
||||||
|
<Button Content="{Binding Loc[donate.confirm]}"
|
||||||
|
Classes="accent"
|
||||||
|
IsEnabled="{Binding HasPendingDonate}"
|
||||||
|
Command="{Binding ConfirmDonateCommand}"/>
|
||||||
|
<Button Content="{Binding Loc[donate.prepare]}"
|
||||||
|
Command="{Binding PrepareDonateCommand}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
|
||||||
<Button Content="{Binding Loc[addr.close]}"
|
<Button Content="{Binding Loc[addr.close]}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
|||||||
Reference in New Issue
Block a user