feat(diagnostics): refresh-staleness badge on the Total Balance card (W6-2)

When the wallet is connected but the balance has quietly stopped refreshing — a busy
daemon can fail z_gettotalbalance without dropping the whole connection (only *both*
core RPCs failing 3x triggers a disconnect) — the old number sits on screen while the
node-status banner stays hidden. The Total Balance card now shows a small pill on its
status line ("Updated 2m ago", amber, escalating to red past 3 min) so the stale value
isn't silently trusted; hovering explains it and points at the node connection.

No refresh-path changes: WalletState::last_balance_update is already stamped only on a
successful fetch (network_refresh_service.cpp), so the badge reads it and computes age
against the same std::time clock via util::formatTimeAgoShort. The decision is a pure,
unit-tested helper (ui/staleness_badge.h::evaluateStalenessBadge, 45s/180s thresholds)
gated on connected so it never contradicts the banner.

Closes P2 (5/5). Build-clean; ctest 1/1 (adds testStalenessBadge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 20:48:56 -05:00
parent e779ded2e8
commit c7c3440a7b
5 changed files with 109 additions and 2 deletions

View File

@@ -1315,6 +1315,11 @@ void I18n::loadBuiltinEnglish()
strings_["node_banner_lite_open_failed"] = "Couldn't open your wallet";
strings_["node_banner_reconnect"] = "Reconnect";
strings_["node_banner_restart"] = "Restart node";
// Refresh-staleness badge (W6-2) on the Total Balance card.
strings_["data_stale_prefix"] = "Updated";
strings_["data_stale_tooltip"] =
"Balance may be out of date — the wallet hasn't received a fresh update recently. "
"Check your node connection.";
strings_["daemon_port_busy_warn"] =
"Port " DRAGONX_DEFAULT_RPC_PORT " is in use but isn't responding as a DragonX node. "
"Close the program using it (or free the port), then restart — the wallet can't start "