fix(history): show shielding moves as neutral "Shielded", not red "Sent"
A coinbase/transparent→shielded move (often auto-shield) was drawn with a red "Sent" label and send arrow yet a green "+X" amount — an internally contradictory row that reads as "money leaving" to anyone who auto-shielded. It now renders as a neutral "Shielded" row (shield icon + the shielded accent colour for label and amount), and since a shield is your own funds going private — not a spend — it's excluded from the Sent card total and the Sent filter (it merges into one row visible under "All"). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -120,7 +120,10 @@ void RenderMiningModeToggle(App* app, const WalletState& state, const MiningInfo
|
|||||||
CancelMiningBenchmark(app, false); // don't leave a pool benchmark running after switching to solo (L-11)
|
CancelMiningBenchmark(app, false); // don't leave a pool benchmark running after switching to solo (L-11)
|
||||||
app->stopPoolMining();
|
app->stopPoolMining();
|
||||||
}
|
}
|
||||||
if (soloHov) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
if (soloHov) {
|
||||||
|
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||||
|
material::Tooltip("%s", TR("mining_solo_tip"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos(poolMin);
|
ImGui::SetCursorScreenPos(poolMin);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ static void DrawTxIcon(ImDrawList* dl, const std::string& type,
|
|||||||
} else if (type == "receive") {
|
} else if (type == "receive") {
|
||||||
icon = ICON_MD_CALL_RECEIVED;
|
icon = ICON_MD_CALL_RECEIVED;
|
||||||
} else if (type == "shield") {
|
} else if (type == "shield") {
|
||||||
icon = ICON_MD_CALL_MADE;
|
icon = ICON_MD_SHIELD; // a shield, not an outgoing arrow — it's an internal privacy move
|
||||||
} else {
|
} else {
|
||||||
icon = ICON_MD_CONSTRUCTION;
|
icon = ICON_MD_CONSTRUCTION;
|
||||||
}
|
}
|
||||||
@@ -185,6 +185,9 @@ void RenderTransactionsTab(App* app)
|
|||||||
ImU32 greenCol = Success();
|
ImU32 greenCol = Success();
|
||||||
ImU32 redCol = Error();
|
ImU32 redCol = Error();
|
||||||
ImU32 goldCol = Warning();
|
ImU32 goldCol = Warning();
|
||||||
|
// Neutral colour for a shielding move (your own funds going transparent→private): neither the
|
||||||
|
// red of a spend nor the green of income, so a shield never reads as "money leaving".
|
||||||
|
ImU32 shieldCol = schema::UI().resolveColor("var(--accent-shielded)", OnSurfaceMedium());
|
||||||
std::string txLoadingText = app->transactionRefreshProgressText();
|
std::string txLoadingText = app->transactionRefreshProgressText();
|
||||||
bool txLoading = !txLoadingText.empty();
|
bool txLoading = !txLoadingText.empty();
|
||||||
|
|
||||||
@@ -248,11 +251,9 @@ void RenderTransactionsTab(App* app)
|
|||||||
if (send_i >= 0 && recv_i >= 0) {
|
if (send_i >= 0 && recv_i >= 0) {
|
||||||
isShieldLeg[send_i] = true;
|
isShieldLeg[send_i] = true;
|
||||||
isShieldLeg[recv_i] = true;
|
isShieldLeg[recv_i] = true;
|
||||||
// The list shows the merged shield under the "Sent" filter, so count it there too —
|
// A shield moves your OWN funds transparent→private — it isn't a spend, so it is NOT
|
||||||
// otherwise the Sent card reads 0 while the Sent list is non-empty. Use the shielded
|
// counted toward the Sent card/total (and no longer appears under the Sent filter).
|
||||||
// (receive-leg) amount, which is what the merged row displays.
|
// It merges into one neutral "Shielded" row, visible under "All".
|
||||||
sendCount++;
|
|
||||||
sendTotal += std::abs(state.transactions[recv_i].amount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,7 +544,7 @@ void RenderTransactionsTab(App* app)
|
|||||||
for (size_t i = 0; i < display_txns.size(); i++) {
|
for (size_t i = 0; i < display_txns.size(); i++) {
|
||||||
const auto& dtx = display_txns[i];
|
const auto& dtx = display_txns[i];
|
||||||
if (type_filter != 0) {
|
if (type_filter != 0) {
|
||||||
if (type_filter == 1 && dtx.display_type != "send" && dtx.display_type != "shield") continue;
|
if (type_filter == 1 && dtx.display_type != "send") continue; // Sent = real spends; shields aren't sends
|
||||||
if (type_filter == 2 && dtx.display_type != "receive") continue;
|
if (type_filter == 2 && dtx.display_type != "receive") continue;
|
||||||
if (type_filter == 3 && dtx.display_type != "generate" && dtx.display_type != "immature" && dtx.display_type != "mined") continue;
|
if (type_filter == 3 && dtx.display_type != "generate" && dtx.display_type != "immature" && dtx.display_type != "mined") continue;
|
||||||
if (type_filter == 4 && !chatStore.hasChatTxid(dtx.txid)) continue; // chat-only
|
if (type_filter == 4 && !chatStore.hasChatTxid(dtx.txid)) continue; // chat-only
|
||||||
@@ -722,7 +723,7 @@ void RenderTransactionsTab(App* app)
|
|||||||
ImU32 iconCol;
|
ImU32 iconCol;
|
||||||
const char* typeStr;
|
const char* typeStr;
|
||||||
if (shieldedDisplay) {
|
if (shieldedDisplay) {
|
||||||
iconCol = redCol; typeStr = TR("sent_type");
|
iconCol = shieldCol; typeStr = TR("shielded_self_type");
|
||||||
} else if (tx.display_type == "receive") {
|
} else if (tx.display_type == "receive") {
|
||||||
iconCol = greenCol; typeStr = TR("recv_type");
|
iconCol = greenCol; typeStr = TR("recv_type");
|
||||||
} else if (tx.display_type == "send") {
|
} else if (tx.display_type == "send") {
|
||||||
@@ -750,7 +751,7 @@ void RenderTransactionsTab(App* app)
|
|||||||
float cy = rowPos.y + Layout::spacingMd();
|
float cy = rowPos.y + Layout::spacingMd();
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
DrawTxIcon(dl, shieldedDisplay ? "send" : tx.display_type,
|
DrawTxIcon(dl, shieldedDisplay ? "shield" : tx.display_type,
|
||||||
cx + rowIconSz, cy + body2->LegacySize * 0.5f, rowIconSz, iconCol);
|
cx + rowIconSz, cy + body2->LegacySize * 0.5f, rowIconSz, iconCol);
|
||||||
|
|
||||||
// Type label
|
// Type label
|
||||||
@@ -769,7 +770,7 @@ void RenderTransactionsTab(App* app)
|
|||||||
OnSurfaceMedium(), addr_display.c_str());
|
OnSurfaceMedium(), addr_display.c_str());
|
||||||
|
|
||||||
// Amount (right-aligned, first line)
|
// Amount (right-aligned, first line)
|
||||||
ImU32 amtCol = (tx.amount >= 0) ? greenCol : redCol;
|
ImU32 amtCol = shieldedDisplay ? shieldCol : ((tx.amount >= 0) ? greenCol : redCol);
|
||||||
if (tx.amount >= 0)
|
if (tx.amount >= 0)
|
||||||
snprintf(buf, sizeof(buf), "+%.8f", tx.amount);
|
snprintf(buf, sizeof(buf), "+%.8f", tx.amount);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1207,6 +1207,7 @@ void I18n::loadBuiltinEnglish()
|
|||||||
strings_["tx_chat_badge"] = "Message";
|
strings_["tx_chat_badge"] = "Message";
|
||||||
strings_["recv_type"] = "Recv";
|
strings_["recv_type"] = "Recv";
|
||||||
strings_["sent_type"] = "Sent";
|
strings_["sent_type"] = "Sent";
|
||||||
|
strings_["shielded_self_type"] = "Shielded";
|
||||||
strings_["immature_type"] = "Immature";
|
strings_["immature_type"] = "Immature";
|
||||||
strings_["mined_type"] = "Mined";
|
strings_["mined_type"] = "Mined";
|
||||||
strings_["mature"] = "Mature";
|
strings_["mature"] = "Mature";
|
||||||
|
|||||||
Reference in New Issue
Block a user