diff --git a/src/ui/pages/settings_page.cpp b/src/ui/pages/settings_page.cpp index e040170..5274840 100644 --- a/src/ui/pages/settings_page.cpp +++ b/src/ui/pages/settings_page.cpp @@ -2012,7 +2012,8 @@ void RenderSettingsPage(App* app) { float nodeBtnW; { if (btnFont) ImGui::PushFont(btnFont); - nodeBtnW = rowBtnW({TR("test_connection"), TR("rescan")}); + nodeBtnW = rowBtnW({TR("test_connection"), TR("rescan"), + TR("delete_blockchain"), TR("repair_wallet")}); if (btnFont) ImGui::PopFont(/* btnFont */); } ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y)); @@ -2045,20 +2046,16 @@ void RenderSettingsPage(App* app) { if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_rescan")); ImGui::EndDisabled(); - // Delete blockchain button (always available when using embedded daemon) + // Row 2: Delete blockchain | Repair wallet (embedded daemon only) — paired on + // one line with the same width/style as the Test connection | Rescan row above. ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y + Layout::spacingSm())); ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon()); - if (TactileButton(TR("delete_blockchain"), ImVec2(0, 0), btnFont)) { + if (TactileButton(TR("delete_blockchain"), ImVec2(nodeBtnW, 0), btnFont)) { s_settingsState.confirm_delete_blockchain = true; } if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_delete_blockchain")); - ImGui::EndDisabled(); - - // Repair wallet (-zapwallettxes=2): wipe & rebuild wallet tx/note records from - // the chain (keys kept). Fixes notes that fail to spend after a rescan. - ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y + Layout::spacingSm())); - ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon()); - if (TactileButton(TR("repair_wallet"), ImVec2(0, 0), btnFont)) { + ImGui::SameLine(0, Layout::spacingMd()); + if (TactileButton(TR("repair_wallet"), ImVec2(nodeBtnW, 0), btnFont)) { s_settingsState.confirm_repair_wallet = true; } if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_repair_wallet")); @@ -2086,7 +2083,7 @@ void RenderSettingsPage(App* app) { localtime_r(&t, &tmv); #endif char buf[32]; - std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M", &tmv); + std::strftime(buf, sizeof(buf), "%Y-%m-%d", &tmv); return std::string(buf); }; @@ -2094,25 +2091,40 @@ void RenderSettingsPage(App* app) { Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("daemon_binary")); ImGui::Dummy(ImVec2(0, Layout::spacingXs())); + // Installed | Bundled side by side, spanning the node column's width. + const float dbStartY = ImGui::GetCursorScreenPos().y; + const float dbLineH = ImGui::GetTextLineHeightWithSpacing(); + const float dbCol2X = leftX + leftColW * 0.5f; + const ImVec4 dbDim = ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()); + + // Column 1 — Installed (version, then size · date) + ImGui::SetCursorScreenPos(ImVec2(leftX, dbStartY)); + Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("daemon_installed")); + ImGui::SetCursorScreenPos(ImVec2(leftX, dbStartY + dbLineH)); if (inst.exists) { - ImGui::Text("%s %s", TR("daemon_installed"), - inst.version.empty() ? TR("unknown") : inst.version.c_str()); - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), " %s · %s", + ImGui::TextUnformatted(inst.version.empty() ? TR("unknown") : inst.version.c_str()); + ImGui::SetCursorScreenPos(ImVec2(leftX, dbStartY + dbLineH * 2)); + ImGui::TextColored(dbDim, "%s · %s", util::Platform::formatFileSize(inst.size).c_str(), fmtDate(inst.modifiedEpoch).c_str()); } else { - ImGui::Text("%s %s", TR("daemon_installed"), TR("daemon_not_installed")); + ImGui::TextColored(dbDim, "%s", TR("daemon_not_installed")); } + // Column 2 — Bundled (version, then size) + ImGui::SetCursorScreenPos(ImVec2(dbCol2X, dbStartY)); + Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("daemon_bundled")); + ImGui::SetCursorScreenPos(ImVec2(dbCol2X, dbStartY + dbLineH)); if (bun.available) { - ImGui::Text("%s %s", TR("daemon_bundled"), - bun.version.empty() ? TR("unknown") : bun.version.c_str()); - ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium()), " %s", - util::Platform::formatFileSize(bun.size).c_str()); + ImGui::TextUnformatted(bun.version.empty() ? TR("unknown") : bun.version.c_str()); + ImGui::SetCursorScreenPos(ImVec2(dbCol2X, dbStartY + dbLineH * 2)); + ImGui::TextColored(dbDim, "%s", util::Platform::formatFileSize(bun.size).c_str()); } else { - ImGui::Text("%s %s", TR("daemon_bundled"), TR("daemon_none_bundled")); + ImGui::TextColored(dbDim, "%s", TR("daemon_none_bundled")); } + // Status line, below both sub-columns, spanning the node column. + ImGui::SetCursorScreenPos(ImVec2(leftX, dbStartY + dbLineH * 3 + Layout::spacingXs())); if (bun.available) { const bool sameSize = inst.exists && inst.size == bun.size; if (!inst.exists) @@ -2124,15 +2136,16 @@ void RenderSettingsPage(App* app) { } ImGui::Dummy(ImVec2(0, Layout::spacingXs())); + // Install bundled daemon | Refresh — paired, same width/style as the rows above. ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y)); ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon() || !bun.available); - if (TactileButton(TR("daemon_install_bundled"), ImVec2(0, 0), btnFont)) { + if (TactileButton(TR("daemon_install_bundled"), ImVec2(nodeBtnW, 0), btnFont)) { s_settingsState.confirm_reinstall_daemon = true; } if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_daemon_install_bundled")); ImGui::EndDisabled(); ImGui::SameLine(0, Layout::spacingMd()); - if (TactileButton(TR("refresh"), ImVec2(0, 0), btnFont)) { + if (TactileButton(TR("refresh"), ImVec2(nodeBtnW, 0), btnFont)) { s_settingsState.daemon_info_loaded = false; // recompute next frame } } diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 6bc7627..582faad 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -424,14 +424,14 @@ void I18n::loadBuiltinEnglish() strings_["confirm_repair_wallet_msg"] = "This restarts the daemon with -zapwallettxes=2: it deletes all of the wallet's transaction and note records, then rebuilds them from the blockchain. Use this when transactions fail to build (\"Invalid sapling spend proof\" / \"shielded requirements not met\") even after a full rescan. It takes a long time and the wallet stays offline until it finishes."; strings_["confirm_repair_wallet_safe"] = "Your keys, addresses and balance are preserved — only the cached transaction records are rebuilt."; strings_["daemon_binary"] = "Daemon binary"; - strings_["daemon_installed"] = "Installed:"; - strings_["daemon_bundled"] = "Bundled:"; + strings_["daemon_installed"] = "Installed"; + strings_["daemon_bundled"] = "Bundled"; strings_["daemon_not_installed"] = "not installed"; strings_["daemon_none_bundled"] = "none in this build"; strings_["daemon_status_match"] = "Installed binary matches the bundled version."; strings_["daemon_status_differ"] = "Installed binary differs from the bundled version."; strings_["daemon_status_missing"] = "No daemon installed — install the bundled version."; - strings_["daemon_install_bundled"] = "Install bundled daemon"; + strings_["daemon_install_bundled"] = "Install bundled"; strings_["tt_daemon_install_bundled"] = "Stop the node, overwrite the installed dragonxd with the version bundled in this wallet build, then restart"; strings_["confirm_reinstall_daemon_title"] = "Install Bundled Daemon"; strings_["confirm_reinstall_daemon_msg"] = "This stops the daemon, overwrites the installed dragonxd (and dragonx-cli/dragonx-tx) with the versions bundled in this wallet build, then restarts the node. Use this to recover or update the node binary.";