improve diagnostics, security UX, and network tab refresh

Diagnostics & logging:
- add verbose logging system (VERBOSE_LOGF) with toggle in Settings
- forward app-level log messages to Console tab for in-UI visibility
- add detailed connection attempt logging (attempt #, daemon state,
  config paths, auth failures, port owner identification)
- detect HTTP 401 auth failures and show actionable error messages
- identify port owner process (PID + name) on both Linux and Windows
- demote noisy acrylic/shader traces from DEBUG_LOGF to VERBOSE_LOGF
- persist verbose_logging preference in settings.json
- link iphlpapi on Windows for GetExtendedTcpTable

Security & encryption:
- update local encryption state immediately after encryptwallet RPC
  so Settings reflects the change before daemon restarts
- show notifications for encrypt success/failure and PIN skip
- use dedicated RPC client for z_importwallet during decrypt flow
  to avoid blocking main rpc_ curl_mutex (which starved peer/tx refresh)
- force full state refresh (addresses, transactions, peers) after
  successful wallet import

Network tab:
- redesign peers refresh button as glass-panel with icon + label,
  matching the mining button style
- add spinning arc animation while peer data is loading
  (peer_refresh_in_progress_ atomic flag set/cleared in refreshPeerInfo)
- prevent double-click spam during refresh
- add refresh-button size to ui.toml

Other:
- use fast_rpc_ for rescan polling to avoid blocking on main rpc_
- enable DRAGONX_DEBUG in all build configs (was debug-only)
- setup.sh: pull latest xmrig-hac when repo already exists
This commit is contained in:
dan_s
2026-03-05 05:26:04 -06:00
parent c51d3dafff
commit 4b16a2a2c4
19 changed files with 461 additions and 52 deletions

View File

