feat: blockchain rescan via daemon restart + status bar progress
- Fix z_importwallet to use full path instead of filename only - Add rescanBlockchain() method that restarts daemon with -rescan flag - Track rescan progress via daemon output parsing and getrescaninfo RPC - Display rescan progress in status bar with animated indicator when starting - Improve dark theme card contrast: lighter surface-variant, tinted borders, stronger rim-light
This commit is contained in:
@@ -108,6 +108,7 @@ static bool sp_stop_external_daemon = false;
|
||||
static std::set<std::string> sp_debug_categories;
|
||||
static bool sp_debug_cats_dirty = false; // true when changed but daemon not yet restarted
|
||||
static bool sp_debug_expanded = false; // collapsible card state
|
||||
static bool sp_confirm_clear_ztx = false; // confirmation dialog for clearing z-tx history
|
||||
|
||||
// (APPEARANCE card now uses ChannelsSplit like all other cards)
|
||||
|
||||
@@ -969,46 +970,41 @@ void RenderSettingsPage(App* app) {
|
||||
ImGui::Indent(pad);
|
||||
|
||||
float contentW = availWidth - pad * 2;
|
||||
bool wideBtns = availWidth >= S.drawElement("components.settings-page", "compact-breakpoint").size;
|
||||
|
||||
// Content-aware button sizing: uniform per-row width based on widest label
|
||||
float minBtnW = S.drawElement("components.settings-page", "wallet-btn-min-width").sizeOr(130.0f);
|
||||
float btnSpacing = Layout::spacingMd();
|
||||
float btnPad = S.drawElement("components.settings-page", "wallet-btn-padding").sizeOr(24.0f);
|
||||
auto rowBtnW = [&](std::initializer_list<const char*> labels) -> float {
|
||||
float maxTextW = 0;
|
||||
for (auto* l : labels) maxTextW = std::max(maxTextW, ImGui::CalcTextSize(l).x);
|
||||
return std::max(minBtnW, maxTextW + btnPad * 2);
|
||||
};
|
||||
|
||||
// Calculate button width that fits available space
|
||||
// 6 buttons total: on wide screens 3+3, on narrow screens 2+2+2
|
||||
int btnsPerRow = (contentW >= 600.0f) ? 3 : 2;
|
||||
float bw = (contentW - btnSpacing * (btnsPerRow - 1)) / btnsPerRow;
|
||||
// Clamp to reasonable size
|
||||
float minBtnW = S.drawElement("components.settings-page", "wallet-btn-min-width").sizeOr(100.0f);
|
||||
bw = std::max(minBtnW, bw);
|
||||
|
||||
// Row 1 — Tools & Actions
|
||||
{
|
||||
float bw = rowBtnW({"Address Book...", "Validate Address...", "Request Payment...", "Shield Mining...", "Merge to Address...", "Clear Z-Tx History"});
|
||||
if (TactileButton("Address Book...", ImVec2(bw, 0), S.resolveFont("button")))
|
||||
AddressBookDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Manage saved addresses for quick sending");
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton("Validate Address...", ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ValidateAddressDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Check if a DragonX address is valid");
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton("Request Payment...", ImVec2(bw, 0), S.resolveFont("button")))
|
||||
RequestPaymentDialog::show();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Generate a payment request with QR code");
|
||||
if (wideBtns) ImGui::SameLine(0, Layout::spacingMd()); else ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
|
||||
if (btnsPerRow >= 3) { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); } else { ImGui::SameLine(0, btnSpacing); }
|
||||
if (TactileButton("Shield Mining...", ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::ShieldCoinbase);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Move transparent mining rewards to a shielded address");
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
ImGui::SameLine(0, btnSpacing);
|
||||
if (TactileButton("Merge to Address...", ImVec2(bw, 0), S.resolveFont("button")))
|
||||
ShieldDialog::show(ShieldDialog::Mode::MergeToAddress);
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Consolidate multiple UTXOs into one address");
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
if (btnsPerRow >= 3) { ImGui::SameLine(0, btnSpacing); } else { ImGui::Dummy(ImVec2(0, Layout::spacingXs())); }
|
||||
if (TactileButton("Clear Z-Tx History", ImVec2(bw, 0), S.resolveFont("button"))) {
|
||||
std::string ztx_file = util::Platform::getDragonXDataDir() + "ztx_history.json";
|
||||
if (util::Platform::deleteFile(ztx_file))
|
||||
Notifications::instance().success("Z-transaction history cleared");
|
||||
else
|
||||
Notifications::instance().info("No history file found");
|
||||
sp_confirm_clear_ztx = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Delete locally cached z-transaction history");
|
||||
}
|
||||
@@ -1348,24 +1344,7 @@ void RenderSettingsPage(App* app) {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("Verify the RPC connection to the daemon");
|
||||
ImGui::SameLine(0, Layout::spacingMd());
|
||||
if (TactileButton("Rescan Blockchain", ImVec2(nodeBtnW, 0), btnFont)) {
|
||||
if (app->rpc() && app->rpc()->isConnected() && app->worker()) {
|
||||
Notifications::instance().info("Starting blockchain rescan...");
|
||||
app->worker()->post([rpc = app->rpc()]() -> rpc::RPCWorker::MainCb {
|
||||
try {
|
||||
rpc->call("rescanblockchain", {0});
|
||||
return []() {
|
||||
Notifications::instance().success("Blockchain rescan started");
|
||||
};
|
||||
} catch (const std::exception& e) {
|
||||
std::string err = e.what();
|
||||
return [err]() {
|
||||
Notifications::instance().error("Failed to start rescan: " + err);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Notifications::instance().warning("Not connected to daemon");
|
||||
}
|
||||
app->rescanBlockchain();
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("Rescan the blockchain for missing transactions");
|
||||
ImGui::EndDisabled();
|
||||
@@ -1839,6 +1818,48 @@ void RenderSettingsPage(App* app) {
|
||||
|
||||
ImGui::EndChild(); // ##SettingsPageScroll
|
||||
|
||||
// Confirmation dialog for clearing z-tx history
|
||||
if (sp_confirm_clear_ztx) {
|
||||
if (BeginOverlayDialog("Confirm Clear Z-Tx History", &sp_confirm_clear_ztx, 480.0f, 0.94f)) {
|
||||
ImGui::PushFont(Type().iconLarge());
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), ICON_MD_WARNING);
|
||||
ImGui::PopFont();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.6f, 0.0f, 1.0f), "Warning");
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextWrapped(
|
||||
"Clearing z-transaction history may cause your shielded balance to show as 0 "
|
||||
"until a wallet rescan is performed.");
|
||||
ImGui::Spacing();
|
||||
ImGui::TextWrapped(
|
||||
"If this happens, you will need to re-import your z-address private keys with "
|
||||
"rescan enabled to recover your balance.");
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
if (ImGui::Button("Cancel", ImVec2(btnW, 40))) {
|
||||
sp_confirm_clear_ztx = false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.3f, 0.3f, 1.0f));
|
||||
if (ImGui::Button("Clear Anyway", ImVec2(btnW, 40))) {
|
||||
std::string ztx_file = util::Platform::getDragonXDataDir() + "ztx_history.json";
|
||||
if (util::Platform::deleteFile(ztx_file)) {
|
||||
Notifications::instance().success("Z-transaction history cleared");
|
||||
} else {
|
||||
Notifications::instance().info("No history file found");
|
||||
}
|
||||
sp_confirm_clear_ztx = false;
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
EndOverlayDialog();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
||||
Reference in New Issue
Block a user