refactor(audit): batch 9 — de-duplicate balance/peers/transactions UI cards

Three UI de-duplications (rendering changes; the test suite skips the GUI, so
these need a manual screenshot check of the Balance/Peers/Transactions tabs).

1. Classic balance layout — the DEFAULT layout — hand-rolled its own ~550-line
   address-list + recent-tx renderers that had DIVERGED from the shared
   RenderSharedAddressList/RenderSharedRecentTx used by the other 9 layouts.
   Deleted the inline copies and called the shared renderers (as the minimal
   layout already does), so the default layout now gains set-label +
   add-to-portfolio context items, custom address icons, drag-to-reorder,
   keyboard nav, copy-flash, and fully TR()'d strings. Hero row and Classic
   sizing (tabs.balance.classic address-table-height=340) preserved; addrH is
   computed before the call exactly as before. This is a deliberate
   feature-parity behavior change for the default layout.

2. peers_tab info cards — extracted drawStatCell() (label + value/em-dash with
   the shared offset math) and one drawCardDivider() replacing two duplicate
   divider lambdas; plain cells drive off a per-card loop. Bespoke cells
   (Blocks "(X left)", copy-on-click Best Block, TLS check-icon) kept inline.

3. transactions_tab — one drawSummaryCard() replaces the three near-identical
   Received/Sent/Mined blocks (same glass panel, icon, hover outline,
   click-to-filter). Byte-equivalent.

Full-node + Lite build clean (net -651 lines, no new warnings); ctest 1/1;
hygiene clean. NEEDS SCREENSHOT VERIFICATION.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 20:18:02 -05:00
parent 262891229a
commit 121a79e768
3 changed files with 144 additions and 795 deletions

View File

