daemon version check, idle mining control, bootstrap mirror, import key paste, and cleanup
- Add startup binary version checking for dragonxd/xmrig - Display daemon version in UI - Add idle mining thread count adjustment - Add bootstrap mirror option (bootstrap2.dragonx.is) in setup wizard - Add paste button to import private key dialog with address validation - Add z-address generation UI feedback (loading indicator) - Add option to delete blockchain data while preserving wallet.dat - Add font scale slider hotkey tooltip (Ctrl+Plus/Ctrl+Minus) - Fix Windows RPC auth: trim \r from config values, add .cookie fallback - Fix connection status message during block index loading - Improve application shutdown to prevent lingering background process
This commit is contained in:
@@ -156,7 +156,9 @@ void RenderMiningTab(App* app)
|
||||
s_pool_state_loaded = true;
|
||||
}
|
||||
|
||||
// Default pool worker to user's first shielded address once addresses are available
|
||||
// Default pool worker to user's first shielded (z) address once available.
|
||||
// For new wallets without a z-address, leave the field blank so the user
|
||||
// is prompted to generate one before mining.
|
||||
{
|
||||
static bool s_pool_worker_defaulted = false;
|
||||
std::string workerStr(s_pool_worker);
|
||||
@@ -169,18 +171,14 @@ void RenderMiningTab(App* app)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (defaultAddr.empty()) {
|
||||
for (const auto& addr : state.addresses) {
|
||||
if (addr.type == "transparent" && !addr.address.empty()) {
|
||||
defaultAddr = addr.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!defaultAddr.empty()) {
|
||||
strncpy(s_pool_worker, defaultAddr.c_str(), sizeof(s_pool_worker) - 1);
|
||||
s_pool_worker[sizeof(s_pool_worker) - 1] = '\0';
|
||||
s_pool_settings_dirty = true;
|
||||
} else {
|
||||
// No z-address yet — clear the placeholder "x" so field shows empty
|
||||
s_pool_worker[0] = '\0';
|
||||
s_pool_settings_dirty = true;
|
||||
}
|
||||
s_pool_worker_defaulted = true;
|
||||
}
|
||||
@@ -536,7 +534,12 @@ void RenderMiningTab(App* app)
|
||||
s_pool_settings_dirty = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", TR("mining_payout_tooltip"));
|
||||
std::string currentWorkerStr(s_pool_worker);
|
||||
if (currentWorkerStr.empty()) {
|
||||
ImGui::SetTooltip("%s", TR("mining_generate_z_address_hint"));
|
||||
} else {
|
||||
ImGui::SetTooltip("%s", TR("mining_payout_tooltip"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Worker: Dropdown arrow button ---
|
||||
@@ -739,7 +742,8 @@ void RenderMiningTab(App* app)
|
||||
|
||||
if (btnClk) {
|
||||
strncpy(s_pool_url, "pool.dragonx.is", sizeof(s_pool_url) - 1);
|
||||
// Default to user's first shielded address for pool payouts
|
||||
// Default to user's first shielded (z) address for pool payouts.
|
||||
// Leave blank if no z-address exists yet.
|
||||
std::string defaultAddr;
|
||||
for (const auto& addr : state.addresses) {
|
||||
if (addr.type == "shielded" && !addr.address.empty()) {
|
||||
@@ -747,15 +751,6 @@ void RenderMiningTab(App* app)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (defaultAddr.empty()) {
|
||||
// Fallback to transparent if no shielded available
|
||||
for (const auto& addr : state.addresses) {
|
||||
if (addr.type == "transparent" && !addr.address.empty()) {
|
||||
defaultAddr = addr.address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(s_pool_worker, defaultAddr.c_str(), sizeof(s_pool_worker) - 1);
|
||||
s_pool_worker[sizeof(s_pool_worker) - 1] = '\0';
|
||||
s_pool_settings_dirty = true;
|
||||
@@ -840,6 +835,7 @@ void RenderMiningTab(App* app)
|
||||
float idleRightEdge = cardMax.x - pad;
|
||||
{
|
||||
bool idleOn = app->settings()->getMineWhenIdle();
|
||||
bool threadScaling = app->settings()->getIdleThreadScaling();
|
||||
ImFont* icoFont = Type().iconSmall();
|
||||
const char* idleIcon = ICON_MD_SCHEDULE;
|
||||
float icoH = icoFont->LegacySize;
|
||||
@@ -875,8 +871,40 @@ void RenderMiningTab(App* app)
|
||||
|
||||
idleRightEdge = btnX - 4.0f * dp;
|
||||
|
||||
// Idle delay combo (to the left of the icon when enabled)
|
||||
// Thread scaling mode toggle (to the left of idle icon, shown when idle is on)
|
||||
if (idleOn) {
|
||||
const char* scaleIcon = threadScaling ? ICON_MD_TUNE : ICON_MD_POWER_SETTINGS_NEW;
|
||||
float sBtnX = idleRightEdge - btnSz;
|
||||
float sBtnY = btnY;
|
||||
|
||||
if (threadScaling) {
|
||||
dl->AddRectFilled(ImVec2(sBtnX, sBtnY), ImVec2(sBtnX + btnSz, sBtnY + btnSz),
|
||||
WithAlpha(Primary(), 40), btnSz * 0.5f);
|
||||
}
|
||||
|
||||
ImVec2 sIcoSz = icoFont->CalcTextSizeA(icoFont->LegacySize, FLT_MAX, 0, scaleIcon);
|
||||
ImU32 sIcoCol = threadScaling ? Primary() : OnSurfaceMedium();
|
||||
dl->AddText(icoFont, icoFont->LegacySize,
|
||||
ImVec2(sBtnX + (btnSz - sIcoSz.x) * 0.5f, sBtnY + (btnSz - sIcoSz.y) * 0.5f),
|
||||
sIcoCol, scaleIcon);
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(sBtnX, sBtnY));
|
||||
ImGui::InvisibleButton("##IdleScaleMode", ImVec2(btnSz, btnSz));
|
||||
if (ImGui::IsItemClicked()) {
|
||||
app->settings()->setIdleThreadScaling(!threadScaling);
|
||||
app->settings()->save();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
ImGui::SetTooltip("%s", threadScaling
|
||||
? TR("mining_idle_scale_on_tooltip")
|
||||
: TR("mining_idle_scale_off_tooltip"));
|
||||
}
|
||||
idleRightEdge = sBtnX - 4.0f * dp;
|
||||
}
|
||||
|
||||
// Idle delay combo (to the left, when idle is enabled and NOT in thread scaling mode)
|
||||
if (idleOn && !threadScaling) {
|
||||
struct DelayOption { int seconds; const char* label; };
|
||||
static const DelayOption delays[] = {
|
||||
{30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"}
|
||||
@@ -907,6 +935,111 @@ void RenderMiningTab(App* app)
|
||||
idleRightEdge = comboX - 4.0f * dp;
|
||||
}
|
||||
|
||||
// Thread scaling controls: idle delay + active threads / idle threads combos
|
||||
if (idleOn && threadScaling) {
|
||||
int hwThreads = std::max(1, (int)std::thread::hardware_concurrency());
|
||||
|
||||
// Idle delay combo
|
||||
{
|
||||
struct DelayOption { int seconds; const char* label; };
|
||||
static const DelayOption delays[] = {
|
||||
{30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"}
|
||||
};
|
||||
int curDelay = app->settings()->getMineIdleDelay();
|
||||
const char* previewLabel = "2m";
|
||||
for (const auto& d : delays) {
|
||||
if (d.seconds == curDelay) { previewLabel = d.label; break; }
|
||||
}
|
||||
float comboW = schema::UI().drawElement("components.settings-page", "idle-combo-width").sizeOr(64.0f);
|
||||
float comboX = idleRightEdge - comboW;
|
||||
float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f;
|
||||
ImGui::SetCursorScreenPos(ImVec2(comboX, comboY));
|
||||
ImGui::SetNextItemWidth(comboW);
|
||||
if (ImGui::BeginCombo("##IdleDelayScale", previewLabel, ImGuiComboFlags_NoArrowButton)) {
|
||||
for (const auto& d : delays) {
|
||||
bool selected = (d.seconds == curDelay);
|
||||
if (ImGui::Selectable(d.label, selected)) {
|
||||
app->settings()->setMineIdleDelay(d.seconds);
|
||||
app->settings()->save();
|
||||
}
|
||||
if (selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", TR("tt_idle_delay"));
|
||||
idleRightEdge = comboX - 4.0f * dp;
|
||||
}
|
||||
|
||||
// Idle threads combo (threads when system is idle)
|
||||
{
|
||||
int curVal = app->settings()->getIdleThreadsIdle();
|
||||
if (curVal <= 0) curVal = hwThreads;
|
||||
char previewBuf[16];
|
||||
snprintf(previewBuf, sizeof(previewBuf), "%d", curVal);
|
||||
float comboW = schema::UI().drawElement("components.settings-page", "idle-combo-width").sizeOr(64.0f);
|
||||
float comboX = idleRightEdge - comboW;
|
||||
float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f;
|
||||
ImGui::SetCursorScreenPos(ImVec2(comboX, comboY));
|
||||
ImGui::SetNextItemWidth(comboW);
|
||||
if (ImGui::BeginCombo("##IdleThreadsIdle", previewBuf, ImGuiComboFlags_NoArrowButton)) {
|
||||
for (int t = 1; t <= hwThreads; t++) {
|
||||
char lbl[16];
|
||||
snprintf(lbl, sizeof(lbl), "%d", t);
|
||||
bool selected = (t == curVal);
|
||||
if (ImGui::Selectable(lbl, selected)) {
|
||||
app->settings()->setIdleThreadsIdle(t);
|
||||
app->settings()->save();
|
||||
}
|
||||
if (selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", TR("mining_idle_threads_idle_tooltip"));
|
||||
idleRightEdge = comboX - 4.0f * dp;
|
||||
}
|
||||
|
||||
// Separator arrow icon
|
||||
{
|
||||
const char* arrowIcon = ICON_MD_ARROW_BACK;
|
||||
ImVec2 arrSz = icoFont->CalcTextSizeA(icoFont->LegacySize, FLT_MAX, 0, arrowIcon);
|
||||
float arrX = idleRightEdge - arrSz.x;
|
||||
float arrY = curY + (headerH - arrSz.y) * 0.5f;
|
||||
dl->AddText(icoFont, icoFont->LegacySize, ImVec2(arrX, arrY), OnSurfaceDisabled(), arrowIcon);
|
||||
idleRightEdge = arrX - 4.0f * dp;
|
||||
}
|
||||
|
||||
// Active threads combo (threads when user is active)
|
||||
{
|
||||
int curVal = app->settings()->getIdleThreadsActive();
|
||||
if (curVal <= 0) curVal = std::max(1, hwThreads / 2);
|
||||
char previewBuf[16];
|
||||
snprintf(previewBuf, sizeof(previewBuf), "%d", curVal);
|
||||
float comboW = schema::UI().drawElement("components.settings-page", "idle-combo-width").sizeOr(64.0f);
|
||||
float comboX = idleRightEdge - comboW;
|
||||
float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f;
|
||||
ImGui::SetCursorScreenPos(ImVec2(comboX, comboY));
|
||||
ImGui::SetNextItemWidth(comboW);
|
||||
if (ImGui::BeginCombo("##IdleThreadsActive", previewBuf, ImGuiComboFlags_NoArrowButton)) {
|
||||
for (int t = 1; t <= hwThreads; t++) {
|
||||
char lbl[16];
|
||||
snprintf(lbl, sizeof(lbl), "%d", t);
|
||||
bool selected = (t == curVal);
|
||||
if (ImGui::Selectable(lbl, selected)) {
|
||||
app->settings()->setIdleThreadsActive(t);
|
||||
app->settings()->save();
|
||||
}
|
||||
if (selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", TR("mining_idle_threads_active_tooltip"));
|
||||
idleRightEdge = comboX - 4.0f * dp;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(savedCur);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user