// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once #include #include #include #include #include #include #include "data/wallet_state.h" #include "ui/sidebar.h" #include "ui/windows/console_tab.h" #include "imgui.h" // Forward declarations namespace dragonx { namespace rpc { class RPCClient; class RPCWorker; struct ConnectionConfig; } namespace config { class Settings; } namespace daemon { class EmbeddedDaemon; class XmrigManager; } namespace util { class Bootstrap; class SecureVault; } } 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 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_; } /** * @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(); } 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(); // Peers const std::vector& getPeers() const { return state_.peers; } const std::vector& getBannedPeers() const { return state_.bannedPeers; } 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; // 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); // Force refresh void refreshNow(); void refreshMiningInfo(); void refreshPeerInfo(); void refreshMarketData(); // UI navigation void setCurrentPage(ui::NavPage page) { current_page_ = 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 use_embedded_daemon_; } void setUseEmbeddedDaemon(bool use) { use_embedded_daemon_ = use; } // 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_; } // 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; decrypt_phase_ = 0; // passphrase entry decrypt_status_.clear(); decrypt_in_progress_ = false; 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; private: // Subsystems std::unique_ptr rpc_; std::unique_ptr worker_; std::unique_ptr settings_; std::unique_ptr embedded_daemon_; std::unique_ptr xmrig_manager_; 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}; std::atomic refresh_in_progress_{false}; bool address_list_dirty_ = false; // P8: dedup rebuildAddressList std::string shutdown_status_; std::thread shutdown_thread_; float shutdown_timer_ = 0.0f; std::chrono::steady_clock::time_point shutdown_start_time_; // Daemon restart (e.g. after changing debug log categories) std::atomic daemon_restarting_{false}; std::thread daemon_restart_thread_; // 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_ = true; std::string daemon_status_; mutable std::string daemon_mem_diag_; // diagnostic info for daemon memory 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; 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_; // Timers (in seconds since last update) float refresh_timer_ = 0.0f; float price_timer_ = 0.0f; float fast_refresh_timer_ = 0.0f; // For mining stats // Refresh intervals (seconds) static constexpr float REFRESH_INTERVAL = 5.0f; static constexpr float PRICE_INTERVAL = 60.0f; static constexpr float FAST_REFRESH_INTERVAL = 1.0f; // Mining refresh guard (prevents worker queue pileup) std::atomic mining_refresh_in_progress_{false}; 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 // Dirty flags for demand-driven refresh bool addresses_dirty_ = true; // true → refreshAddresses() will run bool encryption_state_prefetched_ = false; // suppress duplicate getwalletinfo on connect // First-run wizard state WizardPhase wizard_phase_ = WizardPhase::None; std::unique_ptr bootstrap_; 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; // 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 vault_; // 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; int decrypt_phase_ = 0; // 0=passphrase, 1=working, 2=done, 3=error char decrypt_pass_buf_[256] = {}; std::string decrypt_status_; bool decrypt_in_progress_ = false; // 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(); // Private methods - rendering void renderStatusBar(); void renderAboutDialog(); 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); // Private methods - data refresh void refreshData(); void refreshBalance(); void refreshAddresses(); void refreshTransactions(); void refreshPrice(); void refreshWalletEncryptionState(); void checkAutoLock(); }; } // namespace dragonx