// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once #include #include #include #include #include #include #include #include #include "data/transaction_history_cache.h" #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 "wallet/wallet_capabilities.h" #include "ui/sidebar.h" #include "ui/windows/console_tab.h" #include "imgui.h" // Forward declarations namespace dragonx { namespace rpc { class RPCClient; class RPCWorker; } namespace config { class Settings; } namespace daemon { class DaemonController; class EmbeddedDaemon; class XmrigManager; } namespace util { class Bootstrap; class SecureVault; } namespace wallet { class LiteWalletController; } } namespace dragonx { /** * @brief First-run wizard states */ enum class WizardPhase { None, // No wizard — normal operation BootstrapOffer, // Step 1: offer bootstrap download BootstrapInProgress,// downloading / extracting BootstrapFailed, // error with retry/skip option Appearance, // Step 2: visual effects / performance options EncryptOffer, // Step 3: offer wallet encryption EncryptInProgress, // encrypting + daemon restarting PinSetup, // Step 4: optional PIN setup (after encryption) Done // wizard complete, launch normally }; /** * @brief Encrypt-wallet dialog phases (settings page flow) */ enum class EncryptDialogPhase { PassphraseEntry, // Enter & confirm passphrase Encrypting, // In-progress animation PinSetup, // Offer PIN after successful encryption Done // Finished — close dialog }; /** * @brief Main application class * * Manages application state, RPC connection, and coordinates UI rendering. */ class App { public: App(); ~App(); // Non-copyable App(const App&) = delete; App& operator=(const App&) = delete; /** * @brief Initialize the application * @return true if initialization succeeded */ bool init(); /** * @brief Update application state (called every frame) */ void update(); /** * @brief Pre-frame tasks that must run BEFORE ImGui::NewFrame(). * * Font atlas rebuilds (hot-reload, user font scale changes) must * happen before NewFrame() because NewFrame() caches font pointers. * Rebuilding mid-frame causes dangling pointer crashes. */ void preFrame(); /** * @brief Render the application UI (called every frame) */ void render(); /** * @brief Clean shutdown */ void shutdown(); /** * @brief Check if app should exit (render loop can stop) * Enforces minimum 1-second display of shutdown screen so user sees feedback. */ bool shouldQuit() const { if (!quit_requested_ || !shutdown_complete_) return false; auto elapsed = std::chrono::steady_clock::now() - shutdown_start_time_; return elapsed >= std::chrono::seconds(1); } /** * @brief Request application exit — begins async shutdown */ void requestQuit(); /** * @brief Begin graceful shutdown (called on window close) * Starts daemon stop on a background thread while UI keeps rendering. */ void beginShutdown(); /** * @brief Whether we are in the shutdown phase */ bool isShuttingDown() const { return shutting_down_; } wallet::WalletCapabilities walletCapabilities() const { return wallet::currentWalletCapabilities(); } bool isLiteBuild() const { return wallet::isLiteBuild(walletCapabilities()); } bool supportsEmbeddedDaemon() const { return wallet::supportsEmbeddedDaemon(walletCapabilities()); } bool supportsFullNodeLifecycleActions() const { return wallet::supportsFullNodeLifecycleActions(walletCapabilities()); } bool supportsSoloMining() const { return wallet::supportsSoloMining(walletCapabilities()); } bool supportsPoolMining() const { return wallet::supportsPoolMining(walletCapabilities()); } bool supportsLiteBackend() const { return wallet::supportsLiteBackend(walletCapabilities()); } /** * @brief Render the shutdown overlay (called instead of normal UI during shutdown) */ void renderShutdownScreen(); /** * @brief Render loading overlay in content area while daemon is starting/syncing * @param contentH Height of the content area child window */ void renderLoadingOverlay(float contentH); // Accessors for subsystems rpc::RPCClient* rpc() { return rpc_.get(); } rpc::RPCWorker* worker() { return worker_.get(); } config::Settings* settings() { return settings_.get(); } // Lite wallet controller (non-null only in lite builds with a linked backend). wallet::LiteWalletController* liteWallet() { return lite_wallet_.get(); } // Reason the lite wallet failed to auto-open this session (empty if none / opened OK). const std::string& liteOpenError() const { return lite_open_error_; } // Show the lite send-time unlock modal (called when a spend is attempted on a locked wallet). void requestLiteUnlock() { lite_unlock_prompt_ = true; } // (Re)build the lite controller from current settings so a changed lite-server selection // takes effect. No-op on non-lite/unlinked builds; preserves a live wallet (see app.cpp). void rebuildLiteWallet(bool force = false); WalletState& state() { return state_; } const WalletState& state() const { return state_; } const WalletState& getWalletState() const { return state_; } // Connection state (convenience wrappers) bool isConnected() const { return state_.connected; } int getBlockHeight() const { return state_.sync.blocks; } const std::string& getConnectionStatus() const { return connection_status_; } const std::string& getDaemonStatus() const { return daemon_status_; } // Balance info (convenience wrappers) double getShieldedBalance() const { return state_.shielded_balance; } double getTransparentBalance() const { return state_.transparent_balance; } double getTotalBalance() const { return state_.total_balance; } double getUnconfirmedBalance() const { return state_.unconfirmed_balance; } // Addresses const std::vector& getZAddresses() const { return state_.z_addresses; } const std::vector& getTAddresses() const { return state_.t_addresses; } // Transactions const std::vector& getTransactions() const { return state_.transactions; } // Mining const MiningInfo& getMiningInfo() const { return state_.mining; } void startMining(int threads); void stopMining(); bool isMiningToggleInProgress() const { return mining_toggle_in_progress_.load(std::memory_order_relaxed); } // Pool mining (xmrig) void startPoolMining(int threads); void stopPoolMining(); int getXmrigRequestedThreads() const { return xmrig_manager_ ? xmrig_manager_->getRequestedThreads() : 0; } // True while the pool miner process is live — used to refuse replacing the binary under it. bool isPoolMinerRunning() const { return xmrig_manager_ && xmrig_manager_->isRunning(); } // Mine-when-idle state query bool isIdleMiningActive() const { return idle_mining_active_; } // Peers const std::vector& getPeers() const { return state_.peers; } const std::vector& getBannedPeers() const { return state_.bannedPeers; } 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(); // Address operations void createNewZAddress(std::function callback = nullptr); void createNewTAddress(std::function callback = nullptr); // Hide/unhide addresses from the address list (persisted in settings) void hideAddress(const std::string& addr); void unhideAddress(const std::string& addr); bool isAddressHidden(const std::string& addr) const; int getHiddenAddressCount() const; void favoriteAddress(const std::string& addr); void unfavoriteAddress(const std::string& addr); bool isAddressFavorite(const std::string& addr) const; // Address metadata (labels, icons, custom ordering) void setAddressLabel(const std::string& addr, const std::string& label); void setAddressIcon(const std::string& addr, const std::string& icon); std::string getAddressLabel(const std::string& addr) const; std::string getAddressIcon(const std::string& addr) const; int getAddressSortOrder(const std::string& addr) const; void setAddressSortOrder(const std::string& addr, int order); int getNextSortOrder() const; void swapAddressOrder(const std::string& a, const std::string& b); bool isMiningAddress(const std::string& addr) const; void setMiningAddress(const std::string& addr, bool mining); void invalidateAddressValidationCache(); // Key export/import void exportPrivateKey(const std::string& address, std::function callback); void exportAllKeys(std::function callback); void importPrivateKey(const std::string& key, std::function callback); // Wallet backup void backupWallet(const std::string& destination, std::function callback); // Transaction operations void sendTransaction(const std::string& from, const std::string& to, double amount, double fee, const std::string& memo, std::function callback); // Register a daemon async operation id (z_shieldcoinbase / z_mergetoaddress / // auto-shield) with the shared opid poller so its eventual success/failure is // surfaced and balances/transactions refresh on completion. z_sendmany uses the // richer pending-send path internally; this is for operations with no optimistic // transaction row of their own. void trackOperation(const std::string& opid); // Force refresh void refreshNow(); void refreshMiningInfo(); void refreshPeerInfo(); void refreshMarketData(); /// @brief Per-category refresh intervals, adjusted by active tab using RefreshIntervals = services::NetworkRefreshService::Intervals; /// @brief Get recommended refresh intervals for a given page static RefreshIntervals getIntervalsForPage(ui::NavPage page); // UI navigation void setCurrentPage(ui::NavPage page); ui::NavPage getCurrentPage() const { return current_page_; } // Dialog triggers (used by settings page to open modal dialogs) void showImportKeyDialog() { show_import_key_ = true; } void showExportKeyDialog() { show_export_key_ = true; } void showBackupDialog() { show_backup_ = true; } void showAboutDialog() { show_about_ = true; } // Legacy tab compat — maps int to NavPage void setCurrentTab(int tab); int getCurrentTab() const { return static_cast(current_page_); } // Payment URI handling void handlePaymentURI(const std::string& uri); bool hasPendingPayment() const { return pending_payment_valid_; } void clearPendingPayment() { pending_payment_valid_ = false; } std::string getPendingToAddress() const { return pending_to_address_; } double getPendingAmount() const { return pending_amount_; } std::string getPendingMemo() const { return pending_memo_; } std::string getPendingLabel() const { return pending_label_; } // Embedded daemon control bool startEmbeddedDaemon(); void stopEmbeddedDaemon(); bool isEmbeddedDaemonRunning() const; bool isUsingEmbeddedDaemon() const { return supportsEmbeddedDaemon() && use_embedded_daemon_; } void setUseEmbeddedDaemon(bool use) { use_embedded_daemon_ = use && supportsEmbeddedDaemon(); } void rescanBlockchain(); // restart daemon with -rescan flag void deleteBlockchainData(); // stop daemon, delete chain data, restart fresh bool stopDaemonForBootstrap(); // stop daemon + disconnect for bootstrap, returns true if was running bool isBootstrapDownloading() const { return bootstrap_downloading_; } void setBootstrapDownloading(bool v) { bootstrap_downloading_ = v; } // Get daemon memory usage in MB (uses embedded daemon handle if available, // falls back to platform-level process scan for external daemons) double getDaemonMemoryUsageMB() const; // Diagnostic string describing daemon memory detection path (for debugging) const std::string& getDaemonMemDiag() const { return daemon_mem_diag_; } // Background gradient overlay texture void setGradientTexture(ImTextureID tex) { gradient_tex_ = tex; } ImTextureID getGradientTexture() const { return gradient_tex_; } // Logo texture accessor (wallet branding icon) ImTextureID getLogoTexture() const { return logo_tex_; } int getLogoWidth() const { return logo_w_; } int getLogoHeight() const { return logo_h_; } // Coin logo texture accessor (DragonX currency icon for balance tab) ImTextureID getCoinLogoTexture() const { return coin_logo_tex_; } /** * @brief Reload theme images (background gradient + logo) from new paths * @param bgPath Path to background image override (empty = use default) * @param logoPath Path to logo image override (empty = use default) */ void reloadThemeImages(const std::string& bgPath, const std::string& logoPath); // Wizard / first-run WizardPhase getWizardPhase() const { return wizard_phase_; } bool isFirstRun() const; /** * @brief Stop daemon and re-run the setup wizard * Called from Settings. Daemon restarts automatically when wizard completes. */ void restartWizard(); /** * @brief Restart the embedded daemon (e.g. after changing debug categories) * Shows "Restarting daemon..." in the loading overlay while the daemon cycles. */ void restartDaemon(); // Wallet encryption helpers void encryptWalletWithPassphrase(const std::string& passphrase); void unlockWallet(const std::string& passphrase, int timeout); void lockWallet(); void changePassphrase(const std::string& oldPass, const std::string& newPass); // Dialog triggers for encryption (from settings page) void showEncryptDialog() { show_encrypt_dialog_ = true; encrypt_dialog_phase_ = EncryptDialogPhase::PassphraseEntry; encrypt_status_.clear(); memset(encrypt_pass_buf_, 0, sizeof(encrypt_pass_buf_)); memset(encrypt_confirm_buf_, 0, sizeof(encrypt_confirm_buf_)); memset(enc_dlg_pin_buf_, 0, sizeof(enc_dlg_pin_buf_)); memset(enc_dlg_pin_confirm_buf_, 0, sizeof(enc_dlg_pin_confirm_buf_)); enc_dlg_saved_passphrase_.clear(); enc_dlg_pin_status_.clear(); } void showChangePassphraseDialog() { show_change_passphrase_ = true; } void showDecryptDialog() { show_decrypt_dialog_ = true; wallet_security_workflow_.reset(); memset(decrypt_pass_buf_, 0, sizeof(decrypt_pass_buf_)); } // Dialog triggers for PIN (from settings page) void showPinSetupDialog() { show_pin_setup_ = true; pin_status_.clear(); } void showPinChangeDialog() { show_pin_change_ = true; pin_status_.clear(); } void showPinRemoveDialog() { show_pin_remove_ = true; pin_status_.clear(); } bool hasPinVault() const; /// @brief Check if RPC worker has queued results waiting to be processed bool hasPendingRPCResults() const; bool hasTransactionSendProgress() const { return send_progress_active_ || send_submissions_in_flight_ > 0 || !pending_opids_.empty(); } std::string transactionSendProgressText() const; std::string transactionRefreshProgressText() const; // Copy a SECRET (seed phrase, private key) to the clipboard and arm an auto-clear: after a // short delay the clipboard is wiped IF it still holds this secret (so we don't clobber // something the user copied afterwards). Only a hash of the secret is retained, never the // plaintext. Call pumpSecretClipboardClear() each frame to action the clear. void copySecretToClipboard(const std::string& secret); void pumpSecretClipboardClear(); bool isTransactionRefreshInProgress() const { return network_refresh_.jobInProgress(services::NetworkRefreshService::Job::Transactions); } private: friend class AppDaemonLifecycleRuntime; friend class AppDaemonLifecycleTaskContext; bool sendStopCommandSafely(rpc::RPCClient& client, const char* context); void maybeFinishTransactionSendProgress(); void upsertPendingSendTransaction(const std::string& opid, const std::string& from, const std::string& to, double amount, const std::string& memo); void markPendingSendTransactionSucceeded(const std::string& opid, const std::string& txid); void removePendingSendTransactions(const std::vector& opids, bool restoreBalances); // Deliver a deferred z_sendmany result to its waiting UI callback once the opid // reaches a terminal status. Returns true if a callback was registered (and fired). bool invokeSendResultCallback(const std::string& opid, bool ok, const std::string& result); void applyPendingSendBalanceDeltas(bool includeAggregateBalances); std::string transactionHistoryCacheWalletIdentity() const; bool ensureTransactionHistoryCacheUnlockedFor(const std::string& walletIdentity); void unlockTransactionHistoryCacheWithPassphrase(const std::string& passphrase); void loadTransactionHistoryCacheIfAvailable(); void storeTransactionHistoryCacheIfAvailable(); void wipePendingTransactionHistoryCachePassphrase(); void resetTransactionHistoryCacheSession(); void pruneShieldedHistoryScanProgress(); void invalidateShieldedHistoryScanProgress(bool persistCache); // Subsystems std::unique_ptr rpc_; std::unique_ptr worker_; // Fast-lane: dedicated RPC connection + worker for 1-second mining polls. // Runs on its own thread with its own curl handle so it never blocks behind // the main refresh batch. std::unique_ptr fast_rpc_; std::unique_ptr fast_worker_; // Saved connection credentials (needed to open the fast-lane connection) rpc::ConnectionConfig saved_config_; std::unique_ptr settings_; std::unique_ptr lite_wallet_; // lite builds w/ linked backend // Pending send_tab callback for an in-flight lite send (delivered in update() once the // controller's async broadcast result arrives). Only one lite send runs at a time. std::function lite_send_callback_; // One-shot guard: auto-open an existing lite wallet on the first update() tick (kept off // init() so a slow initialize_existing network call doesn't freeze startup before the window). bool lite_autoopen_done_ = false; double lite_open_last_attempt_ = 0.0; // ImGui time of the last async open attempt (retry timer) // Reason an existing lite wallet failed to auto-open (e.g. server unreachable). Surfaced in // the UI so a stuck "disconnected" state isn't silent; cleared once a wallet opens. std::string lite_open_error_; // Lite first-run welcome prompt: dismissed for the session once the user picks an action. bool lite_firstrun_dismissed_ = false; // Lite send-time unlock: set to show the unlock modal when a spend is attempted while locked. bool lite_unlock_prompt_ = false; // One-shot: prompt to unlock on startup once we learn the auto-opened wallet is encrypted+locked. bool lite_startup_lock_checked_ = false; std::unique_ptr daemon_controller_; std::unique_ptr xmrig_manager_; util::AsyncTaskManager async_tasks_; bool pending_antivirus_dialog_ = false; // Show Windows Defender help dialog // Wallet state WalletState state_; // Shutdown state std::atomic shutting_down_{false}; std::atomic shutdown_complete_{false}; bool address_list_dirty_ = false; // P8: dedup rebuildAddressList std::string shutdown_status_; std::thread shutdown_thread_; float shutdown_timer_ = 0.0f; bool force_quit_confirm_ = false; std::chrono::steady_clock::time_point shutdown_start_time_; // Daemon restart (e.g. after changing debug log categories) std::atomic daemon_restarting_{false}; // Encryption state check timeout float encryption_check_timer_ = 0.0f; // UI State bool quit_requested_ = false; bool show_demo_window_ = false; bool show_settings_ = false; bool show_about_ = false; bool show_import_key_ = false; bool show_export_key_ = false; bool show_backup_ = false; bool show_address_book_ = false; // Embedded daemon state bool use_embedded_daemon_ = wallet::supportsEmbeddedDaemon(wallet::currentWalletCapabilities()); std::string daemon_status_; mutable std::string daemon_mem_diag_; // diagnostic info for daemon memory detection size_t daemon_output_offset_ = 0; // for incremental output parsing (rescan detection) // Export/Import state std::string export_result_; char import_key_input_[512] = {0}; std::string export_address_; std::string import_status_; bool import_success_ = false; std::string backup_status_; bool backup_success_ = false; // Connection std::string connection_status_ = "Disconnected"; bool connection_in_progress_ = false; bool remote_rpc_plaintext_warning_shown_ = false; // Startup daemon-launch diagnostics: bound the "RPC port busy, no config" wait before warning, // and show the embedded-daemon start failure (binary/params/spawn) only once. Reset on connect. int daemon_wait_attempts_ = 0; bool daemon_start_error_shown_ = false; int daemon_last_seen_crashes_ = 0; // surface each new embedded-daemon crash reason once bool refresh_policy_syncing_ = false; // whether the sync-throttle refresh profile is active // Auto-clear for secrets copied to the clipboard. Only a hash of the copied secret is kept. std::uint64_t clipboard_secret_hash_ = 0; double clipboard_clear_deadline_ = 0.0; float loading_timer_ = 0.0f; // spinner animation for loading overlay // Current page (sidebar navigation) ui::NavPage current_page_ = ui::NavPage::Overview; ui::NavPage prev_page_ = ui::NavPage::Overview; float page_alpha_ = 1.0f; // 0→1 fade on page switch bool sidebar_collapsed_ = false; // true = icon-only mode bool sidebar_user_toggled_ = false; // user manually toggled — suppress auto-collapse float sidebar_width_anim_ = 0.0f; // animated width (0 = uninitialized) float prev_dpi_scale_ = 0.0f; // detect DPI changes to snap sidebar width // Background gradient overlay ImTextureID gradient_tex_ = 0; // Logo texture (reload on skin change / dark↔light switch) ImTextureID logo_tex_ = 0; int logo_w_ = 0; int logo_h_ = 0; bool logo_loaded_ = false; bool logo_is_dark_variant_ = true; // tracks which variant is currently loaded // Coin logo texture (DragonX currency icon, separate from wallet branding) ImTextureID coin_logo_tex_ = 0; int coin_logo_w_ = 0; int coin_logo_h_ = 0; bool coin_logo_loaded_ = false; // Console tab ui::ConsoleTab console_tab_; // Pending payment from URI bool pending_payment_valid_ = false; std::string pending_to_address_; double pending_amount_ = 0.0; std::string pending_memo_; std::string pending_label_; // 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 mining_toggle_in_progress_{false}; // Auto-shield guard (prevents concurrent auto-shield operations) std::atomic auto_shield_pending_{false}; // P4: Incremental transaction cache int last_tx_block_height_ = -1; // block height at last full tx fetch static constexpr int MAX_VIEWTX_PER_CYCLE = 25; // cap z_viewtransaction calls per refresh std::size_t shielded_history_scan_cursor_ = 0; bool shielded_history_scan_pending_ = false; std::unordered_map shielded_history_scan_heights_; // P4b: z_viewtransaction result cache — avoids re-calling the RPC for // txids we've already enriched. Keyed by txid. 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 // recent/unconfirmed txns are re-fetched from the daemon each time. std::vector confirmed_tx_cache_; std::unordered_set confirmed_tx_ids_; // fast lookup int confirmed_cache_block_ = -1; // block height when cache was last built // Dirty flags for demand-driven refresh bool addresses_dirty_ = true; // true → refreshAddresses() will run bool address_validation_cache_dirty_ = true; bool transactions_dirty_ = false; // true → force tx refresh regardless of block height bool encryption_state_prefetched_ = false; // suppress duplicate getwalletinfo on connect bool rescan_status_poll_in_progress_ = false; // True once we've actually observed the rescan running (daemon restarted into -rescan warmup). // Gates the "rescan complete" detection so a getrescaninfo poll that hits the still-running // pre-restart daemon (which reports rescanning=false) can't fire a false "complete" instantly. bool rescan_confirmed_active_ = false; bool opid_poll_in_progress_ = false; // Consecutive Core-refresh cycles where BOTH core RPCs failed → likely a dead // connection. After kCoreFailuresBeforeDisconnect, tear down and reconnect. int consecutive_core_failures_ = 0; // Pending z_sendmany operation tracking bool send_progress_active_ = false; int send_submissions_in_flight_ = 0; std::vector pending_opids_; // opids to poll for completion struct PendingSendInfo { std::string from; std::string to; std::string memo; double amount = 0.0; std::int64_t timestamp = 0; }; std::unordered_map pending_send_info_; // z_sendmany UI callbacks held until the opid reaches a terminal status, so the // user isn't told "sent successfully" before the tx is actually built/broadcast. std::unordered_map> pending_send_callbacks_; // Txids from completed z_sendmany operations. // Ensures shielded sends are discoverable by z_viewtransaction // even when they don't appear in listtransactions or // z_listreceivedbyaddress. std::unordered_set send_txids_; // First-run wizard state WizardPhase wizard_phase_ = WizardPhase::None; std::unique_ptr bootstrap_; bool bootstrap_downloading_ = false; // true while settings bootstrap dialog is active std::string wizard_pending_passphrase_; // held until daemon connects std::string wizard_saved_passphrase_; // held until PinSetup completes/skipped // 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_; // PIN vault std::unique_ptr vault_; data::TransactionHistoryCache transaction_history_cache_; std::string pending_transaction_history_cache_passphrase_; bool transaction_history_cache_loaded_ = false; // Lock screen state bool lock_screen_was_visible_ = false; // tracks lock→unlock transitions for auto-focus bool lock_use_pin_ = true; // true = PIN input, false = passphrase input char lock_pin_buf_[16] = {}; char lock_passphrase_buf_[256] = {}; std::string lock_error_msg_; float lock_error_timer_ = 0.0f; int lock_attempts_ = 0; float lock_lockout_timer_ = 0.0f; bool lock_unlock_in_progress_ = false; // Encrypt wallet dialog state bool show_encrypt_dialog_ = false; bool show_change_passphrase_ = false; EncryptDialogPhase encrypt_dialog_phase_ = EncryptDialogPhase::PassphraseEntry; char encrypt_pass_buf_[256] = {}; char encrypt_confirm_buf_[256] = {}; char change_old_pass_buf_[256] = {}; char change_new_pass_buf_[256] = {}; char change_confirm_buf_[256] = {}; std::string encrypt_status_; bool encrypt_in_progress_ = false; std::string enc_dlg_saved_passphrase_; // held for PIN setup after encrypt char enc_dlg_pin_buf_[16] = {}; char enc_dlg_pin_confirm_buf_[16] = {}; std::string enc_dlg_pin_status_; // PIN setup dialog state (settings page) bool show_pin_setup_ = false; bool show_pin_change_ = false; bool show_pin_remove_ = false; char pin_buf_[16] = {}; char pin_confirm_buf_[16] = {}; char pin_old_buf_[16] = {}; char pin_passphrase_buf_[256] = {}; std::string pin_status_; bool pin_in_progress_ = false; // Decrypt wallet dialog state bool show_decrypt_dialog_ = false; char decrypt_pass_buf_[256] = {}; // Wizard PIN setup state char wizard_pin_buf_[16] = {}; char wizard_pin_confirm_buf_[16] = {}; std::string wizard_pin_status_; // Auto-lock on idle std::chrono::steady_clock::time_point last_interaction_ = std::chrono::steady_clock::now(); // Mine-when-idle: auto-start/stop mining based on system idle state bool idle_mining_active_ = false; // true when mining was auto-started by idle detection bool idle_scaled_to_idle_ = false; // true when threads have been scaled up for idle // Private methods - rendering void renderStatusBar(); void renderAboutDialog(); void renderLiteFirstRunPrompt(); // lite-only welcome modal when no wallet exists yet void renderLiteUnlockPrompt(); // lite-only send-time unlock modal void renderImportKeyDialog(); void renderExportKeyDialog(); void renderBackupDialog(); void renderFirstRunWizard(); void renderLockScreen(); void renderEncryptWalletDialog(); void renderDecryptWalletDialog(); void renderPinDialogs(); void renderAntivirusHelpDialog(); void processDeferredEncryption(); // Private methods - connection void tryConnect(); void onConnected(); void onDisconnected(const std::string& reason); // Set the "node is initializing" UI state (status line + overlay description) from the // embedded/external daemon's launch state and its own console output (current phase + block // height), so a connect probe that times out while the daemon loads shows WHAT it's doing. // `reachableButBusy` is true when the probe connected but got no RPC reply (a timeout), // false when the daemon is merely launching (not bound yet). Returns the status title. std::string applyDaemonInitStatus(bool reachableButBusy); // Tear down a connection that died mid-session (daemon crash / restart / dropped // socket) so update()'s reconnect branch re-enters tryConnect(). Unlike onDisconnected // alone, this also rpc_->disconnect()s so rpc_->isConnected() actually flips to false. void handleLostConnection(const std::string& reason); void applyDefaultBanlist(); // Private methods - data refresh void refreshData(); // Orchestrator: dispatches per-category refreshes void refreshCoreData(); // Balance + blockchain info (can use fast_worker_) void refreshAddressData(); // Address lists + balances void refreshTransactionData(); // Transaction list + z_viewtransaction enrichment void refreshRecentTransactionData(); // Lightweight recent/unconfirmed tx poll bool refreshEncryptionState(); // Wallet encryption/lock state void refreshBalance(); // Legacy: balance-only refresh (used by specific callers) void refreshAddresses(); // Legacy: standalone address refresh void refreshPrice(); void refreshWalletEncryptionState(); void applyRefreshPolicy(ui::NavPage page); bool currentPageNeedsWalletDataRefresh() const; bool shouldRunWalletTransactionRefresh() const; bool shouldRefreshTransactions() const; bool shouldRefreshRecentTransactions() const; void checkAutoLock(); void checkIdleMining(); }; } // namespace dragonx