added visual feedback to mining button to show miner is in process of startup/shutdown

This commit is contained in:
dan_s
2026-02-27 00:48:13 -06:00
parent d90e271097
commit b1d87a65f8

View File

@@ -607,12 +607,20 @@ void RenderMiningTab(App* app)
bool btnClicked = btnHovered && ImGui::IsMouseClicked(0);
bool isSyncing = state.sync.syncing;
bool poolBlockedBySolo = s_pool_mode && mining.generate && !state.pool_mining.xmrig_running;
bool disabled = !app->isConnected() || app->isMiningToggleInProgress() || isSyncing || poolBlockedBySolo;
bool isToggling = app->isMiningToggleInProgress();
bool disabled = !app->isConnected() || isToggling || isSyncing || poolBlockedBySolo;
// Glass panel background with state-dependent tint
GlassPanelSpec btnGlass;
btnGlass.rounding = Layout::glassRounding();
if (isMiningActive) {
if (isToggling) {
// Toggling: subtle pulsing glow to indicate activity
float pulse = effects::isLowSpecMode()
? 0.5f
: 0.5f + 0.5f * (float)std::sin((double)ImGui::GetTime() * 4.0);
int glowA = (int)(15 + 25 * pulse);
btnGlass.fillAlpha = glowA;
} else if (isMiningActive) {
// Active mining: warm glow
float pulse = effects::isLowSpecMode()
? schema::UI().drawElement("animations", "pulse-base-glow").size
@@ -638,36 +646,84 @@ void RenderMiningTab(App* app)
float cx = bMin.x + btnW * 0.5f;
float cy = bMin.y + btnH * schema::UI().drawElement("tabs.mining", "button-icon-y-ratio").size; // shift up to leave room for label
ImU32 iconCol;
if (disabled) {
iconCol = OnSurfaceDisabled();
} else if (isMiningActive) {
float pulse = effects::isLowSpecMode()
? schema::UI().drawElement("animations", "pulse-base-normal").size
: schema::UI().drawElement("animations", "pulse-base-normal").size + schema::UI().drawElement("animations", "pulse-amp-normal").size * (float)std::sin((double)ImGui::GetTime() * schema::UI().drawElement("animations", "pulse-speed-normal").size);
iconCol = WithAlpha(Error(), (int)(200 + 55 * pulse));
} else {
iconCol = btnHovered ? WithAlpha(Success(), 255) : OnSurfaceMedium();
}
if (isToggling) {
// Draw a spinning arc spinner to indicate progress
float spinnerR = std::min(btnW, btnH) * 0.18f;
float thickness = std::max(2.5f, spinnerR * 0.15f);
float time = (float)ImGui::GetTime();
// Use XL icon for the large mining button
ImFont* iconFont = Type().iconXL();
const char* mineIcon = isMiningActive ? ICON_MD_CLOSE : ICON_MD_CONSTRUCTION;
ImVec2 iconSz = iconFont->CalcTextSizeA(iconFont->LegacySize, 1000.0f, 0.0f, mineIcon);
dl->AddText(iconFont, iconFont->LegacySize,
ImVec2(cx - iconSz.x * 0.5f, cy - iconSz.y * 0.5f), iconCol, mineIcon);
// Track circle (faint)
ImU32 trackCol = WithAlpha(Primary(), 40);
dl->AddCircle(ImVec2(cx, cy), spinnerR, trackCol, 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 i = 0; i < segments; i++) {
float a1 = startAngle + angleStep * i;
float a2 = startAngle + angleStep * (i + 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 {
ImU32 iconCol;
if (disabled) {
iconCol = OnSurfaceDisabled();
} else if (isMiningActive) {
float pulse = effects::isLowSpecMode()
? schema::UI().drawElement("animations", "pulse-base-normal").size
: schema::UI().drawElement("animations", "pulse-base-normal").size + schema::UI().drawElement("animations", "pulse-amp-normal").size * (float)std::sin((double)ImGui::GetTime() * schema::UI().drawElement("animations", "pulse-speed-normal").size);
iconCol = WithAlpha(Error(), (int)(200 + 55 * pulse));
} else {
iconCol = btnHovered ? WithAlpha(Success(), 255) : OnSurfaceMedium();
}
// Use XL icon for the large mining button
ImFont* iconFont = Type().iconXL();
const char* mineIcon = isMiningActive ? ICON_MD_CLOSE : ICON_MD_CONSTRUCTION;
ImVec2 iconSz = iconFont->CalcTextSizeA(iconFont->LegacySize, 1000.0f, 0.0f, mineIcon);
dl->AddText(iconFont, iconFont->LegacySize,
ImVec2(cx - iconSz.x * 0.5f, cy - iconSz.y * 0.5f), iconCol, mineIcon);
}
}
// Label below icon
{
float btnW = bMax.x - bMin.x;
float btnH = bMax.y - bMin.y;
const char* label = isMiningActive ? "STOP" : "MINE";
const char* label;
ImU32 lblCol;
if (isToggling) {
label = isMiningActive ? "STOPPING" : "STARTING";
// Animated dots effect via alpha pulse
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 if (isMiningActive) {
label = "STOP";
lblCol = WithAlpha(Error(), 220);
} else if (disabled) {
label = "MINE";
lblCol = WithAlpha(OnSurface(), 50);
} else {
label = "MINE";
lblCol = WithAlpha(OnSurface(), 160);
}
ImVec2 lblSz = ovFont->CalcTextSizeA(ovFont->LegacySize, FLT_MAX, 0, label);
float lblX = bMin.x + (btnW - lblSz.x) * 0.5f;
float lblY = bMin.y + btnH * schema::UI().drawElement("tabs.mining", "button-label-y-ratio").size;
ImU32 lblCol = disabled ? WithAlpha(OnSurface(), 50) :
(isMiningActive ? WithAlpha(Error(), 220) : WithAlpha(OnSurface(), 160));
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(lblX, lblY), lblCol, label);
}
@@ -675,7 +731,9 @@ void RenderMiningTab(App* app)
if (btnHovered) {
if (!disabled)
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (isSyncing)
if (isToggling)
ImGui::SetTooltip(isMiningActive ? "Stopping miner..." : "Starting miner...");
else if (isSyncing)
ImGui::SetTooltip("Syncing blockchain... (%.1f%%)", state.sync.verification_progress * 100.0);
else if (poolBlockedBySolo)
ImGui::SetTooltip("Stop solo mining before starting pool mining");