Commit Graph

51 Commits

Author SHA1 Message Date
1b3446e43c feat(contacts): richer edit-dialog avatar picker (preview, chips, image, icons)
Four refinements now that the two-column layout has room:

1. Image mode shows a large circular preview of the chosen picture (or a
   placeholder circle with an add-photo glyph, or a broken-image glyph if the
   file went missing), the filename, and centered Choose/Remove buttons —
   instead of a bare button.
2. The live-preview avatar is larger (r20 → r26) and the address is now
   middle-truncated (head + tail) so both ends read, like the real list row.
3. Badge mode shows the two actual chips — Z (shielded) and T (transparent) —
   with labels, making clear the badge is auto-picked from the address type,
   rather than a line of text.
4. The Badge/Icon/Image segmented control gains glyphs (badge / palette /
   image) beside its labels via a small two-font inline control (the shared
   SegmentedControl helper is single-font).

Adds contact_avatar_shielded / _transparent keys and rewords the badge hint
(the chips now carry the Z/T meaning); +8-language translations, all within
the existing CJK subset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 08:07:07 -05:00
2d4ba89c00 feat(contacts): revamp edit dialog with live preview + avatar picker
Rebuild the add/edit contact dialog on the portfolio-editor design language:

- A live preview card at the top shows the contact exactly as it renders in the
  list (avatar + name + address), updating as you type and pick an avatar.
- An avatar picker (Badge / Icon / Image segmented control) lets you keep the
  default Z/T type badge, choose a Material wallet icon from a searchable grid,
  or set a custom image. The picker area is fixed-height so the modal doesn't
  jump when switching modes.
- Custom images go through a new in-app ImagePicker (image_picker.h): a
  Material overlay that browses the filesystem starting at the user's Pictures
  folder, shows a thumbnail grid (decoded to raw pixels, box-downscaled to a
  small texture, cached per directory and freed on navigate/close, budgeted a
  few decodes per frame so large folders don't hitch), and returns the chosen
  path. The chosen image is copied into <config>/contact-avatars/ (named by an
  FNV hash of the source path, so re-picking is idempotent) and stored as
  "img:<path>". Like FolderPicker, it takes over the modal surface while open.
- Paste is now available on both add and edit; buttons are content-sized.

Adds three sweep surfaces (contacts-edit-{icon,badge,image}) that open the
dialog on a seeded contact in each avatar mode, plus i18n keys (+ 8-language
translations; reworded two zh/ja strings to stay within the existing CJK
subset, so no font rebuild).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 07:10:00 -05:00
1b0006a4af fix(contacts): audit fixes — clip, tofu badge, plural, DPI, columns, toolbar
Address the confirmed findings from a workflow audit of the Contacts tab body:

- Label clip: the Label column was WidthFixed 150px and clipped long labels
  mid-word ("drgx pool payout a…"). Make all three columns WidthStretch (label 1.5,
  address 2.6, notes 1.0) so the label grows with the tab and the notes column no
  longer reserves a fixed empty block on the right (notes = low weight, per request).
- Globe badge tofu: the global-contact ICON_MD_PUBLIC badge was drawn with the text
  font (no Material glyphs) → rendered as "?". Push Type().iconSmall() around it.
- Plural: "1 addresses saved" -> add address_book_count_one ("%zu address saved",
  8 langs, %zu kept so the format signature matches) and branch on count == 1.
- DPI: the SameLine badge gaps (6/8px) and the table-height floor (120px) are now
  * Layout::dpiScale(); the WidthStretch columns are relative so need no scaling.
- Toolbar: give the four actions leading Material icons (person-add / edit / delete /
  content-copy) and accent the primary "Add New" — via a small local icon+label
  tactile-button helper (ImGui has no two-font button), icons inherit the
  disabled-aware text alpha so they gray out with BeginDisabled().

Build + ctest + hygiene clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:49:15 -05:00
ca65aa8bf7 feat(send): migrate the Shield/Merge modal to the reference design
Presentation-only migration of ShieldDialog::render (Shield coinbase / Merge funds)
— a fund-moving modal:
- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth win.width,
  idSuffix shielddialog}) replacing the legacy positional overload
- drop the description divider and the form->footer divider (keep the post-submit
  operation-id section divider)
- 3 StyledButton -> TactileButton (submit / cancel / check-status)
- TR() the hardcoded "No shielded (z) address yet …" note -> new shield_no_zaddr_hint
  key, 8 langs (em-dash preserved); the "DRGX" ticker stays hardcoded per convention

The fund path is byte-for-byte unchanged: the can_submit guard, fee/utxo clamps, the
"ANY_TADDR" setup, the z_shieldcoinbase / z_mergetoaddress worker->post calls + their
opid/status/Notifications/trackOperation callbacks, and the BeginDisabled/tooltip logic.

Verified: build + ctest + hygiene clean; a 2-lens adversarial review
(fund-path-untouched / presentation-i18n) returned zero findings, proving the fund
path diffs byte-for-byte identical to HEAD via isolation diffs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 18:03:54 -05:00
dae677acd8 feat(send): migrate the Confirm-Send modal to the reference design
Presentation-only migration of RenderSendConfirmPopup (the confirm-before-broadcast
popup) — a fund-moving modal:
- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth popupW,
  idSuffix confirmsend}) replacing the legacy positional overload; p_open stays
  nullptr (the popup keeps its own Escape + Cancel handling)
- TR() the one hardcoded status string in the synchronous live-revalidation guard
  ("Cannot send now …") -> new send_cannot_send_now key, 8 langs (em-dash preserved)

