feat(market): auto-populate exchange pairs from CoinGecko (adds OurBit); DRGX dashboard
- Fetch /coins/dragonx-2/tickers once per session (App::refreshExchanges, reusing the
price-fetch worker path) and build the exchange registry at runtime into
state.market.exchanges; parseCoinGeckoTickers groups tickers by venue. The Market tab
sources from this live list and falls back to the compiled-in registry (now including
OurBit + Nonkyc.io) when offline. Fixes the missing OurBit pair and auto-tracks future
listings.
- Fix stale selection defaults (TradeOgre / DRGX-BTC -> Nonkyc.io / DRGX/USDT) that never
matched the registry, and make the attribution generic ("Price data from CoinGecko").
- Reframe the single-asset portfolio card as a DRGX holdings dashboard: relabel to
"MY DRGX" and show the 24h change on the holdings value (colored by direction).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,13 +43,19 @@ static float s_pair_drag_start_x = 0.0f;
|
||||
static float s_pair_drag_start_scroll = 0.0f;
|
||||
static bool s_market_state_loaded = false;
|
||||
|
||||
// The effective exchange registry: the live CoinGecko list when available, else the
|
||||
// compiled-in fallback.
|
||||
static const std::vector<data::ExchangeInfo>& EffectiveRegistry(const MarketInfo& market)
|
||||
{
|
||||
return market.exchanges.empty() ? data::getExchangeRegistry() : market.exchanges;
|
||||
}
|
||||
|
||||
// Helper: load selected exchange/pair from settings
|
||||
static void LoadMarketState(config::Settings* settings)
|
||||
static void LoadMarketState(config::Settings* settings, const std::vector<data::ExchangeInfo>& registry)
|
||||
{
|
||||
if (s_market_state_loaded || !settings) return;
|
||||
s_market_state_loaded = true;
|
||||
|
||||
const auto& registry = data::getExchangeRegistry();
|
||||
std::string savedExchange = settings->getSelectedExchange();
|
||||
std::string savedPair = settings->getSelectedPair();
|
||||
|
||||
@@ -104,11 +110,14 @@ void RenderMarketTab(App* app)
|
||||
const auto& state = app->getWalletState();
|
||||
const auto& market = state.market;
|
||||
|
||||
// Load persisted exchange/pair on first frame
|
||||
LoadMarketState(app->settings());
|
||||
// Kick a once-per-session live exchange-list fetch (self-guarded), then source the
|
||||
// registry from it (falling back to the compiled-in list until it arrives).
|
||||
app->refreshExchanges();
|
||||
const auto& registry = EffectiveRegistry(market);
|
||||
|
||||
// Load persisted exchange/pair on first frame
|
||||
LoadMarketState(app->settings(), registry);
|
||||
|
||||
// Exchange registry
|
||||
const auto& registry = data::getExchangeRegistry();
|
||||
if (s_exchange_idx >= (int)registry.size()) s_exchange_idx = 0;
|
||||
const auto& currentExchange = registry[s_exchange_idx];
|
||||
if (s_pair_idx >= (int)currentExchange.pairs.size()) s_pair_idx = 0;
|
||||
@@ -787,6 +796,17 @@ void RenderMarketTab(App* app)
|
||||
snprintf(buf, sizeof(buf), "$%.6f USD", portfolio_usd);
|
||||
DrawTextShadow(dl, sub1, sub1->LegacySize, ImVec2(cx, cy), Success(), buf);
|
||||
|
||||
// 24h change on the holdings (the coin's 24h % applies to the value), shown
|
||||
// beside the USD figure and colored by direction.
|
||||
if (market.change_24h != 0.0) {
|
||||
float usdW = sub1->CalcTextSizeA(sub1->LegacySize, FLT_MAX, 0, buf).x;
|
||||
char chg[48];
|
||||
snprintf(chg, sizeof(chg), "%+.2f%% %s", market.change_24h, TR("market_24h_change"));
|
||||
ImU32 chgCol = market.change_24h >= 0 ? Success() : Error();
|
||||
dl->AddText(capFont, capFont->LegacySize,
|
||||
ImVec2(cx + usdW + Layout::spacingMd(), cy + 3), chgCol, chg);
|
||||
}
|
||||
|
||||
double portfolio_btc = total_balance * market.price_btc;
|
||||
snprintf(buf, sizeof(buf), "%.10f BTC", portfolio_btc);
|
||||
float valW = sub1->CalcTextSizeA(sub1->LegacySize, FLT_MAX, 0, buf).x;
|
||||
|
||||
Reference in New Issue
Block a user