Files
ObsidianDragon/src/data/wallet_state.cpp
dan_s d684db446e Refactor app services and stabilize refresh/UI flows
- Add refresh scheduler and network refresh service boundaries for typed
  refresh results, ordered RPC collectors, applicators, and price parsing.
- Add daemon lifecycle and wallet security workflow helpers while preserving
  App-owned command RPC, decrypt, cancellation, and UI handoff behavior.
- Split balance, console, mining, amount formatting, and async task logic into
  focused modules with expanded Phase 4 test coverage.
- Fix market price loading by triggering price refresh immediately, avoiding
  queue-pressure drops, tracking loading/error state, and adding translations.
- Polish send, explorer, peers, settings, theme/schema, and related tab UI.
- Replace checked-in generated language headers with build-generated resources.
- Document the cleanup audit, UI static-state guidance, and architecture updates.
2026-04-29 12:47:57 -05:00

90 lines
2.5 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "wallet_state.h"
#include <algorithm>
#include <ctime>
#include <sstream>
#include <iomanip>
namespace dragonx {
std::vector<size_t> sortedSpendableAddressIndices(const std::vector<AddressInfo>& addresses,
bool requirePositiveBalance)
{
std::vector<size_t> indices;
indices.reserve(addresses.size());
for (size_t i = 0; i < addresses.size(); ++i) {
const auto& address = addresses[i];
if (!address.isSpendable()) continue;
if (requirePositiveBalance && address.balance <= 0.0) continue;
indices.push_back(i);
}
std::sort(indices.begin(), indices.end(), [&](size_t lhs, size_t rhs) {
return addresses[lhs].balance > addresses[rhs].balance;
});
return indices;
}
int bestSpendableAddressIndex(const std::vector<AddressInfo>& addresses)
{
int bestIndex = -1;
double bestBalance = 0.0;
for (size_t i = 0; i < addresses.size(); ++i) {
if (addresses[i].isSpendable() && addresses[i].balance > bestBalance) {
bestBalance = addresses[i].balance;
bestIndex = static_cast<int>(i);
}
}
return bestIndex;
}
std::string TransactionInfo::getTimeString() const
{
if (timestamp == 0) return "Unknown";
std::time_t t = static_cast<std::time_t>(timestamp);
std::tm* tm = std::localtime(&t);
std::stringstream ss;
ss << std::put_time(tm, "%Y-%m-%d %H:%M");
return ss.str();
}
std::string TransactionInfo::getTypeDisplay() const
{
if (type == "send") return "Sent";
if (type == "receive") return "Received";
if (type == "mined" || type == "generate" || type == "immature") return "Mined";
return type;
}
std::string PeerInfo::getConnectionTime() const
{
if (conntime == 0) return "Unknown";
int64_t now = std::time(nullptr);
int64_t diff = now - conntime;
if (diff < 60) return std::to_string(diff) + "s";
if (diff < 3600) return std::to_string(diff / 60) + "m";
if (diff < 86400) return std::to_string(diff / 3600) + "h";
return std::to_string(diff / 86400) + "d";
}
std::string BannedPeer::getBannedUntilString() const
{
if (banned_until == 0) return "Never";
std::time_t t = static_cast<std::time_t>(banned_until);
std::tm* tm = std::localtime(&t);
std::stringstream ss;
ss << std::put_time(tm, "%Y-%m-%d %H:%M");
return ss.str();
}
} // namespace dragonx