feat(mining): persistent start/stop error caption + timeout-aware pool status

- A mining start/stop/pool failure now sets a persistent App::mining_last_error_
  (cleared on the next attempt), rendered as a red caption with "Press Mine to
  try again" below the Mine button (plus a Dismiss, and a Windows-Defender
  "How to fix" on an AV block), so a crashed/blocked/failed miner is no longer
  just a button that "did nothing" once its toast faded. Two more hardcoded
  English strings (pool-payout-invalid, AV-blocked) moved to i18n.
- Pool connection status is now a persistent "Status" row in the pool stats
  card (PoolMiningState.running_since / last_error): it flips from "Connecting…"
  to "Can't reach pool — check the URL" after a 30s timeout instead of sitting
  on red forever, and no longer vanishes once logs arrive. The old transient
  banner in mining_tab.cpp was removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 12:09:49 -05:00
co-authored by Claude Opus 4.8
parent 15c1181aef
commit 8fe20f6385
8 changed files with 104 additions and 29 deletions
+24
View File
@@ -991,6 +991,30 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
ImGui::SetCursorScreenPos(ImVec2(cardMin.x, cardMax.y));
ImGui::Dummy(ImVec2(availWidth, 0));
// Persistent error caption (a crashed/AV-blocked/failed miner otherwise leaves a button that
// "did nothing" once its toast faded). Normal ImGui flow, OUTSIDE the hand-drawn button card.
const std::string& merr = app->miningLastError();
if (!merr.empty() && !app->isMiningToggleInProgress()) {
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
ImGui::PushTextWrapPos(cardMin.x + availWidth);
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(Error()));
ImGui::TextWrapped("%s", merr.c_str());
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()));
ImGui::TextUnformatted(TR("mining_error_retry_hint"));
ImGui::PopStyleColor();
ImGui::PopTextWrapPos();
#ifdef _WIN32
if (app->miningErrorIsAntivirus()) {
ImGui::SameLine(0, Layout::spacingSm());
if (ImGui::SmallButton(TR("mining_error_av_help"))) app->showAntivirusHelp();
}
#endif
ImGui::SameLine(0, Layout::spacingSm());
if (ImGui::SmallButton(TR("mining_error_dismiss"))) app->clearMiningError();
}
ImGui::Dummy(ImVec2(0, gap));
}