- Replace all hardcoded English strings with TR() translation keys across every tab, dialog, and component (~20 UI files) - Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with complete translations (~37k lines added) - Improve i18n loader with exe-relative path fallback and English base fallback for missing keys - Add pool-side hashrate polling via pool stats API in xmrig_manager - Introduce Layout::beginFrame() per-frame caching and refresh balance layout config only on schema generation change - Offload daemon output parsing to worker thread - Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
602 lines
24 KiB
C++
602 lines
24 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#include "settings_window.h"
|
|
#include "../../app.h"
|
|
#include "../../config/version.h"
|
|
#include "../../config/settings.h"
|
|
#include "../../util/i18n.h"
|
|
#include "../../util/platform.h"
|
|
#include "../../rpc/rpc_client.h"
|
|
#include "../theme.h"
|
|
#include "../schema/ui_schema.h"
|
|
#include "../schema/skin_manager.h"
|
|
#include "../notifications.h"
|
|
#include "../effects/imgui_acrylic.h"
|
|
#include "../material/draw_helpers.h"
|
|
#include "../../embedded/IconsMaterialDesign.h"
|
|
#include "imgui.h"
|
|
#include <vector>
|
|
#include <filesystem>
|
|
|
|
// Icon text for settings UI
|
|
#define ICON_CUSTOM_THEME ICON_MD_TUNE
|
|
#define ICON_REFRESH_THEMES ICON_MD_REFRESH
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
|
|
// Helper: build "TranslatedLabel##id" for ImGui widgets that use label as ID
|
|
static std::string TrId(const char* tr_key, const char* id) {
|
|
std::string s = TR(tr_key);
|
|
s += "##";
|
|
s += id;
|
|
return s;
|
|
}
|
|
|
|
// Settings state - these get loaded from Settings on window open
|
|
static bool s_initialized = false;
|
|
static int s_language_index = 0;
|
|
static bool s_save_ztxs = true;
|
|
static bool s_allow_custom_fees = false;
|
|
static bool s_auto_shield = false;
|
|
static bool s_fetch_prices = true;
|
|
static bool s_use_tor = false;
|
|
static char s_rpc_host[128] = DRAGONX_DEFAULT_RPC_HOST;
|
|
static char s_rpc_port[16] = DRAGONX_DEFAULT_RPC_PORT;
|
|
static char s_rpc_user[64] = "";
|
|
static char s_rpc_password[64] = "";
|
|
static char s_tx_explorer[256] = "https://explorer.dragonx.is/tx/";
|
|
static char s_addr_explorer[256] = "https://explorer.dragonx.is/address/";
|
|
|
|
// Acrylic settings
|
|
static bool s_acrylic_enabled = true;
|
|
static float s_blur_amount = 1.5f; // 0.0=Off, continuous blur multiplier
|
|
static float s_noise_opacity = 0.5f;
|
|
static bool s_reduced_transparency = false; // Accessibility option
|
|
static bool s_gradient_background = false; // Gradient background mode
|
|
|
|
// Saved skin ID for cancel/revert
|
|
static std::string s_saved_skin_id;
|
|
|
|
// Load current settings into UI state
|
|
static void loadSettingsToUI(config::Settings* settings) {
|
|
if (!settings) return;
|
|
|
|
s_saved_skin_id = settings->getSkinId();
|
|
s_save_ztxs = settings->getSaveZtxs();
|
|
s_allow_custom_fees = settings->getAllowCustomFees();
|
|
s_auto_shield = settings->getAutoShield();
|
|
s_fetch_prices = settings->getFetchPrices();
|
|
s_use_tor = settings->getUseTor();
|
|
|
|
strncpy(s_tx_explorer, settings->getTxExplorerUrl().c_str(), sizeof(s_tx_explorer) - 1);
|
|
strncpy(s_addr_explorer, settings->getAddressExplorerUrl().c_str(), sizeof(s_addr_explorer) - 1);
|
|
|
|
// Set language index
|
|
auto& i18n = util::I18n::instance();
|
|
const auto& languages = i18n.getAvailableLanguages();
|
|
std::string current_lang = settings->getLanguage();
|
|
if (current_lang.empty()) current_lang = "en";
|
|
|
|
s_language_index = 0;
|
|
int idx = 0;
|
|
for (const auto& lang : languages) {
|
|
if (lang.first == current_lang) {
|
|
s_language_index = idx;
|
|
break;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
s_initialized = true;
|
|
}
|
|
|
|
// Save UI state to settings
|
|
static void saveSettingsFromUI(config::Settings* settings) {
|
|
if (!settings) return;
|
|
|
|
settings->setTheme(settings->getSkinId()); // Theme now synced with skin
|
|
settings->setSaveZtxs(s_save_ztxs);
|
|
settings->setAllowCustomFees(s_allow_custom_fees);
|
|
settings->setAutoShield(s_auto_shield);
|
|
settings->setFetchPrices(s_fetch_prices);
|
|
settings->setUseTor(s_use_tor);
|
|
settings->setTxExplorerUrl(s_tx_explorer);
|
|
settings->setAddressExplorerUrl(s_addr_explorer);
|
|
|
|
// Save language
|
|
auto& i18n = util::I18n::instance();
|
|
const auto& languages = i18n.getAvailableLanguages();
|
|
auto it = languages.begin();
|
|
std::advance(it, s_language_index);
|
|
if (it != languages.end()) {
|
|
settings->setLanguage(it->first);
|
|
}
|
|
|
|
// Save acrylic / visual effects settings
|
|
settings->setAcrylicEnabled(s_acrylic_enabled);
|
|
settings->setAcrylicQuality(s_blur_amount > 0.001f ? static_cast<int>(effects::AcrylicQuality::Low) : static_cast<int>(effects::AcrylicQuality::Off));
|
|
settings->setBlurMultiplier(s_blur_amount);
|
|
settings->setReducedTransparency(s_reduced_transparency);
|
|
settings->setNoiseOpacity(s_noise_opacity);
|
|
settings->setGradientBackground(s_gradient_background);
|
|
|
|
settings->save();
|
|
}
|
|
|
|
void RenderSettingsWindow(App* app, bool* p_open)
|
|
{
|
|
// Load settings on first open
|
|
if (!s_initialized && app->settings()) {
|
|
loadSettingsToUI(app->settings());
|
|
// Initialize acrylic settings from current state
|
|
s_acrylic_enabled = effects::ImGuiAcrylic::IsEnabled();
|
|
s_blur_amount = effects::ImGuiAcrylic::GetBlurMultiplier();
|
|
s_noise_opacity = effects::ImGuiAcrylic::GetNoiseOpacity();
|
|
s_reduced_transparency = effects::ImGuiAcrylic::GetReducedTransparency();
|
|
s_gradient_background = schema::SkinManager::instance().isGradientMode();
|
|
}
|
|
|
|
auto& S = schema::UI();
|
|
auto win = S.window("dialogs.settings");
|
|
auto lbl = S.label("dialogs.settings", "label");
|
|
auto cmb = S.combo("dialogs.settings", "combo");
|
|
auto connLbl = S.label("dialogs.settings", "connection-label");
|
|
auto portInput = S.input("dialogs.settings", "port-input");
|
|
auto walletBtn = S.button("dialogs.settings", "wallet-button");
|
|
auto saveBtn = S.button("dialogs.settings", "save-button");
|
|
auto cancelBtn = S.button("dialogs.settings", "cancel-button");
|
|
|
|
if (!material::BeginOverlayDialog(TR("settings"), p_open, win.width, 0.94f)) {
|
|
return;
|
|
}
|
|
|
|
if (ImGui::BeginTabBar("SettingsTabs")) {
|
|
// General settings tab
|
|
if (ImGui::BeginTabItem(TR("general"))) {
|
|
ImGui::Spacing();
|
|
|
|
// Skin/theme selection
|
|
ImGui::Text("%s", TR("theme"));
|
|
ImGui::SameLine(lbl.position);
|
|
|
|
// Active skin combo (populated from SkinManager)
|
|
auto& skinMgr = schema::SkinManager::instance();
|
|
const auto& skins = skinMgr.available();
|
|
|
|
// Find active skin for preview text
|
|
std::string active_preview = "DragonX";
|
|
bool active_is_custom = false;
|
|
for (const auto& skin : skins) {
|
|
if (skin.id == skinMgr.activeSkinId()) {
|
|
active_preview = skin.name;
|
|
active_is_custom = !skin.bundled;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
if (ImGui::BeginCombo("##Theme", active_preview.c_str())) {
|
|
// Bundled themes header
|
|
ImGui::TextDisabled("%s", TR("settings_builtin"));
|
|
ImGui::Separator();
|
|
for (size_t i = 0; i < skins.size(); i++) {
|
|
const auto& skin = skins[i];
|
|
if (!skin.bundled) continue;
|
|
bool is_selected = (skin.id == skinMgr.activeSkinId());
|
|
|
|
if (ImGui::Selectable(skin.name.c_str(), is_selected)) {
|
|
skinMgr.setActiveSkin(skin.id);
|
|
if (app->settings()) {
|
|
app->settings()->setSkinId(skin.id);
|
|
app->settings()->save();
|
|
}
|
|
}
|
|
if (is_selected) {
|
|
ImGui::SetItemDefaultFocus();
|
|
}
|
|
}
|
|
|
|
// Custom themes (if any)
|
|
bool has_custom = false;
|
|
for (const auto& skin : skins) {
|
|
if (!skin.bundled) { has_custom = true; break; }
|
|
}
|
|
if (has_custom) {
|
|
ImGui::Spacing();
|
|
ImGui::TextDisabled("%s", TR("settings_custom"));
|
|
ImGui::Separator();
|
|
for (size_t i = 0; i < skins.size(); i++) {
|
|
const auto& skin = skins[i];
|
|
if (skin.bundled) continue;
|
|
bool is_selected = (skin.id == skinMgr.activeSkinId());
|
|
|
|
if (!skin.valid) {
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
|
|
ImGui::BeginDisabled(true);
|
|
std::string label = skin.name + " (invalid)";
|
|
ImGui::Selectable(label.c_str(), false);
|
|
ImGui::EndDisabled();
|
|
ImGui::PopStyleColor();
|
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
|
ImGui::SetTooltip("%s", skin.validationError.c_str());
|
|
}
|
|
} else {
|
|
std::string label = skin.name;
|
|
if (!skin.author.empty()) {
|
|
label += " (" + skin.author + ")";
|
|
}
|
|
if (ImGui::Selectable(label.c_str(), is_selected)) {
|
|
skinMgr.setActiveSkin(skin.id);
|
|
if (app->settings()) {
|
|
app->settings()->setSkinId(skin.id);
|
|
app->settings()->save();
|
|
}
|
|
}
|
|
if (is_selected) {
|
|
ImGui::SetItemDefaultFocus();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndCombo();
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", TR("tt_theme_hotkey"));
|
|
|
|
// Show indicator if custom theme is active
|
|
if (active_is_custom) {
|
|
ImGui::SameLine();
|
|
ImGui::PushFont(material::Type().iconSmall());
|
|
ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), ICON_CUSTOM_THEME);
|
|
ImGui::PopFont();
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("%s", TR("tt_custom_theme"));
|
|
}
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
ImGui::PushFont(material::Type().iconSmall());
|
|
if (material::StyledButton(ICON_REFRESH_THEMES, ImVec2(0, 0))) {
|
|
skinMgr.refresh();
|
|
Notifications::instance().info("Theme list refreshed");
|
|
}
|
|
ImGui::PopFont();
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip(TR("tt_scan_themes"),
|
|
schema::SkinManager::getUserSkinsDirectory().c_str());
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
|
|
// Language selection
|
|
ImGui::Text("%s", TR("language"));
|
|
ImGui::SameLine(lbl.position);
|
|
auto& i18n = util::I18n::instance();
|
|
const auto& languages = i18n.getAvailableLanguages();
|
|
|
|
// Build language display names array
|
|
std::vector<const char*> lang_names;
|
|
lang_names.reserve(languages.size());
|
|
for (const auto& lang : languages) {
|
|
lang_names.push_back(lang.second.c_str()); // Display name
|
|
}
|
|
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
if (ImGui::Combo("##Language", &s_language_index, lang_names.data(), static_cast<int>(lang_names.size()))) {
|
|
// Get locale code from index
|
|
auto it = languages.begin();
|
|
std::advance(it, s_language_index);
|
|
i18n.loadLanguage(it->first);
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("settings_language_note"));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Acrylic Effects settings
|
|
ImGui::Text("%s", TR("settings_visual_effects"));
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("settings_acrylic_level"));
|
|
ImGui::SameLine(lbl.position);
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
{
|
|
char blur_fmt[16];
|
|
if (s_blur_amount < 0.01f)
|
|
snprintf(blur_fmt, sizeof(blur_fmt), "Off");
|
|
else
|
|
snprintf(blur_fmt, sizeof(blur_fmt), "%.0f%%%%", s_blur_amount * 25.0f);
|
|
if (ImGui::SliderFloat("##AcrylicBlur", &s_blur_amount, 0.0f, 4.0f, blur_fmt,
|
|
ImGuiSliderFlags_AlwaysClamp)) {
|
|
if (s_blur_amount > 0.0f && s_blur_amount < 0.15f) s_blur_amount = 0.0f;
|
|
s_acrylic_enabled = (s_blur_amount > 0.001f);
|
|
effects::ImGuiAcrylic::ApplyBlurAmount(s_blur_amount);
|
|
}
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("tt_blur"));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Text("%s", TR("settings_noise_opacity"));
|
|
ImGui::SameLine(lbl.position);
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
{
|
|
char noise_fmt[16];
|
|
if (s_noise_opacity < 0.01f)
|
|
snprintf(noise_fmt, sizeof(noise_fmt), "Off");
|
|
else
|
|
snprintf(noise_fmt, sizeof(noise_fmt), "%.0f%%%%", s_noise_opacity * 100.0f);
|
|
if (ImGui::SliderFloat("##NoiseOpacity", &s_noise_opacity, 0.0f, 1.0f, noise_fmt,
|
|
ImGuiSliderFlags_AlwaysClamp)) {
|
|
effects::ImGuiAcrylic::SetNoiseOpacity(s_noise_opacity);
|
|
}
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("tt_noise"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
// Accessibility: Reduced transparency
|
|
if (ImGui::Checkbox(TrId("settings_reduce_transparency", "reduce_trans").c_str(), &s_reduced_transparency)) {
|
|
effects::ImGuiAcrylic::SetReducedTransparency(s_reduced_transparency);
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("settings_solid_colors_desc"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (ImGui::Checkbox(TrId("simple_background", "simple_bg").c_str(), &s_gradient_background)) {
|
|
schema::SkinManager::instance().setGradientMode(s_gradient_background);
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("settings_gradient_desc"));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Privacy settings
|
|
ImGui::Text("%s", TR("settings_privacy"));
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Checkbox(TrId("settings_save_shielded_local", "save_ztx_w").c_str(), &s_save_ztxs);
|
|
ImGui::TextDisabled(" %s", TR("settings_save_shielded_desc"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Checkbox(TrId("settings_auto_shield_funds", "auto_shld_w").c_str(), &s_auto_shield);
|
|
ImGui::TextDisabled(" %s", TR("settings_auto_shield_desc"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Checkbox(TrId("settings_use_tor_network", "tor_w").c_str(), &s_use_tor);
|
|
ImGui::TextDisabled(" %s", TR("settings_tor_desc"));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Other settings
|
|
ImGui::Text("%s", TR("settings_other"));
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Checkbox(TrId("custom_fees", "fees_w").c_str(), &s_allow_custom_fees);
|
|
ImGui::Checkbox(TrId("fetch_prices", "prices_w").c_str(), &s_fetch_prices);
|
|
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
// Connection settings tab
|
|
if (ImGui::BeginTabItem(TR("settings_connection"))) {
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("settings_rpc_connection"));
|
|
ImGui::TextDisabled("%s", TR("settings_configure_rpc"));
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("rpc_host"));
|
|
ImGui::SameLine(connLbl.position);
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
ImGui::InputText("##RPCHost", s_rpc_host, sizeof(s_rpc_host));
|
|
|
|
ImGui::Text("%s", TR("rpc_port"));
|
|
ImGui::SameLine(connLbl.position);
|
|
ImGui::SetNextItemWidth(portInput.width);
|
|
ImGui::InputText("##RPCPort", s_rpc_port, sizeof(s_rpc_port));
|
|
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("rpc_user"));
|
|
ImGui::SameLine(connLbl.position);
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
ImGui::InputText("##RPCUser", s_rpc_user, sizeof(s_rpc_user));
|
|
|
|
ImGui::Text("%s", TR("rpc_pass"));
|
|
ImGui::SameLine(connLbl.position);
|
|
ImGui::SetNextItemWidth(cmb.width);
|
|
ImGui::InputText("##RPCPassword", s_rpc_password, sizeof(s_rpc_password),
|
|
ImGuiInputTextFlags_Password);
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::TextDisabled("%s", TR("settings_rpc_note"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
if (material::StyledButton(TR("test_connection"), ImVec2(0,0), S.resolveFont("button"))) {
|
|
if (app->rpc()) {
|
|
app->rpc()->getInfo([](const nlohmann::json& result, const std::string& error) {
|
|
if (error.empty()) {
|
|
std::string version = result.value("version", "unknown");
|
|
std::string msg = "Connection successful!\ndragonxd version: " + version;
|
|
Notifications::instance().success(msg);
|
|
} else {
|
|
Notifications::instance().error("Connection failed: " + error);
|
|
}
|
|
});
|
|
} else {
|
|
Notifications::instance().error("RPC client not initialized");
|
|
}
|
|
}
|
|
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
// Wallet tab
|
|
if (ImGui::BeginTabItem(TR("wallet"))) {
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("settings_wallet_maintenance"));
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
if (material::StyledButton(TR("rescan"), ImVec2(walletBtn.width, 0), S.resolveFont(walletBtn.font))) {
|
|
if (app->rpc()) {
|
|
// Start rescan from block 0
|
|
app->rpc()->rescanBlockchain(0, [](const nlohmann::json& result, const std::string& error) {
|
|
if (error.empty()) {
|
|
int start = result.value("start_height", 0);
|
|
int end = result.value("stop_height", 0);
|
|
std::string msg = "Rescan started from block " + std::to_string(start) +
|
|
" to " + std::to_string(end);
|
|
Notifications::instance().success(msg);
|
|
} else {
|
|
Notifications::instance().error("Rescan failed: " + error);
|
|
}
|
|
});
|
|
} else {
|
|
Notifications::instance().error("RPC client not initialized");
|
|
}
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("settings_rescan_desc"));
|
|
|
|
ImGui::Spacing();
|
|
|
|
static bool s_confirm_clear_ztx = false;
|
|
if (material::StyledButton(TR("settings_clear_ztx_long"), ImVec2(walletBtn.width, 0), S.resolveFont(walletBtn.font))) {
|
|
s_confirm_clear_ztx = true;
|
|
}
|
|
ImGui::TextDisabled(" %s", TR("settings_clear_ztx_desc"));
|
|
|
|
// Confirmation dialog
|
|
if (s_confirm_clear_ztx) {
|
|
if (material::BeginOverlayDialog(TR("confirm_clear_ztx_title"), &s_confirm_clear_ztx, 480.0f, 0.94f)) {
|
|
ImGui::PushFont(material::Type().iconLarge());
|
|
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), ICON_MD_WARNING);
|
|
ImGui::PopFont();
|
|
ImGui::SameLine();
|
|
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "%s", TR("warning"));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::TextWrapped("%s", TR("confirm_clear_ztx_warning1"));
|
|
ImGui::Spacing();
|
|
ImGui::TextWrapped("%s", TR("confirm_clear_ztx_warning2"));
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
|
if (ImGui::Button(TR("cancel"), ImVec2(btnW, 40))) {
|
|
s_confirm_clear_ztx = false;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f));
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.3f, 0.3f, 1.0f));
|
|
if (ImGui::Button(TrId("clear_anyway", "clear_ztx_w").c_str(), ImVec2(btnW, 40))) {
|
|
std::string ztx_file = util::Platform::getDragonXDataDir() + "ztx_history.json";
|
|
if (util::Platform::deleteFile(ztx_file)) {
|
|
Notifications::instance().success("Z-transaction history cleared");
|
|
} else {
|
|
Notifications::instance().info("No history file found");
|
|
}
|
|
s_confirm_clear_ztx = false;
|
|
}
|
|
ImGui::PopStyleColor(2);
|
|
material::EndOverlayDialog();
|
|
}
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("settings_wallet_info"));
|
|
ImGui::Spacing();
|
|
|
|
// Get actual wallet size
|
|
std::string wallet_path = util::Platform::getDragonXDataDir() + "wallet.dat";
|
|
uint64_t wallet_size = util::Platform::getFileSize(wallet_path);
|
|
if (wallet_size > 0) {
|
|
std::string size_str = util::Platform::formatFileSize(wallet_size);
|
|
ImGui::Text(TR("settings_wallet_file_size"), size_str.c_str());
|
|
} else {
|
|
ImGui::TextDisabled("%s", TR("settings_wallet_not_found"));
|
|
}
|
|
ImGui::Text(TR("settings_wallet_location"), wallet_path.c_str());
|
|
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
// Explorer tab
|
|
if (ImGui::BeginTabItem(TR("explorer"))) {
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("settings_block_explorer_urls"));
|
|
ImGui::TextDisabled("%s", TR("settings_configure_explorer"));
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::Text("%s", TR("transaction_url"));
|
|
ImGui::SetNextItemWidth(-1);
|
|
ImGui::InputText("##TxExplorer", s_tx_explorer, sizeof(s_tx_explorer));
|
|
|
|
ImGui::Text("%s", TR("address_url"));
|
|
ImGui::SetNextItemWidth(-1);
|
|
ImGui::InputText("##AddrExplorer", s_addr_explorer, sizeof(s_addr_explorer));
|
|
|
|
ImGui::Spacing();
|
|
ImGui::TextDisabled("%s", TR("settings_explorer_hint"));
|
|
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
ImGui::EndTabBar();
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Save/Cancel buttons
|
|
if (material::StyledButton(TR("save"), ImVec2(saveBtn.width, 0), S.resolveFont(saveBtn.font))) {
|
|
saveSettingsFromUI(app->settings());
|
|
Notifications::instance().success("Settings saved");
|
|
*p_open = false;
|
|
}
|
|
ImGui::SameLine();
|
|
if (material::StyledButton(TR("cancel"), ImVec2(cancelBtn.width, 0), S.resolveFont(cancelBtn.font))) {
|
|
// Reload settings to revert changes
|
|
loadSettingsToUI(app->settings());
|
|
// Revert skin to what was active when settings opened
|
|
if (!s_saved_skin_id.empty()) {
|
|
schema::SkinManager::instance().setActiveSkin(s_saved_skin_id);
|
|
if (app->settings()) {
|
|
app->settings()->setSkinId(s_saved_skin_id);
|
|
app->settings()->save();
|
|
}
|
|
}
|
|
*p_open = false;
|
|
}
|
|
|
|
material::EndOverlayDialog();
|
|
}
|
|
|
|
} // namespace ui
|
|
} // namespace dragonx
|