feat(app): navbar restructure, contacts tab and address info window

- Reorder tabs: Storico / Invia / Ricevi / Indirizzi / Contatti
- Invia: ComboBox to quick-fill recipient from saved contacts
- Contatti: new tab to add/remove contacts (name + address), persisted
  to the wallet file via WalletDocument.Contacts
- Indirizzi: clicking any address (left or right click) opens a modal
  window with derivation path, public key and private key as selectable
  text (no copy button needed — user selects and copies manually);
  AddressRow now carries PubKey, PrivKey, DerivPath pre-computed
- AddressInfoWindow: new Window with SelectableTextBlock per field,
  private key section hidden for watch-only wallets
- Loc: adds tab.contacts, addr.*, contacts.*, send.from.contact keys
  in all 6 languages
This commit is contained in:
2026-06-11 21:39:32 +02:00
parent 6fe31964e1
commit fe320584eb
6 changed files with 331 additions and 43 deletions
+27 -1
View File
@@ -1,7 +1,12 @@
using System.Linq;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using PalladiumWallet.App.ViewModels;
namespace PalladiumWallet.App.Views;
@@ -13,7 +18,6 @@ public partial class MainWindow : Window
InitializeComponent();
}
/// <summary>File → Apri wallet da file (il picker richiede il TopLevel, da qui).</summary>
private async void OnOpenWalletFileClick(object? sender, RoutedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm)
@@ -32,4 +36,26 @@ public partial class MainWindow : Window
if (files.FirstOrDefault()?.TryGetLocalPath() is { } path)
vm.OpenFromPath(path);
}
private async void OnAddressListTapped(object? sender, TappedEventArgs e)
{
if (DataContext is not MainWindowViewModel vm || vm.SelectedAddressRow is not { } row)
return;
var info = new AddressInfo(vm.Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey);
await new AddressInfoWindow(info).ShowDialog(this);
}
private async void OnAddressListPointerPressed(object? sender, PointerPressedEventArgs e)
{
if (!e.GetCurrentPoint(null).Properties.IsRightButtonPressed) return;
if (sender is not ListBox lb || DataContext is not MainWindowViewModel vm) return;
var item = (e.Source as Visual)?.FindAncestorOfType<ListBoxItem>();
if (item is not { DataContext: AddressRow row }) return;
lb.SelectedItem = row;
var info = new AddressInfo(vm.Loc, row.Indirizzo, row.DerivPath, row.PubKey, row.PrivKey);
await new AddressInfoWindow(info).ShowDialog(this);
}
}