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>
This commit is contained in:
2026-07-07 22:16:47 -05:00
parent 48c79567d7
commit 82e61da62f
17 changed files with 418 additions and 22 deletions

View File

@@ -699,6 +699,19 @@ private:
enum class SeedMigrationStep { Intro, Working, ShowSeed, Sweep, Sweeping, Confirming, Adopting, Done, Error };
bool show_seed_migration_ = false;
SeedMigrationStep seed_migration_step_ = SeedMigrationStep::Intro;
// Intro pre-flight: probe the current wallet before offering to create a seed wallet, so we can
// skip a pointless migration (AlreadyMnemonic → offer backup) or explain why it can't run
// (DaemonTooOld). Set from beginSeedMigrationPrecheck()'s async callback (main thread).
enum class SeedMigrationPrecheck { Pending, Legacy, AlreadyMnemonic, DaemonTooOld, CheckFailed };
SeedMigrationPrecheck seed_migration_precheck_ = SeedMigrationPrecheck::Pending;
bool seed_migration_precheck_started_ = false;
bool seed_migration_balance_loaded_ = false; // Sweep step: distinguishes "0 funds" from "not loaded yet"
bool seed_migration_nofunds_confirmed_ = false; // "replace my wallet" gate for the no-funds adopt
// "A newer node is bundled — update?" startup prompt (see maybeOfferDaemonUpdate).
bool show_daemon_update_prompt_ = false;
unsigned long long daemon_update_bundled_size_ = 0; // bundled daemon size the prompt offers
bool seed_migration_in_flight_ = false; // main-thread guard while the bg create task runs
std::string seed_migration_seed_; // SECRET — the revealed phrase, wiped on close
std::string seed_migration_dest_; // new shielded z-address (Phase 2 sweep target)
@@ -1018,6 +1031,9 @@ private:
void renderBackupDialog();
void renderSeedBackupDialog(); // full-node "Back up seed phrase" modal (z_exportmnemonic)
void renderSeedMigrationDialog(); // "Migrate to a seed wallet" guided modal (Phase 1: create)
void beginSeedMigrationPrecheck(); // Intro: probe whether the wallet is legacy / already-seeded
void maybeOfferDaemonUpdate(); // at startup, flag the prompt if a newer daemon is bundled
void renderDaemonUpdatePrompt(); // "a newer node is bundled — update the installed daemon?"
void renderFirstRunWizard();
void renderLockScreen();
void renderEncryptWalletDialog();