Refactor app services and stabilize refresh/UI flows

- Add refresh scheduler and network refresh service boundaries for typed
  refresh results, ordered RPC collectors, applicators, and price parsing.
- Add daemon lifecycle and wallet security workflow helpers while preserving
  App-owned command RPC, decrypt, cancellation, and UI handoff behavior.
- Split balance, console, mining, amount formatting, and async task logic into
  focused modules with expanded Phase 4 test coverage.
- Fix market price loading by triggering price refresh immediately, avoiding
  queue-pressure drops, tracking loading/error state, and adding translations.
- Polish send, explorer, peers, settings, theme/schema, and related tab UI.
- Replace checked-in generated language headers with build-generated resources.
- Document the cleanup audit, UI static-state guidance, and architecture updates.
This commit is contained in:
2026-04-29 12:47:57 -05:00
parent ee8a08e569
commit 9edab31728
95 changed files with 8776 additions and 37563 deletions

View File

@@ -267,13 +267,12 @@ static void fetchBlockDetailByHash(App* app, const std::string& hash) {
});
}
static void fetchRecentBlocks(App* app, int currentHeight, int count = 10) {
static bool fetchRecentBlocks(App* app, int currentHeight, int count = 10) {
auto* worker = app->worker();
auto* rpc = app->rpc();
if (!worker || !rpc || s_pending_block_fetches > 0) return;
if (!worker || !rpc || s_pending_block_fetches > 0) return false;
s_recent_blocks.clear();
s_recent_blocks.resize(count);
if (s_recent_blocks.empty()) s_recent_blocks.resize(count);
s_pending_block_fetches = 1; // single batched fetch
worker->post([rpc, currentHeight, count]() -> rpc::RPCWorker::MainCb {
@@ -295,11 +294,19 @@ static void fetchRecentBlocks(App* app, int currentHeight, int count = 10) {
bs.tx_count = static_cast<int>(result["tx"].size());
} catch (...) {}
}
return [results]() {
s_recent_blocks = results;
return [results = std::move(results)]() mutable {
bool gotAny = false;
for (const auto& block : results) {
if (block.height > 0) {
gotAny = true;
break;
}
}
if (gotAny) s_recent_blocks = std::move(results);
s_pending_block_fetches = 0;
};
});
return true;
}
static void fetchMempoolInfo(App* app) {
@@ -567,10 +574,12 @@ static void renderRecentBlocks(App* app, float availWidth) {
if (bs.height > 0) blocks.push_back(&bs);
}
// Fixed card height — content scrolls inside
// Stretch card to fill the remaining tab height; rows scroll inside.
float maxRows = 10.0f;
float contentH = capFont->LegacySize + Layout::spacingXs() + rowH * maxRows;
float tableH = headerH + contentH + pad;
float minTableH = headerH + contentH + pad;
float remainingH = ImGui::GetContentRegionAvail().y;
float tableH = std::max(minTableH, remainingH - Layout::spacingSm());
ImVec2 cardMin = ImGui::GetCursorScreenPos();
ImVec2 cardMax(cardMin.x + availWidth, cardMin.y + tableH);
@@ -1024,12 +1033,15 @@ void RenderExplorerTab(App* app)
float availWidth = ImGui::GetContentRegionAvail().x;
// Auto-refresh recent blocks when chain height changes
if (state.sync.blocks > 0 && state.sync.blocks != s_last_known_height) {
s_last_known_height = state.sync.blocks;
// Auto-refresh recent blocks when chain height changes, but avoid
// starting expensive block fetches while the user is viewing details.
if (state.sync.blocks > 0 && state.sync.blocks != s_last_known_height &&
!s_show_detail_modal && !s_detail_loading && !s_tx_loading) {
if (rpc && rpc->isConnected()) {
fetchRecentBlocks(app, state.sync.blocks);
fetchMempoolInfo(app);
if (fetchRecentBlocks(app, state.sync.blocks)) {
s_last_known_height = state.sync.blocks;
fetchMempoolInfo(app);
}
}
}