From a107fda9b8f1adda9e85da65ff906884adb312af Mon Sep 17 00:00:00 2001 From: DanS Date: Sun, 12 Jul 2026 09:38:44 -0500 Subject: [PATCH] feat(market): loading spinner while the price chart fetches (pair switches) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching exchange pairs (or first load) briefly leaves the chart with no series while the venue's candles fetch, which showed the bare "No price history available" empty state. When a chart fetch is in flight — App::isMarketChartLoading() (the CoinGecko aggregate OR the per-exchange fetch) — draw a spinner + animated "Loading price history…" in the plot area instead; the "no history" text only shows when genuinely empty and idle. New i18n key market_chart_loading across all 8 languages. Verified via a forced-state render (spinner + label centered). Co-Authored-By: Claude Opus 4.8 (1M context) --- res/fonts/NotoSansCJK-Subset.ttf | Bin 618560 -> 618560 bytes res/lang/de.json | 1 + res/lang/es.json | 1 + res/lang/fr.json | 1 + res/lang/ja.json | 1 + res/lang/ko.json | 1 + res/lang/pt.json | 1 + res/lang/ru.json | 1 + res/lang/zh.json | 1 + scripts/add_missing_translations.py | 6 ++++++ src/app.h | 3 +++ src/ui/windows/market_tab.cpp | 27 ++++++++++++++++++++++----- src/util/i18n.cpp | 1 + 13 files changed, 40 insertions(+), 5 deletions(-) diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 1051892820f2b181016865251302b021bce8536c..71b0d1b0f24fc6e3191cf7051170676b0f69b49e 100644 GIT binary patch delta 83 zcmX@`K=r@_)d@vRn!OWCCQ27vV2bCr`O3h^{DJ`p?ri8Y1<}tc!z!B<7~2&XL6`}M YnSq!Eh*^P{4T#x+m}9#FBd0<>0Dle^xBvhE delta 83 zcmX@`K=r@_)d@vR9GfPVOq4DZ+!4=j^Ob>-`2_CalcTextSizeA(sub1->LegacySize, FLT_MAX, 0, msg); - dl->AddText(sub1, sub1->LegacySize, - ImVec2(chartMin.x + (availWidth - ts.x) * 0.5f, (plotTop + plotBottom) * 0.5f - ts.y * 0.5f), - OnSurfaceDisabled(), msg); + const float dp = Layout::dpiScale(); + const float ecx = chartMin.x + availWidth * 0.5f; + const float ecy = (plotTop + plotBottom) * 0.5f; + if (app->isMarketChartLoading()) { + // A fetch is in flight — e.g. just switched exchange pairs. Show a spinner + animated label + // instead of "no history", since the data is on its way. + const float r = 10.0f * dp; + const float t = (float)ImGui::GetTime() * 4.5f; // rotate ~0.7 rev/s + dl->PathArcTo(ImVec2(ecx, ecy - 8.0f * dp), r, t, t + IM_PI * 1.5f, 24); + dl->PathStroke(OnSurfaceMedium(), false, 2.5f * dp); + char lb[80]; + snprintf(lb, sizeof(lb), "%s%s", TR("market_chart_loading"), LoadingDots()); + ImVec2 ts = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, lb); + dl->AddText(capFont, capFont->LegacySize, + ImVec2(ecx - ts.x * 0.5f, ecy + 10.0f * dp), OnSurfaceMedium(), lb); + } else { + const char* msg = TR("market_no_history"); + ImVec2 ts = sub1->CalcTextSizeA(sub1->LegacySize, FLT_MAX, 0, msg); + dl->AddText(sub1, sub1->LegacySize, + ImVec2(chartMin.x + (availWidth - ts.x) * 0.5f, ecy - ts.y * 0.5f), + OnSurfaceDisabled(), msg); + } } ImGui::SetCursorScreenPos(ImVec2(chartMin.x, chartMin.y + chartH)); diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 516e4f8..627bdf2 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -1347,6 +1347,7 @@ void I18n::loadBuiltinEnglish() strings_["market_attribution"] = "Price data from CoinGecko"; strings_["market_btc_price"] = "BTC PRICE"; strings_["market_no_history"] = "No price history available"; + strings_["market_chart_loading"] = "Loading price history"; strings_["market_no_price"] = "No price data"; strings_["market_now"] = "Now"; strings_["market_pct_shielded"] = "%.0f%% Shielded";