From 29fbe46cce37f10278eba0e34a5dc7b2b99ba7d2 Mon Sep 17 00:00:00 2001 From: DanS Date: Thu, 16 Jul 2026 23:36:14 -0500 Subject: [PATCH] fix(chat): un-hide on lite receives + scope the contact picker per wallet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review of fc414ee found two issues: - HIGH: the lite variant harvests chat via ingestLiteChatMemos, which called ingest() without the newIncomingCids out-param — so the un-hide never ran and a hidden conversation stayed hidden PERMANENTLY on new messages (chat is default-ON and fully supported in Lite), breaking the "a new message brings it back" invariant. Wire the same un-hide + off-tab toast into the lite path. - LOW: the new-conversation contact picker listed every z-address contact, ignoring the per-wallet scope the Contacts tab enforces — leaking another wallet's scoped contact into this wallet's picker. Apply the same scope test (global + legacy fail open; "w:" scopes match the active wallet). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app_network.cpp | 17 ++++++++++++++++- src/ui/windows/chat_tab.cpp | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/app_network.cpp b/src/app_network.cpp index 181a89d..3a213df 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -3147,7 +3147,22 @@ void App::ingestLiteChatMemos(const wallet::LiteWalletAppRefreshModel& model) auto extracted = chat::extractHushChatTransactionMetadata(entry.second, true); for (auto& meta : extracted.metadata) metadata.push_back(std::move(meta)); } - if (!metadata.empty()) chat_service_.ingest(metadata, txTimestamps, std::time(nullptr)); + if (!metadata.empty()) { + std::vector newChatCids; + chat_service_.ingest(metadata, txTimestamps, std::time(nullptr), &newChatCids); + // Mirror the full-node paths: a new incoming message un-hides a hidden conversation (you can't + // un-receive), and a non-muted new message toasts when we're off the Chat tab. + if (settings_) { + bool unhid = false; + for (const auto& cid : newChatCids) + if (settings_->isChatHidden(cid)) { settings_->setChatHidden(cid, false); unhid = true; } + if (unhid) settings_->save(); + } + if (current_page_ != ui::NavPage::Chat && + std::any_of(newChatCids.begin(), newChatCids.end(), + [this](const std::string& cid){ return !(settings_ && settings_->isChatMuted(cid)); })) + ui::Notifications::instance().info(TR("chat_new_message_toast")); + } } bool App::lockLiteWallet() diff --git a/src/ui/windows/chat_tab.cpp b/src/ui/windows/chat_tab.cpp index 32c5571..a31443e 100644 --- a/src/ui/windows/chat_tab.cpp +++ b/src/ui/windows/chat_tab.cpp @@ -635,9 +635,15 @@ void RenderChatTab(App* app) // Selecting one fills the field above (manual paste still works). ImGui::SetNextItemWidth(fieldW); if (ImGui::BeginCombo("##newzpick", TR("chat_pick_contact"), ImGuiComboFlags_HeightLarge)) { + const std::string activeHash = app->activeWalletScopeId(); // per-wallet contact scope int shown = 0; for (const auto& e : book.entries()) { if (e.address.empty() || e.address[0] != 'z') continue; // chat requires a z-address + // Respect the same per-wallet scope the Contacts tab enforces — don't leak another + // wallet's scoped contact into this wallet's picker (global + legacy fail open). + const bool visible = e.isGlobal() || + (e.scope.rfind("w:", 0) == 0 ? (!activeHash.empty() && e.scope == activeHash) : true); + if (!visible) continue; ++shown; const std::string item = e.label + " " + shorten(e.address, 16, 8); if (ImGui::Selectable(item.c_str())) {