Per-frame hot paths in the immediate-mode UI were allocating needlessly:
- Address filtering in the balance tab rebuilt a std::string filter per address AND
containsIgnoreCase() lower-cased two fresh copies per call — ~6×N allocations/frame
on large wallets. New util::containsIgnoreCase(string_view, string_view) is
allocation-free, and the filter is now built once outside the loop.
- Four duplicated "time ago" implementations (balance_tab_helpers, balance_recent_tx,
send_tab, transactions_tab) are consolidated into util::formatTimeAgo (localized long
form) + util::formatTimeAgoShort (compact "5s ago"), preserving each call site's exact
display style. Both use snprintf, no per-row string concatenation.
- The send-tab address-suggestion scan (a walk over the whole tx list) is memoized on the
typed text + tx count, so it no longer recomputes every frame while the user pauses.
New src/util/text_format.{h,cpp}; the two existing containsIgnoreCase/timeAgo definitions
now delegate to it. Added to both the app and test targets (test target also gains i18n.cpp,
which text_format's localized path needs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
1.1 KiB
C++
47 lines
1.1 KiB
C++
#include "balance_recent_tx.h"
|
|
#include "../../config/version.h"
|
|
#include "../../util/text_format.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <ctime>
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
|
|
namespace {
|
|
std::string truncateRecentAddress(const std::string& address, int maxLen)
|
|
{
|
|
if (maxLen <= 3 || address.length() <= static_cast<size_t>(maxLen)) return address;
|
|
int half = (maxLen - 3) / 2;
|
|
return address.substr(0, half) + "..." + address.substr(address.length() - half);
|
|
}
|
|
|
|
std::string formatRecentAmount(const std::string& type, double amount)
|
|
{
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%s%.4f %s",
|
|
type == "send" ? "-" : "+",
|
|
std::abs(amount), DRAGONX_TICKER);
|
|
return std::string(buffer);
|
|
}
|
|
|
|
std::string recentTimeAgo(int64_t timestamp)
|
|
{
|
|
return util::formatTimeAgoShort(timestamp);
|
|
}
|
|
}
|
|
|
|
RecentTxDisplay buildRecentTxDisplay(const TransactionInfo& tx, int addressMaxLen)
|
|
{
|
|
return {
|
|
tx.getTypeDisplay(),
|
|
truncateRecentAddress(tx.address, addressMaxLen),
|
|
formatRecentAmount(tx.type, tx.amount),
|
|
recentTimeAgo(tx.timestamp)
|
|
};
|
|
}
|
|
|
|
} // namespace ui
|
|
} // namespace dragonx
|