diff --git a/res/fonts/NotoSansCJK-Subset.ttf b/res/fonts/NotoSansCJK-Subset.ttf index 1051892..71b0d1b 100644 Binary files a/res/fonts/NotoSansCJK-Subset.ttf and b/res/fonts/NotoSansCJK-Subset.ttf differ diff --git a/res/lang/de.json b/res/lang/de.json index 02a710d..aeb94cc 100644 --- a/res/lang/de.json +++ b/res/lang/de.json @@ -534,6 +534,7 @@ "market_btc_price": "BTC PREIS", "market_cap": "Marktkapitalisierung", "market_cap_short": "Kap.", + "market_chart_loading": "Preisverlauf wird geladen", "market_iv_1d": "1T", "market_iv_1h": "1S", "market_iv_1m": "1M", diff --git a/res/lang/es.json b/res/lang/es.json index a1ec805..197b511 100644 --- a/res/lang/es.json +++ b/res/lang/es.json @@ -534,6 +534,7 @@ "market_btc_price": "PRECIO BTC", "market_cap": "Cap. de Mercado", "market_cap_short": "Cap.", + "market_chart_loading": "Cargando historial de precios", "market_iv_1d": "1D", "market_iv_1h": "1H", "market_iv_1m": "1M", diff --git a/res/lang/fr.json b/res/lang/fr.json index c961ea3..3f0ad45 100644 --- a/res/lang/fr.json +++ b/res/lang/fr.json @@ -534,6 +534,7 @@ "market_btc_price": "PRIX BTC", "market_cap": "Capitalisation", "market_cap_short": "Cap.", + "market_chart_loading": "Chargement de l'historique des prix", "market_iv_1d": "1J", "market_iv_1h": "1H", "market_iv_1m": "1M", diff --git a/res/lang/ja.json b/res/lang/ja.json index 3d87dd3..e78bc8d 100644 --- a/res/lang/ja.json +++ b/res/lang/ja.json @@ -534,6 +534,7 @@ "market_btc_price": "BTC価格", "market_cap": "時価総額", "market_cap_short": "時価総額", + "market_chart_loading": "価格履歴を読み込み中", "market_iv_1d": "1日", "market_iv_1h": "1時間", "market_iv_1m": "1ヶ月", diff --git a/res/lang/ko.json b/res/lang/ko.json index c1f3a49..3e1a982 100644 --- a/res/lang/ko.json +++ b/res/lang/ko.json @@ -534,6 +534,7 @@ "market_btc_price": "BTC 가격", "market_cap": "시가총액", "market_cap_short": "시총", + "market_chart_loading": "가격 기록 불러오는 중", "market_iv_1d": "1일", "market_iv_1h": "1시간", "market_iv_1m": "1개월", diff --git a/res/lang/pt.json b/res/lang/pt.json index 4930e31..ae07b6c 100644 --- a/res/lang/pt.json +++ b/res/lang/pt.json @@ -534,6 +534,7 @@ "market_btc_price": "PREÇO BTC", "market_cap": "Capitalização", "market_cap_short": "Cap.", + "market_chart_loading": "Carregando histórico de preços", "market_iv_1d": "1D", "market_iv_1h": "1H", "market_iv_1m": "1M", diff --git a/res/lang/ru.json b/res/lang/ru.json index 411a114..211d945 100644 --- a/res/lang/ru.json +++ b/res/lang/ru.json @@ -534,6 +534,7 @@ "market_btc_price": "ЦЕНА BTC", "market_cap": "Рыночная капитализация", "market_cap_short": "Кап.", + "market_chart_loading": "Загрузка истории цен", "market_iv_1d": "1Д", "market_iv_1h": "1Ч", "market_iv_1m": "1М", diff --git a/res/lang/zh.json b/res/lang/zh.json index 7c0f123..c1d4d01 100644 --- a/res/lang/zh.json +++ b/res/lang/zh.json @@ -534,6 +534,7 @@ "market_btc_price": "BTC 价格", "market_cap": "市值", "market_cap_short": "市值", + "market_chart_loading": "正在加载价格历史", "market_iv_1d": "1天", "market_iv_1h": "1时", "market_iv_1m": "1M", diff --git a/scripts/add_missing_translations.py b/scripts/add_missing_translations.py index 7a07fd3..486bfa2 100644 --- a/scripts/add_missing_translations.py +++ b/scripts/add_missing_translations.py @@ -2254,6 +2254,12 @@ TRANSLATIONS = { "ja": "フォルダーをスキャンして他のウォレットを探す", "ko": "폴더를 스캔하여 다른 지갑 찾기" }, + "market_chart_loading": { + "es": "Cargando historial de precios", "de": "Preisverlauf wird geladen", + "fr": "Chargement de l'historique des prix", "pt": "Carregando histórico de preços", + "ru": "Загрузка истории цен", "zh": "正在加载价格历史", + "ja": "価格履歴を読み込み中", "ko": "가격 기록 불러오는 중" + }, } def main(): diff --git a/src/app.h b/src/app.h index 081f7fc..683e3c6 100644 --- a/src/app.h +++ b/src/app.h @@ -339,6 +339,9 @@ public: // Market chart shows the real per-exchange price. Re-fetches on pair change; falls back to the // CoinGecko aggregate for unmapped venues / failed fetches. Safe to call every frame. void refreshExchangeChart(); + // True while a market price-history fetch is in flight (CoinGecko aggregate OR per-exchange). The + // Market chart shows a loading indicator instead of the empty state during pair switches. + bool isMarketChartLoading() const { return chart_fetch_in_flight_ || exchange_chart_fetch_in_flight_; } /// @brief Per-category refresh intervals, adjusted by active tab using RefreshIntervals = services::NetworkRefreshService::Intervals; diff --git a/src/ui/windows/market_tab.cpp b/src/ui/windows/market_tab.cpp index 9500bd3..ea3a93d 100644 --- a/src/ui/windows/market_tab.cpp +++ b/src/ui/windows/market_tab.cpp @@ -1605,11 +1605,28 @@ static void mktDrawPriceChart(const MktCtx& cx) } } else { // Empty state, centered in the plot area (the interval strip + refresh are already drawn). - 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, (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";