feat: Full UI internationalization, pool hashrate stats, and layout caching

- Replace all hardcoded English strings with TR() translation keys across
  every tab, dialog, and component (~20 UI files)
- Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with
  complete translations (~37k lines added)
- Improve i18n loader with exe-relative path fallback and English base
  fallback for missing keys
- Add pool-side hashrate polling via pool stats API in xmrig_manager
- Introduce Layout::beginFrame() per-frame caching and refresh balance
  layout config only on schema generation change
- Offload daemon output parsing to worker thread
- Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
This commit is contained in:
dan_s
2026-03-11 00:40:50 -05:00
parent cc617dd5be
commit 96c27bb949
71 changed files with 43567 additions and 5267 deletions

View File

@@ -742,9 +742,14 @@ void App::refreshData()
state_.sync.headers = blockInfo["headers"].get<int>();
if (blockInfo.contains("verificationprogress"))
state_.sync.verification_progress = blockInfo["verificationprogress"].get<double>();
state_.sync.syncing = (state_.sync.blocks < state_.sync.headers - 2);
if (blockInfo.contains("longestchain"))
state_.longestchain = blockInfo["longestchain"].get<int>();
// Use longestchain (actual network tip) for sync check when available,
// since headers can be inflated by misbehaving peers.
if (state_.longestchain > 0)
state_.sync.syncing = (state_.sync.blocks < state_.longestchain - 2);
else
state_.sync.syncing = (state_.sync.blocks < state_.sync.headers - 2);
if (blockInfo.contains("notarized"))
state_.notarized = blockInfo["notarized"].get<int>();
}
@@ -886,12 +891,12 @@ void App::refreshBalance()
state_.sync.headers = blockInfo["headers"].get<int>();
if (blockInfo.contains("verificationprogress"))
state_.sync.verification_progress = blockInfo["verificationprogress"].get<double>();
state_.sync.syncing = (state_.sync.blocks < state_.sync.headers - 2);
// Consolidate chain-tip fields that were previously fetched
// via a separate getinfo call in refreshMiningInfo.
if (blockInfo.contains("longestchain"))
state_.longestchain = blockInfo["longestchain"].get<int>();
if (state_.longestchain > 0)
state_.sync.syncing = (state_.sync.blocks < state_.longestchain - 2);
else
state_.sync.syncing = (state_.sync.blocks < state_.sync.headers - 2);
if (blockInfo.contains("notarized"))
state_.notarized = blockInfo["notarized"].get<int>();
}
@@ -1182,7 +1187,7 @@ void App::refreshPrice()
}
std::string response_data;
const char* url = "https://api.coingecko.com/api/v3/simple/price?ids=hush&vs_currencies=usd,btc&include_24hr_change=true&include_24hr_vol=true&include_market_cap=true";
const char* url = "https://api.coingecko.com/api/v3/simple/price?ids=dragonx-2&vs_currencies=usd,btc&include_24hr_change=true&include_24hr_vol=true&include_market_cap=true";
auto write_callback = [](void* contents, size_t size, size_t nmemb, std::string* userp) -> size_t {
size_t totalSize = size * nmemb;
@@ -1205,8 +1210,8 @@ void App::refreshPrice()
if (res == CURLE_OK && http_code == 200) {
auto j = json::parse(response_data);
if (j.contains("hush")) {
const auto& data = j["hush"];
if (j.contains("dragonx-2")) {
const auto& data = j["dragonx-2"];
market.price_usd = data.value("usd", 0.0);
market.price_btc = data.value("btc", 0.0);
market.change_24h = data.value("usd_24h_change", 0.0);