feat(history): view the transactions involving an address

Adds a "View transactions" action that opens the History tab pre-filtered
to a chosen address. SetTransactionsAddressFilter() stores a pending filter
that RenderTransactionsTab consumes on its next frame — pre-filling the
search box and resetting the type filter to All — then the caller navigates
to NavPage::History. This reuses the existing "prefill + navigate" pattern
(cf. SetSendFromAddress) and all of History's rendering, detail and export.

Triggers:
- Contacts: a context-menu item and a 4th per-row action icon (copy /
  view-transactions / edit / delete; the trailing width is widened to fit).
- Balance address list: a per-address context-menu item (own z/t addresses).
- Receive tab: the recent-received rows now carry their address into the
  filter instead of jumping to History unfiltered.

The History search also now matches from_address, so filtering by one of your
own addresses catches sends FROM it, not only receives INTO it.

Scoping is honest, not exhaustive: transparent is well covered, but shielded
counterparties are private and the transparent sender of received funds is
never recorded on-chain, so this shows transactions *involving* the address.
On Lite, from_address is thin, so own-address send filtering is weaker.

New i18n keys view_transactions / tt_view_transactions translated into all
eight locales (no new glyphs). Builds + test suites pass on both variants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 10:13:15 -05:00
co-authored by Claude Opus 4.8
parent 5fcab14e4e
commit 2282f332a6
14 changed files with 78 additions and 9 deletions
+21
View File
@@ -45,6 +45,17 @@ static bool containsIgnoreCase(const std::string& str, const std::string& search
return dragonx::util::containsIgnoreCase(str, search);
}
// Pending "view transactions for this address" request. Set by SetTransactionsAddressFilter()
// from Contacts / the Balance address list / the Receive tab, consumed on the next
// RenderTransactionsTab frame to pre-fill the search box (see the consume block below).
static std::string s_pending_addr_filter;
static bool s_pending_addr_filter_set = false;
void SetTransactionsAddressFilter(const std::string& address) {
s_pending_addr_filter = address;
s_pending_addr_filter_set = true;
}
// A display-ready transaction that may be a merged autoshield pair.
// For non-merged entries, send_idx or recv_idx is -1.
struct DisplayTx {
@@ -313,6 +324,15 @@ void RenderTransactionsTab(App* app)
// Search & Filter bar
// ================================================================
static char search_filter[128] = "";
// Consume a pending "view transactions for this address" request: pre-fill the search box
// with the address and reset the type filter to All so no matching row is hidden. The
// changed search_str resets pagination/expansion via filterInputsChanged() below.
if (s_pending_addr_filter_set) {
strncpy(search_filter, s_pending_addr_filter.c_str(), sizeof(search_filter) - 1);
search_filter[sizeof(search_filter) - 1] = '\0';
type_filter = 0;
s_pending_addr_filter_set = false;
}
float searchMaxW = (searchInput.maxWidth >= 0) ? searchInput.maxWidth : 300.0f;
float searchRatio = (searchInput.widthRatio >= 0) ? searchInput.widthRatio : 0.30f;
float searchWidth = std::min(searchMaxW * hs, availWidth * searchRatio);
@@ -530,6 +550,7 @@ void RenderTransactionsTab(App* app)
}
if (!search_str.empty()) {
if (!containsIgnoreCase(dtx.address, search_str) &&
!containsIgnoreCase(dtx.from_address, search_str) &&
!containsIgnoreCase(dtx.txid, search_str) &&
!containsIgnoreCase(dtx.memo, search_str) &&
!(dtx.is_shield && containsIgnoreCase(std::string("shielded"), search_str))) {