Commit Graph

21 Commits

Author SHA1 Message Date
8290e96ec4 test(sweep): add modal-pin-setup/-change/-remove capture surfaces
Register the three redesigned PIN dialogs as sweep surfaces for visual review.
Each setup only sets the show flag (never fires the async vault store/verify); the
teardown clears the status and zeroes the PIN/passphrase buffers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:29:02 -05:00
5bd07b0505 test(sweep): add modal-decrypt capture surface
Register the redesigned "Remove Wallet Encryption" dialog as a sweep surface so
its passphrase-entry phase is captured for visual review. The setup resets the
WalletSecurityWorkflow (keeping it in PassphraseEntry) and never fires the async
unlock/export/restart pyramid; the teardown resets and zeroes decrypt_pass_buf_.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:02:11 -05:00
5985f05fb2 test(sweep): add modal-encrypt & modal-change-passphrase capture surfaces
The redesigned settings-tab Encrypt Wallet and Change Passphrase dialogs had no
sweep surfaces, so the full UI sweep only captured the first-run wizard-encrypt /
wizard-pin variants — the settings modals were never rendered for visual review.
Register modal-encrypt (redesigned passphrase-entry phase) and
modal-change-passphrase, each with a defensive teardown that resets the phase and
zeroes the passphrase buffers. Neither setup path fires the async encrypt/change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 11:31:31 -05:00
63d5c817aa chore(sweep): add modal-bootstrap surface for the standalone bootstrap dialog
The settings-triggered BootstrapDownloadDialog wasn't captured (only the wizard's
bootstrap page was). Add BootstrapDownloadDialog::hide() + a modal-bootstrap sweep
surface (opens the confirm screen) so the migrated dialog is verifiable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 22:37:26 -05:00
822891d4ef feat(settings): migrate Export All Keys modal to the reference design
Phase 1. DialogWarningHeader care header (was a hand-rolled red icon+text);
centered DialogActionFooter (Export + Close) replacing the StyledButtons + two
separators; on full success the saved path shows in a copy field with a green
check, partial/error render inline; export progress uses LoadingDots. Full i18n:
the previously-hardcoded notification + status strings now use TR (8 new
export_keys_* keys in en + 8 langs). Added hide() + a modal-export-all-keys sweep
surface. Also fixes a latent Begin/EndOverlayDialog imbalance on the 0-address
early return. No change to the export RPC logic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 21:43:53 -05:00
bf81ec1702 feat(settings): migrate Export-Transactions-CSV modal to the reference design
Phase 1 (first modal). Bring the CSV export dialog onto the key-import reference:
- Struct-form OverlayDialogSpec / BlurFloat (was the legacy positional overload).
- material::DialogActionFooter (centered TactileButton pair) replacing the
  StyledButtons + the two ImGui::Separators.
- Full i18n: TR("close") and the success/error status now via TR (were hardcoded
  English); on success the saved path shows in a widgets::AddressCopyField with a
  green check.
