fix(diagnostics): address adversarial review of the QoL UI (popup, staleness, DPI, i18n)

Follow-up to the node-banner / staleness-badge / alert-history features — a 5-dimension
finder->verify review surfaced 4 real issues (the ImGui-stack-balance finder found none):

- Alert popup grew off the right edge: pivot (0,1) pinned the panel's LEFT edge at the
  bell, which sits near the window's right edge, so a 320px panel overflowed rightward
  (an explicit SetNextWindowPos pivot skips ImGui's on-screen clamp). Anchor the
  bottom-RIGHT corner at the bell instead (pivot (1,1) at bellMax.x) so it grows left.

- Staleness badge could flash red on reconnect: WalletState::clear() reset everything
  except the four last_*_update stamps, so the pre-outage timestamp survived and the
  badge briefly showed "Updated Nm ago" the same frame the node banner cleared. Zero the
  stamps in clear() (all readers treat 0 as "never"; app_network.cpp:1473 guards != 0).

- Banner min-height floor wasn't DPI-scaled: std::max(minH, baseH*vScale()) now uses
  minH * dpiScale() so both operands are in scaled px.

- New i18n keys weren't in res/lang/: back-filled all 16 diagnostics/QoL keys into the 8
  language files, additively (128 insertions, 0 deletions). zh/ja/ko reworded around 2
  glyphs missing from the CJK subset and hard-asserted tofu-free against the subset font.

Build-clean both variants; ctest 1/1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 21:14:38 -05:00
parent 4b3f0fa92b
commit 8bb3198562
11 changed files with 147 additions and 5 deletions

View File

@@ -2182,7 +2182,9 @@ void App::renderNodeStatusBanner()
const auto& S = ui::schema::UI();
const float minH = S.drawElement("banners.node-status", "min-height").size;
const float baseH = S.drawElement("banners.node-status", "height").size;
const float bannerH = std::max(minH, baseH * ui::Layout::vScale());
// Both operands must be in scaled px: vScale() already folds in dpiScale(), so the raw min-height
// floor needs the same dpiScale() or it under-clamps the banner at HiDPI.
const float bannerH = std::max(minH * ui::Layout::dpiScale(), baseH * ui::Layout::vScale());
const bool isError = (banner.severity == ui::NodeBannerSeverity::Error);
const ImU32 sevCol = isError ? m::Error() : m::Warning();
@@ -2703,10 +2705,12 @@ void App::renderStatusBar()
ImGui::OpenPopup("##AlertHistoryPopup");
}
// The status bar sits at the window bottom, so grow the popup UPWARD from the bell
// (pivot bottom-left → the anchor point becomes the popup's bottom-left corner).
ImGui::SetNextWindowPos(ImVec2(bellMin.x, bellMin.y - 4.0f * dp),
ImGuiCond_Always, ImVec2(0.0f, 1.0f));
// The bell sits near the window's bottom-right, so anchor the popup's bottom-RIGHT
// corner at the bell's right edge (pivot (1,1)) — it then grows LEFT over the canvas and
// UP from the status bar. A left pivot would push a 320px panel off the right edge (and
// an explicit SetNextWindowPos pivot skips ImGui's on-screen clamp, so it would overflow).
ImGui::SetNextWindowPos(ImVec2(bellMax.x, bellMin.y - 4.0f * dp),
ImGuiCond_Always, ImVec2(1.0f, 1.0f));
const float panelW = 320.0f * dp;
ImGui::SetNextWindowSizeConstraints(ImVec2(panelW, 0), ImVec2(panelW, 360.0f * dp));
if (ImGui::BeginPopup("##AlertHistoryPopup")) {