@@ -1200,7 +1200,7 @@ void AcrylicMaterial::resize(int width, int height)
dx_blurHeight_ = bh;
dx_blurCurrent_ = 0;
dirtyFrames_ = 2;
DEBUG_LOGF("[Acrylic DX11] Resized %dx%d (blur %dx%d)\n", width, height, bw, bh);
VERBOSE_LOGF("[Acrylic DX11] Resized %dx%d (blur %dx%d)\n", width, height, bw, bh);
}
void AcrylicMaterial::captureBackground()
@@ -1391,7 +1391,7 @@ void AcrylicMaterial::applyBlur(float radius)
static bool s_traced = false;
if (!s_traced) {
s_traced = true;
DEBUG_LOGF("[Acrylic DX11] applyBlur: %d passes, radius=%.1f, blurSize=%dx%d\n",
VERBOSE_LOGF("[Acrylic DX11] applyBlur: %d passes, radius=%.1f, blurSize=%dx%d\n",
passes, effectiveRadius, dx_blurWidth_, dx_blurHeight_);
}
@@ -1469,7 +1469,7 @@ void AcrylicMaterial::drawRect(ImDrawList* drawList, const ImVec2& pMin, const I
static bool s_traced = false;
if (!s_traced) {
s_traced = true;
DEBUG_LOGF("[Acrylic DX11] drawRect first call: fallback=%d enabled=%d quality=%d "
VERBOSE_LOGF("[Acrylic DX11] drawRect first call: fallback=%d enabled=%d quality=%d "
"hasCapture=%d blurValid=%d viewport=%dx%d\n",
(int)currentFallback_, (int)settings_.enabled,
(int)settings_.quality, (int)hasValidCapture_,
@@ -1524,7 +1524,7 @@ void AcrylicMaterial::drawRect(ImDrawList* drawList, const ImVec2& pMin, const I
static bool s_blurTraced = false;
if (!s_blurTraced && blurTex) {
s_blurTraced = true;
DEBUG_LOGF("[Acrylic DX11] blur tex=%p UV: (%.3f,%.3f)-(%.3f,%.3f)\n",
VERBOSE_LOGF("[Acrylic DX11] blur tex=%p UV: (%.3f,%.3f)-(%.3f,%.3f)\n",
(void*)blurTex, u0, v0, u1, v1);
}

View File

@@ -310,7 +310,7 @@ struct ScrollFadeShader {
return false;
}
DEBUG_LOGF("ScrollFadeShader: DX11 pixel shader + CB created\n");
VERBOSE_LOGF("ScrollFadeShader: DX11 pixel shader + CB created\n");
return true;
}

View File

@@ -6,6 +6,7 @@
#include "../../app.h"
#include "../../config/version.h"
#include "../../config/settings.h"
#include "../../util/logger.h"
#include "../windows/balance_tab.h"
#include "../windows/console_tab.h"
#include "../../util/i18n.h"
@@ -103,6 +104,7 @@ static LowSpecSnapshot s_lowSpecSnap;
// Daemon — keep running on close
static bool sp_keep_daemon_running = false;
static bool sp_stop_external_daemon = false;
static bool sp_verbose_logging = false;
// Debug logging categories
static std::set<std::string> sp_debug_categories;
@@ -163,6 +165,7 @@ static void loadSettingsPageState(config::Settings* settings) {
Layout::setUserFontScale(sp_font_scale); // sync with Layout on load
sp_keep_daemon_running = settings->getKeepDaemonRunning();
sp_stop_external_daemon = settings->getStopExternalDaemon();
sp_verbose_logging = settings->getVerboseLogging();
sp_debug_categories = settings->getDebugCategories();
sp_debug_cats_dirty = false;
@@ -209,6 +212,7 @@ static void saveSettingsPageState(config::Settings* settings) {
settings->setFontScale(sp_font_scale);
settings->setKeepDaemonRunning(sp_keep_daemon_running);
settings->setStopExternalDaemon(sp_stop_external_daemon);
settings->setVerboseLogging(sp_verbose_logging);
settings->setDebugCategories(sp_debug_categories);
settings->save();
@@ -1060,6 +1064,13 @@ void RenderSettingsPage(App* app) {
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Applies when connecting to a daemon\nyou started outside this wallet");
ImGui::SameLine(0, sp);
if (ImGui::Checkbox("Verbose logging", &sp_verbose_logging)) {
dragonx::util::Logger::instance().setVerbose(sp_verbose_logging);
saveSettingsPageState(app->settings());
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Log detailed connection diagnostics,\ndaemon state, and port owner info\nto the Console tab");
if (scale < 1.0f) ImGui::SetWindowFontScale(1.0f);
}

View File

@@ -271,7 +271,9 @@ void RenderMiningTab(App* app)
s_pool_mode = true;
app->settings()->setPoolMode(true);
app->settings()->save();
app->stopMining();
// Note: soloMiningActive is already false (checked above),
// so no need to call stopMining() — it would just set the
// toggle-in-progress flag and make the button show "STARTING".
}
if (poolHov && !soloMiningActive) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (poolHov && soloMiningActive && !s_pool_mode) {

View File

@@ -7,6 +7,7 @@
#include "../../data/wallet_state.h"
#include "../theme.h"
#include "../effects/imgui_acrylic.h"
#include "../effects/low_spec.h"
#include "../schema/ui_schema.h"
#include "../material/type.h"
#include "../material/draw_helpers.h"
@@ -505,28 +506,111 @@ void RenderPeersTab(App* app)
}
if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
// Refresh button — top-right of the toggle header line
// Refresh button — top-right, glass panel style (similar to mining button)
{
bool isRefreshing = app->isPeerRefreshInProgress();
auto refreshBtn = S.drawElement("tabs.peers", "refresh-button");
float btnW = refreshBtn.size;
float btnH = toggleH - 4.0f * Layout::dpiScale();
float btnX = ImGui::GetWindowPos().x + availWidth - btnW - Layout::spacingSm();
float btnY = toggleY + (toggleH - btnH) * 0.5f;
ImVec2 bMin(btnX, btnY);
ImVec2 bMax(btnX + btnW, btnY + btnH);
bool btnHovered = material::IsRectHovered(bMin, bMax);
bool btnClicked = btnHovered && ImGui::IsMouseClicked(0);
// Glass panel background
GlassPanelSpec btnGlass;
btnGlass.rounding = Layout::glassRounding();
if (isRefreshing) {
float pulse = effects::isLowSpecMode()
? 0.5f
: 0.5f + 0.5f * (float)std::sin((double)ImGui::GetTime() * 4.0);
btnGlass.fillAlpha = (int)(15 + 25 * pulse);
} else {
btnGlass.fillAlpha = btnHovered ? 30 : 18;
}
DrawGlassPanel(dl, bMin, bMax, btnGlass);
// Hover highlight
if (btnHovered && !isRefreshing) {
dl->AddRectFilled(bMin, bMax, WithAlpha(Primary(), 20), btnGlass.rounding);
}
// Icon: spinner while refreshing, refresh icon otherwise
float cx = bMin.x + btnW * 0.35f;
float cy = bMin.y + btnH * 0.5f;
ImFont* iconFont = Type().iconMed();
float iconSz = iconFont->LegacySize;
float btnPad = Layout::spacingSm();
float btnX = ImGui::GetWindowPos().x + availWidth - iconSz - btnPad;
float btnY = toggleY + (toggleH - iconSz) * 0.5f;
ImGui::SetCursorScreenPos(ImVec2(btnX, btnY));
ImGui::PushID("##peersRefresh");
if (ImGui::InvisibleButton("##btn", ImVec2(iconSz + btnPad, iconSz + btnPad))) {
app->refreshPeerInfo();
app->refreshNow();
if (isRefreshing) {
// Spinning arc spinner (same style as mining toggle)
float spinnerR = iconSz * 0.5f;
float thickness = std::max(1.5f, spinnerR * 0.18f);
float time = (float)ImGui::GetTime();
// Track circle (faint)
dl->AddCircle(ImVec2(cx, cy), spinnerR, WithAlpha(Primary(), 40), 0, thickness);
// Animated arc
float rotation = fmodf(time * 2.0f * IM_PI / 1.4f, IM_PI * 2.0f);
float cycleTime = fmodf(time, 1.333f);
float arcLength = (cycleTime < 0.666f)
? (cycleTime / 0.666f) * 0.75f + 0.1f
: ((1.333f - cycleTime) / 0.666f) * 0.75f + 0.1f;
float startAngle = rotation - IM_PI * 0.5f;
float endAngle = startAngle + IM_PI * 2.0f * arcLength;
int segments = (int)(32 * arcLength) + 1;
float angleStep = (endAngle - startAngle) / segments;
ImU32 arcCol = Primary();
for (int si = 0; si < segments; si++) {
float a1 = startAngle + angleStep * si;
float a2 = startAngle + angleStep * (si + 1);
ImVec2 p1(cx + cosf(a1) * spinnerR, cy + sinf(a1) * spinnerR);
ImVec2 p2(cx + cosf(a2) * spinnerR, cy + sinf(a2) * spinnerR);
dl->AddLine(p1, p2, arcCol, thickness);
}
} else {
// Static refresh icon
ImU32 iconCol = btnHovered ? OnSurface() : OnSurfaceMedium();
ImVec2 iSz = iconFont->CalcTextSizeA(iconFont->LegacySize, FLT_MAX, 0, ICON_MD_REFRESH);
dl->AddText(iconFont, iconFont->LegacySize,
ImVec2(cx - iSz.x * 0.5f, cy - iSz.y * 0.5f),
iconCol, ICON_MD_REFRESH);
}
bool hovered = ImGui::IsItemHovered();
if (hovered) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
ImU32 iconCol = hovered ? OnSurface() : OnSurfaceMedium();
// Centre icon within the invisible button
float drawX = btnX + (iconSz + btnPad - iconSz) * 0.5f;
float drawY = btnY + (iconSz + btnPad - iconSz) * 0.5f;
dl->AddText(iconFont, iconSz, ImVec2(drawX, drawY), iconCol, ICON_MD_REFRESH);
if (hovered) {
ImGui::SetTooltip("Refresh peers & blockchain");
// Label to the right of icon
{
const char* label = isRefreshing ? "REFRESHING" : "REFRESH";
ImU32 lblCol;
if (isRefreshing) {
float pulse = effects::isLowSpecMode()
? 0.7f
: 0.5f + 0.5f * (float)std::sin((double)ImGui::GetTime() * 3.0);
lblCol = WithAlpha(Primary(), (int)(120 + 135 * pulse));
} else {
lblCol = btnHovered ? OnSurface() : WithAlpha(OnSurface(), 160);
}
ImVec2 lblSz = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, label);
float lblX = cx + iconSz * 0.5f + Layout::spacingXs();
float lblY = cy - lblSz.y * 0.5f;
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(lblX, lblY), lblCol, label);
}
// Invisible button for click handling
ImGui::SetCursorScreenPos(bMin);
ImGui::PushID("##peersRefresh");
if (ImGui::InvisibleButton("##btn", ImVec2(btnW, btnH))) {
if (!isRefreshing) {
app->refreshPeerInfo();
app->refreshNow();
}
}
if (ImGui::IsItemHovered()) {
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (!isRefreshing)
ImGui::SetTooltip("Refresh peers & blockchain");
}
ImGui::PopID();
}