feat(wallet): richer detail in the wallet-switch progress modal
The switch modal now shows more than a bare phase line:
- The title carries the target wallet ("Switching wallet — savings") and a
"from <previous>" caption for context (names prettified: wallet.dat → "Default
wallet", wallet-<name>.dat → "<name>", in-place links → "External wallet").
- During the Reconnecting phase — the ~30-60s where the node loads the block
index, verifies, and rescans — it surfaces the node's LIVE init stage
(state_.warmup_status/description via the existing translateWarmup mapping:
"Loading blockchain data…", "Verifying blockchain…", "Scanning for
transactions…") instead of a static "Reconnecting…".
- An elapsed timer (m:ss) so the wait visibly progresses.
i18n: from/elapsed/default-wallet/external-wallet labels (EN + 8 languages,
additive; no new CJK glyphs). No switch-flow logic change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
65
src/app.cpp
65
src/app.cpp
@@ -3870,10 +3870,24 @@ void App::renderSwitchStopDaemonDialog()
|
||||
const auto phase = static_cast<WalletSwitchPhase>(wallet_switch_phase_.load());
|
||||
const bool failed = progress && phase == WalletSwitchPhase::Failed;
|
||||
|
||||
// Prettify a wallet filename for display (wallet.dat → "Default wallet", wallet-savings.dat → "savings").
|
||||
auto pretty = [this](const std::string& f) -> std::string {
|
||||
if (f.empty() || f == "wallet.dat") return TR("switch_progress_default_wallet");
|
||||
std::string s = f;
|
||||
if (s.size() > 4 && s.substr(s.size() - 4) == ".dat") s.resize(s.size() - 4);
|
||||
if (s.rfind("wallet-ip-", 0) == 0) return TR("switch_progress_external_wallet");
|
||||
if (s.rfind("wallet-", 0) == 0) s = s.substr(7);
|
||||
return s;
|
||||
};
|
||||
const std::string toName = pretty(settings_ ? settings_->getActiveWalletFile() : std::string());
|
||||
|
||||
// Progress title carries the target wallet ("Switching wallet — savings"); keep the string alive.
|
||||
std::string titleStr = confirm ? std::string(TR("switch_stopnode_title"))
|
||||
: failed ? std::string(TR("switch_progress_failed_title"))
|
||||
: std::string(TR("switch_progress_title")) + " — " + toName;
|
||||
|
||||
ui::material::OverlayDialogSpec ov;
|
||||
ov.title = confirm ? TR("switch_stopnode_title")
|
||||
: failed ? TR("switch_progress_failed_title")
|
||||
: TR("switch_progress_title");
|
||||
ov.title = titleStr.c_str();
|
||||
// A confirm can be dismissed via X/backdrop (= cancel); a running switch cannot (stay until it's up).
|
||||
ov.p_open = confirm ? &show_switch_stop_daemon_confirm_ : nullptr;
|
||||
ov.style = ui::material::OverlayStyle::BlurFloat;
|
||||
@@ -3911,18 +3925,43 @@ void App::renderSwitchStopDaemonDialog()
|
||||
wallet_switch_error_.clear();
|
||||
}
|
||||
} else {
|
||||
// Live progress: an animated phase line, kept redrawing by isWalletSwitchInProgress().
|
||||
const char* status =
|
||||
phase == WalletSwitchPhase::Starting ? TR("switch_progress_starting")
|
||||
: phase == WalletSwitchPhase::Reconnecting ? TR("switch_progress_reconnecting")
|
||||
: TR("switch_progress_stopping");
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
|
||||
ui::material::Type().text(ui::material::TypeStyle::Subtitle1,
|
||||
(std::string(status) + ui::material::LoadingDots()).c_str());
|
||||
// Live progress, kept redrawing by isWalletSwitchInProgress().
|
||||
// Source context (the target is already in the title).
|
||||
ImGui::PushFont(ui::material::Type().caption());
|
||||
ImGui::TextDisabled("%s %s", TR("switch_progress_from_label"), pretty(wallet_switch_prev_file_).c_str());
|
||||
ImGui::PopFont();
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingMd()));
|
||||
|
||||
// Primary status + detail. During Reconnecting the node is loading the block index / verifying /
|
||||
// rescanning — surface its live init stage (state_.warmup_status/description) instead of a bare
|
||||
// "Reconnecting…", so the ~30-60s wait shows real progress.
|
||||
std::string primary, detail;
|
||||
if (phase == WalletSwitchPhase::Stopping) {
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
|
||||
ImGui::TextWrapped("%s", TR("switch_progress_hint"));
|
||||
primary = TR("switch_progress_stopping");
|
||||
detail = TR("switch_progress_hint");
|
||||
} else if (phase == WalletSwitchPhase::Starting) {
|
||||
primary = TR("switch_progress_starting");
|
||||
} else { // Reconnecting
|
||||
if (!state_.warmup_status.empty()) { primary = state_.warmup_status; detail = state_.warmup_description; }
|
||||
else primary = TR("switch_progress_reconnecting");
|
||||
}
|
||||
ui::material::Type().text(ui::material::TypeStyle::Subtitle1,
|
||||
(primary + ui::material::LoadingDots()).c_str());
|
||||
if (!detail.empty()) {
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
|
||||
ImGui::PushFont(ui::material::Type().body2());
|
||||
ImGui::TextWrapped("%s", detail.c_str());
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
// Elapsed timer — captured on the first progress frame (reset per switch in switchToWallet).
|
||||
if (wallet_switch_started_time_ <= 0.0) wallet_switch_started_time_ = ImGui::GetTime();
|
||||
const int el = static_cast<int>(ImGui::GetTime() - wallet_switch_started_time_);
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingSm()));
|
||||
ImGui::PushFont(ui::material::Type().caption());
|
||||
ImGui::TextDisabled("%s %d:%02d", TR("switch_progress_elapsed"), el / 60, el % 60);
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Dummy(ImVec2(0, ui::Layout::spacingMd()));
|
||||
// Escape hatch — the switch keeps running in the background (a toast reports the result).
|
||||
if (ui::material::TactileButton(TR("switch_progress_background"), ImVec2(220.0f * dp, 0)))
|
||||
|
||||
Reference in New Issue
Block a user