feat(ui): Wallet menu overlay — info, xpub, and password-protected seed reveal
Add a Wallet menu item (between File and Settings) that opens an in-app overlay showing wallet metadata: file name, network, type (HD seed / xprv / WIF / watch-only), script kind, derivation path, master fingerprint, and account xpub. Includes a seed section: if the wallet has no seed, a note is shown; if it has one and is unencrypted the seed is revealed directly; if encrypted the user must enter the wallet file password before the mnemonic is displayed. The revealed seed is shown in a danger-coloured bordered box with a warning. Closing the overlay (backdrop, Close button, or Esc) always clears the password input and hides the seed. Also adds the private-key password-prompt overlay and its localization keys (shared UI scaffolding used by the following commit).
This commit is contained in:
@@ -195,6 +195,8 @@ public sealed class Loc
|
||||
["addr.pubkey"] = ["Chiave pubblica:", "Public key:", "Clave pública:", "Clé publique :", "Chave pública:", "Öffentlicher Schlüssel:"],
|
||||
["addr.privkey"] = ["Chiave privata (WIF):", "Private key (WIF):", "Clave privada (WIF):", "Clé privée (WIF) :", "Chave privada (WIF):", "Privater Schlüssel (WIF):"],
|
||||
["addr.show.privkey"] = ["Mostra", "Show", "Mostrar", "Afficher", "Mostrar", "Anzeigen"],
|
||||
["addr.privkey.prompt.title"] = ["Conferma identità", "Confirm identity", "Confirmar identidad", "Confirmer l'identité", "Confirmar identidade", "Identität bestätigen"],
|
||||
["addr.privkey.prompt.desc"] = ["Inserisci la password del wallet per visualizzare la chiave privata.", "Enter the wallet password to reveal the private key.", "Ingresa la contraseña del wallet para ver la clave privada.", "Entrez le mot de passe du wallet pour afficher la clé privée.", "Digite a senha da carteira para ver a chave privada.", "Geben Sie das Wallet-Passwort ein, um den privaten Schlüssel anzuzeigen."],
|
||||
["addr.hide.privkey"] = ["Nascondi", "Hide", "Ocultar", "Masquer", "Ocultar", "Ausblenden"],
|
||||
["addr.receive"] = ["ricezione", "receive", "recepción", "réception", "recebimento", "Empfang"],
|
||||
["addr.change"] = ["change", "change", "cambio", "monnaie", "troco", "Wechselgeld"],
|
||||
@@ -248,6 +250,35 @@ public sealed class Loc
|
||||
["send.summary"] = ["Riepilogo", "Summary", "Resumen", "Résumé", "Resumo", "Zusammenfassung"],
|
||||
["receive.your.address"] = ["Il tuo indirizzo", "Your address", "Tu dirección", "Votre adresse", "Seu endereço", "Deine Adresse"],
|
||||
|
||||
// Wallet info overlay
|
||||
["menu.wallet"] = ["_Wallet", "_Wallet", "_Wallet", "_Wallet", "_Wallet", "_Wallet"],
|
||||
["walletinfo.title"] = ["Informazioni Wallet", "Wallet Information", "Información del Wallet", "Informations Wallet", "Informações da Carteira", "Wallet-Informationen"],
|
||||
["walletinfo.file"] = ["File", "File", "Archivo", "Fichier", "Arquivo", "Datei"],
|
||||
["walletinfo.network"] = ["Rete", "Network", "Red", "Réseau", "Rede", "Netzwerk"],
|
||||
["walletinfo.type"] = ["Tipo wallet", "Wallet type", "Tipo de wallet", "Type de wallet", "Tipo de carteira", "Wallet-Typ"],
|
||||
["walletinfo.type.seed"] = ["HD (seed BIP39)", "HD (BIP39 seed)", "HD (seed BIP39)", "HD (graine BIP39)", "HD (semente BIP39)", "HD (BIP39-Seed)"],
|
||||
["walletinfo.type.xprv"] = ["HD (xprv importato)", "HD (imported xprv)", "HD (xprv importado)", "HD (xprv importé)", "HD (xprv importado)", "HD (importierter xprv)"],
|
||||
["walletinfo.type.wif"] = ["Chiave WIF importata", "Imported WIF key", "Clave WIF importada", "Clé WIF importée", "Chave WIF importada", "Importierter WIF-Schlüssel"],
|
||||
["walletinfo.type.watchonly"] = ["Watch-only (xpub)", "Watch-only (xpub)", "Watch-only (xpub)", "Watch-only (xpub)", "Watch-only (xpub)", "Watch-only (xpub)"],
|
||||
["walletinfo.script"] = ["Script", "Script", "Script", "Script", "Script", "Script"],
|
||||
["walletinfo.derivpath"] = ["Percorso derivazione", "Derivation path", "Ruta de derivación", "Chemin de dérivation", "Caminho de derivação", "Ableitungspfad"],
|
||||
["walletinfo.xpub"] = ["Chiave pubblica estesa", "Extended public key", "Clave pública extendida", "Clé publique étendue", "Chave pública estendida", "Erweiterter öffentlicher Schlüssel"],
|
||||
["walletinfo.fingerprint"] = ["Master fingerprint", "Master fingerprint", "Huella maestra", "Empreinte maître", "Impressão digital mestre", "Master-Fingerprint"],
|
||||
["walletinfo.seed.section"] = ["Seed (mnemonica BIP39)", "Seed (BIP39 mnemonic)", "Semilla (mnemónico BIP39)", "Graine (mnémonique BIP39)", "Semente (mnemônico BIP39)", "Seed (BIP39-Mnemonic)"],
|
||||
["walletinfo.seed.noseed"] = ["Questo wallet non ha una seed (watch-only o importato).", "This wallet has no seed (watch-only or imported).", "Este wallet no tiene seed (watch-only o importado).", "Ce wallet n'a pas de graine (watch-only ou importé).", "Esta carteira não tem semente (watch-only ou importada).", "Dieses Wallet hat keinen Seed (watch-only oder importiert)."],
|
||||
["walletinfo.seed.password"] = ["Password del file wallet per sbloccare il seed:", "Wallet file password to unlock the seed:", "Contraseña del archivo para desbloquear la seed:", "Mot de passe du fichier pour déverrouiller la graine :", "Senha do arquivo para desbloquear a semente:", "Dateipasswort zum Entsperren des Seeds:"],
|
||||
["walletinfo.seed.reveal"] = ["Mostra seed", "Show seed", "Mostrar seed", "Afficher la graine", "Mostrar semente", "Seed anzeigen"],
|
||||
["walletinfo.seed.hide"] = ["Nascondi", "Hide", "Ocultar", "Masquer", "Ocultar", "Ausblenden"],
|
||||
["walletinfo.seed.warning"] = [
|
||||
"Non condividere mai queste parole. Chi le possiede controlla i fondi.",
|
||||
"Never share these words. Whoever holds them controls the funds.",
|
||||
"Nunca compartas estas palabras. Quien las tenga controla los fondos.",
|
||||
"Ne partagez jamais ces mots. Celui qui les possède contrôle les fonds.",
|
||||
"Nunca compartilhe essas palavras. Quem as tiver controla os fundos.",
|
||||
"Teilen Sie diese Wörter niemals. Wer sie hat, kontrolliert die Gelder."],
|
||||
["walletinfo.passphrase"] = ["Passphrase BIP39", "BIP39 passphrase", "Frase de contraseña BIP39", "Phrase de passe BIP39", "Frase-senha BIP39", "BIP39-Passphrase"],
|
||||
["walletinfo.passphrase.set"] = ["(impostata)", "(set)", "(establecida)", "(définie)", "(definida)", "(gesetzt)"],
|
||||
|
||||
// Connection status
|
||||
["conn.none"] = ["non connesso", "not connected", "no conectado", "non connecté", "não conectado", "nicht verbunden"],
|
||||
["conn.disconnected"] = ["disconnesso", "disconnected", "desconectado", "déconnecté", "desconectado", "getrennt"],
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.IO;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using PalladiumWallet.App.Localization;
|
||||
|
||||
namespace PalladiumWallet.App.ViewModels;
|
||||
|
||||
public partial class MainWindowViewModel
|
||||
{
|
||||
[ObservableProperty]
|
||||
private bool isWalletInfoOpen;
|
||||
|
||||
[ObservableProperty]
|
||||
private string walletInfoSeedPasswordInput = "";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isWalletInfoSeedRevealed;
|
||||
|
||||
[ObservableProperty]
|
||||
private string walletInfoSeedError = "";
|
||||
|
||||
// ---- computed wallet info (populated when overlay opens) ----
|
||||
|
||||
public string WalletInfoFileName =>
|
||||
_walletPath is null ? "" :
|
||||
Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(_walletPath));
|
||||
|
||||
public string WalletInfoNetwork => _doc?.Network ?? "";
|
||||
|
||||
public string WalletInfoType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_doc is null) return "";
|
||||
if (_doc.Mnemonic is not null) return Loc.Tr("walletinfo.type.seed");
|
||||
if (_doc.AccountXprv is not null) return Loc.Tr("walletinfo.type.xprv");
|
||||
if (_doc.WifKeys is { Count: > 0 }) return Loc.Tr("walletinfo.type.wif");
|
||||
return Loc.Tr("walletinfo.type.watchonly");
|
||||
}
|
||||
}
|
||||
|
||||
public string WalletInfoScriptKind => _doc?.ScriptKind ?? "";
|
||||
|
||||
public string WalletInfoDerivPath => _doc?.AccountPath ?? "";
|
||||
|
||||
public string WalletInfoXpub => _doc?.AccountXpub ?? "";
|
||||
|
||||
public string WalletInfoFingerprint => _doc?.MasterFingerprint ?? "";
|
||||
|
||||
public bool WalletInfoHasSeed => _doc?.Mnemonic is not null;
|
||||
|
||||
public bool WalletInfoSeedNeedsPassword => !string.IsNullOrEmpty(_password);
|
||||
|
||||
public string WalletInfoSeedText => IsWalletInfoSeedRevealed ? (_doc?.Mnemonic ?? "") : "";
|
||||
|
||||
public bool WalletInfoHasPassphrase => !string.IsNullOrEmpty(_doc?.Passphrase);
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenWalletInfo()
|
||||
{
|
||||
WalletInfoSeedPasswordInput = "";
|
||||
IsWalletInfoSeedRevealed = false;
|
||||
WalletInfoSeedError = "";
|
||||
OnPropertyChanged(nameof(WalletInfoFileName));
|
||||
OnPropertyChanged(nameof(WalletInfoNetwork));
|
||||
OnPropertyChanged(nameof(WalletInfoType));
|
||||
OnPropertyChanged(nameof(WalletInfoScriptKind));
|
||||
OnPropertyChanged(nameof(WalletInfoDerivPath));
|
||||
OnPropertyChanged(nameof(WalletInfoXpub));
|
||||
OnPropertyChanged(nameof(WalletInfoFingerprint));
|
||||
OnPropertyChanged(nameof(WalletInfoHasSeed));
|
||||
OnPropertyChanged(nameof(WalletInfoSeedNeedsPassword));
|
||||
OnPropertyChanged(nameof(WalletInfoHasPassphrase));
|
||||
IsWalletInfoOpen = true;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CloseWalletInfo()
|
||||
{
|
||||
IsWalletInfoOpen = false;
|
||||
WalletInfoSeedPasswordInput = "";
|
||||
IsWalletInfoSeedRevealed = false;
|
||||
WalletInfoSeedError = "";
|
||||
OnPropertyChanged(nameof(WalletInfoSeedText));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void RevealSeed()
|
||||
{
|
||||
if (_doc?.Mnemonic is null) return;
|
||||
|
||||
if (WalletInfoSeedNeedsPassword)
|
||||
{
|
||||
if (WalletInfoSeedPasswordInput != _password)
|
||||
{
|
||||
WalletInfoSeedError = Loc.Tr("msg.wrongpassword");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WalletInfoSeedError = "";
|
||||
IsWalletInfoSeedRevealed = true;
|
||||
OnPropertyChanged(nameof(WalletInfoSeedText));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void HideSeed()
|
||||
{
|
||||
IsWalletInfoSeedRevealed = false;
|
||||
WalletInfoSeedPasswordInput = "";
|
||||
WalletInfoSeedError = "";
|
||||
OnPropertyChanged(nameof(WalletInfoSeedText));
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,9 @@
|
||||
<MenuItem Header="{Binding Loc[menu.file.close]}" Command="{Binding CloseWalletCommand}"
|
||||
IsEnabled="{Binding IsWalletOpen}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{Binding Loc[menu.wallet]}"
|
||||
Command="{Binding OpenWalletInfoCommand}"
|
||||
IsEnabled="{Binding IsWalletOpen}"/>
|
||||
<MenuItem Header="{Binding Loc[menu.settings]}"
|
||||
Command="{Binding OpenSettingsCommand}"/>
|
||||
<MenuItem Header="{Binding Loc[menu.help]}"
|
||||
@@ -47,6 +50,9 @@
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="8"
|
||||
HorizontalAlignment="Right" Margin="8,4"
|
||||
IsVisible="{Binding IsMobile}">
|
||||
<Button Content="{Binding Loc[menu.wallet]}"
|
||||
Command="{Binding OpenWalletInfoCommand}"
|
||||
IsEnabled="{Binding IsWalletOpen}"/>
|
||||
<Button Content="{Binding Loc[menu.settings]}" Command="{Binding OpenSettingsCommand}"/>
|
||||
<Button Content="{Binding Loc[menu.help]}" Command="{Binding OpenHelpCommand}"/>
|
||||
</StackPanel>
|
||||
@@ -943,12 +949,25 @@
|
||||
</StackPanel>
|
||||
|
||||
<!-- Private key (only when available) -->
|
||||
<StackPanel Spacing="4" IsVisible="{Binding HasPrivKey}">
|
||||
<TextBlock Text="{Binding Loc[addr.privkey]}" FontSize="11" Foreground="{DynamicResource DangerBrush}"/>
|
||||
<StackPanel Spacing="8" IsVisible="{Binding HasPrivKey}">
|
||||
<TextBlock Text="{Binding Loc[addr.privkey]}" FontSize="11"
|
||||
Foreground="{DynamicResource DangerBrush}"/>
|
||||
|
||||
<!-- Not yet revealed: single reveal button -->
|
||||
<Button IsVisible="{Binding !$parent[UserControl].((vm:MainWindowViewModel)DataContext).IsAddressPrivKeyRevealed}"
|
||||
Content="{Binding Loc[walletinfo.seed.reveal]}"
|
||||
Command="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).RequestPrivKeyRevealCommand}"/>
|
||||
|
||||
<!-- Revealed: key text + hide button -->
|
||||
<StackPanel IsVisible="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).IsAddressPrivKeyRevealed}"
|
||||
Spacing="6">
|
||||
<SelectableTextBlock Text="{Binding PrivKey}"
|
||||
FontFamily="monospace" FontSize="12"
|
||||
Foreground="{DynamicResource DangerBrush}"
|
||||
TextWrapping="Wrap"/>
|
||||
<Button Content="{Binding Loc[walletinfo.seed.hide]}"
|
||||
Command="{Binding $parent[UserControl].((vm:MainWindowViewModel)DataContext).HideAddressPrivKeyCommand}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Button Content="{Binding Loc[addr.close]}"
|
||||
@@ -959,6 +978,38 @@
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
<!-- ============ PRIVATE KEY PASSWORD PROMPT ============ -->
|
||||
<!-- Appears on top of the address detail overlay when the wallet is encrypted. -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
Background="{DynamicResource ScrimBrush}"
|
||||
IsVisible="{Binding IsPrivKeyPromptOpen}">
|
||||
<Border Background="{DynamicResource OverlayCardBrush}"
|
||||
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
|
||||
MaxWidth="360" Margin="16"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<StackPanel Margin="24" Spacing="14">
|
||||
<TextBlock Text="{Binding Loc[addr.privkey.prompt.title]}"
|
||||
FontSize="16" FontWeight="Bold"/>
|
||||
<TextBlock Text="{Binding Loc[addr.privkey.prompt.desc]}"
|
||||
FontSize="12" TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBox Text="{Binding PrivKeyPromptPassword}"
|
||||
PasswordChar="●"
|
||||
PlaceholderText="{Binding Loc[wiz.open.placeholder]}"/>
|
||||
<TextBlock Text="{Binding PrivKeyPromptError}"
|
||||
Foreground="{DynamicResource DangerBrush}" FontSize="12"
|
||||
IsVisible="{Binding PrivKeyPromptError,
|
||||
Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right">
|
||||
<Button Content="{Binding Loc[addr.close]}"
|
||||
Command="{Binding CancelPrivKeyPromptCommand}"/>
|
||||
<Button Content="{Binding Loc[walletinfo.seed.reveal]}" Classes="accent"
|
||||
Command="{Binding ConfirmPrivKeyPasswordCommand}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
<!-- ============ TRANSACTION DETAIL OVERLAY ============ -->
|
||||
<!-- In-app overlay (like the address overlay): appears immediately with a
|
||||
spinner; data arrives from the server in the background; instant close. -->
|
||||
@@ -1267,6 +1318,154 @@
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
<!-- ============ WALLET INFO OVERLAY ============ -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
Background="{DynamicResource ScrimBrush}"
|
||||
Tapped="OnWalletInfoOverlayBackdropTapped"
|
||||
IsVisible="{Binding IsWalletInfoOpen}">
|
||||
<Border Background="{DynamicResource OverlayCardBrush}"
|
||||
BorderBrush="{DynamicResource BorderSubtleBrush}" BorderThickness="1" CornerRadius="8"
|
||||
MaxWidth="500" Margin="16"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<ScrollViewer MaxHeight="620">
|
||||
<StackPanel Margin="24" Spacing="14">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.title]}"
|
||||
FontSize="18" FontWeight="Bold"/>
|
||||
|
||||
<!-- File name -->
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.file]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<SelectableTextBlock Text="{Binding WalletInfoFileName}"
|
||||
FontFamily="monospace" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Network -->
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.network]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBlock Text="{Binding WalletInfoNetwork}" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Wallet type -->
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.type]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBlock Text="{Binding WalletInfoType}" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Script kind -->
|
||||
<StackPanel Spacing="3">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.script]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBlock Text="{Binding WalletInfoScriptKind}" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Derivation path (only if present) -->
|
||||
<StackPanel Spacing="3"
|
||||
IsVisible="{Binding WalletInfoDerivPath,
|
||||
Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.derivpath]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<SelectableTextBlock Text="{Binding WalletInfoDerivPath}"
|
||||
FontFamily="monospace" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Master fingerprint (only if present) -->
|
||||
<StackPanel Spacing="3"
|
||||
IsVisible="{Binding WalletInfoFingerprint,
|
||||
Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.fingerprint]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<SelectableTextBlock Text="{Binding WalletInfoFingerprint}"
|
||||
FontFamily="monospace" FontSize="13"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Account xpub (only if present) -->
|
||||
<StackPanel Spacing="3"
|
||||
IsVisible="{Binding WalletInfoXpub,
|
||||
Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.xpub]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<SelectableTextBlock Text="{Binding WalletInfoXpub}"
|
||||
FontFamily="monospace" FontSize="11"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- BIP39 passphrase indicator -->
|
||||
<StackPanel Spacing="3" IsVisible="{Binding WalletInfoHasPassphrase}">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.passphrase]}" FontSize="11"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBlock Text="{Binding Loc[walletinfo.passphrase.set]}"
|
||||
FontSize="13" Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Separator -->
|
||||
<Border Height="1" Background="{DynamicResource BorderSubtleBrush}" Margin="0,4"/>
|
||||
|
||||
<!-- Seed section -->
|
||||
<TextBlock Text="{Binding Loc[walletinfo.seed.section]}"
|
||||
FontSize="13" FontWeight="SemiBold"/>
|
||||
|
||||
<!-- No seed wallet -->
|
||||
<TextBlock IsVisible="{Binding !WalletInfoHasSeed}"
|
||||
Text="{Binding Loc[walletinfo.seed.noseed]}"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"
|
||||
FontSize="12" TextWrapping="Wrap"/>
|
||||
|
||||
<!-- Seed wallet: needs password -->
|
||||
<StackPanel IsVisible="{Binding WalletInfoHasSeed}" Spacing="10">
|
||||
|
||||
<!-- Not yet revealed + password needed -->
|
||||
<StackPanel IsVisible="{Binding WalletInfoSeedNeedsPassword}" Spacing="8">
|
||||
<StackPanel IsVisible="{Binding !IsWalletInfoSeedRevealed}" Spacing="8">
|
||||
<TextBlock Text="{Binding Loc[walletinfo.seed.password]}"
|
||||
FontSize="12" TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource TextSecondaryBrush}"/>
|
||||
<TextBox Text="{Binding WalletInfoSeedPasswordInput}"
|
||||
PasswordChar="●"
|
||||
PlaceholderText="{Binding Loc[wiz.open.placeholder]}"/>
|
||||
<TextBlock Text="{Binding WalletInfoSeedError}"
|
||||
Foreground="{DynamicResource DangerBrush}" FontSize="12"
|
||||
IsVisible="{Binding WalletInfoSeedError,
|
||||
Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
|
||||
<Button Content="{Binding Loc[walletinfo.seed.reveal]}"
|
||||
Command="{Binding RevealSeedCommand}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Not yet revealed + no password needed -->
|
||||
<Button IsVisible="{Binding !WalletInfoSeedNeedsPassword}"
|
||||
Content="{Binding Loc[walletinfo.seed.reveal]}"
|
||||
Command="{Binding RevealSeedCommand}"
|
||||
IsEnabled="{Binding !IsWalletInfoSeedRevealed}"/>
|
||||
|
||||
<!-- Revealed seed -->
|
||||
<StackPanel IsVisible="{Binding IsWalletInfoSeedRevealed}" Spacing="8">
|
||||
<Border BorderBrush="{DynamicResource DangerBrush}" BorderThickness="1"
|
||||
CornerRadius="6" Padding="14"
|
||||
Background="{DynamicResource SurfaceAltBrush}">
|
||||
<SelectableTextBlock Text="{Binding WalletInfoSeedText}"
|
||||
FontFamily="monospace" FontSize="15"
|
||||
TextWrapping="Wrap"/>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Loc[walletinfo.seed.warning]}"
|
||||
Foreground="{DynamicResource DangerBrush}"
|
||||
FontSize="12" TextWrapping="Wrap"/>
|
||||
<Button Content="{Binding Loc[walletinfo.seed.hide]}"
|
||||
Command="{Binding HideSeedCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<Button Content="{Binding Loc[addr.close]}"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding CloseWalletInfoCommand}"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Border>
|
||||
|
||||
<!-- ============ SETTINGS OVERLAY ============ -->
|
||||
<!-- In-app instead of nested submenus: avoids slow OS popups on WSLg. -->
|
||||
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||
|
||||
@@ -126,6 +126,13 @@ public partial class MainView : UserControl
|
||||
vm.IsServerSettingsOpen = true;
|
||||
}
|
||||
|
||||
private void OnWalletInfoOverlayBackdropTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
if (!ReferenceEquals(e.Source, sender)) return;
|
||||
if (DataContext is MainWindowViewModel vm)
|
||||
vm.CloseWalletInfoCommand.Execute(null);
|
||||
}
|
||||
|
||||
private void OnSettingsOverlayBackdropTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
if (!ReferenceEquals(e.Source, sender)) return;
|
||||
@@ -146,8 +153,10 @@ public partial class MainView : UserControl
|
||||
if ((e.Key == Key.Escape || e.Key == Key.Back) && DataContext is MainWindowViewModel vm)
|
||||
{
|
||||
if (vm.IsTxDetailsOpen) { vm.CloseTransactionDetailsCommand.Execute(null); e.Handled = true; return; }
|
||||
if (vm.AddressInfo is not null) { vm.AddressInfo = null; e.Handled = true; return; }
|
||||
if (vm.IsPrivKeyPromptOpen) { vm.CancelPrivKeyPromptCommand.Execute(null); e.Handled = true; return; }
|
||||
if (vm.AddressInfo is not null) { vm.CloseAddressInfoCommand.Execute(null); e.Handled = true; return; }
|
||||
if (vm.IsServerSettingsOpen) { vm.IsServerSettingsOpen = false; e.Handled = true; return; }
|
||||
if (vm.IsWalletInfoOpen) { vm.CloseWalletInfoCommand.Execute(null); e.Handled = true; return; }
|
||||
if (vm.IsSettingsOpen) { vm.IsSettingsOpen = false; e.Handled = true; return; }
|
||||
if (vm.IsHelpOpen) { vm.IsHelpOpen = false; e.Handled = true; return; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user