#include "balance_address_list.h" #include #include #include namespace dragonx { namespace ui { namespace { bool containsIgnoreCase(const std::string& haystack, const std::string& needle) { if (needle.empty()) return true; auto it = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](char a, char b) { return std::tolower(static_cast(a)) == std::tolower(static_cast(b)); }); return it != haystack.end(); } } // namespace bool AddressListMatchesFilter(const AddressListInput& input, const std::string& filter) { if (!input.info) return false; return containsIgnoreCase(input.info->address, filter) || containsIgnoreCase(input.info->label, filter) || containsIgnoreCase(input.label, filter); } std::vector BuildAddressListRows(const std::vector& inputs, const std::string& filter, bool hideZeroBalances, bool showHidden) { std::vector rows; rows.reserve(inputs.size()); for (const auto& input : inputs) { if (!input.info) continue; if (!AddressListMatchesFilter(input, filter)) continue; if (input.hidden && !showHidden) continue; // Keep mining-flagged addresses visible even at 0 balance (they receive payouts). if (hideZeroBalances && input.info->balance < 1e-9 && !input.hidden && !input.favorite && !input.mining) continue; rows.push_back({input.info, input.isZ, input.hidden, input.favorite, input.mining, input.label, input.icon, input.sortOrder}); } std::sort(rows.begin(), rows.end(), [](const AddressListRow& a, const AddressListRow& b) { bool aHasOrder = a.sortOrder >= 0; bool bHasOrder = b.sortOrder >= 0; if (aHasOrder && bHasOrder) return a.sortOrder < b.sortOrder; if (aHasOrder != bHasOrder) return aHasOrder > bHasOrder; if (a.favorite != b.favorite) return a.favorite > b.favorite; if (a.isZ != b.isZ) return a.isZ > b.isZ; return a.info->balance > b.info->balance; }); return rows; } AddressRowLayout ComputeAddressRowLayout(float rowX, float rowY, float rowWidth, float rowHeight, float rowPadLeft, float rowIconSize, float spacingMd, float spacingSm, float spacingXs) { AddressRowLayout layout; layout.contentStartX = rowX + rowPadLeft; layout.contentStartY = rowY + spacingMd; layout.buttonSize = rowHeight - spacingMd * 2.0f; const float buttonY = rowY + (rowHeight - layout.buttonSize) * 0.5f; const float rightEdge = rowX + rowWidth; const float favoriteX = rightEdge - layout.buttonSize - spacingXs; const float visibilityX = favoriteX - spacingSm - layout.buttonSize; layout.favoriteButton = {favoriteX, buttonY, layout.buttonSize, layout.buttonSize}; layout.visibilityButton = {visibilityX, buttonY, layout.buttonSize, layout.buttonSize}; layout.contentRight = visibilityX - spacingSm; layout.labelX = layout.contentStartX + rowIconSize * 2.0f + spacingMd; return layout; } std::string FormatAddressUsdValue(double balance, double priceUsd) { if (priceUsd <= 0.0 || balance <= 0.0) return {}; char buffer[32]; const double usdValue = balance * priceUsd; if (usdValue >= 1.0) { std::snprintf(buffer, sizeof(buffer), "$%.2f", usdValue); } else if (usdValue >= 0.01) { std::snprintf(buffer, sizeof(buffer), "$%.4f", usdValue); } else { std::snprintf(buffer, sizeof(buffer), "$%.6f", usdValue); } return buffer; } } // namespace ui } // namespace dragonx