From 43c7be55c650fad826af7469c4ceba2ed758ba50 Mon Sep 17 00:00:00 2001 From: DanS Date: Tue, 1 Sep 2026 23:42:37 -0500 Subject: [PATCH] fix(ui): relocate + reword node auto-shield status; add chat-management FAQ entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Auto-shield status: the node's z_autoshieldstatus disabled_reason was echoed verbatim ("HD seed origin is not known-recoverable; back the seed up and pass -autoshield=1") and drawn INSIDE the Wallet OPTIONS checkbox grid, wedging a full-width line between the checkboxes. Move it to a full-width note BELOW the grid, and replace the raw daemon text with friendly, actionable wording keyed on the seed_recoverable flag (back up your seed to enable it); the raw daemon reason is kept on hover. Adds App::daemonAutoShieldSeedRecoverable(). - FAQ: add a Chat & Contacts entry ("How do I hide, delete, or block a conversation?") covering the hide / delete-revive / delete-&-block actions and the local-only caveat — data + i18n only, no UI code change. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app.h | 1 + src/ui/pages/settings_page.cpp | 47 +++++++++++++++++----------------- src/ui/windows/faq_content.cpp | 1 + src/util/i18n.cpp | 6 ++++- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/app.h b/src/app.h index 610e0b3..dbb6794 100644 --- a/src/app.h +++ b/src/app.h @@ -169,6 +169,7 @@ public: bool daemonAutoShieldActive() const { return daemon_autoshield_active_; } const std::string& daemonAutoShieldAddress() const { return daemon_autoshield_address_; } const std::string& daemonAutoShieldDisabledReason() const { return daemon_autoshield_disabled_reason_; } + bool daemonAutoShieldSeedRecoverable() const { return daemon_autoshield_seed_recoverable_; } // W7 QoL: a plaintext support-diagnostics snapshot (version, variant, daemon/RPC/wallet/log state) // for the "Copy diagnostics" action. Contains no secrets. diff --git a/src/ui/pages/settings_page.cpp b/src/ui/pages/settings_page.cpp index 70e8f5d..6a53da9 100644 --- a/src/ui/pages/settings_page.cpp +++ b/src/ui/pages/settings_page.cpp @@ -1193,29 +1193,6 @@ void RenderSettingsPage(App* app) { if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_save_ztx")); CB(TrId("auto_shield", "auto_shld"), &s_settingsState.auto_shield); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_auto_shield")); - // O1: when a v1.3.0+ node auto-shields coinbase itself, show its real state — the checkbox - // above only governs the wallet's own fallback shielder (which defers to the node). Nothing - // renders on pre-1.3.0 daemons (never probed), so their behaviour is unchanged. - // This status must NOT flow with ImGui's cursor: the checkbox grid is absolutely positioned - // (SetCursorScreenPos at rowY), so a normal-flow Text would land under the auto-shield checkbox - // and the next grid row (Use Tor / Keep daemon) would draw on top of it. Instead, draw it on its - // own full-width row at the grid's current rowY, wrapped to the card, then advance rowY past it. - if (app && app->daemonAutoShieldProbed() && - (app->daemonAutoShieldActive() || !app->daemonAutoShieldDisabledReason().empty())) { - ImGui::SetCursorScreenPos(ImVec2(cx, rowY)); - ImGui::PushTextWrapPos((cx + cw) - ImGui::GetWindowPos().x); // wrap to the card content width - if (app->daemonAutoShieldActive()) { - ImGui::TextColored(ImVec4(0.40f, 0.78f, 0.40f, 1.0f), " %s", TR("autoshield_by_node")); - if (!app->daemonAutoShieldAddress().empty()) - ImGui::TextDisabled(" %s", app->daemonAutoShieldAddress().c_str()); - } else { - ImGui::TextDisabled(" %s", app->daemonAutoShieldDisabledReason().c_str()); - } - ImGui::PopTextWrapPos(); - last = ImGui::GetCursorScreenPos().y; // cursor is now below the status text - rowY = last + gp; // next grid row starts below it - c = 0; - } CB(TrId("use_tor", "tor"), &s_settingsState.use_tor); if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_tor")); if (showDaemonOptions) { @@ -1232,6 +1209,30 @@ void RenderSettingsPage(App* app) { saveSettingsPageState(app->settings()); } if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_verbose")); + + // O1: node coinbase auto-shield status (v1.3.0+). Rendered as a full-width note BELOW the + // checkbox grid (not wedged between checkboxes) with friendly wording — the daemon's raw + // technical reason is available on hover. Nothing renders on pre-1.3.0 daemons (never probed). + if (app && app->daemonAutoShieldProbed() && + (app->daemonAutoShieldActive() || !app->daemonAutoShieldDisabledReason().empty())) { + ImGui::SetCursorScreenPos(ImVec2(cx, last + gp)); + ImGui::PushTextWrapPos((cx + cw) - ImGui::GetWindowPos().x); // wrap to the card content width + if (app->daemonAutoShieldActive()) { + ImGui::TextColored(ImVec4(0.40f, 0.78f, 0.40f, 1.0f), "%s", TR("autoshield_by_node")); + if (!app->daemonAutoShieldAddress().empty()) + ImGui::TextDisabled(" %s", app->daemonAutoShieldAddress().c_str()); + } else { + // Friendly, actionable wording. The seed-not-recoverable case is the common one and has a + // clear fix (back up the seed); anything else gets a generic line. Raw daemon text on hover. + ImGui::TextDisabled("%s", app->daemonAutoShieldSeedRecoverable() + ? TR("autoshield_off_generic") + : TR("autoshield_off_backup_seed")); + if (ImGui::IsItemHovered()) + material::Tooltip("%s", app->daemonAutoShieldDisabledReason().c_str()); + } + ImGui::PopTextWrapPos(); + last = ImGui::GetCursorScreenPos().y; // grow the card to include the note + } cardClose(0, last); } diff --git a/src/ui/windows/faq_content.cpp b/src/ui/windows/faq_content.cpp index d67a979..e47d20a 100644 --- a/src/ui/windows/faq_content.cpp +++ b/src/ui/windows/faq_content.cpp @@ -50,6 +50,7 @@ const std::vector& walletFaq() { "faq_w_chat_1_q", "faq_w_chat_1_a" }, { "faq_w_chat_2_q", "faq_w_chat_2_a" }, { "faq_w_chat_3_q", "faq_w_chat_3_a" }, + { "faq_w_chat_4_q", "faq_w_chat_4_a" }, }}, { "faq_w_set_title", { { "faq_w_set_1_q", "faq_w_set_1_a" }, diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index e2657c4..7a52056 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -1274,7 +1274,9 @@ void I18n::loadBuiltinEnglish() strings_["wallet_recovered_restore_sub"] = "Puts your largest untouched backup back in place, verbatim, then re-scans — slightly faster, but only as complete as that one file was. Your current file is kept as a dated backup either way."; strings_["wallet_recovered_notify"] = "Your wallet file needed a repair — your original was safely backed up. Open the app to review your options."; strings_["wallet_degraded_notify"] = "Your wallet opened in reduced-function mode: existing funds are safe and spendable, but creating new addresses and shielding are disabled. Back up your seed phrase and restore it to fully repair the wallet."; - strings_["autoshield_by_node"] = "Auto-shield is handled by your node"; + strings_["autoshield_by_node"] = "Your node auto-shields mined coinbase for you."; + strings_["autoshield_off_backup_seed"] = "Mined coinbase isn't being auto-shielded yet. Back up your seed phrase (Settings \xE2\x86\x92 Backup & Data) so your node can safely turn it on."; + strings_["autoshield_off_generic"] = "Your node isn't auto-shielding mined coinbase right now."; // In-dialog recovery lifecycle (Offer → Working → Done/Failed) + disclosures. strings_["wallet_recovery_working_label"] = "Working"; strings_["wallet_recovery_done"] = "Done"; @@ -1650,6 +1652,8 @@ void I18n::loadBuiltinEnglish() strings_["faq_w_chat_2_a"] = "Your chat identity is derived from your wallet's recovery phrase, so it travels with your wallet \xE2\x80\x94 restore the wallet and your identity comes back. You don't create a separate account or password."; strings_["faq_w_chat_3_q"] = "How do contacts work?"; strings_["faq_w_chat_3_a"] = "Add a contact by their address in the Contacts tab, optionally with a name and avatar. Contacts can be kept private to the current wallet or shared across all wallets you open on this computer."; + strings_["faq_w_chat_4_q"] = "How do I hide, delete, or block a conversation?"; + strings_["faq_w_chat_4_a"] = "Open a conversation and use the icons in its header. Hide (the eye) drops it from the list but keeps every message \xE2\x80\x94 a new message un-hides it. Delete (the trash) opens a dialog: 'Delete' clears the history on this device (if that person messages you again, the conversation comes back), while 'Delete & block' also stops their future messages until you unblock them from the 'Blocked' list above the conversation list. Everything here is local to this device \xE2\x80\x94 the messages stay on the blockchain and the other person keeps their own copy, so it isn't an 'unsend'."; // Wallet > Settings & Appearance strings_["faq_w_set_1_q"] = "How do I change the theme?";