@@ -96,6 +96,44 @@ static void DrawTxIcon(ImDrawList* dl, const std::string& type,
ImVec2(cx - sz.x * 0.5f, cy - sz.y * 0.5f), col, icon);
}
// Draw one Received/Sent/Mined summary card: icon + label + count + signed total, with a
// hover outline and click-to-toggle type filter. All three cards are identical apart from the
// per-card data passed here. cMin is the card's top-left; filterValue is the type_filter value
// this card selects (clicking again clears it).
static void drawSummaryCard(ImDrawList* dl, ImVec2 cMin, float cardW, float cardH,
float innerPad, float iconSz, const GlassPanelSpec& glassSpec,
ImFont* ovFont, ImFont* capFont, ImFont* body2,
const char* iconType, ImU32 accentCol, const char* labelKey,
int count, double total, const char* signPrefix,
int filterValue, int& type_filter)
{
char buf[128];
ImVec2 cMax(cMin.x + cardW, cMin.y + cardH);
DrawGlassPanel(dl, cMin, cMax, glassSpec);
float cx = cMin.x + innerPad;
float cy = cMin.y + Layout::spacingMd();
DrawTxIcon(dl, iconType, cx + iconSz, cy + iconSz * 1.33f, iconSz, accentCol);
float labelX = cx + iconSz * 3.0f;
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(labelX, cy), OnSurfaceMedium(), TR(labelKey));
cy += ovFont->LegacySize + Layout::spacingSm();
snprintf(buf, sizeof(buf), TR("txs_count"), count);
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx, cy), OnSurfaceDisabled(), buf);
cy += capFont->LegacySize + Layout::spacingXs();
snprintf(buf, sizeof(buf), "%s%.4f %s", signPrefix, total, DRAGONX_TICKER);
dl->AddText(body2, body2->LegacySize, ImVec2(cx, cy), accentCol, buf);
if (material::IsRectHovered(cMin, cMax)) {
dl->AddRect(cMin, cMax, IM_COL32(255, 255, 255, 40), glassSpec.rounding, 0, 1.5f);
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (ImGui::IsMouseClicked(0)) type_filter = (type_filter == filterValue) ? 0 : filterValue;
}
}
void RenderTransactionsTab(App* app)
{
auto& S = schema::UISchema::instance();
@@ -203,95 +241,17 @@ void RenderTransactionsTab(App* app)
// Sort mode: 0 = newest first, 1 = oldest first, 2 = largest amount, 3 = smallest amount.
static int s_sort_mode = 0;
// --- Received card ---
{
ImVec2 cMin = origin;
ImVec2 cMax(cMin.x + cardW, cMin.y + cardH);
DrawGlassPanel(dl, cMin, cMax, glassSpec);
float cx = cMin.x + innerPad;
float cy = cMin.y + Layout::spacingMd();
// Icon
DrawTxIcon(dl, "receive", cx + iconSz, cy + iconSz * 1.33f, iconSz, greenCol);
float labelX = cx + iconSz * 3.0f;
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(labelX, cy), OnSurfaceMedium(), TR("received_upper"));
cy += ovFont->LegacySize + Layout::spacingSm();
snprintf(buf, sizeof(buf), TR("txs_count"), recvCount);
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx, cy), OnSurfaceDisabled(), buf);
cy += capFont->LegacySize + Layout::spacingXs();
snprintf(buf, sizeof(buf), "+%.4f %s", recvTotal, DRAGONX_TICKER);
dl->AddText(body2, body2->LegacySize, ImVec2(cx, cy), greenCol, buf);
if (material::IsRectHovered(cMin, cMax)) {
dl->AddRect(cMin, cMax, IM_COL32(255, 255, 255, 40), glassSpec.rounding, 0, 1.5f);
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (ImGui::IsMouseClicked(0)) type_filter = (type_filter == 2) ? 0 : 2;
}
}
// --- Sent card ---
{
float xOff = cardW + cardGap;
ImVec2 cMin(origin.x + xOff, origin.y);
ImVec2 cMax(cMin.x + cardW, cMin.y + cardH);
DrawGlassPanel(dl, cMin, cMax, glassSpec);
float cx = cMin.x + innerPad;
float cy = cMin.y + Layout::spacingMd();
DrawTxIcon(dl, "send", cx + iconSz, cy + iconSz * 1.33f, iconSz, redCol);
float labelX = cx + iconSz * 3.0f;
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(labelX, cy), OnSurfaceMedium(), TR("sent_upper"));
cy += ovFont->LegacySize + Layout::spacingSm();
snprintf(buf, sizeof(buf), TR("txs_count"), sendCount);
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx, cy), OnSurfaceDisabled(), buf);
cy += capFont->LegacySize + Layout::spacingXs();
snprintf(buf, sizeof(buf), "-%.4f %s", sendTotal, DRAGONX_TICKER);
dl->AddText(body2, body2->LegacySize, ImVec2(cx, cy), redCol, buf);
if (material::IsRectHovered(cMin, cMax)) {
dl->AddRect(cMin, cMax, IM_COL32(255, 255, 255, 40), glassSpec.rounding, 0, 1.5f);
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (ImGui::IsMouseClicked(0)) type_filter = (type_filter == 1) ? 0 : 1;
}
}
// --- Mined card ---
{
float xOff = 2 * (cardW + cardGap);
ImVec2 cMin(origin.x + xOff, origin.y);
ImVec2 cMax(cMin.x + cardW, cMin.y + cardH);
DrawGlassPanel(dl, cMin, cMax, glassSpec);
float cx = cMin.x + innerPad;
float cy = cMin.y + Layout::spacingMd();
DrawTxIcon(dl, "mined", cx + iconSz, cy + iconSz * 1.33f, iconSz, goldCol);
float labelX = cx + iconSz * 3.0f;
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(labelX, cy), OnSurfaceMedium(), TR("mined_upper"));
cy += ovFont->LegacySize + Layout::spacingSm();
snprintf(buf, sizeof(buf), TR("txs_count"), minedCount);
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx, cy), OnSurfaceDisabled(), buf);
cy += capFont->LegacySize + Layout::spacingXs();
snprintf(buf, sizeof(buf), "+%.4f %s", minedTotal, DRAGONX_TICKER);
dl->AddText(body2, body2->LegacySize, ImVec2(cx, cy), goldCol, buf);
if (material::IsRectHovered(cMin, cMax)) {
dl->AddRect(cMin, cMax, IM_COL32(255, 255, 255, 40), glassSpec.rounding, 0, 1.5f);
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (ImGui::IsMouseClicked(0)) type_filter = (type_filter == 3) ? 0 : 3;
}
}
// --- Received / Sent / Mined cards ---
// filter values: Received = 2, Sent = 1, Mined = 3 (see idx_map for the accent bar below)
drawSummaryCard(dl, origin, cardW, cardH, innerPad, iconSz, glassSpec,
ovFont, capFont, body2, "receive", greenCol, "received_upper",
recvCount, recvTotal, "+", 2, type_filter);
drawSummaryCard(dl, ImVec2(origin.x + (cardW + cardGap), origin.y), cardW, cardH,
innerPad, iconSz, glassSpec, ovFont, capFont, body2, "send", redCol, "sent_upper",
sendCount, sendTotal, "-", 1, type_filter);
drawSummaryCard(dl, ImVec2(origin.x + 2 * (cardW + cardGap), origin.y), cardW, cardH,
innerPad, iconSz, glassSpec, ovFont, capFont, body2, "mined", goldCol, "mined_upper",
minedCount, minedTotal, "+", 3, type_filter);
// Selected card accent
if (type_filter > 0) {