Files
ObsidianDragon/src/ui/windows/backup_wallet_dialog.cpp
DanS 3aee55b49c ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency.
Built with Dear ImGui, SDL3, and OpenGL3/DX11.

Features:
- Send/receive shielded and transparent transactions
- Autoshield with merged transaction display
- Built-in CPU mining (xmrig)
- Peer management and network monitoring
- Wallet encryption with PIN lock
- QR code generation for receive addresses
- Transaction history with pagination
- Console for direct RPC commands
- Cross-platform (Linux, Windows)
2026-02-27 00:26:01 -06:00

200 lines
7.1 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "backup_wallet_dialog.h"
#include "../../app.h"
#include "../../rpc/rpc_client.h"
#include "../../rpc/rpc_worker.h"
#include "../../util/i18n.h"
#include "../../util/platform.h"
#include "../notifications.h"
#include "../schema/ui_schema.h"
#include "../material/draw_helpers.h"
#include "../theme.h"
#include "../effects/imgui_acrylic.h"
#include "imgui.h"
#include <string>
#include <ctime>
#include <fstream>
#include <filesystem>
namespace dragonx {
namespace ui {
namespace fs = std::filesystem;
using json = nlohmann::json;
// Static state
static bool s_open = false;
static char s_destination[512] = "";
static std::string s_status;
static bool s_backing_up = false;
void BackupWalletDialog::show()
{
s_open = true;
s_status.clear();
s_backing_up = false;
// Generate default destination with timestamp
std::time_t now = std::time(nullptr);
char timebuf[32];
std::strftime(timebuf, sizeof(timebuf), "%Y%m%d_%H%M%S", std::localtime(&now));
// Default to home directory
std::string home = util::Platform::getHomeDir();
snprintf(s_destination, sizeof(s_destination), "%s/wallet_backup_%s.dat", home.c_str(), timebuf);
}
bool BackupWalletDialog::isOpen()
{
return s_open;
}
void BackupWalletDialog::render(App* app)
{
if (!s_open) return;
auto& S = schema::UI();
auto win = S.window("dialogs.backup-wallet");
auto backupBtn = S.button("dialogs.backup-wallet", "backup-button");
auto closeBtn = S.button("dialogs.backup-wallet", "close-button");
ImGui::SetNextWindowSize(ImVec2(win.width, win.height), ImGuiCond_FirstUseEver);
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowFocus();
const auto& acrylicTheme = GetCurrentAcrylicTheme();
ImGui::OpenPopup("Backup Wallet");
if (effects::ImGuiAcrylic::BeginAcrylicPopupModal("Backup Wallet", &s_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar, acrylicTheme.popup)) {
ImGui::TextWrapped(
"Create a backup of your wallet.dat file. This file contains all your "
"private keys and transaction history. Store the backup in a secure location."
);
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
if (s_backing_up) {
ImGui::BeginDisabled();
}
// Destination path
ImGui::Text("Backup destination:");
ImGui::SetNextItemWidth(-1);
ImGui::InputText("##Destination", s_destination, sizeof(s_destination));
ImGui::Spacing();
// Show wallet.dat location
std::string walletPath = util::Platform::getDataDir() + "/wallet.dat";
ImGui::TextDisabled("Source: %s", walletPath.c_str());
// Check if source exists
bool sourceExists = fs::exists(walletPath);
if (!sourceExists) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));
ImGui::Text("Warning: wallet.dat not found at expected location");
ImGui::PopStyleColor();
}
if (s_backing_up) {
ImGui::EndDisabled();
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Backup button - use RPC backupwallet
if (s_backing_up) {
ImGui::BeginDisabled();
}
if (material::StyledButton("Create Backup", ImVec2(backupBtn.width, 0), S.resolveFont(backupBtn.font))) {
if (strlen(s_destination) == 0) {
Notifications::instance().warning("Please enter a destination path");
} else if (!app->rpc() || !app->rpc()->isConnected()) {
Notifications::instance().error("Not connected to daemon");
} else {
s_backing_up = true;
s_status = "Creating backup...";
// Run backup on worker thread to avoid freezing UI
std::string dest(s_destination);
if (app->worker()) {
app->worker()->post([rpc = app->rpc(), dest]() -> rpc::RPCWorker::MainCb {
bool success = false;
std::string statusMsg;
try {
rpc->call("backupwallet", json::array({dest}));
// Check if file was created
if (fs::exists(dest)) {
auto size = fs::file_size(dest);
char sizebuf[32];
if (size > 1024 * 1024) {
snprintf(sizebuf, sizeof(sizebuf), "%.2f MB", size / (1024.0 * 1024.0));
} else if (size > 1024) {
snprintf(sizebuf, sizeof(sizebuf), "%.2f KB", size / 1024.0);
} else {
snprintf(sizebuf, sizeof(sizebuf), "%zu bytes", size);
}
statusMsg = std::string("Backup created successfully (") + sizebuf + ")";
success = true;
} else {
statusMsg = "Backup may have failed - file not found";
}
} catch (const std::exception& e) {
statusMsg = std::string("Backup failed: ") + e.what();
}
return [success, statusMsg]() {
s_status = statusMsg;
s_backing_up = false;
if (success) {
Notifications::instance().success("Wallet backup created");
} else {
Notifications::instance().warning(statusMsg);
}
};
});
}
}
}
if (s_backing_up) {
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::TextDisabled("Backing up...");
}
ImGui::SameLine();
if (material::StyledButton("Close", ImVec2(closeBtn.width, 0), S.resolveFont(closeBtn.font))) {
s_open = false;
}
// Status
if (!s_status.empty()) {
ImGui::Spacing();
ImGui::TextWrapped("%s", s_status.c_str());
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Tips
ImGui::TextDisabled("Tips:");
ImGui::BulletText("Store backups on external drives or cloud storage");
ImGui::BulletText("Create multiple backups in different locations");
ImGui::BulletText("Test restoring from backup periodically");
}
effects::ImGuiAcrylic::EndAcrylicPopup();
}
} // namespace ui
} // namespace dragonx