Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a9ded6497a | |||
| 46aca513b8 | |||
| 6c01d7e6bd | |||
| 3cffba6e98 | |||
| 865daa137d |
@@ -91,6 +91,3 @@ settings.local.json
|
|||||||
# Local agent/tooling metadata
|
# Local agent/tooling metadata
|
||||||
.agents/
|
.agents/
|
||||||
.codex/
|
.codex/
|
||||||
CLAUDE.md
|
|
||||||
|
|
||||||
blueprint.md
|
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Role
|
||||||
|
|
||||||
|
Operate as an **expert in cryptocurrencies and cryptography**: reason with the domain's rigor about UTXO consensus, HD key derivation (BIP32/39/SLIP-132), signature schemes and scripts (P2PKH/P2SH/P2WPKH, PSBT), address encoding (base58/bech32), Merkle/SPV proofs, and at-rest encryption. When a choice touches cryptographic correctness or fund safety, judge it through that lens and flag known risks and pitfalls (nonce reuse, missing validation, exposed keys/seed, wrong fee/coin-selection, unverified server responses). Explain trade-offs with technical precision; never take for granted what hasn't been verified.
|
||||||
|
|
||||||
|
## How to assist
|
||||||
|
|
||||||
|
On **every requested change**, before implementing, judge whether it makes sense and say so plainly: if a request is useful and consistent with the project, proceed; if it is useless, redundant, already covered elsewhere, or risks degrading the code, **say so** with a short rationale and propose the better alternative (or doing nothing). No automatic agreement — an honest opinion is worth more than blind execution.
|
||||||
|
|
||||||
|
## What it is
|
||||||
|
|
||||||
|
SPV desktop wallet (Sparrow-style) for the **Palladium (PLM)** cryptocurrency, a Bitcoin-derived UTXO chain. Windows/Linux only, no mobile. Lightning is excluded from the first release.
|
||||||
|
|
||||||
|
[blueprint.md](blueprint.md) is a **reference for understanding** (consensus parameters verified against the node, algorithms, network protocol): consult it when it helps to understand an area, but **it is no longer binding** — it need not be followed to the letter or read before every change. The source of truth is the current code; the `§` references below point to the blueprint only as further reading.
|
||||||
|
|
||||||
|
## Stack and structure
|
||||||
|
|
||||||
|
.NET 8 + Avalonia UI + NBitcoin.
|
||||||
|
|
||||||
|
```
|
||||||
|
src/Core/ Chain/ Crypto/ Wallet/ Spv/ Net/ Storage/ (no UI dependency)
|
||||||
|
src/App/ Avalonia GUI src/Cli/ CLI tests/ xUnit
|
||||||
|
```
|
||||||
|
|
||||||
|
**Non-negotiable dependency rule:** `App`/`Cli` depend only on `Core`; the UI goes through the wallet domain, never directly through network or cryptography. `Core` knows nothing about the UI.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
.NET 8 SDK lives in `~/.dotnet`: in non-interactive shells, before any `dotnet` command run
|
||||||
|
`export PATH="$HOME/.dotnet:$PATH" DOTNET_ROOT="$HOME/.dotnet"`.
|
||||||
|
|
||||||
|
- Build: `dotnet build`
|
||||||
|
- Tests (headless, the primary verification layer): `dotnet test` — single: `dotnet test --filter "FullyQualifiedName~TestName"`
|
||||||
|
- GUI hot reload: `dotnet watch --project src/App` (on WSL2/WSLg the window shows on the Windows desktop, no graphics dependencies to install)
|
||||||
|
- CLI: `dotnet run --project src/Cli -- <command>` (no args → usage)
|
||||||
|
- Windows publish: `dotnet publish src/App -r win-x64 -p:PublishSingleFile=true --self-contained`
|
||||||
|
- Linux publish: `dotnet publish src/App -r linux-x64 --self-contained` (then AppImage via PupNet Deploy)
|
||||||
|
|
||||||
|
**CLI** (`src/Cli`): `create`/`restore`/`restore-xpub`/`info`; `sync`/`send`/`servers`/`reset-certs` (`--server host:port [--ssl]`); `newseed`/`addresses`. Default wallet file `~/.palladium-wallet/<network>/wallets/default.wallet.json` (`--file` to change it).
|
||||||
|
|
||||||
|
## Architecture (points that require reading multiple files)
|
||||||
|
|
||||||
|
- **Layers (§2):** GUI → wallet domain → SPV/Sync → Network → Cryptography → Persistence; each layer depends only downward.
|
||||||
|
- **Network profile (§3):** all chain constants (address prefixes, BIP32 headers, bech32 HRP, genesis, ports, coin_type 746) **centralized in `Core/Chain`** (`ChainProfiles`/`PalladiumNetworks`), selectable per network (mainnet/testnet/regtest). No scattered magic numbers.
|
||||||
|
- **LWMA / skip PoW (§3, §7):** LWMA difficulty, 2-minute blocks; an SPV client cannot recompute it → `SkipPowValidation = true`, trust anchored to **hardcoded checkpoints** (§7.3). Custom layer: NBitcoin assumes Bitcoin's retargeting.
|
||||||
|
- **NBitcoin vs custom (§19.2):** NBitcoin covers the custom network, BIP32/39, addresses, transactions, PSBT, signing, encoding, hashing — **do not reimplement these**. Hand-written custom code: JSON-RPC client for the indexing server (ElectrumX-like, §10); SPV sync with Merkle verification (§7.4); header/checkpoint validation; coin selection and fee policy; versioned encrypted JSON wallet file.
|
||||||
|
- **PSBT-centric (§6.5):** every signing flow goes through PSBT (offline/air-gapped/multisig/hardware).
|
||||||
|
- **Ports:** 50001/50002 = indexing server (what the SPV wallet talks to), **not** the node's P2P port (2333).
|
||||||
|
|
||||||
|
## GUI conventions (`src/App`)
|
||||||
|
|
||||||
|
- **Single ViewModel** `MainWindowViewModel` (CommunityToolkit.Mvvm: `[ObservableProperty]`, `[RelayCommand]`); `Core` is driven directly from here.
|
||||||
|
- **In-app overlays, not OS windows:** details (address, transaction), settings, and help are full-screen `Border`s gated by an `IsXxxOpen` flag, not separate `Window`s — popups/top-levels are slow on WSLg. Pattern: bool property + Open/Close commands + backdrop handler and Esc key in `MainWindow`'s code-behind. Heavy network work runs off the UI thread (`Task.Run`) so the overlay never freezes.
|
||||||
|
- **Localization:** `Localization/Loc.cs`, key→6 languages dictionary (it/en/es/fr/pt/de); in XAML `{Binding Loc[key]}`, in C# `Loc.Tr("key")`. On language change the `Loc` instance is replaced.
|
||||||
|
- **App version:** single source = `<Version>` in `src/App/PalladiumWallet.App.csproj`; read at runtime (`MainWindowViewModel.AppVersion`) and shown in the title.
|
||||||
|
|
||||||
|
## Implementation state (§16 steps 1–7 + GUI)
|
||||||
|
|
||||||
|
`Core/Chain` network profiles; `Core/Crypto` BIP39/32/SLIP-132/`HdAccount`; `Core/Storage` JSON wallet v1 + AES-GCM (PBKDF2-SHA512) + data paths; `Core/Net` `ElectrumClient` (newline JSON-RPC over TCP/TLS, TOFU in `server-certs.json`, concurrent requests) + `ElectrumApi`; `Core/Spv` scripthash, mandatory Merkle verification on every confirmed tx, sync with gap limit; `Core/Wallet` `TransactionFactory` (RBF on, send-all, watch-only PSBT), `TransactionInspector` (tx detail from the server), `WalletLoader`. GUI: setup wizard, dashboard (history/send/receive with QR+copy/addresses/contacts), transaction detail, settings/server/help, multi-wallet.
|
||||||
|
|
||||||
|
**TODO (§16 steps 8–9):** multisig, hardware wallet, coin control UI, fee ETA/mempool, RBF/CPFP UI, on-disk header chain, multi-server pool, proxy/Tor.
|
||||||
|
|
||||||
|
## Working rules
|
||||||
|
|
||||||
|
- **Cross-implementation tests (§16):** compare addresses, txids, and PSBTs against a reference wallet (golden vectors). A different address or txid is a blocking bug.
|
||||||
|
- **Security (§17):** seed and private keys never in plaintext on disk/logs/network; every server response validated with Merkle + checkpoints; watch-only truly read-only.
|
||||||
|
- *(Optional)* blueprint features may be deferred but must still be considered in the design.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Davide Grilli
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
# Palladium Wallet
|
||||||
|
|
||||||
|
**An SPV desktop wallet built specifically for the Palladium (PLM) cryptocurrency** and optimized for its chain.
|
||||||
|
|
||||||
|
Unlike generic wallets adapted to many coins, Palladium Wallet is designed around Palladium's consensus parameters — a Bitcoin-derived UTXO chain with 2-minute blocks and LWMA difficulty — and centralizes them in a single network profile. This keeps it lightweight, predictable and faithful to the chain: no client-side difficulty recalculation (trust is anchored to hardcoded checkpoints), mandatory Merkle verification on every confirmed transaction, and a network client written specifically for Palladium's indexing server.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Lightweight SPV**: syncs against an indexing server (ElectrumX-like protocol) without downloading the full chain.
|
||||||
|
- **Security**: seed and private keys encrypted on disk (AES-GCM, PBKDF2-SHA512), never in plaintext in logs or on the wire; every server response is validated with Merkle proofs + checkpoints.
|
||||||
|
- **HD wallet** (BIP39/BIP32), SegWit/wrapped/legacy addresses, watch-only from xpub.
|
||||||
|
- **PSBT-centric**: signing flows go through PSBT (offline / air-gapped / multisig).
|
||||||
|
- **Multi-network**: mainnet, testnet, regtest.
|
||||||
|
- **GUI** (Avalonia) and **CLI** on the same core.
|
||||||
|
- **Multilingual**: Italian, English, Spanish, French, Portuguese, German.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
PalladiumWallet.sln
|
||||||
|
├─ src/Core/ Chain/ Crypto/ Wallet/ Spv/ Net/ Storage/ (no UI dependency)
|
||||||
|
├─ src/App/ Avalonia GUI
|
||||||
|
├─ src/Cli/ CLI on the same Core
|
||||||
|
└─ tests/ xUnit
|
||||||
|
```
|
||||||
|
|
||||||
|
Stack: **.NET 8 + Avalonia UI + NBitcoin**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development environment
|
||||||
|
|
||||||
|
You only need the **.NET 8 SDK**. The core and crypto are fully testable without the GUI or a real network.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
1. Install the .NET 8 SDK:
|
||||||
|
```powershell
|
||||||
|
winget install Microsoft.DotNet.SDK.8
|
||||||
|
```
|
||||||
|
(alternatively, the installer from <https://dotnet.microsoft.com/download/dotnet/8.0>)
|
||||||
|
2. Clone the repository and restore dependencies:
|
||||||
|
```powershell
|
||||||
|
git clone <repo-URL>
|
||||||
|
cd PalladiumWallet
|
||||||
|
dotnet restore
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
1. Install the .NET 8 SDK through your distro's package manager, or without root via the official script:
|
||||||
|
```bash
|
||||||
|
curl -sSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0
|
||||||
|
export PATH="$HOME/.dotnet:$PATH" DOTNET_ROOT="$HOME/.dotnet"
|
||||||
|
```
|
||||||
|
(add the two `export` lines to your `~/.bashrc` to make them permanent)
|
||||||
|
2. Clone and restore:
|
||||||
|
```bash
|
||||||
|
git clone <repo-URL>
|
||||||
|
cd PalladiumWallet
|
||||||
|
dotnet restore
|
||||||
|
```
|
||||||
|
|
||||||
|
> The GUI uses Avalonia, which runs natively on both platforms with no extra graphics dependencies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running it
|
||||||
|
|
||||||
|
**GUI** (with hot reload for development):
|
||||||
|
```bash
|
||||||
|
dotnet watch --project src/App
|
||||||
|
```
|
||||||
|
or a single run:
|
||||||
|
```bash
|
||||||
|
dotnet run --project src/App
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI** (same core, useful for scripts and headless environments):
|
||||||
|
```bash
|
||||||
|
dotnet run --project src/Cli -- <command>
|
||||||
|
```
|
||||||
|
Run without arguments for the full list of commands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
|
||||||
|
Tests are the **primary verification layer** — the core logic and crypto run headless, without the GUI or a real network.
|
||||||
|
|
||||||
|
Run the whole suite:
|
||||||
|
```bash
|
||||||
|
dotnet test
|
||||||
|
```
|
||||||
|
|
||||||
|
Run a single test (or a group) by name:
|
||||||
|
```bash
|
||||||
|
dotnet test --filter "FullyQualifiedName~TestName"
|
||||||
|
```
|
||||||
|
|
||||||
|
Run only the tests in one project:
|
||||||
|
```bash
|
||||||
|
dotnet test tests/PalladiumWallet.Tests
|
||||||
|
```
|
||||||
|
|
||||||
|
> Cross-implementation tests compare addresses, txids and PSBTs against reference golden vectors: a different address or txid is a blocking bug.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
**Development build:**
|
||||||
|
```bash
|
||||||
|
dotnet build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows publish** (single self-contained executable):
|
||||||
|
```bash
|
||||||
|
dotnet publish src/App -r win-x64 -p:PublishSingleFile=true --self-contained
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux publish** (self-contained; the AppImage is then produced with [PupNet Deploy](https://github.com/kuiperzone/PupNet-Deploy)):
|
||||||
|
```bash
|
||||||
|
dotnet publish src/App -r linux-x64 --self-contained
|
||||||
|
```
|
||||||
|
|
||||||
|
The application **version** is set in a single place: the `<Version>` tag in [`src/App/PalladiumWallet.App.csproj`](src/App/PalladiumWallet.App.csproj). It appears in the window title and is stamped into the published binaries.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## User guide (quick)
|
||||||
|
|
||||||
|
### First launch
|
||||||
|
1. On first launch, choose **where to store data** (wallet, configuration, certificates) — the default path or a folder of your choice.
|
||||||
|
2. Create a new wallet, restore from seed, or open an existing wallet.
|
||||||
|
3. If you create a wallet, **write the seed phrase down on paper**: it will not be shown again. You can protect the file with a password.
|
||||||
|
|
||||||
|
### Main tabs
|
||||||
|
- **History** — list of transactions. *Double-click* a row to open the full detail (amount, fee, addresses, sizes, confirmations).
|
||||||
|
- **Send** — recipient + amount (or "send all"), adjustable fee; for watch-only wallets a PSBT is produced to be signed offline.
|
||||||
|
- **Receive** — next unused address, with a **QR code** and a **Copy** button.
|
||||||
|
- **Addresses** — all derived addresses with balances; click for details (keys, derivation path).
|
||||||
|
- **Contacts** — address book with labels.
|
||||||
|
|
||||||
|
### Connection
|
||||||
|
- The status indicator at the bottom shows the connection to the **indexing server**; tapping it opens the server settings.
|
||||||
|
- Sync is SPV: it downloads only what concerns your wallet and verifies every confirmed transaction with a Merkle proof.
|
||||||
|
|
||||||
|
### Settings and Help
|
||||||
|
- **Settings**: language, display unit (PLM / mPLM / µPLM / sat), server.
|
||||||
|
- **Help**: software information and version.
|
||||||
|
|
||||||
|
### CLI in brief
|
||||||
|
```bash
|
||||||
|
# Wallet
|
||||||
|
dotnet run --project src/Cli -- create [--words 12|24] [--kind segwit|wrapped|legacy] [--net mainnet|testnet|regtest] [--password P]
|
||||||
|
dotnet run --project src/Cli -- restore "<mnemonic>" [...]
|
||||||
|
dotnet run --project src/Cli -- info [--net ...] [--password P]
|
||||||
|
|
||||||
|
# Network
|
||||||
|
dotnet run --project src/Cli -- sync [--server host[:port]] [--ssl]
|
||||||
|
dotnet run --project src/Cli -- send --to ADDRESS (--amount X | --all) [--feerate sat/vB] [--broadcast]
|
||||||
|
```
|
||||||
|
The default wallet file is `~/.palladium-wallet/<network>/wallets/default.wallet.json` (override with `--file`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Released under the MIT License. See the [LICENSE](LICENSE) file.
|
||||||
@@ -51,6 +51,15 @@ public sealed class Loc
|
|||||||
["menu.net.discover"] = ["Cerca altri server (peer)", "Discover servers (peers)", "Buscar otros servidores (peers)", "Rechercher d'autres serveurs (pairs)", "Procurar outros servidores (peers)", "Weitere Server suchen (Peers)"],
|
["menu.net.discover"] = ["Cerca altri server (peer)", "Discover servers (peers)", "Buscar otros servidores (peers)", "Rechercher d'autres serveurs (pairs)", "Procurar outros servidores (peers)", "Weitere Server suchen (Peers)"],
|
||||||
["menu.net.resetcerts"] = ["Reset certificati SSL", "Reset SSL certificates", "Restablecer certificados SSL", "Réinitialiser les certificats SSL", "Redefinir certificados SSL", "SSL-Zertifikate zurücksetzen"],
|
["menu.net.resetcerts"] = ["Reset certificati SSL", "Reset SSL certificates", "Restablecer certificados SSL", "Réinitialiser les certificats SSL", "Redefinir certificados SSL", "SSL-Zertifikate zurücksetzen"],
|
||||||
["menu.settings"] = ["_Impostazioni", "_Settings", "_Configuración", "_Paramètres", "_Configurações", "_Einstellungen"],
|
["menu.settings"] = ["_Impostazioni", "_Settings", "_Configuración", "_Paramètres", "_Configurações", "_Einstellungen"],
|
||||||
|
["menu.help"] = ["_Help", "_Help", "_Ayuda", "_Aide", "_Ajuda", "_Hilfe"],
|
||||||
|
["help.title"] = ["Informazioni sul software", "About this software", "Información del software", "À propos du logiciel", "Sobre o software", "Über die Software"],
|
||||||
|
["help.info"] = [
|
||||||
|
"Wallet SPV per la criptovaluta Palladium (PLM).",
|
||||||
|
"SPV wallet for the Palladium (PLM) cryptocurrency.",
|
||||||
|
"Monedero SPV para la criptomoneda Palladium (PLM).",
|
||||||
|
"Portefeuille SPV pour la cryptomonnaie Palladium (PLM).",
|
||||||
|
"Carteira SPV para a criptomoeda Palladium (PLM).",
|
||||||
|
"SPV-Wallet für die Kryptowährung Palladium (PLM)."],
|
||||||
["settings.unit.short"] = ["Unità", "Unit", "Unidad", "Unité", "Unidade", "Einheit"],
|
["settings.unit.short"] = ["Unità", "Unit", "Unidad", "Unité", "Unidade", "Einheit"],
|
||||||
|
|
||||||
// Wizard
|
// Wizard
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<!-- Versione dell'applicazione: unico punto da modificare. Compare nel
|
||||||
|
titolo della finestra ed è incisa nei binari pubblicati. -->
|
||||||
|
<Version>0.9.0</Version>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
<ApplicationIcon>Assets\logo.ico</ApplicationIcon>
|
<ApplicationIcon>Assets\logo.ico</ApplicationIcon>
|
||||||
|
|||||||
@@ -73,6 +73,15 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
private Loc _loc = Loc.Instance;
|
private Loc _loc = Loc.Instance;
|
||||||
public Loc Loc => _loc;
|
public Loc Loc => _loc;
|
||||||
|
|
||||||
|
/// <summary>Versione dell'app (da <Version> nel csproj), formato Major.Minor.Patch.</summary>
|
||||||
|
public static string AppVersion =>
|
||||||
|
typeof(MainWindowViewModel).Assembly.GetName().Version is { } v
|
||||||
|
? $"{v.Major}.{v.Minor}.{v.Build}"
|
||||||
|
: "";
|
||||||
|
|
||||||
|
/// <summary>Titolo della finestra con la versione, es. "Palladium Wallet 0.9.0".</summary>
|
||||||
|
public string WindowTitle => $"Palladium Wallet {AppVersion}";
|
||||||
|
|
||||||
/// <summary>Unità corrente per il campo importo del pannello Invia.</summary>
|
/// <summary>Unità corrente per il campo importo del pannello Invia.</summary>
|
||||||
public string UnitLabel => _config.Unit;
|
public string UnitLabel => _config.Unit;
|
||||||
|
|
||||||
@@ -309,6 +318,16 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void CloseSettings() => IsSettingsOpen = false;
|
private void CloseSettings() => IsSettingsOpen = false;
|
||||||
|
|
||||||
|
/// <summary>Overlay informazioni sul software (menu Help).</summary>
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isHelpOpen;
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void OpenHelp() => IsHelpOpen = true;
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void CloseHelp() => IsHelpOpen = false;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string connectionStatus = Loc.Tr("conn.none");
|
private string connectionStatus = Loc.Tr("conn.none");
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
x:DataType="vm:MainWindowViewModel"
|
x:DataType="vm:MainWindowViewModel"
|
||||||
Icon="/Assets/logo.ico"
|
Icon="/Assets/logo.ico"
|
||||||
Width="900" Height="620"
|
Width="900" Height="620"
|
||||||
Title="Palladium Wallet">
|
Title="{Binding WindowTitle}">
|
||||||
|
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<vm:MainWindowViewModel/>
|
<vm:MainWindowViewModel/>
|
||||||
@@ -28,6 +28,8 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="{Binding Loc[menu.settings]}"
|
<MenuItem Header="{Binding Loc[menu.settings]}"
|
||||||
Command="{Binding OpenSettingsCommand}"/>
|
Command="{Binding OpenSettingsCommand}"/>
|
||||||
|
<MenuItem Header="{Binding Loc[menu.help]}"
|
||||||
|
Command="{Binding OpenHelpCommand}"/>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<!-- ============ WIZARD DI SETUP (§15): un passo alla volta ============ -->
|
<!-- ============ WIZARD DI SETUP (§15): un passo alla volta ============ -->
|
||||||
@@ -714,5 +716,33 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- ============ OVERLAY HELP / INFORMAZIONI ============ -->
|
||||||
|
<!-- Stesso pattern dell'overlay impostazioni: apertura/chiusura istantanee. -->
|
||||||
|
<Border Grid.Row="0" Grid.RowSpan="3"
|
||||||
|
Background="#99000000"
|
||||||
|
Tapped="OnHelpOverlayBackdropTapped"
|
||||||
|
IsVisible="{Binding IsHelpOpen}">
|
||||||
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumLowBrush}"
|
||||||
|
BorderBrush="Gray" BorderThickness="1" CornerRadius="8"
|
||||||
|
Width="460"
|
||||||
|
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="Gray"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Text="{Binding Loc[help.info]}" TextWrapping="Wrap"/>
|
||||||
|
|
||||||
|
<Button Content="{Binding Loc[addr.close]}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Command="{Binding CloseHelpCommand}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -128,6 +128,13 @@ public partial class MainWindow : Window
|
|||||||
vm.IsSettingsOpen = false;
|
vm.IsSettingsOpen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnHelpOverlayBackdropTapped(object? sender, TappedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!ReferenceEquals(e.Source, sender)) return;
|
||||||
|
if (DataContext is MainWindowViewModel vm)
|
||||||
|
vm.IsHelpOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnKeyDown(KeyEventArgs e)
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Escape && DataContext is MainWindowViewModel vm)
|
if (e.Key == Key.Escape && DataContext is MainWindowViewModel vm)
|
||||||
@@ -136,6 +143,7 @@ public partial class MainWindow : Window
|
|||||||
if (vm.AddressInfo is not null) { vm.AddressInfo = null; e.Handled = true; return; }
|
if (vm.AddressInfo is not null) { vm.AddressInfo = null; e.Handled = true; return; }
|
||||||
if (vm.IsServerSettingsOpen) { vm.IsServerSettingsOpen = false; e.Handled = true; return; }
|
if (vm.IsServerSettingsOpen) { vm.IsServerSettingsOpen = false; e.Handled = true; return; }
|
||||||
if (vm.IsSettingsOpen) { vm.IsSettingsOpen = false; e.Handled = true; return; }
|
if (vm.IsSettingsOpen) { vm.IsSettingsOpen = false; e.Handled = true; return; }
|
||||||
|
if (vm.IsHelpOpen) { vm.IsHelpOpen = false; e.Handled = true; return; }
|
||||||
}
|
}
|
||||||
base.OnKeyDown(e);
|
base.OnKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user