- Add ExportTransactionsDialog::hide() + a modal-export-transactions sweep surface
  so the dialog is captured (it wasn't before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 21:22:41 -05:00
f428292ea4 feat(settings): split import into separate key + viewing-key buttons
Backup & Data now has two distinct import actions instead of one
auto-detecting dialog:

- "Import Key" imports a spending key (transparent WIF or shielded
  z-spending key) with the strong "grants access to funds" warning.
- "Import Viewing Key" imports a watch-only shielded viewing key
  (zxviews…) with a milder eye/watch-only note and an optional
  "scan from block height" field — z_importviewingkey accepts a start
  height, so watching a recent address needn't rescan the whole chain.

The shared Material dialog (renderImportKeyDialog) branches on
import_view_mode_: title, warning tone, field label, the live type
indicator, and the recognition guard. A key valid for the *other*
button (e.g. a spending key pasted into the viewing-key dialog) now
shows a redirect hint rather than a generic "unrecognized" error.

importPrivateKey gains a startHeight arg, appended to the shielded
import RPCs (z_importviewingkey / z_importkey) and ignored for
transparent WIF (importprivkey has no start-height param). The
scan-height buffer is wiped on open/close alongside the key buffer.

i18n: 9 new keys (button label + tooltip, viewing title/note/field,
scan label/hint, two wrong-type redirect hints) with translations for
all 8 languages; CJK subset rebuilt (+1 glyph). A modal-import-viewkey
sweep surface is added for the viewing-mode dialog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:53:35 -05:00
46fb0029b8 feat(settings): gate debug options behind a confirmation (+ re-auth if secured)
Revealing the DEBUG OPTIONS dropdown now opens a confirmation modal with a
warning instead of expanding directly. If the wallet is secured, it also requires
re-authentication before the options appear:
- a quick-unlock PIN → verified against the vault (Argon2id derive, off-thread,
  no wallet side effects);
- otherwise an encrypted wallet → the passphrase, verified via walletpassphrase.
Unsecured wallets just confirm. Collapsing needs no gate; each expand re-gates.

App gains debugGateRequiresAuth() + verifyDebugCredential() (cb on the main
thread; secrets wiped). Adds a modal-debug-gate sweep surface. Verified 100% +
150%, dark + light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 18:46:50 -05:00
aa587d1d84 feat(seed): glow the Migrate-to-seed button for a legacy wallet
A pre-seed-phrase (legacy, non-mnemonic) wallet is exactly the one that benefits
from migrating — so nudge the user by glowing the Settings "Migrate to seed"
button with a soft pulsing accent halo.

Adds a cached wallet mnemonic status (probeWalletSeedStatus), classified once per
connect via z_exportmnemonic (the same signal the migration Intro pre-flight
uses): NoMnemonic = legacy → glow; HasMnemonic / Incapable (old daemon) / while
locked or on lite = no glow. Reset on disconnect so it re-probes after a wallet
switch or a post-migration adopt, with a small attempt cap to avoid re-probing on
a persistent transient error. The sweep forces the status so the glow is
captured (restored after). Verified dark + light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 18:24:41 -05:00
3a9edf2200 feat(xmrig-update): two-pane version picker matching the node updater
Bring the miner (DRG-XMRig) updater to the same design as the daemon updater:
two-pane layout with tactile version cards (text label + right-aligned icon
badge: installed check / pre-release flask / newest new-releases, hover-only
tooltips) on the left, and the selected version's detail on the right — a unified
rounded info surface holding the version header + markdown-rendered release notes,
with the verify note and a centered, text-fit install button below it, and a
larger Close in the footer.

Fetches the full release list up front; Downloading/Done/Failed render in the
right pane. Preserves the miner specifics: installs are refused while the miner
is running (button disabled + a stop-mining note), and the installed tag is
persisted via setXmrigVersion on success. Adds a modal-xmrig-update sweep surface
(fake releases). Verified 100% + 150%, dark + light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 17:56:59 -05:00
6b7438b529 feat(daemon-update): render release notes as markdown + tactile Material cards
Refine the two-pane node updater:
- Release notes now render as in-app markdown (new src/ui/material/markdown.h):
  # / ## / ### headings, **bold**, `inline code` (tinted + subtle pill), and
  - / * / + bullets, word-wrapped with mixed fonts via the draw list. cleanNotes
  keeps the markdown now (only the trailing checksum table is cut), so the
  renderer styles it.
- Each version is a tactile Material card — filled rounded surface with
  hover/press/selected states (primary-tinted + outlined when selected), a
  rounded status accent bar, tag + latest/installed/pre-release badges + date —
  instead of a plain Selectable row.
- Dropped the thin 1px outlines: the version list is borderless and the notes
  sit on a filled, rounded Material surface.

The sweep's fake release body gains bold/code/multi-heading markdown to exercise
the renderer. Verified 100% + 150%, dark + light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 16:44:25 -05:00
c6624913de feat(daemon-update): two-pane version picker (versions left, detail right)
Redesign the Update Node dialog to mirror the Manage-Portfolio editor: the list
of node versions on the LEFT (with latest / installed / pre-release badges +
date), the selected version's detail on the RIGHT — status vs installed, release
notes (checksum table + markdown heading markers stripped), the verify/downgrade
note, and the install action (Download & install / Install this version /
Reinstall). One Close in the footer.

The dialog now fetches the full release list up front (startListReleases) so the
picker is populated immediately; Downloading/Verifying/Done/Failed render in the
right pane with the list still visible. Layout is GetContentRegionAvail-based so
it adapts to a viewport-capped card (verified 100% + 150%, dark + light).

Adds a sweep seam (sweepSeed/sweepClose) + a modal-daemon-update sweep surface
seeded with fake releases for offline visual verification. Adversarially
reviewed (3 lenses); fixed the real findings — live list was never populated
from getReleases() (only the sweep seeded it), defensive s_rows bounds in the
detail pane, notes box dropped when the pane is too short so the install button
stays visible, and a badge-overrun guard for long tags. DPI "findings" were the
recurring false positives (LegacySize/spacing/GetFrameHeight are all dp-scaled).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 16:28:33 -05:00
3df516be70 fix(wallets): cap card at viewport + flex list so many wallets never clip
The wallets dialog hand-computed a content-sized card height. With many wallets
on a small / HiDPI (150%) window the computed height could exceed the viewport,
and the framework clips a too-tall card — footer and all.

Cap the card at 0.86 of the viewport height. When capped, the wallet list flexes
to the space left above the create/scan/footer controls and scrolls internally,
so those controls stay pinned and visible; uncapped (the common case, few
wallets) nothing changes and there's no spurious scrollbar. Add a
modal-wallets-many sweep surface (8 wallets, self-cleaning teardown) to exercise
the capped-scroll path. Verified at 100% + 150%.

This is the one real fixed-height clip risk from the modal audit; the other 44
modals use auto-height (grow-to-fit, capped at a viewport ratio) and were
confirmed non-clipping — e.g. the 24-word seed-backup grid renders fully at 150%
in a 720px window.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 14:47:59 -05:00
06c8b99bce feat(wallets): in-app folder picker + roomier, full-width list controls
Wallets dialog refinements:
- More space between wallet cards (cardGap: spacingSm -> spacingMd).
- "Scan another folder" is now always visible as a full-width button (no
  expandable toggle) that opens the new picker.
- The Create-wallet row and the scan button span the full list width, so their
  right edges align with the wallet cards / Open|Import buttons.

New in-app folder picker (folder_picker.h): a Material-styled modal replacing
the raw path input. Browse the filesystem (Up / Home / click a sub-folder),
see the *.dat wallet files present + a count, and pick a folder to scan. The
picker takes over the modal surface while open (the overlay framework doesn't
nest); it remembers the last browsed location across opens. Fixed-height card
(no auto-height feedback), UTF-8-aware truncation, full-node icons confirmed
in the embedded MaterialIcons range. Added a modal-folder-picker sweep surface;
verified at 100% + 150%, dark + light.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 14:11:39 -05:00
13ff20d791 fix(ui): console-commands modal slide + wallets footer clipping
Two follow-ups to the modal float work:

- Console RPC command reference (renderCommandsPopup) had the SAME auto-height
  feedback bug as Wallets: BlurFloat with no cardHeight, and its fill-height
  command list read GetContentRegionAvail() inside the AutoResizeY child ->
  self-referential, sliding content off-screen after a monitor move. Give it a
  FIXED viewport-relative cardHeight (fills ~84% of the viewport). Also removed
  its duplicate body H6 heading (the framework h6 title already shows it) —
  missed earlier because it's spec-form, not the positional overload.

- Wallets footer clipping: after the fixed-height conversion the content child
  clips overflow (NoScrollbar), and the hardcoded 130*dp reserve below the table
  was too small for the create/add-folder rows + separator + footer (~160*dp),
  so the buttons clipped — worse at 150%. Compute the reserve from real widget
  metrics (GetFrameHeightWithSpacing + caption height) so it holds at any DPI.

Added a modal-console-commands sweep surface (debug-gated ConsoleTab setter) so
the popup is captured. Verified both at 100% and font_scale 1.5 (150%): footers
on-screen, single headings, lists fill, nothing clipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 22:40:26 -05:00
8846a96e3d fix(sweep): flush leaked ImGui popup so scroll survives the full UI sweep
The send-confirm surface renders via RenderSendConfirmPopup, which calls
ImGui::OpenPopup() every frame — but BeginOverlayDialog is a plain window,
so that popup is never consumed by a BeginPopup and is normally cleared
only when a mouse click triggers ImGui's click-to-dismiss. The headless
sweep never clicks and tears the surface down by just clearing its flag,
so the orphaned popup lingered on OpenPopupStack past the end of the sweep.

A stuck popup makes IsPopupOpen(AnyPopup) permanently true, which disables
the smooth-scroll wheel capture in draw_helpers::ApplySmoothScroll — so
after a sweep the mouse wheel stopped scrolling Settings / Explorer /
Console (the tabs that use ApplySmoothScroll; native-scroll tabs were
unaffected).

Flush any lingering popup (ClosePopupToLevel) right after each surface's
teardown, so it can't bleed into the next capture or survive the sweep.
Confirmed via instrumentation: only 'popup-send-confirm' leaked (stack=1,
once per skin); now flushed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 20:03:56 -05:00
5db7941fbc feat(market): portfolio row-style redesign + per-wallet scope
Replace the drag/resize dashboard grid on the Market tab's portfolio with
three full-width row styles — compact (single-line), detailed (two-line),
and value-hero — cycled with Left/Right arrows like the Overview layouts.
Rows live in an internal scroll region bounded to the portfolio's height
budget, so the section stays put as groups are added.

- pfDrawRow renders each group in the selected style, reusing the icon /
  value / DRGX / 24h / sparkline pieces; per-entry field toggles honored.
- portfolio_style setting (0/1/2) persisted; arrow-key switcher + toast.
- Portfolio groups gain a per-wallet scope: new groups default to the
  active wallet's identity hash; legacy groups (empty scope) stay visible
  in every wallet. Scope filter drives both the height budget and the rows.
- Remove the now-dead grid machinery (mktDrawCard, pfComputeGridLayout,
  PfCell, PfGridDrag, MktCardCtx + MktCtx grid fields) — net code drop.
- Full UI sweep: seed demo portfolio groups + wavy price history and add
  market-rows-{compact,detailed,featured} surfaces so the styles are
  captured per skin (snapshot/restore the real portfolio + market data).
- i18n: portfolio_style_{label,compact,detailed,featured} + 8 langs; CJK
  subset rebuilt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 19:03:07 -05:00
d23ee9b75f feat(wallet): new/import wallets + multi-wallet i18n (P3)
Completes the wallet-files dialog and localizes the feature.

- Create a new wallet: a name is normalized to wallet-<name>.dat and opened
  via switchToWallet; the daemon mints it (seed-backed, -usemnemonic=1) on
  first load. Rejects blank names + name collisions.
- Import: out-of-datadir wallets get an Import action that copies the file
  into the datadir (never overwriting) under a wallet-*.dat name, then opens
  it — the daemon only loads plain filenames from the datadir.
- i18n: the 32 new multi-wallet / per-wallet-contacts / mining-payout strings
  translated into all 8 languages (de/es/fr/ja/ko/pt/ru/zh), CJK subset font
  rebuilt. Verified: the Chinese Wallets dialog renders with no missing glyphs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 17:54:29 -05:00
e8a8ce68b2 feat(wallet): wallet-files list + switching (P2)
Second phase of multi-wallet: list wallet files and switch the active one.

- Daemon plumbing: EmbeddedDaemon::setWalletFile -> start() passes -wallet=<name>
  (non-default only; skipped during the isolated seed-migration start), and
  DaemonController::syncSettings pushes active_wallet_file on each start.
- App::switchToWallet: persist the new active wallet, then stop + restart the
  node on -wallet=<name> (rescan only if it was never synced in this datadir).
  Reuses the seed-adopt restart coordination; WalletState clears on disconnect
  and the P1 identity-scoped caches re-key, so no previous-wallet data leaks.
  Guarded: full-node, embedded daemon, not mid-restart, no pending send.
- Wallets dialog (Settings -> Backup & Data -> "Wallets…"): a table of wallet
  files (datadir wallet*.dat + user-added folders' *.dat) with size (disk) and
  cached balance / address count / last-opened (wallet index), a current/Active
  badge, Open (switch), and Add folder. Out-of-datadir wallets show "import to
  open" (P3). Added as a sweep surface.
- Mining payout safety: non-destructive warning if the pool-mode worker looks
  like a DragonX address not in the current wallet (stale after a switch).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 16:20:41 -05:00
82e61da62f feat(migrate): daemon-update prompt + migrate-to-seed UX polish + i18n
Fixes the Windows migrate-to-seed failure (the old bundled daemon lacked
z_exportmnemonic) and rounds out the flow:

- seed_wallet_creator: actionable "daemon too old" message instead of the
  raw "Method not found" RPC error.
- Startup daemon-update prompt: if the wallet bundles a newer node than the
  installed one, offer to update it (once per version, keyed on a new
  daemon_update_prompted_size setting; never silently clobbers a custom
  node). "Install bundled" now also works when attached to an external /
  leftover daemon (RPC-stops it, then swaps + restarts).
- Migrate-to-seed Intro pre-flight: detect an already-mnemonic wallet
  (offer backup instead), an old daemon, or a locked/disconnected wallet
  before offering to create anything.
- No-funds path: a zero-balance wallet can adopt the new seed wallet
  directly (behind an acknowledgement checkbox) instead of a dead sweep.
- Loading spinners on the Working/Sweeping/Adopting steps; sweep coverage
  for the new intro / no-funds surfaces.
- Translations for all 18 new strings across 8 languages (+ rebuilt CJK
  subset font).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 22:16:47 -05:00
a86cb8f0f3 feat(debug): full UI screenshot sweep — captures modals/dialogs/flows/states
The existing sweep only captures tabs. This adds a "Full UI sweep" (DEBUG
OPTIONS) that also drives every normally-hidden surface into view and captures
it under every skin, so all the UI a normal sweep misses can be reviewed at
once.

- The capture unit becomes a "surface" (SweepTarget: a base tab, optionally
  with a setup()/teardown() that forces a modal / multi-step flow / state
  overlay on top). Tabs are surfaces with a null setup. The existing tab sweep
  is folded into the same state machine (one code path). All sweep logic +
  the catalog + demo data move into a new src/app_sweep.cpp.
- Runs OFFLINE against injected demo data (installDemoWalletData snapshots then
  restores the real state_ — WalletState isn't copy-assignable, so a targeted
  field snapshot is used) and fires NO live op: capture_mode_ guards the
  seed-backup RPC, auto-lock, and the migration pumps; the async-firing dialogs
  are neutralized by pre-setting their state (fetch_started_ + demo phrase;
  seed_migration_step_ set directly). Verified: 0 RPC/secret/send calls.
- Catalog (v1): tabs + the bool-flag modals (import/export key, backup,
  seed-backup, about, settings) + the 6 migrate-to-seed steps + 4 wizard steps
  + lock/warmup/not-ready overlays + the send-confirm popup (via a new
  ui::SweepShowSendConfirm debug hook, since its state is send_tab-static).
- Overlay/blur surfaces settle 8 frames (blur backdrop freeze); setup re-runs
  each frame (OpenPopup popups must re-fire). updateScreenshotSweep now runs
  before the first-run-wizard early-return in render() so the sweep advances
  while a wizard step is shown. main.cpp drops vsync during a sweep so it isn't
  throttled to the compositor's unfocused rate. Output:
  <config>/screenshots-full/<surface>/<skin>.png + index.md.
- DRAGONX_FULL_SWEEP=1 runs the sweep headlessly then quits (CI / verification).

Verified end-to-end under WSLg: 288 PNGs (9 skins x 32 surfaces), all 1200x720,
[Sweep] done, clean quit, no daemon. Byte-identity across runs holds only for
static skins on data-free surfaces — the rest vary by animated theme effects /
live price / relative timestamps (expected for a review tool, not a bug).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:57:54 -05:00