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

@@ -14,6 +14,10 @@
#include <unordered_set>
#include "data/wallet_state.h"
#include "rpc/connection.h"
#include "services/network_refresh_service.h"
#include "services/wallet_security_controller.h"
#include "services/wallet_security_workflow.h"
#include "util/async_task_manager.h"
#include "ui/sidebar.h"
#include "ui/windows/console_tab.h"
#include "imgui.h"
@@ -25,7 +29,7 @@ namespace dragonx {
class RPCWorker;
}
namespace config { class Settings; }
namespace daemon { class EmbeddedDaemon; class XmrigManager; }
namespace daemon { class DaemonController; class EmbeddedDaemon; class XmrigManager; }
namespace util { class Bootstrap; class SecureVault; }
}
@@ -183,7 +187,9 @@ public:
// Peers
const std::vector<PeerInfo>& getPeers() const { return state_.peers; }
const std::vector<BannedPeer>& getBannedPeers() const { return state_.bannedPeers; }
bool isPeerRefreshInProgress() const { return peer_refresh_in_progress_.load(std::memory_order_relaxed); }
bool isPeerRefreshInProgress() const {
return network_refresh_.jobInProgress(services::NetworkRefreshService::Job::Peers);
}
void banPeer(const std::string& ip, int duration_seconds = 86400);
void unbanPeer(const std::string& ip);
void clearBans();
@@ -232,12 +238,7 @@ public:
void refreshMarketData();
/// @brief Per-category refresh intervals, adjusted by active tab
struct RefreshIntervals {
float core; // balance + sync status
float transactions; // tx list + enrichment
float addresses; // address lists + balances
float peers; // peer info (0 = disabled)
};
using RefreshIntervals = services::NetworkRefreshService::Intervals;
/// @brief Get recommended refresh intervals for a given page
static RefreshIntervals getIntervalsForPage(ui::NavPage page);
@@ -340,10 +341,7 @@ public:
void showChangePassphraseDialog() { show_change_passphrase_ = true; }
void showDecryptDialog() {
show_decrypt_dialog_ = true;
decrypt_phase_ = 0; // passphrase entry
decrypt_step_ = 0;
decrypt_status_.clear();
decrypt_in_progress_ = false;
wallet_security_workflow_.reset();
memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_));
}
@@ -357,6 +355,11 @@ public:
bool hasPendingRPCResults() const;
private:
friend class AppDaemonLifecycleRuntime;
friend class AppDaemonLifecycleTaskContext;
bool sendStopCommandSafely(rpc::RPCClient& client, const char* context);
// Subsystems
std::unique_ptr<rpc::RPCClient> rpc_;
std::unique_ptr<rpc::RPCWorker> worker_;
@@ -371,8 +374,9 @@ private:
rpc::ConnectionConfig saved_config_;
std::unique_ptr<config::Settings> settings_;
std::unique_ptr<daemon::EmbeddedDaemon> embedded_daemon_;
std::unique_ptr<daemon::DaemonController> daemon_controller_;
std::unique_ptr<daemon::XmrigManager> xmrig_manager_;
util::AsyncTaskManager async_tasks_;
bool pending_antivirus_dialog_ = false; // Show Windows Defender help dialog
// Wallet state
@@ -390,7 +394,6 @@ private:
// Daemon restart (e.g. after changing debug log categories)
std::atomic<bool> daemon_restarting_{false};
std::thread daemon_restart_thread_;
// Encryption state check timeout
float encryption_check_timer_ = 0.0f;
@@ -423,6 +426,7 @@ private:
// Connection
std::string connection_status_ = "Disconnected";
bool connection_in_progress_ = false;
bool remote_rpc_plaintext_warning_shown_ = false;
float loading_timer_ = 0.0f; // spinner animation for loading overlay
// Current page (sidebar navigation)
@@ -460,64 +464,24 @@ private:
std::string pending_memo_;
std::string pending_label_;
// Per-category timers (in seconds since last refresh)
float core_timer_ = 0.0f; // balance + sync status
float address_timer_ = 0.0f; // address lists
float transaction_timer_ = 0.0f; // transaction list
float peer_timer_ = 0.0f; // peer info
float price_timer_ = 0.0f;
float fast_refresh_timer_ = 0.0f; // For mining stats
// Default refresh intervals (seconds)
static constexpr float CORE_INTERVAL_DEFAULT = 5.0f;
static constexpr float ADDRESS_INTERVAL_DEFAULT = 15.0f;
static constexpr float TX_INTERVAL_DEFAULT = 10.0f;
static constexpr float PEER_INTERVAL_DEFAULT = 10.0f;
static constexpr float PRICE_INTERVAL = 60.0f;
static constexpr float FAST_REFRESH_INTERVAL = 1.0f;
// Active intervals — adjusted by tab priority via applyRefreshPolicy()
float active_core_interval_ = CORE_INTERVAL_DEFAULT;
float active_tx_interval_ = TX_INTERVAL_DEFAULT;
float active_addr_interval_ = ADDRESS_INTERVAL_DEFAULT;
float active_peer_interval_ = PEER_INTERVAL_DEFAULT;
// Per-category refresh guards (prevent worker queue pileup)
std::atomic<bool> core_refresh_in_progress_{false};
std::atomic<bool> address_refresh_in_progress_{false};
std::atomic<bool> tx_refresh_in_progress_{false};
// Mining refresh guard (prevents worker queue pileup)
std::atomic<bool> mining_refresh_in_progress_{false};
// Per-category refresh timers, policy, and worker queue guards.
services::NetworkRefreshService network_refresh_;
int mining_slow_counter_ = 0; // counts fast ticks; fires slow refresh every N
// Mining toggle guard (prevents concurrent setgenerate calls)
std::atomic<bool> mining_toggle_in_progress_{false};
// Peer refresh guard (visual feedback for refresh button)
std::atomic<bool> peer_refresh_in_progress_{false};
// Auto-shield guard (prevents concurrent auto-shield operations)
std::atomic<bool> auto_shield_pending_{false};
// P4: Incremental transaction cache
int last_tx_block_height_ = -1; // block height at last full tx fetch
float tx_age_timer_ = 0.0f; // seconds since last tx fetch
static constexpr float TX_MAX_AGE = 15.0f; // force tx refresh every N seconds even without new blocks
static constexpr int MAX_VIEWTX_PER_CYCLE = 25; // cap z_viewtransaction calls per refresh
// P4b: z_viewtransaction result cache — avoids re-calling the RPC for
// txids we've already enriched. Keyed by txid.
struct ViewTxCacheEntry {
std::string from_address; // first spend address
struct Output {
std::string address;
double value = 0.0;
std::string memo;
};
std::vector<Output> outgoing_outputs;
};
std::unordered_map<std::string, ViewTxCacheEntry> viewtx_cache_;
using ViewTxCacheEntry = services::NetworkRefreshService::TransactionViewCacheEntry;
services::NetworkRefreshService::TransactionViewCache viewtx_cache_;
// P4c: Confirmed transaction cache — deeply-confirmed txns (>= 10 confs)
// are accumulated here and reused across refresh cycles. Only
@@ -533,9 +497,6 @@ private:
// Pending z_sendmany operation tracking
std::vector<std::string> pending_opids_; // opids to poll for completion
float opid_poll_timer_ = 0.0f;
static constexpr float OPID_POLL_INTERVAL = 2.0f;
// Txids from completed z_sendmany operations.
// Ensures shielded sends are discoverable by z_viewtransaction
// even when they don't appear in listtransactions or
@@ -549,15 +510,13 @@ private:
std::string wizard_pending_passphrase_; // held until daemon connects
std::string wizard_saved_passphrase_; // held until PinSetup completes/skipped
// Deferred encryption (wizard background task)
std::string deferred_encrypt_passphrase_;
std::string deferred_encrypt_pin_;
bool deferred_encrypt_pending_ = false;
// Wallet security flow state shared by wizard/settings encryption paths.
services::WalletSecurityController wallet_security_;
services::WalletSecurityWorkflow wallet_security_workflow_;
// Wizard: stopping an external daemon before bootstrap
bool wizard_stopping_external_ = false;
std::string wizard_stop_status_;
std::thread wizard_stop_thread_;
// PIN vault
std::unique_ptr<util::SecureVault> vault_;
@@ -602,14 +561,7 @@ private:
// Decrypt wallet dialog state
bool show_decrypt_dialog_ = false;
int decrypt_phase_ = 0; // 0=passphrase, 1=working, 2=done, 3=error
int decrypt_step_ = 0; // 0=unlock, 1=export, 2=stop, 3=rename, 4=restart, 5=import
char decrypt_pass_buf_[256] = {};
std::string decrypt_status_;
bool decrypt_in_progress_ = false;
std::chrono::steady_clock::time_point decrypt_step_start_time_{};
std::chrono::steady_clock::time_point decrypt_overall_start_time_{};
std::atomic<bool> decrypt_import_active_{false}; // background z_importwallet running
// Wizard PIN setup state
char wizard_pin_buf_[16] = {};