refactor(app): replace AddressInfoWindow with in-app overlay

The address detail panel is now rendered as a modal overlay inside
MainWindow instead of a separate top-level Window, avoiding the
create/destroy cost of a dialog and working better under WSLg.

Backdrop tap and Esc both close the overlay.
This commit is contained in:
2026-06-12 08:16:39 +02:00
parent fe320584eb
commit cf6e2d7654
5 changed files with 89 additions and 75 deletions
+11
View File
@@ -249,6 +249,17 @@ public partial class MainWindowViewModel : ViewModelBase
[ObservableProperty] [ObservableProperty]
private AddressRow? selectedAddressRow; private AddressRow? selectedAddressRow;
/// <summary>Dettaglio indirizzo mostrato nell'overlay in-app; null = nascosto.</summary>
[ObservableProperty]
private AddressInfo? addressInfo;
/// <summary>Apre l'overlay con i dati dell'indirizzo passato.</summary>
public void ShowAddressInfo(AddressRow row) =>
AddressInfo = new AddressInfo(Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey);
[RelayCommand]
private void CloseAddressInfo() => AddressInfo = null;
// ---- rubrica contatti ---- // ---- rubrica contatti ----
public ObservableCollection<ContactEntry> Contacts { get; } = []; public ObservableCollection<ContactEntry> Contacts { get; } = [];
-49
View File
@@ -1,49 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:PalladiumWallet.App.ViewModels"
x:Class="PalladiumWallet.App.Views.AddressInfoWindow"
x:DataType="vm:AddressInfo"
Title="{Binding Loc[addr.info.title]}"
Width="560" SizeToContent="Height"
CanResize="False"
WindowStartupLocation="CenterOwner">
<StackPanel Margin="24" Spacing="16">
<!-- Indirizzo -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.address]}" FontSize="11" Foreground="Gray"/>
<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="Gray"/>
<SelectableTextBlock Text="{Binding DerivPath}"
FontFamily="monospace" FontSize="13"/>
</StackPanel>
<!-- Chiave pubblica -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.pubkey]}" FontSize="11" Foreground="Gray"/>
<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="OrangeRed"/>
<SelectableTextBlock Text="{Binding PrivKey}"
FontFamily="monospace" FontSize="12"
Foreground="OrangeRed"
TextWrapping="Wrap"/>
</StackPanel>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Click="OnCloseClick"/>
</StackPanel>
</Window>
-20
View File
@@ -1,20 +0,0 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using PalladiumWallet.App.ViewModels;
namespace PalladiumWallet.App.Views;
public partial class AddressInfoWindow : Window
{
public AddressInfoWindow()
{
InitializeComponent();
}
public AddressInfoWindow(AddressInfo info) : this()
{
DataContext = info;
}
private void OnCloseClick(object? sender, RoutedEventArgs e) => Close();
}
+55
View File
@@ -375,5 +375,60 @@
Padding="10,6"> Padding="10,6">
<TextBlock Text="{Binding StatusMessage}" FontSize="12" TextWrapping="Wrap"/> <TextBlock Text="{Binding StatusMessage}" FontSize="12" TextWrapping="Wrap"/>
</Border> </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="#99000000"
Tapped="OnAddressOverlayBackdropTapped"
IsVisible="{Binding AddressInfo, Converter={x:Static ObjectConverters.IsNotNull}}">
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
BorderBrush="Gray" BorderThickness="1" CornerRadius="8"
Width="560" Padding="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
DataContext="{Binding AddressInfo}">
<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="Gray"/>
<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="Gray"/>
<SelectableTextBlock Text="{Binding DerivPath}"
FontFamily="monospace" FontSize="13"/>
</StackPanel>
<!-- Chiave pubblica -->
<StackPanel Spacing="4">
<TextBlock Text="{Binding Loc[addr.pubkey]}" FontSize="11" Foreground="Gray"/>
<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="OrangeRed"/>
<SelectableTextBlock Text="{Binding PrivKey}"
FontFamily="monospace" FontSize="12"
Foreground="OrangeRed"
TextWrapping="Wrap"/>
</StackPanel>
<Button Content="{Binding Loc[addr.close]}"
HorizontalAlignment="Right"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).CloseAddressInfoCommand}"/>
</StackPanel>
</Border>
</Border>
</Grid> </Grid>
</Window> </Window>
+23 -6
View File
@@ -37,15 +37,14 @@ public partial class MainWindow : Window
vm.OpenFromPath(path); vm.OpenFromPath(path);
} }
private async void OnAddressListTapped(object? sender, TappedEventArgs e) private void OnAddressListTapped(object? sender, TappedEventArgs e)
{ {
if (DataContext is not MainWindowViewModel vm || vm.SelectedAddressRow is not { } row) if (DataContext is not MainWindowViewModel vm || vm.SelectedAddressRow is not { } row)
return; return;
var info = new AddressInfo(vm.Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey); vm.ShowAddressInfo(row);
await new AddressInfoWindow(info).ShowDialog(this);
} }
private async void OnAddressListPointerPressed(object? sender, PointerPressedEventArgs e) private void OnAddressListPointerPressed(object? sender, PointerPressedEventArgs e)
{ {
if (!e.GetCurrentPoint(null).Properties.IsRightButtonPressed) return; if (!e.GetCurrentPoint(null).Properties.IsRightButtonPressed) return;
if (sender is not ListBox lb || DataContext is not MainWindowViewModel vm) return; if (sender is not ListBox lb || DataContext is not MainWindowViewModel vm) return;
@@ -54,8 +53,26 @@ public partial class MainWindow : Window
if (item is not { DataContext: AddressRow row }) return; if (item is not { DataContext: AddressRow row }) return;
lb.SelectedItem = row; lb.SelectedItem = row;
vm.ShowAddressInfo(row);
}
var info = new AddressInfo(vm.Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey); // Chiusura dell'overlay dettaglio indirizzo: click sullo sfondo scuro
await new AddressInfoWindow(info).ShowDialog(this); // (solo sullo sfondo, non sulla scheda) o tasto Esc.
private void OnAddressOverlayBackdropTapped(object? sender, TappedEventArgs e)
{
if (!ReferenceEquals(e.Source, sender)) return;
if (DataContext is MainWindowViewModel vm)
vm.AddressInfo = null;
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && DataContext is MainWindowViewModel { AddressInfo: not null } vm)
{
vm.AddressInfo = null;
e.Handled = true;
return;
}
base.OnKeyDown(e);
} }
} }