The fund path is byte-for-byte unchanged: the live re-validation guard, the
app->sendTransaction call + its success/failure callback, the lite-locked
requestLiteUnlock branch, the s_sending/s_show_confirm state, the Escape handler,
and the FROM/TO cards + fee-tier/summary rendering.

Verified: build + ctest + hygiene clean; a 2-lens adversarial review
(fund-path-untouched / ui-i18n) returned zero findings, with the fund-path lens
proving the send path diffs byte-for-byte identical to HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 17:58:11 -05:00
abbdf3f4f7 feat(mining): migrate the Windows Defender antivirus-help dialog to reference design
Bring renderAntivirusHelpDialog onto the reference design and remove its hardcoded
English (the last Wave-1 modal):
- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth 560,
  idSuffix antivirus}) replacing the legacy positional overload
- the hardcoded "Windows Defender Blocked Miner" title and all 10 step/intro/bullet
  strings -> TR() (11 new av_* keys + reuse `close`; 8-lang translations, Windows
  env vars / xmrig.exe kept literal, menu names localized)
- 2 StyledButton -> TactileButton, drop the footer divider, dp-scale the button widths
- CJK subset rebuilt (glyphs 1741->1751; kept — new glyphs are used)

NOTE: this dialog is inside #ifdef _WIN32, so the Linux build compiles it out and
cannot verify it — needs a Windows build to compile-check. The edits mirror the
already-verified daemon-update-prompt / migrate-to-seed struct-overlay pattern and
leave the ShellExecuteA call untouched. i18n.cpp + the daemon prompt (cross-platform)
build + ctest + hygiene clean on Linux.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 16:38:07 -05:00
28288d7197 feat(ui): migrate Explorer detail/loading + daemon-update prompt to reference design
Presentation-only reference-design migration:
- Explorer loading modal -> struct-form overlay (idSuffix explorerloading); block-
  detail modal loses its header divider; the search button + the prev/next nav
  become TactileButton; TR() the hardcoded "Previous block"/"Next block" tooltips,
  "TxID:", and the "shielded" output fallback (3 new explorer_* keys + reuse the
  existing `shielded` key), all 8 langs. Block-fetch RPC path untouched.
- Daemon-update startup prompt -> struct-form overlay (idSuffix daemonupdprompt),
  2 StyledButton -> TactileButton, drop the footer divider. The reinstall/
  prompted-size persistence logic is unchanged.

Build + ctest + hygiene clean; "DRGX" ticker left hardcoded per convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 16:33:52 -05:00
46f7da4fac feat(settings): redesign the PIN setup/change/remove modals onto reference design
Migrate the three PIN dialogs in App::renderPinDialogs (Set PIN / Change PIN /
Remove PIN) onto the settings-modal reference design — presentation-only, plus a
deliberate secret-hygiene addition:

- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth 420/420/400,
  idSuffix pinsetup/pinchange/pinremove}) replacing the legacy positional overload
