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.
This commit is contained in:
2026-04-29 12:47:57 -05:00
parent ee8a08e569
commit 9edab31728
95 changed files with 8776 additions and 37563 deletions

View File

@@ -6,6 +6,8 @@
#include <cstdlib>
#include <cstdio>
#include <cerrno>
#include <cctype>
#include <cstring>
#include <fstream>
#include <sstream>
@@ -31,6 +33,8 @@
#include <pwd.h>
#include <dirent.h>
#include <dlfcn.h>
#include <spawn.h>
#include <sys/wait.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <sys/sysctl.h>
@@ -40,25 +44,83 @@
#include "../util/logger.h"
#ifndef _WIN32
extern char **environ;
#endif
namespace dragonx {
namespace util {
namespace {
bool hasAllowedUrlScheme(const std::string& url)
{
auto startsWithNoCase = [&url](const char* prefix) {
for (size_t i = 0; prefix[i] != '\0'; ++i) {
if (i >= url.size()) return false;
unsigned char lhs = static_cast<unsigned char>(url[i]);
unsigned char rhs = static_cast<unsigned char>(prefix[i]);
if (std::tolower(lhs) != std::tolower(rhs)) return false;
}
return true;
};
return startsWithNoCase("http://") || startsWithNoCase("https://");
}
#ifndef _WIN32
bool launchOpener(const char* opener, const std::string& target)
{
char* const argv[] = {
const_cast<char*>(opener),
const_cast<char*>(target.c_str()),
nullptr
};
pid_t pid = 0;
int rc = posix_spawnp(&pid, opener, nullptr, nullptr, argv, environ);
if (rc != 0) {
DEBUG_LOGF("Failed to launch %s: %s\n", opener, std::strerror(rc));
return false;
}
int status = 0;
pid_t waited = 0;
do {
waited = waitpid(pid, &status, 0);
} while (waited < 0 && errno == EINTR);
if (waited < 0) {
DEBUG_LOGF("Failed waiting for %s launcher: %s\n", opener, std::strerror(errno));
return false;
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
DEBUG_LOGF("Launcher %s exited with status %d\n", opener,
WIFEXITED(status) ? WEXITSTATUS(status) : -1);
return false;
}
return true;
}
#endif
} // namespace
bool Platform::openUrl(const std::string& url)
{
if (url.empty()) return false;
if (!hasAllowedUrlScheme(url)) {
DEBUG_LOGF("Refusing to open URL with unsupported scheme: %s\n", url.c_str());
return false;
}
#ifdef _WIN32
// Windows: Use ShellExecute
HINSTANCE result = ShellExecuteA(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
return (reinterpret_cast<intptr_t>(result) > 32);
#elif defined(__APPLE__)
// macOS: Use 'open' command
std::string cmd = "open \"" + url + "\" &";
return (system(cmd.c_str()) == 0);
return launchOpener("open", url);
#else
// Linux: Use xdg-open
std::string cmd = "xdg-open \"" + url + "\" >/dev/null 2>&1 &";
return (system(cmd.c_str()) == 0);
return launchOpener("xdg-open", url);
#endif
}
@@ -68,15 +130,12 @@ bool Platform::openFolder(const std::string& path, bool createIfMissing)
// Create directory if it doesn't exist
if (createIfMissing) {
#ifdef _WIN32
// Windows: Create directory recursively
std::string cmd = "mkdir \"" + path + "\" 2>nul";
(void)system(cmd.c_str()); // Ignore return value - dir may already exist
#else
// Linux/macOS: Create directory with parents
std::string cmd = "mkdir -p \"" + path + "\" 2>/dev/null";
(void)system(cmd.c_str()); // Ignore return value - dir may already exist
#endif
std::error_code ec;
std::filesystem::create_directories(path, ec);
if (ec) {
DEBUG_LOGF("Failed to create folder %s: %s\n", path.c_str(), ec.message().c_str());
return false;
}
}
#ifdef _WIN32
@@ -84,13 +143,9 @@ bool Platform::openFolder(const std::string& path, bool createIfMissing)
HINSTANCE result = ShellExecuteA(nullptr, "explore", path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
return (reinterpret_cast<intptr_t>(result) > 32);
#elif defined(__APPLE__)
// macOS: Use 'open' command (works for folders too)
std::string cmd = "open \"" + path + "\" &";
return (system(cmd.c_str()) == 0);
return launchOpener("open", path);
#else
// Linux: Use xdg-open (works for folders too)
std::string cmd = "xdg-open \"" + path + "\" >/dev/null 2>&1 &";
return (system(cmd.c_str()) == 0);
return launchOpener("xdg-open", path);
#endif
}