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)
This commit is contained in:
173
src/ui/windows/export_transactions_dialog.cpp
Normal file
173
src/ui/windows/export_transactions_dialog.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "export_transactions_dialog.h"
|
||||
#include "../../app.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 <fstream>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
// Static state
|
||||
static bool s_open = false;
|
||||
static char s_filename[256] = "";
|
||||
static std::string s_status;
|
||||
|
||||
// Helper to escape CSV field
|
||||
static std::string escapeCSV(const std::string& field)
|
||||
{
|
||||
if (field.find(',') != std::string::npos ||
|
||||
field.find('"') != std::string::npos ||
|
||||
field.find('\n') != std::string::npos) {
|
||||
// Escape quotes and wrap in quotes
|
||||
std::string escaped;
|
||||
escaped.reserve(field.size() + 4);
|
||||
escaped += '"';
|
||||
for (char c : field) {
|
||||
if (c == '"') escaped += "\"\"";
|
||||
else escaped += c;
|
||||
}
|
||||
escaped += '"';
|
||||
return escaped;
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
void ExportTransactionsDialog::show()
|
||||
{
|
||||
s_open = true;
|
||||
s_status.clear();
|
||||
|
||||
// Generate default filename 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));
|
||||
snprintf(s_filename, sizeof(s_filename), "dragonx_transactions_%s.csv", timebuf);
|
||||
}
|
||||
|
||||
bool ExportTransactionsDialog::isOpen()
|
||||
{
|
||||
return s_open;
|
||||
}
|
||||
|
||||
void ExportTransactionsDialog::render(App* app)
|
||||
{
|
||||
if (!s_open) return;
|
||||
|
||||
auto& S = schema::UI();
|
||||
auto win = S.window("dialogs.export-transactions");
|
||||
auto exportBtn = S.button("dialogs.export-transactions", "export-button");
|
||||
auto closeBtn = S.button("dialogs.export-transactions", "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("Export Transactions to CSV");
|
||||
if (effects::ImGuiAcrylic::BeginAcrylicPopupModal("Export Transactions to CSV", &s_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar, acrylicTheme.popup)) {
|
||||
const auto& state = app->getWalletState();
|
||||
|
||||
ImGui::Text("Export %zu transactions to CSV file.", state.transactions.size());
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Filename
|
||||
ImGui::Text("Output filename:");
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
ImGui::InputText("##Filename", s_filename, sizeof(s_filename));
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextDisabled("File will be saved in: ~/.config/ObsidianDragon/");
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Export button
|
||||
if (material::StyledButton("Export", ImVec2(exportBtn.width, 0), S.resolveFont(exportBtn.font))) {
|
||||
if (state.transactions.empty()) {
|
||||
Notifications::instance().warning("No transactions to export");
|
||||
} else {
|
||||
std::string configDir = util::Platform::getConfigDir();
|
||||
std::string filepath = configDir + "/" + s_filename;
|
||||
|
||||
std::ofstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
s_status = "Failed to create file";
|
||||
Notifications::instance().error("Failed to create CSV file");
|
||||
} else {
|
||||
// Write CSV header
|
||||
file << "Date,Type,Amount,Address,TXID,Confirmations,Memo\n";
|
||||
|
||||
// Write transactions
|
||||
for (const auto& tx : state.transactions) {
|
||||
// Date
|
||||
std::time_t t = static_cast<std::time_t>(tx.timestamp);
|
||||
char datebuf[32];
|
||||
std::strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M:%S", std::localtime(&t));
|
||||
file << datebuf << ",";
|
||||
|
||||
// Type
|
||||
file << escapeCSV(tx.type) << ",";
|
||||
|
||||
// Amount
|
||||
std::ostringstream amt;
|
||||
amt << std::fixed << std::setprecision(8) << tx.amount;
|
||||
file << amt.str() << ",";
|
||||
|
||||
// Address
|
||||
file << escapeCSV(tx.address) << ",";
|
||||
|
||||
// TXID
|
||||
file << escapeCSV(tx.txid) << ",";
|
||||
|
||||
// Confirmations
|
||||
file << tx.confirmations << ",";
|
||||
|
||||
// Memo
|
||||
file << escapeCSV(tx.memo) << "\n";
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
s_status = "Exported " + std::to_string(state.transactions.size()) +
|
||||
" transactions to: " + filepath;
|
||||
Notifications::instance().success("Transactions exported successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
effects::ImGuiAcrylic::EndAcrylicPopup();
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user