- drop each dialog's redundant post-description Separator
- every rendered-chrome string -> TR(): titles/buttons reuse settings_set_pin /
  settings_change_pin / settings_remove_pin, the Set-PIN confirm reuses
  wiz_pin_confirm; 7 new pin_* keys added to the English source + all 8
  res/lang/*.json additively; ImGui::Text -> TextUnformatted for labels
- HARDENING: wipe the passphrase/PIN input buffers on BlurFloat dismiss
  (X/Esc/outside-click) for all three dialogs. Set PIN's wallet-passphrase buffer
  (pin_passphrase_buf_) was previously left resident on dismiss; it is now zeroed.

The vault/RPC path is byte-for-byte unchanged: the submit-time memsets, the
walletpassphrase/walletlock RPCs, vault_->store/changePin/retrieve/removeVault,
SecureVault::secureZero, and setPinEnabled/save are untouched. The pin_status_ and
toast strings inside the worker callbacks are left in English (a separate
service-layer i18n pass), to avoid editing the secret path.

Verified: build + ctest + hygiene clean; i18n complete in 8 langs with no format
specifiers; a 3-lens adversarial review (secret-hygiene / presentation-only /
ui-i18n) returned zero findings, with the presentation lens proving the vault path
diffs byte-for-byte identical against HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:29:02 -05:00
90df19b8b6 feat(settings): redesign the remove-encryption (decrypt) modal onto reference design
Migrate App::renderDecryptWalletDialog ("Remove Wallet Encryption") onto the
settings-modal reference design — presentation-only for a fund-critical dialog,
plus one deliberate secret-hygiene addition:

- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth 480,
  idSuffix "decrypt"}) replacing the legacy positional overload
- Phase 0 amber TextWrapped warning -> material::DialogWarningHeader(decrypt_warning)
- drop the redundant Phase 0 Separator
- every rendered-chrome string across all 4 phases (PassphraseEntry / Working /
  Success / Error) -> TR() (14 new decrypt_*/try_again keys added to the English
  source + all 8 res/lang/*.json additively; the button reuses
  settings_remove_encryption, the label reuses change_pass_current, cancel/close reused)
- HARDENING: wipe decrypt_pass_buf_ on BlurFloat dismiss (X/Esc/outside-click),
  mirroring the change-passphrase fix; canClose() gates pOpen so this cannot fire
  during the Working phase

The fund-moving async worker pyramid (unlock -> export -> stop -> backup ->
restart -> re-import, vault/PIN cleanup) is byte-for-byte unchanged; the three
in-worker toast notifications and the "Incorrect passphrase" status are left in
English to avoid touching the fund path (a separate service-layer i18n pass).

Verified: build + ctest + hygiene clean; i18n complete in 8 langs with no format
specifiers and the wallet.dat.encrypted.bak literal preserved; a 3-lens adversarial
review (secret-hygiene / fund-path-untouched / ui-i18n) returned zero findings, with
the fund-path lens proving the async pyramid diffs IDENTICAL against HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:02:11 -05:00
625df8abe6 feat(settings): redesign encrypt & change-passphrase modals onto reference design
Migrate the Encrypt Wallet (3-phase) and Change Passphrase dialogs in
renderEncryptWalletDialog onto the settings-modal reference design —
presentation-only, no change to the crypto/state-machine/secret-wipe logic:

- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth, idSuffix})
  replacing the legacy positional overload (same visual style, dp-scaled width)
- amber TextWrapped warning -> material::DialogWarningHeader(wiz_encrypt_warning)
- drop redundant Separator dividers
- every hardcoded English string -> TR() (13 new enc_*/change_pass_* keys added to
  the English source + all 8 res/lang/*.json additively; CJK subset rebuilt)

The strength-meter math, 3-phase transitions, "cannot close while encrypting"
guard, memset/SecureVault buffer wipes, and the encrypt/changePassphrase/vault
async paths are byte-for-byte unchanged. Verified: build + ctest + hygiene clean,
wiz_strength %s format-string safe across all languages, and a 3-lens adversarial
review (secret-hygiene / presentation-only / ui-i18n) returned zero findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 11:13:44 -05:00
8a30578872 feat(settings): migrate Export Private Key modal + fix outside-click secret leak
Phase 2 (first security modal), presentation-only + the review's one finding.

Migration: struct-form BlurFloat overlay (was legacy positional); full i18n
(reusing export_private_key / key_export_private_warning / key_export_private_key /
select_address / key_export_fetching / export / copy / close, plus one new
key_export_failed); DialogWarningHeader; centered DialogActionFooter (Export +
Close) + a Copy TactileButton; async UX (export_in_progress_ spinner, export_error_
line). The exported key stays in the char[256] buffer shown via a read-only
InputTextMultiline (deliberately NOT AddressCopyField, which would copy the secret
into a lingering std::string). exportPrivateKey is untouched.

Security fix (found by the adversarial review): the 0a "outside-click/Esc wipe" via
the Begin-returns-false early-return was UNREACHABLE — BeginOverlayDialog clears
show_export_key_ mid-frame but still returns true, so an outside-click/Esc dismiss
left the exported spending key un-wiped in export_result_. Add the in-body
`if (!show_export_key_)` teardown before EndOverlayDialog (the proven import-dialog
pattern), which is the real wipe point for every dismiss path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 23:47:11 -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
22638b094c feat(settings): migrate Backup Wallet modal to the reference design
Phase 1. Struct-form BlurFloat overlay (was the legacy positional overload);
DialogWarningHeader care header; centered DialogActionFooter (Create Backup +
Close) replacing the StyledButtons + separator; full i18n — title/destination/
button reuse existing backup_* keys, plus two new keys (backup_warn one-line care
line, backup_overwrite_confirm) added in en + 8 langs. No change to backupWallet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 21:37:58 -05:00
828018de2b feat(settings): sweep a private key's funds to your own wallet
Add a "Sweep to my wallet (don't keep the key)" option to the Import Private
Key dialog (spending keys only). Rather than keeping the key, it imports the
key, then sends ALL its funds to a destination you control — a freshly
generated shielded address by default, or an existing wallet address you pick.

Flow (App::sweepPrivateKey): import the key (rescan; the stock node has no
address index, so its UTXOs/notes can't be enumerated otherwise) → confirm it
holds spendable funds → resolve the destination → z_sendmany balance-minus-fee
from the key's address to the destination, via the existing tested submitZSendMany
wrapper + async-operation tracker. The imported key is left in the wallet with an
empty balance (there is no remove-key RPC) — stated plainly in the UI caveat.

Design notes forced by this daemon (verified against external/dragonx):
- z_importkey returns null here, so the shielded source address is found by
  diffing z_listaddresses before/after import (aborts if the pre-snapshot fails,
  so a wrong address can never be picked). Transparent uses importprivkey's return.
- z_sendmany, NOT z_mergetoaddress: moves a single-UTXO transparent source (the
  common paper-wallet case) and fails loudly instead of silently leaving a
  remainder. Amount computed in integer satoshis for an exact fixed-decimal string.
- Clear errors for no-funds / unconfirmed / dust-below-fee / already-imported.
- The mode + destination are locked during a running sweep; a sweep that finishes
  while the dialog is closed still shows its Done/Error+txid on reopen; sweep UI
  can't bleed into the watch-only viewing dialog.

i18n: 8 new sweep_* keys (en + 8 langs); dynamic status strings are English,
matching the beginSweepToSeedWallet precedent.

Reviewed across three adversarial multi-agent rounds (fund-safety focus): round 1
caught the feature was broken for shielded keys (z_importkey null) and rejected
single-UTXO transparent sources; round 2 caught reopen/double-submit/precision
issues; round 3 verified the fixes. NOT yet exercised against a live daemon —
needs a small-amount mainnet test before it's trusted, like migrate-to-seed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 17:29:10 -05:00
2a96c41e07 feat(settings): polish the import-key dialog + paste verify preview
Design pass on the Import Private/Viewing Key dialog:

- Group the optional scan-from-height section (label, slider, field, hint) in a
  subtle glass panel via a draw-list splitter so it reads as one distinct,
  clearly-optional block.
- Replace the boxed reveal / Paste / Clear buttons with frameless Material icon
  buttons: the eye toggle sits flush at the Key field's right edge (rounded to
  match the input frame), Paste / Clear are faint icon pills with tooltips.
- Add a centered %-of-chain label to the slider (mirrors the send-tab amount bar).

New: hovering Paste peeks at the clipboard and verifies it before pasting —
a tooltip classifies the clipboard the same way the field indicator does
(✓ valid type for this dialog / ⚠ a key for the other button / ✗ not a key),
with a preview line masked with '*' unless the key is currently revealed (then a
truncated peek). Empty clipboard shows "Clipboard is empty".

i18n: added paste_clip_empty (en + 8 langs); the preview reuses the field
indicator's type / wrong-type keys.

Reviewed via three adversarial multi-agent passes (splitter/panel, icon buttons,
slider math, and the paste preview's correctness/security + i18n); the confirmed
findings (eye hover-pill rounding, unrecognized-state color) are addressed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 16:38:36 -05:00
0c55ed0fe4 feat(settings): send-tab-style slider for the rescan start height
The optional "scan from block height" control in the Import Private/Viewing
Key dialog now leads with a slider styled like the send-tab amount bar
(rounded track, accent fill, glass thumb) bounded by the chain tip, with the
numeric field beside it for exact entry and the current chain height
right-aligned above. When the node's height is unknown (state_.sync.blocks == 0,
e.g. not yet synced) the slider is omitted and the field spans the full row —
which also fixes the previous cramped 140px field that left the row half empty.

- New static helpers in app.cpp: formatIntWithCommas() and RenderScanHeightControl()
  (mirrors RenderAmountBar in send_tab.cpp). The height decimal string is the single
  source of truth shared by slider + field; the slider reserves/queries its
  InvisibleButton before drawing so a drag has no one-frame lag; the bar height is
  ImGui::GetFrameHeight() so it aligns with the numeric field.
- Import handler clamps the parsed start height to the chain tip.
- i18n: added import_scan_tip ("current height") in en + 8 langs.

Reviewed via an adversarial multi-agent pass (slider-math / state-sync /
dpi-layout / consistency); the one confirmed finding (bar/field height mismatch)
is fixed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:17:15 -05:00
1fc3e03e6f feat(settings): rename to "Import Private Key" + add scan height to it
Follow-up to the key/viewing-key button split:

- Rename the "Import Key…" button to "Import Private Key…" (settings_import_key
  value in en + all 8 langs, reusing the existing import_key_title wording) so it
  reads as the natural counterpart to "Import Viewing Key…". The dialog title was
  already "Import Private Key". The viewing-key wrong-type redirect hint now names
  the renamed button.

- Show the "scan from block height" field in the private-key (spending) dialog too,
  not just the viewing-key one. z_importkey accepts a start height, so a shielded
  spend import of a recent key needn't rescan the whole chain. Transparent WIF
  (importprivkey) has no such param, so once a transparent key is recognized the
  field is disabled, its buffer cleared, and a "Transparent keys always rescan
  fully" note replaces the hint. importPrivateKey already gates the start-height
  append on (viewing || shielded), so transparent imports never receive it.

- i18n: shared scan keys renamed import_viewkey_scan_{label,hint} ->
  import_scan_{label,hint}; added import_scan_transparent (en + 8 langs).

Reviewed via an adversarial multi-agent pass (rpc-routing / i18n / ui-logic /
consistency); only two nits surfaced (stale disabled-field value + a stale
comment), both fixed here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:38:40 -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
46f3001360 feat(settings): redesign the Import Key dialog
Rework the full-node Import Key dialog into a safer, Material-consistent, more
capable flow:

- Security: the key is masked by default (Password) with a reveal (eye) toggle,
  a DialogWarningHeader "only import a key you own" note, and the buffer is
  wiped with sodium_memzero on close and on successful import.
- Progress: import triggers a blocking full-chain rescan; the dialog now shows
  "Importing & rescanning — this can take several minutes" with LoadingDots and
  disables Import while it runs (no double-submit). Offline shows a "connect a
  running node" note and disables Import up front.
- Viewing keys: the classifier gains isViewingKey / isRecognizedImportKey;
  importPrivateKey auto-detects a shielded viewing key (zxviews…) and routes to
  z_importviewingkey (watch-only) vs z_importkey / importprivkey. The live type
  indicator shows Transparent / Shielded spending / Shielded viewing (watch-only).
- Result: on success the imported address is captured from the RPC result and
  shown via AddressCopyField.
- Material restyle (OverlayDialogSpec/BlurFloat + TactileButton + Esc) and full
  i18n (12 new keys x 8 languages; CJK subset rebuilt).

Verified: rendered on dark + light skins; a seeded zxviews… key shows the masked
field + "Shielded viewing key (watch-only)" indicator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:58:36 -05:00
4416e01f9c feat(console): parameter builder in the command explorer (phase 3)
The detail pane's Parameters section is now an editable form: each parameter is
a type-hinted input field (string / number / json, optional marked), and a live
"Builds" preview shows the command being assembled. String values are
auto-quoted; a required field left empty keeps its placeholder and disables
"Insert & run"; trailing empty optionals are omitted.

Insert and Insert & run now use the assembled command (not just the template),
so Insert & run works for parameterized commands once the required fields are
filled — destructive commands still confirm first. Param fields reset when the
selected command changes or the modal opens. Keyboard nav (Up/Down/Enter) is
scoped to the search box so typing in a field doesn't move the selection.

A best-effort parseParamSpecs turns the human-readable param templates into
fields; JSON-array params (z_sendmany, createrawtransaction) surface as a single
"json" field the user pastes into. Adds the console_ref_builds label + 8
translations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:32:35 -05:00
c9e9c9f979 feat(console): redesign the RPC reference as a novice-friendly command explorer
Replace the flat, terse command-reference table with a guided two-pane
explorer built for users who don't know the RPC commands:

- Search by name OR task: keyword synonyms let "balance" find getbalance,
  "send money" find sendtoaddress; results are ranked (name-prefix > name >
  keyword > desc).
- Two panes (mirrors the portfolio editor): a category-grouped master list
  (mono names, a warning dot on consequential commands) + a rich detail pane
  with a plain-language explanation, a per-parameter type breakdown (string /
  number / json, optional dimmed), and a concrete example.
- Insert into console (fills the input with a template to review + run) and,
  for no-parameter commands, Insert & run — with a confirm for destructive
  ones. Deferred via pending_submit_ so the modal needs no executor.
- Keyboard: type to filter, Up/Down to move, Enter to insert; auto-focus and
  auto-select the top result.

Data model: ConsoleCommandEntry gains details/example/keywords/destructive
(C++17 defaults, so the ~60 un-enriched entries are untouched); ~20 common
commands enriched and 18 consequential ones flagged. Command docs stay English
(technical); the UI chrome + 7 category names are translated into all 8
languages (CJK subset rebuilt, +3 glyphs).

Verified: two-pane renders on dark + light skins and at font_scale 1.5; detail
pane shows explanation/params/example; danger dots + safety badge on
destructive commands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:07:49 -05:00
ab4dd370c0 fix(console): RPC command-reference modal audit fixes
- Clicking a command now actually closes the modal. It called
  ImGui::CloseCurrentPopup(), a no-op here (BeginOverlayDialog is Begin/
  BeginChild, not an ImGui popup), so the picker stayed open covering the input
  and the insert looked like it did nothing. Set show_commands_popup_=false.
- Search filter is now a member cleared when the modal opens, so it isn't stale
  on reopen after an outside-click / command-click dismiss (was reset only by
  the Close button).
- Esc dismisses the modal (this overlay has no built-in Esc handling), and the
  search box auto-focuses on open so the user can type immediately.
- Scale the 2-vs-3 column breakpoint (cmd-min-width) by dpiScale() — it was a
  logical-px threshold compared against a physical-px available width.
- Give each category's table a unique ImGui id (##cmdsN) instead of sharing
  "##cmds", and translate the 7 category names (Control/Network/... — command
  descriptions stay English) into all 8 languages; CJK subset rebuilt (+2).

(Investigated but rejected: the command-name blue was flagged as low-contrast
on light skins, but the modal card is a dark glass panel on every theme, so the
original color is correct — verified by rendering marble/light/color-pop-light.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 19:25:51 -05:00
232b81f8ee feat(settings): surface the console color toggles as checkboxes
Add "Color accents" and "Text colors" checkboxes under the effects section
(both layout variants) so the console output display prefs are discoverable
outside the console toolbar. They mirror the toolbar buttons — bound live to
the ConsoleTab statics and written through to settings on change.

Unlike scanline/theme-effects they carry no GPU cost, so a small helper closes
the effects row's BeginDisabled(low_spec), draws them on their own always-
enabled row, and reopens it for the acrylic sliders (net-balanced). Adds
console_accents / console_text_colors labels + 8 translations; the tooltips
reuse the existing toggle keys.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:40:25 -05:00
c40c252c9a feat(console): persist accent toggle + add monochrome-text toggle
Persist the two console output display preferences and add a second toolbar
toggle for monochrome text.

- Persistence: new Settings fields console_line_accents / console_text_color
  (both default true, matching the ConsoleTab statics so an upgrade re-save
  can't flip visible behavior). Restored into the statics at startup in the App
  constructor, and saved from a diff-and-save after the console renders (only
  when a value actually changed — save() is disk I/O). The startup restore also
  fixes a pre-existing bug: scanline was only synced from settings when the
  Settings page or first-run wizard ran, so an existing wallet ignored a saved
  scanline preference on launch.
- Monochrome text: a new toolbar toggle (FORMAT_COLOR_TEXT, dimmed when off)
  next to the accent toggle. channelTextColor() early-returns the neutral
  COLOR_RESULT for every channel (and JSON syntax role) when off, leaving the
  left accent bars independent. COLOR_RESULT is contrast-floored per theme, so
  text stays readable on light and dark terminals.

Adds console_toggle_text_color to the English source + all 8 translations.
Verified: both toggles independent, persistence round-trips across restart,
monochrome readable on light + dark skins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 16:26:44 -05:00
d156dddcd0 feat(console): toolbar toggle to hide per-line color accent bars
Adds a paint-bucket toggle button to the console toolbar (in the appearance
cluster next to zoom) that shows/hides the per-line left color accent bars for
a cleaner monochrome gutter. The icon reflects state (FORMAT_COLOR_FILL when on,
a dimmed FORMAT_COLOR_RESET when off) with a tooltip. Session-only, like the
console zoom factor; default on.

Adds console_toggle_accents to the English source and all eight translations
(no new CJK glyphs — the subset font already covers them).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:36:51 -05:00
0e1957c5f9 feat(market): explain why the portfolio Save button is disabled
Hovering the disabled Save button now shows which requirement is missing
(name / at least one address / a manual price above 0), mirroring the
send-tab disabled-submit tooltip idiom (IsItemHovered(AllowWhenDisabled)).
The hint only appears for a validation gap — not the self-evident "nothing
changed" case.

Adds portfolio_save_need_{name,address,price} to the English source and all
eight translations; rebuilds the CJK subset font for the new JA/KO/ZH glyphs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:22:56 -05:00
76708e9191 feat(market): line/candle toggle + ~50% taller chart
- Add a chart-style toggle (line vs candlestick) next to the interval buttons,
  shown only when the selected range has per-exchange candles (the aggregate /
  Live view is line-only). It flips s_mkt.chartStyle; candles draw when OHLC
  exists AND the user hasn't switched to the line. Icon reflects the current
  style; tooltip says what a click switches to. Two i18n keys across 8 languages.
- Make the price chart ~50% taller: scale the height floor / desired / viewport
  cap (110->165, x1.5 desired, 0.22->0.33 of available) for a roomier plot.

Verified via a forced-OHLC render: the taller chart, the toggle button, and
candles with a correct week/day x-axis.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 11:54:08 -05:00
a107fda9b8 feat(market): loading spinner while the price chart fetches (pair switches)
Switching exchange pairs (or first load) briefly leaves the chart with no series
while the venue's candles fetch, which showed the bare "No price history
available" empty state. When a chart fetch is in flight — App::isMarketChartLoading()
(the CoinGecko aggregate OR the per-exchange fetch) — draw a spinner + animated
"Loading price history…" in the plot area instead; the "no history" text only
shows when genuinely empty and idle. New i18n key market_chart_loading across all
8 languages. Verified via a forced-state render (spinner + label centered).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 09:38:44 -05:00
2f86bec98e feat(wallets): subtle empty-state hint in the fixed-height list
With the list now pinned at max height, a few wallets leave blank space below
the cards. Fill it — only when there's real room to spare — with a subtle
centered folder glyph + "Scan a folder to find more wallets" (OnSurfaceDisabled),
so the area reads as a gentle nudge toward the scan action rather than dead
space. Purely decorative (draw-list only, clipped to the list); the actions stay
below. New i18n key wallets_empty_hint, translated across all 8 languages.

Verified on the sweep: the hint centers in the gap and reads subtly on both dark
and light themes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 07:17:34 -05:00
6310f51f65 feat(wallets): fixed max-height list + manage scanned folders
Two wallets-modal changes:

- The wallet list now always renders at its max height (kMaxVisibleRows) instead
  of shrinking to the wallet count, so the modal is a consistent size whether you
  have one wallet or many — fewer rows leave empty space, more than 7 scroll.

- Add a "Scanned folders" manager: each user-added scan folder is listed with a
  control to stop scanning it (removeExtraFolder + save + re-scan so its wallets
  drop out). Paths front-elide to keep the identifying leaf visible, with a
  full-path tooltip. The card-height math reserves the manager's rows so nothing
  clips. Two new i18n keys (wallets_scanned_folders / wallets_remove_folder),
  translated across all 8 languages; CJK subset rebuilt.

Verified on the sweep at 1.0 and 1.5x DPI: max-height list on both the few- and
many-wallet surfaces, the folder manager renders and stays clear of the footer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 07:04:43 -05:00
09e0b962c3 i18n(wizard): translate the first-run wizard (was all hardcoded English)
The first-run wizard predated the i18n system — every label, button, and help
line was hardcoded English. Route them all through TR():

- 62 literals in app_wizard.cpp replaced with TR(). Where a wizard string is a
  parallel of existing content, it reuses the existing key (the whole bootstrap_*
  family, plus theme / language / balance_layout / low_spec_mode / ui_opacity /
  console_scanline / download / retry / cancel) so it inherits their translations
  and stays consistent with Settings. Button labels drop their ##id suffix and use
  TR(key) directly (the app's established TactileButton(TR(...)) pattern; the
  wizard's phase buttons never share a frame, so no id collision).
- 55 new wiz_* English keys in i18n.cpp for the wizard-specific strings, and their
  translations back-filled across all 8 languages (es/de/fr/pt/ru/zh/ja/ko);
  format specifiers (%s, %zu) and newlines preserved. CJK subset rebuilt.

Verified on the sweep: English renders with correct labels in place (all keys
resolve), and a German run shows the reused + new keys translated end-to-end
(Darstellung / Acryl-Glaseffekte / Verschlüsseln & Weiter …).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 01:41:18 -05:00
b7da6335d1 feat(wallets): open external wallets in place via datadir link (no copy)
Replace the "Import" action — which copied an out-of-datadir wallet into the
datadir and cluttered the list with hard-to-tell-apart duplicates — with an
in-place "Open" that links the real file into the datadir under a stable
per-target name (wallet-ip-<FNV8>.dat) and switches to it. The daemon only
loads a bare filename from its own datadir, so a link is the minimal bridge:
hard link first (no privileges, same volume — covers non-admin Windows),
symlink fallback (cross-volume), then an error. Never a copy (that would fork
the wallet) and never a delete of a real file.

Also:
- show each external wallet's originating sub-directory (…/Backups/2021)
- add a per-row "open folder location" button
- widen the modal (780 → 860) for the extra button
- guard the daemon against a dangling link (external file moved / USB
  unplugged) by falling back to wallet.dat rather than creating an empty one

Per-target link names (not one shared name) make switching between two
external wallets a real -wallet switch, so the rescan/cache index tracks each
correctly. Drops the now-dead wallets_import* i18n keys and back-fills the new
open/folder strings across all 8 languages + rebuilds the CJK subset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 21:21:30 -05:00
fe40d38f0d feat(wallets): segmented sort control (like the Receive all/z/t toggle)
Replace the sort dropdown with a material::SegmentedControl — Created / Addresses
/ Txs / Size — matching the Receive tab's address-type toggle, with the asc/desc
arrow beside it. Shorten the four sort labels to fit the segments (updated across
all eight languages + the back-fill script). The direction arrow is positioned
explicitly on the segment's baseline (the control is draw-list based and doesn't
advance the layout cursor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 17:01:51 -05:00
d549127e41 i18n(wallets): translate created-date + sort keys, rebuild CJK subset
Back-fill the 8 new keys (created label + the four sort options and asc/desc
tooltips) into all eight languages via add_missing_translations.py (+64 keys,
additive), and rebuild res/fonts/NotoSansCJK-Subset.ttf for the new glyphs (升 昇 렬).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 16:37:36 -05:00
8eefab99ec i18n(wallets): clarify never-opened wallet label ("Never" -> "Never opened")
Standalone "Never" in the wallet list's last-opened slot was ambiguous; make it
"Never opened" (and update all eight translations). Glyphs already covered by the
CJK subset, so no font rebuild needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 16:22:13 -05:00
4fdf281230 i18n(wallets): translate the new badge/count keys + rebuild CJK subset
Back-fill the 10 new Wallets-dialog keys (metadata "keys"/"txs" columns and the
Encrypted/Seed/Legacy/Unknown badge labels + tooltips) into all eight languages
via scripts/add_missing_translations.py (additive; +80 keys, no reformatting), and
rebuild res/fonts/NotoSansCJK-Subset.ttf so the new zh/ja/ko glyphs (判 種 類 …)
render instead of tofu.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 16:11:29 -05:00
b2882095bb feat(wallets): redesign the modal layout — content-sized, framed, aligned
Act on the design review of the Wallets modal (all six points):

1. Content-sized card — size the card to the wallet count (up to 8 rows, then the
   list scrolls) instead of a fixed 620px, killing the huge empty void a short
   list floated in. Computed from the KNOWN row count, so it stays a fixed-height
   dialog (no auto-height feedback — that's what slid content off-screen on a
   monitor move).
2. Framed wallet list — BordersOuter + PadOuterX so the list reads as a contained
   panel with room to grow, not loose rows on the backdrop.
3. Right-aligned numeric columns (Size / Addresses / Balance) and their headers,
   via a custom header row + a right-aligned cell helper, so the numbers line up.
4. Consistent action column — the active wallet's row gets a subtle green tint and
   an "Active" chip (badge), distinct from the Open/Import buttons.
5. De-cluttered bottom — "Create wallet" stays the primary action; the folder-scan
   is tucked behind a "+ Scan another folder…" toggle.
6. Polish — the external-file marker is now a real info icon + tooltip (was
   ICON_MD_FOLDER rendering as a "?" tofu, since that glyph isn't in the subset);
   Refresh is an icon-only button, de-emphasized next to Close.

New i18n keys (wallets_add_folder_toggle, wallets_external_tt) + 8 langs; CJK
subset rebuilt. Verified via the headless sweep at 100% and font_scale 1.5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 01:58:27 -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
a09adb14fb fix(i18n): back-fill 323 untranslated keys across all 8 languages
Many keys added over time (lite-wallet, portfolio, xmrig/daemon updaters,
market, console, explorer, transactions, mining, …) were English-only in
res/lang and only ever fell back to English. Translated all 323 into
de/es/fr/ja/ko/pt/ru/zh — matched to each file's existing terminology, with
printf format specifiers (%s/%d/%.8f/%llu/…) preserved and verified. Every
language now covers all keys except daemon_port_busy_warn, which embeds a
compile-time port macro and intentionally stays on the English fallback.
CJK subset font rebuilt (1687 glyphs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 18:02:39 -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
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
5228da707f i18n(wallet): translate the migrate-to-seed UI + document it in CLAUDE.md
Route the migration modal (renderSeedMigrationDialog) through TR() — 32 new
keys (30 mig_* plus the previously-untranslated seed_migrate_button/
tt_seed_migrate), reusing existing common keys (cancel/close/refresh/
seed_backup_save*). Format-arg strings go through snprintf(buf, TR(...), v)
so the %.8f/%d specifiers stay in the (validated) translations; plain
strings use "%s", TR(...) to avoid -Wformat-security.

Translated into de/es/fr/ja/ko/pt/ru/zh — additive only (972 -> 1004 keys
per language, format specifiers verified preserved); CJK subset font rebuilt.

CLAUDE.md gains a "Seed phrase & migrate-to-seed" section documenting the
hd-transparent-keys daemon dependency, -usemnemonic, the backup screen, and
the Phase 1 (isolated create) / Phase 2 (sweep + Confirming gate + adopt)
flow that was live-verified on mainnet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 15:58:12 -05:00
403e145b30 feat(wallet): give new full-node wallets a BIP39 seed phrase + backup UI
New full-node wallets now get a real 24-word recovery phrase, and users can
reveal/back it up from Settings.

- Pass -usemnemonic=1 to dragonxd. The daemon reads it only inside
  GenerateNewSeed() when a wallet has no seed yet, so it is inert on existing
  wallets (safe to pass unconditionally) and makes every freshly-created
  wallet mnemonic-backed — its phrase is then exportable via z_exportmnemonic
  and portable to SDXLite/ObsidianDragonLite. (Existing/legacy wallets are
  unaffected and keep using the chat identity's z_exportkey fallback.)
- App::exportSeedPhrase() wraps z_exportmnemonic on the RPC worker with
  sodium_memzero wiping on every path; it flags the daemon's "not derived
  from a mnemonic" error as a legacy wallet rather than a failure.
- New "Back up seed phrase" modal (Settings -> Backup & Data, full-node
  gated): reveals the phrase in a numbered word grid, copy (45s clipboard
  auto-clear) + save-to-file (0600), wipes the secret on every close path
  incl. dismiss-mid-fetch. Shared ui/windows/seed_display.h grid helper.
- One-time nudge (settings flag seed_backup_reminded) toasts mnemonic-wallet
  users to back up their phrase; legacy wallets are not nagged.
- 15 new strings translated into all 8 languages (additive, 957->972 keys);
  CJK subset font rebuilt for the new glyphs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 10:49:03 -05:00
b75801f5c4 i18n(chat): translate the chat send/receive toasts into all 8 languages
The HushChat UI labels were already translated, but the send-path
notifications (not-connected, no-z-address, waiting-for-reply, compose
failures, contact-request queued, lite busy) were still hardcoded English.
Route all eight call sites in app_network.cpp through TR() with seven new
keys (the three "no z-address" variants unified into chat_toast_no_zaddr),
add the English fallbacks in i18n.cpp, and translate the keys into de/es/fr/
ja/ko/pt/ru/zh — reusing each file's existing chat_* terminology (z-address,
contact request, message) for consistency. Additive only (950 -> 957 keys
per language). CJK subset font rebuilt to cover the new zh/ja/ko glyphs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:36:56 -05:00
ca1ac22b17 i18n(chat): translate the Chat UI strings into all 8 languages
Add the 15 HushChat UI strings (nav label, locked/empty/select/waiting hints,
composer + new-conversation dialog, You / contact request / not-sent tags) to
res/lang/{de,es,fr,ja,ko,pt,ru,zh}.json. Previously they fell back to English.

Added directly to the JSON files (935 -> 950 keys, additive only): the
scripts/gen_<lang>.py generators are stale — they emit ~285 fewer keys than the
committed JSONs, so regenerating from them would silently drop translations.
(Pre-existing issue; noted for follow-up. The generators are left untouched.)

Rebuilt the usage-based CJK subset font (res/fonts/NotoSansCJK-Subset.ttf) from
the full JSONs so the new chat glyphs (聊天 / 对话 / 会話 / 답장, etc.) render —
verified every CJK code point in the full JSONs is covered (no glyph regression).

Verified: Linux + Windows build (embedded lang headers regenerated via xxd, font
re-embedded via INCBIN), hygiene clean; per-file diff is additive (15 keys, 0
deletions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:23:01 -05:00
9edab31728 Refactor app services and stabilize refresh/UI flows
- Add refresh scheduler and network refresh service boundaries for typed
  refresh results, ordered RPC collectors, applicators, and price parsing.
- Add daemon lifecycle and wallet security workflow helpers while preserving
  App-owned command RPC, decrypt, cancellation, and UI handoff behavior.
- Split balance, console, mining, amount formatting, and async task logic into
  focused modules with expanded Phase 4 test coverage.
- Fix market price loading by triggering price refresh immediately, avoiding
  queue-pressure drops, tracking loading/error state, and adding translations.
- Polish send, explorer, peers, settings, theme/schema, and related tab UI.
- Replace checked-in generated language headers with build-generated resources.
- Document the cleanup audit, UI static-state guidance, and architecture updates.
2026-04-29 12:47:57 -05:00
aa26ab5fbd fix: sidebar nav text overflow for long translations
- Add text scaling for section labels (TOOLS, ADVANCED) in sidebar
- Separate explorer_section key from explorer nav label to fix ALL CAPS
- Shorten long sidebar translations: es/pt settings, pt overview, ru tools/advanced
- Fix explorer translations from ALL CAPS to proper case in all languages
2026-04-12 18:45:48 -05:00
40cec14ebf Add bootstrap download dialog and fix 100 missing translation keys
- New BootstrapDownloadDialog accessible from Settings page
  - Stops daemon before download, prevents auto-restart during bootstrap
  - Confirm/Downloading/Done/Failed states with progress display
  - Mirror support (bootstrap2.dragonx.is)
- Add bootstrap_downloading_ flag to prevent tryConnect() auto-reconnect
- Right-align Download Bootstrap + Setup Wizard buttons in settings
- Add 100 missing i18n keys to all 8 language files (de/es/fr/ja/ko/pt/ru/zh)
  - Includes bootstrap, explorer, mining benchmark, transfer, delete blockchain,
    force quit, address label, and settings section translations
- Update add_missing_translations.py with new translation batch
2026-04-12 18:19:01 -05:00
6e2db50675 fix: accurate sync speed display, add missing i18n keys, native language names
- Fix blk/s calculation that was inflated ~10x due to resetting the
  time baseline every frame instead of only when blocks advanced
- Add decay when no new blocks arrive for 10s so rate doesn't stay stale
- Add 7 missing translation keys (timeout_off/1min/5min/15min/30min/1hour,
  slider_off) to all 8 language files so settings dropdowns translate
- Show language names in native script (中文, Русский, 日本語, 한국어)
2026-04-12 15:12:36 -05:00
2c5a658ea5 feat: Full UI internationalization, pool hashrate stats, and layout caching
- Replace all hardcoded English strings with TR() translation keys across
  every tab, dialog, and component (~20 UI files)
- Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with
  complete translations (~37k lines added)
- Improve i18n loader with exe-relative path fallback and English base
  fallback for missing keys
- Add pool-side hashrate polling via pool stats API in xmrig_manager
- Introduce Layout::beginFrame() per-frame caching and refresh balance
  layout config only on schema generation change
- Offload daemon output parsing to worker thread
- Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
2026-03-11 00:40:50 -05:00