New full-node wallets now get a real 24-word recovery phrase, and users can reveal/back it up from Settings. - Pass -usemnemonic=1 to dragonxd. The daemon reads it only inside GenerateNewSeed() when a wallet has no seed yet, so it is inert on existing wallets (safe to pass unconditionally) and makes every freshly-created wallet mnemonic-backed — its phrase is then exportable via z_exportmnemonic and portable to SDXLite/ObsidianDragonLite. (Existing/legacy wallets are unaffected and keep using the chat identity's z_exportkey fallback.) - App::exportSeedPhrase() wraps z_exportmnemonic on the RPC worker with sodium_memzero wiping on every path; it flags the daemon's "not derived from a mnemonic" error as a legacy wallet rather than a failure. - New "Back up seed phrase" modal (Settings -> Backup & Data, full-node gated): reveals the phrase in a numbered word grid, copy (45s clipboard auto-clear) + save-to-file (0600), wipes the secret on every close path incl. dismiss-mid-fetch. Shared ui/windows/seed_display.h grid helper. - One-time nudge (settings flag seed_backup_reminded) toasts mnemonic-wallet users to back up their phrase; legacy wallets are not nagged. - 15 new strings translated into all 8 languages (additive, 957->972 keys); CJK subset font rebuilt for the new glyphs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
521 lines
24 KiB
C++
521 lines
24 KiB
C++
// DragonX Wallet - ImGui Edition
|
||
// Copyright 2024-2026 The Hush Developers
|
||
// Released under the GPLv3
|
||
|
||
#pragma once
|
||
|
||
#include <algorithm>
|
||
#include <cstddef>
|
||
#include <map>
|
||
#include <string>
|
||
#include <set>
|
||
#include <vector>
|
||
|
||
namespace dragonx {
|
||
namespace config {
|
||
|
||
/**
|
||
* @brief Application settings manager
|
||
*
|
||
* Handles loading and saving of user preferences.
|
||
*/
|
||
class Settings {
|
||
public:
|
||
Settings();
|
||
~Settings();
|
||
|
||
/**
|
||
* @brief Load settings from default location
|
||
* @return true if loaded successfully
|
||
*/
|
||
bool load();
|
||
|
||
/**
|
||
* @brief Load settings from specific path
|
||
* @param path Path to settings file
|
||
* @return true if loaded successfully
|
||
*/
|
||
bool load(const std::string& path);
|
||
|
||
/**
|
||
* @brief Save settings to default location
|
||
* @return true if saved successfully
|
||
*/
|
||
bool save();
|
||
|
||
/**
|
||
* @brief Save settings to specific path
|
||
* @param path Path to settings file
|
||
* @return true if saved successfully
|
||
*/
|
||
bool save(const std::string& path);
|
||
|
||
/**
|
||
* @brief Get default settings file path
|
||
*/
|
||
static std::string getDefaultPath();
|
||
|
||
enum class LiteServerSelectionPreferenceMode {
|
||
Sticky,
|
||
Random
|
||
};
|
||
|
||
// Pool selection mode for the mining tab: Manual (user picks the pool) or
|
||
// AutoBalance (the wallet spreads miners across the official pools by hashrate).
|
||
enum class PoolSelectMode {
|
||
Manual,
|
||
AutoBalance
|
||
};
|
||
|
||
struct LiteServerPreference {
|
||
std::string url;
|
||
std::string label;
|
||
bool enabled = true;
|
||
};
|
||
|
||
// A user-defined portfolio entry: a custom label tied to a group of wallet addresses.
|
||
// The Market tab's portfolio card sums these addresses' balances under the label.
|
||
struct PortfolioEntry {
|
||
std::string label;
|
||
std::vector<std::string> addresses;
|
||
std::string icon; // project_icons wallet-icon name; empty = no icon
|
||
unsigned int color = 0; // packed IM_COL32 accent; 0 = theme default
|
||
int outlineOpacity = 25; // accent-outline opacity, percent (0-100)
|
||
// Per-group price data. priceBasis: 0 = live market (USD), 1 = live market (BTC),
|
||
// 2 = DRGX only (no fiat value), 3 = manual price. Defaults preserve prior behavior
|
||
// (show DRGX + USD value).
|
||
int priceBasis = 0;
|
||
double manualPrice = 0.0; // price per DRGX for the Manual basis
|
||
std::string manualCurrency = "USD";
|
||
bool showDrgx = true; // show the DRGX amount on the card
|
||
bool showValue = true; // show the converted/fiat value on the card
|
||
bool show24h = false; // show the 24h % change (live-market bases only)
|
||
bool showSparkline = false; // show a price-trend sparkline (live-market bases only)
|
||
int sparklineInterval = 0; // 0=minute 1=hour 2=day 3=week 4=month (resample of price history)
|
||
// Dashboard grid placement on the Market portfolio. col/row in fine ~32px square cells
|
||
// (-1 = auto-place), w/h in cells (span). Set when the user drags/resizes a card.
|
||
int gridCol = -1;
|
||
int gridRow = -1;
|
||
int gridW = 8; // default group width (cells); minimum is 8
|
||
int gridH = 3; // default group height (cells); minimum is 2, card design adapts
|
||
};
|
||
|
||
// Theme
|
||
std::string getTheme() const { return theme_; }
|
||
void setTheme(const std::string& theme) { theme_ = theme; }
|
||
|
||
// Unified skin
|
||
std::string getSkinId() const { return skin_id_; }
|
||
void setSkinId(const std::string& id) { skin_id_ = id; }
|
||
|
||
// Stable z-address chosen for HushChat: the reply-to address in outgoing headers, and (for
|
||
// legacy/non-mnemonic wallets) the source of the seed-derived chat identity. Persisted so the
|
||
// identity + reply address don't shift when new addresses are generated.
|
||
std::string getChatReplyZaddr() const { return chat_reply_zaddr_; }
|
||
void setChatReplyZaddr(const std::string& z) { chat_reply_zaddr_ = z; }
|
||
|
||
// Privacy
|
||
bool getSaveZtxs() const { return save_ztxs_; }
|
||
void setSaveZtxs(bool save) { save_ztxs_ = save; }
|
||
|
||
bool getAutoShield() const { return auto_shield_; }
|
||
void setAutoShield(bool shield) { auto_shield_ = shield; }
|
||
|
||
bool getUseTor() const { return use_tor_; }
|
||
void setUseTor(bool tor) { use_tor_ = tor; }
|
||
|
||
// Fees
|
||
bool getAllowCustomFees() const { return allow_custom_fees_; }
|
||
void setAllowCustomFees(bool allow) { allow_custom_fees_ = allow; }
|
||
|
||
double getDefaultFee() const { return default_fee_; }
|
||
void setDefaultFee(double fee) { default_fee_ = fee; }
|
||
|
||
// Price
|
||
bool getFetchPrices() const { return fetch_prices_; }
|
||
void setFetchPrices(bool fetch) { fetch_prices_ = fetch; }
|
||
|
||
// Explorer URLs
|
||
std::string getTxExplorerUrl() const { return tx_explorer_url_; }
|
||
void setTxExplorerUrl(const std::string& url) { tx_explorer_url_ = url; }
|
||
|
||
std::string getAddressExplorerUrl() const { return address_explorer_url_; }
|
||
void setAddressExplorerUrl(const std::string& url) { address_explorer_url_ = url; }
|
||
|
||
// Language
|
||
std::string getLanguage() const { return language_; }
|
||
void setLanguage(const std::string& lang) { language_ = lang; }
|
||
|
||
// Visual effects
|
||
bool getAcrylicEnabled() const { return acrylic_enabled_; }
|
||
void setAcrylicEnabled(bool v) { acrylic_enabled_ = v; }
|
||
|
||
int getAcrylicQuality() const { return acrylic_quality_; }
|
||
void setAcrylicQuality(int v) { acrylic_quality_ = v; }
|
||
|
||
float getBlurMultiplier() const { return blur_multiplier_; }
|
||
void setBlurMultiplier(float v) { blur_multiplier_ = v; }
|
||
|
||
bool getReducedTransparency() const { return ui_opacity_ >= 0.99f; }
|
||
void setReducedTransparency(bool v) { if (v) ui_opacity_ = 1.0f; }
|
||
|
||
float getUIOpacity() const { return ui_opacity_; }
|
||
void setUIOpacity(float v) { ui_opacity_ = std::max(0.3f, std::min(1.0f, v)); }
|
||
|
||
float getWindowOpacity() const { return window_opacity_; }
|
||
void setWindowOpacity(float v) { window_opacity_ = std::max(0.3f, std::min(1.0f, v)); }
|
||
|
||
float getNoiseOpacity() const { return noise_opacity_; }
|
||
void setNoiseOpacity(float v) { noise_opacity_ = v; }
|
||
|
||
// Gradient background mode (use gradient variant of theme background)
|
||
bool getGradientBackground() const { return gradient_background_; }
|
||
void setGradientBackground(bool v) { gradient_background_ = v; }
|
||
|
||
// Balance layout (string ID, e.g. "classic", "donut")
|
||
std::string getBalanceLayout() const { return balance_layout_; }
|
||
void setBalanceLayout(const std::string& v) { balance_layout_ = v; }
|
||
|
||
// Console scanline effect
|
||
bool getScanlineEnabled() const { return scanline_enabled_; }
|
||
void setScanlineEnabled(bool v) { scanline_enabled_ = v; }
|
||
|
||
// Hidden addresses (addresses hidden from the UI by the user)
|
||
const std::set<std::string>& getHiddenAddresses() const { return hidden_addresses_; }
|
||
bool isAddressHidden(const std::string& addr) const { return hidden_addresses_.count(addr) > 0; }
|
||
void hideAddress(const std::string& addr) { hidden_addresses_.insert(addr); }
|
||
void unhideAddress(const std::string& addr) { hidden_addresses_.erase(addr); }
|
||
int getHiddenAddressCount() const { return (int)hidden_addresses_.size(); }
|
||
|
||
// Favorite addresses (pinned to top of address list)
|
||
const std::set<std::string>& getFavoriteAddresses() const { return favorite_addresses_; }
|
||
bool isAddressFavorite(const std::string& addr) const { return favorite_addresses_.count(addr) > 0; }
|
||
void favoriteAddress(const std::string& addr) { favorite_addresses_.insert(addr); }
|
||
void unfavoriteAddress(const std::string& addr) { favorite_addresses_.erase(addr); }
|
||
int getFavoriteAddressCount() const { return (int)favorite_addresses_.size(); }
|
||
|
||
// Address metadata (labels, icons, custom ordering)
|
||
struct AddressMeta {
|
||
std::string label;
|
||
std::string icon; // material icon name, e.g. "savings"
|
||
int sortOrder = -1; // -1 = auto (use default sort)
|
||
bool mining = false;
|
||
};
|
||
const AddressMeta& getAddressMeta(const std::string& addr) const {
|
||
static const AddressMeta empty{};
|
||
auto it = address_meta_.find(addr);
|
||
return it != address_meta_.end() ? it->second : empty;
|
||
}
|
||
void setAddressLabel(const std::string& addr, const std::string& label) {
|
||
address_meta_[addr].label = label;
|
||
}
|
||
void setAddressIcon(const std::string& addr, const std::string& icon) {
|
||
address_meta_[addr].icon = icon;
|
||
}
|
||
void setAddressSortOrder(const std::string& addr, int order) {
|
||
address_meta_[addr].sortOrder = order;
|
||
}
|
||
bool isMiningAddress(const std::string& addr) const {
|
||
auto it = address_meta_.find(addr);
|
||
return it != address_meta_.end() && it->second.mining;
|
||
}
|
||
void setMiningAddress(const std::string& addr, bool mining) {
|
||
address_meta_[addr].mining = mining;
|
||
}
|
||
std::set<std::string> getMiningAddresses() const {
|
||
std::set<std::string> addresses;
|
||
for (const auto& [addr, meta] : address_meta_) {
|
||
if (meta.mining) addresses.insert(addr);
|
||
}
|
||
return addresses;
|
||
}
|
||
int getNextSortOrder() const {
|
||
int mx = -1;
|
||
for (const auto& [k, v] : address_meta_)
|
||
if (v.sortOrder > mx) mx = v.sortOrder;
|
||
return mx + 1;
|
||
}
|
||
void swapAddressOrder(const std::string& a, const std::string& b) {
|
||
int oa = address_meta_[a].sortOrder;
|
||
int ob = address_meta_[b].sortOrder;
|
||
address_meta_[a].sortOrder = ob;
|
||
address_meta_[b].sortOrder = oa;
|
||
}
|
||
|
||
// First-run wizard
|
||
bool getWizardCompleted() const { return wizard_completed_; }
|
||
void setWizardCompleted(bool v) { wizard_completed_ = v; }
|
||
|
||
// Whether the one-time "back up your seed phrase" reminder has already been shown.
|
||
bool getSeedBackupReminded() const { return seed_backup_reminded_; }
|
||
void setSeedBackupReminded(bool v) { seed_backup_reminded_ = v; }
|
||
|
||
// Security — auto-lock timeout (seconds; 0 = disabled)
|
||
int getAutoLockTimeout() const { return auto_lock_timeout_; }
|
||
void setAutoLockTimeout(int seconds) { auto_lock_timeout_ = seconds; }
|
||
|
||
// Security — unlock duration (seconds) for walletpassphrase
|
||
int getUnlockDuration() const { return unlock_duration_; }
|
||
void setUnlockDuration(int seconds) { unlock_duration_ = seconds; }
|
||
|
||
// Security — PIN unlock enabled
|
||
bool getPinEnabled() const { return pin_enabled_; }
|
||
void setPinEnabled(bool v) { pin_enabled_ = v; }
|
||
|
||
// Daemon — keep running in background when closing the app
|
||
bool getKeepDaemonRunning() const { return keep_daemon_running_; }
|
||
void setKeepDaemonRunning(bool v) { keep_daemon_running_ = v; }
|
||
|
||
// Daemon — stop externally-started daemons on exit (default: false)
|
||
bool getStopExternalDaemon() const { return stop_external_daemon_; }
|
||
void setStopExternalDaemon(bool v) { stop_external_daemon_ = v; }
|
||
|
||
// Daemon — maximum peer connections (0 = daemon default)
|
||
int getMaxConnections() const { return max_connections_; }
|
||
void setMaxConnections(int v) { max_connections_ = std::max(0, v); }
|
||
|
||
// Lite wallet server selection
|
||
LiteServerSelectionPreferenceMode getLiteServerSelectionMode() const { return lite_server_selection_mode_; }
|
||
void setLiteServerSelectionMode(LiteServerSelectionPreferenceMode mode) { lite_server_selection_mode_ = mode; }
|
||
std::string getLiteStickyServerUrl() const { return lite_sticky_server_url_; }
|
||
void setLiteStickyServerUrl(const std::string& url) { lite_sticky_server_url_ = url; }
|
||
std::string getLiteChainName() const { return lite_chain_name_; }
|
||
void setLiteChainName(const std::string& chainName) { lite_chain_name_ = chainName; }
|
||
std::size_t getLiteRandomSelectionSeed() const { return lite_random_selection_seed_; }
|
||
void setLiteRandomSelectionSeed(std::size_t seed) { lite_random_selection_seed_ = seed; }
|
||
bool getLitePersistSelectedServer() const { return lite_persist_selected_server_; }
|
||
void setLitePersistSelectedServer(bool persist) { lite_persist_selected_server_ = persist; }
|
||
const std::vector<LiteServerPreference>& getLiteServers() const { return lite_servers_; }
|
||
void setLiteServers(const std::vector<LiteServerPreference>& servers) { lite_servers_ = servers; }
|
||
|
||
// User-defined portfolio entries (Market tab). "All funds" is implicit, not stored here.
|
||
const std::vector<PortfolioEntry>& getPortfolioEntries() const { return portfolio_entries_; }
|
||
void setPortfolioEntries(const std::vector<PortfolioEntry>& entries) { portfolio_entries_ = entries; }
|
||
|
||
// Lite servers the user has hidden from the Network tab (kept by URL, shown via a toggle).
|
||
const std::set<std::string>& getLiteHiddenServers() const { return lite_hidden_servers_; }
|
||
bool isLiteServerHidden(const std::string& url) const { return lite_hidden_servers_.count(url) > 0; }
|
||
void hideLiteServer(const std::string& url) { lite_hidden_servers_.insert(url); }
|
||
void unhideLiteServer(const std::string& url) { lite_hidden_servers_.erase(url); }
|
||
|
||
// Lite wallet rollout / kill-switch (see wallet/lite_rollout_policy.h).
|
||
// Override: "auto" (honor rollout manifest), "force_on", or "force_off".
|
||
std::string getLiteRolloutOverride() const { return lite_rollout_override_; }
|
||
void setLiteRolloutOverride(const std::string& v) { lite_rollout_override_ = v; }
|
||
// Stable, locally-generated install id used only to derive the staged-rollout bucket.
|
||
// Never transmitted; carries no PII. Generated on first use if empty.
|
||
std::string getLiteInstallId() const { return lite_install_id_; }
|
||
void setLiteInstallId(const std::string& v) { lite_install_id_ = v; }
|
||
|
||
// Verbose diagnostic logging (connection attempts, daemon state, port owner, etc.)
|
||
bool getVerboseLogging() const { return verbose_logging_; }
|
||
void setVerboseLogging(bool v) { verbose_logging_ = v; }
|
||
|
||
// Daemon — debug logging categories
|
||
const std::set<std::string>& getDebugCategories() const { return debug_categories_; }
|
||
void setDebugCategories(const std::set<std::string>& cats) { debug_categories_ = cats; }
|
||
bool hasDebugCategory(const std::string& cat) const { return debug_categories_.count(cat) > 0; }
|
||
void toggleDebugCategory(const std::string& cat) {
|
||
if (debug_categories_.count(cat)) debug_categories_.erase(cat);
|
||
else debug_categories_.insert(cat);
|
||
}
|
||
|
||
// Visual effects — animated theme effects (hue cycling, shimmer, glow, etc.)
|
||
bool getThemeEffectsEnabled() const { return theme_effects_enabled_; }
|
||
void setThemeEffectsEnabled(bool v) { theme_effects_enabled_ = v; }
|
||
|
||
// Low-spec mode — disables heavy visual effects for better performance
|
||
bool getLowSpecMode() const { return low_spec_mode_; }
|
||
void setLowSpecMode(bool v) { low_spec_mode_ = v; }
|
||
|
||
// Reduce motion — disables animated transitions for accessibility
|
||
bool getReduceMotion() const { return reduce_motion_; }
|
||
void setReduceMotion(bool v) { reduce_motion_ = v; }
|
||
|
||
// Market — last selected exchange + pair
|
||
std::string getSelectedExchange() const { return selected_exchange_; }
|
||
void setSelectedExchange(const std::string& v) { selected_exchange_ = v; }
|
||
std::string getSelectedPair() const { return selected_pair_; }
|
||
void setSelectedPair(const std::string& v) { selected_pair_ = v; }
|
||
|
||
// Pool mining
|
||
std::string getPoolUrl() const { return pool_url_; }
|
||
void setPoolUrl(const std::string& v) { pool_url_ = v; }
|
||
std::string getPoolAlgo() const { return pool_algo_; }
|
||
void setPoolAlgo(const std::string& v) { pool_algo_ = v; }
|
||
std::string getPoolWorker() const { return pool_worker_; }
|
||
void setPoolWorker(const std::string& v) { pool_worker_ = v; }
|
||
int getPoolThreads() const { return pool_threads_; }
|
||
void setPoolThreads(int v) { pool_threads_ = v; }
|
||
bool getPoolTls() const { return pool_tls_; }
|
||
void setPoolTls(bool v) { pool_tls_ = v; }
|
||
bool getPoolHugepages() const { return pool_hugepages_; }
|
||
void setPoolHugepages(bool v) { pool_hugepages_ = v; }
|
||
bool getPoolMode() const { return pool_mode_; }
|
||
void setPoolMode(bool v) { pool_mode_ = v; }
|
||
PoolSelectMode getPoolSelectMode() const { return pool_select_mode_; }
|
||
void setPoolSelectMode(PoolSelectMode v) { pool_select_mode_ = v; }
|
||
|
||
// Installed DRG-XMRig release tag (for in-app miner update detection); empty if unknown/bundled.
|
||
std::string getXmrigVersion() const { return xmrig_version_; }
|
||
void setXmrigVersion(const std::string& v) { xmrig_version_ = v; }
|
||
|
||
// Mine when idle (auto-start mining when system is idle)
|
||
bool getMineWhenIdle() const { return mine_when_idle_; }
|
||
void setMineWhenIdle(bool v) { mine_when_idle_ = v; }
|
||
int getMineIdleDelay() const { return mine_idle_delay_; }
|
||
void setMineIdleDelay(int seconds) { mine_idle_delay_ = std::max(30, seconds); }
|
||
|
||
// Idle thread scaling — scale thread count instead of start/stop
|
||
bool getIdleThreadScaling() const { return idle_thread_scaling_; }
|
||
void setIdleThreadScaling(bool v) { idle_thread_scaling_ = v; }
|
||
int getIdleThreadsActive() const { return idle_threads_active_; }
|
||
void setIdleThreadsActive(int v) { idle_threads_active_ = std::max(0, v); }
|
||
int getIdleThreadsIdle() const { return idle_threads_idle_; }
|
||
void setIdleThreadsIdle(int v) { idle_threads_idle_ = std::max(0, v); }
|
||
bool getIdleGpuAware() const { return idle_gpu_aware_; }
|
||
void setIdleGpuAware(bool v) { idle_gpu_aware_ = v; }
|
||
|
||
// Saved pool URLs (user-managed favorites dropdown)
|
||
const std::vector<std::string>& getSavedPoolUrls() const { return saved_pool_urls_; }
|
||
void addSavedPoolUrl(const std::string& url) {
|
||
// Don't add duplicates
|
||
for (const auto& u : saved_pool_urls_) if (u == url) return;
|
||
saved_pool_urls_.push_back(url);
|
||
}
|
||
void removeSavedPoolUrl(const std::string& url) {
|
||
saved_pool_urls_.erase(
|
||
std::remove(saved_pool_urls_.begin(), saved_pool_urls_.end(), url),
|
||
saved_pool_urls_.end());
|
||
}
|
||
|
||
// Saved pool worker addresses (user-managed favorites dropdown)
|
||
const std::vector<std::string>& getSavedPoolWorkers() const { return saved_pool_workers_; }
|
||
void addSavedPoolWorker(const std::string& addr) {
|
||
for (const auto& a : saved_pool_workers_) if (a == addr) return;
|
||
saved_pool_workers_.push_back(addr);
|
||
}
|
||
void removeSavedPoolWorker(const std::string& addr) {
|
||
saved_pool_workers_.erase(
|
||
std::remove(saved_pool_workers_.begin(), saved_pool_workers_.end(), addr),
|
||
saved_pool_workers_.end());
|
||
}
|
||
|
||
// Font scale (user accessibility setting, 1.0–1.5)
|
||
float getFontScale() const { return font_scale_; }
|
||
void setFontScale(float v) { font_scale_ = std::max(1.0f, std::min(1.5f, v)); }
|
||
|
||
// Window size persistence (logical pixels at 1x scale)
|
||
int getWindowWidth() const { return window_width_; }
|
||
int getWindowHeight() const { return window_height_; }
|
||
void setWindowSize(int w, int h) { window_width_ = w; window_height_ = h; }
|
||
|
||
// Returns true once after an upgrade (version mismatch detected on load)
|
||
bool needsUpgradeSave() const { return needs_upgrade_save_; }
|
||
void clearUpgradeSave() { needs_upgrade_save_ = false; }
|
||
|
||
private:
|
||
std::string settings_path_;
|
||
|
||
// Settings values
|
||
std::string theme_ = "dragonx";
|
||
std::string skin_id_ = "dragonx";
|
||
std::string chat_reply_zaddr_;
|
||
bool save_ztxs_ = true;
|
||
bool auto_shield_ = true;
|
||
bool use_tor_ = false;
|
||
bool allow_custom_fees_ = false;
|
||
double default_fee_ = 0.0001;
|
||
bool fetch_prices_ = true;
|
||
std::string tx_explorer_url_ = "https://explorer.dragonx.is/tx/";
|
||
std::string address_explorer_url_ = "https://explorer.dragonx.is/address/";
|
||
std::string language_ = "en";
|
||
bool acrylic_enabled_ = true;
|
||
int acrylic_quality_ = 2;
|
||
float blur_multiplier_ = 0.10f;
|
||
float noise_opacity_ = 0.5f;
|
||
bool gradient_background_ = false;
|
||
#ifdef _WIN32
|
||
float ui_opacity_ = 0.50f; // Card/sidebar opacity (0.3–1.0, 1.0 = opaque)
|
||
float window_opacity_ = 0.75f; // Background alpha (0.3–1.0, <1 = desktop visible)
|
||
#else
|
||
float ui_opacity_ = 1.0f; // Mac/Linux: default fully opaque
|
||
float window_opacity_ = 1.0f; // Mac/Linux: default fully opaque
|
||
#endif
|
||
std::string balance_layout_ = "classic";
|
||
bool scanline_enabled_ = true;
|
||
std::set<std::string> hidden_addresses_;
|
||
std::set<std::string> favorite_addresses_;
|
||
std::map<std::string, AddressMeta> address_meta_;
|
||
bool wizard_completed_ = false;
|
||
bool seed_backup_reminded_ = false;
|
||
int auto_lock_timeout_ = 900; // 15 minutes
|
||
int unlock_duration_ = 600; // 10 minutes
|
||
bool pin_enabled_ = false;
|
||
bool keep_daemon_running_ = false;
|
||
bool stop_external_daemon_ = false;
|
||
int max_connections_ = 0; // 0 = daemon default
|
||
|
||
// Lite wallet server preferences. These are user/server settings only;
|
||
// wallet secrets, wallet files, and lifecycle state are never stored here.
|
||
LiteServerSelectionPreferenceMode lite_server_selection_mode_ = LiteServerSelectionPreferenceMode::Sticky;
|
||
std::string lite_sticky_server_url_ = "https://lite.dragonx.is";
|
||
std::string lite_chain_name_ = "main"; // SDXL backend chain id; must be main/test/regtest
|
||
std::size_t lite_random_selection_seed_ = 0;
|
||
bool lite_persist_selected_server_ = true;
|
||
std::string lite_rollout_override_ = "auto"; // auto|force_on|force_off
|
||
std::string lite_install_id_; // random local-only id; rollout-bucket source
|
||
std::vector<LiteServerPreference> lite_servers_ = {
|
||
{"https://lite.dragonx.is", "DragonX Lite", true},
|
||
{"https://lite1.dragonx.is", "DragonX Lite 1", true},
|
||
{"https://lite2.dragonx.is", "DragonX Lite 2", true},
|
||
{"https://lite3.dragonx.is", "DragonX Lite 3", true},
|
||
{"https://lite4.dragonx.is", "DragonX Lite 4", true},
|
||
{"https://lite5.dragonx.is", "DragonX Lite 5", true}
|
||
};
|
||
std::set<std::string> lite_hidden_servers_; // server URLs hidden from the Network tab
|
||
|
||
std::vector<PortfolioEntry> portfolio_entries_; // Market tab custom portfolio groups
|
||
|
||
bool verbose_logging_ = false;
|
||
std::set<std::string> debug_categories_;
|
||
bool theme_effects_enabled_ = true;
|
||
bool low_spec_mode_ = false;
|
||
bool reduce_motion_ = false;
|
||
std::string selected_exchange_ = "Nonkyc.io";
|
||
std::string selected_pair_ = "DRGX/USDT";
|
||
|
||
// Pool mining
|
||
std::string pool_url_ = "pool.dragonx.is:3433";
|
||
std::string pool_algo_ = "rx/hush";
|
||
std::string pool_worker_ = "";
|
||
int pool_threads_ = 0;
|
||
bool pool_tls_ = false;
|
||
bool pool_hugepages_ = true;
|
||
bool pool_mode_ = false; // false=solo, true=pool
|
||
PoolSelectMode pool_select_mode_ = PoolSelectMode::Manual; // manual vs auto-balance pool choice
|
||
std::string xmrig_version_; // installed DRG-XMRig release tag (update detection)
|
||
bool mine_when_idle_ = false; // auto-start mining when system idle
|
||
int mine_idle_delay_= 120; // seconds of idle before mining starts
|
||
bool idle_thread_scaling_ = false; // scale threads instead of start/stop
|
||
int idle_threads_active_ = 0; // threads when user active (0 = auto)
|
||
int idle_threads_idle_ = 0; // threads when idle (0 = auto = all)
|
||
bool idle_gpu_aware_ = true; // treat GPU activity as non-idle
|
||
std::vector<std::string> saved_pool_urls_; // user-saved pool URL favorites
|
||
std::vector<std::string> saved_pool_workers_; // user-saved worker address favorites
|
||
|
||
// Font scale (user accessibility, 1.0–3.0; 1.0 = default)
|
||
float font_scale_ = 1.0f;
|
||
|
||
// Window size (logical pixels at 1x scale; 0 = use default 1200×775)
|
||
int window_width_ = 0;
|
||
int window_height_ = 0;
|
||
|
||
// Wallet version that last wrote this settings file (for upgrade detection)
|
||
std::string settings_version_;
|
||
bool needs_upgrade_save_ = false; // true when version changed
|
||
};
|
||
|
||
} // namespace config
|
||
} // namespace dragonx
|