diff --git a/src/app.h b/src/app.h index a64d35e..308e3d7 100644 --- a/src/app.h +++ b/src/app.h @@ -174,6 +174,10 @@ public: // message (to a conversation whose peer key we know) / a new-conversation contact request. void sendChatMessage(const std::string& conversationId, const std::string& text); void startChatConversation(const std::string& peerZaddr, const std::string& text); + // Debug/sweep convenience: give the Chat tab a demo identity + a few sample conversations + // (in-memory only, not persisted) so the screenshot sweep captures the populated UI. No-op when + // the chat feature is off. + void seedChatDemoData(); // Reason the lite wallet failed to auto-open this session (empty if none / opened OK). const std::string& liteOpenError() const { return lite_open_error_; } // Show the lite send-time unlock modal (called when a spend is attempted on a locked wallet). diff --git a/src/app_network.cpp b/src/app_network.cpp index bf6cf61..2f910e5 100644 --- a/src/app_network.cpp +++ b/src/app_network.cpp @@ -2660,6 +2660,46 @@ void App::ingestLiteChatMemos(const wallet::LiteWalletAppRefreshModel& model) if (!metadata.empty()) chat_service_.ingest(metadata, txTimestamps, std::time(nullptr)); } +void App::seedChatDemoData() +{ + if (!chat::hushChatFeatureEnabledAtBuild()) return; + + // Demo identity so the tab renders the populated UI (hasIdentity()==true). Injected messages go + // straight into the in-memory store (no DB attached here → not persisted, gone on restart). + chat::ChatKeyPair keys; + if (chat::deriveChatIdentityFromSecret("obsidian-dragon-demo-chat", keys).status + == chat::ChatIdentityStatus::Ready) { + chat_service_.setIdentity(keys); + } + chat::wipeChatKeyPair(keys); + + auto& store = chat_service_.store(); + const std::string zAlice = "zs1demoalice6xh2n8fchrz23thcgqqd2353v8ev2pr7p7lq4p3elsyrfkuenq"; + const std::string zBob = "zs1demobob9k4p3elsyrfkuenq4kl79j2pg7l3h2juz4t6q9wqxkha2n8fchrz2"; + auto add = [&](const std::string& cid, const std::string& z, const std::string& pk, + chat::ChatDirection dir, chat::ChatMessageKind kind, const std::string& body, + std::int64_t ts, const std::string& id) { + chat::ChatMessage m; + m.direction = dir; m.kind = kind; m.conversation_id = cid; m.peer_zaddr = z; + m.peer_public_key_hex = pk; m.body = body; m.timestamp = ts; m.txid = id; + m.payload_position = 0; + store.append(m); + }; + // A full thread (peer key known → composer enabled). + add("demo-1", zAlice, std::string(64, 'a'), chat::ChatDirection::Incoming, chat::ChatMessageKind::Message, + "hey! got the DragonX wallet running, chat works great", 1751284800, "demo:a1"); + add("demo-1", zAlice, std::string(64, 'a'), chat::ChatDirection::Outgoing, chat::ChatMessageKind::Message, + "nice - this is end-to-end encrypted over shielded memos", 1751285400, "demo:a2"); + add("demo-1", zAlice, std::string(64, 'a'), chat::ChatDirection::Incoming, chat::ChatMessageKind::Message, + "and it survives the daemon's output shuffle now", 1751286000, "demo:a3"); + // An incoming contact request (peer key known → can reply). + add("demo-2", zBob, std::string(64, 'b'), chat::ChatDirection::Incoming, chat::ChatMessageKind::ContactRequest, + "hi, add me? - bob", 1751200000, "demo:b1"); + // An outgoing contact request awaiting a reply (no peer key → "waiting" composer state). + add("demo-3", "zs1demopeerawaitingtheirfirstreplybeforewecanmessagethemyet00", "", + chat::ChatDirection::Outgoing, chat::ChatMessageKind::ContactRequest, "hey, let's chat", 1751100000, "demo:c1"); +} + void App::exportAllKeys(std::function callback) { if (!state_.connected || !rpc_) { diff --git a/src/ui/pages/settings_page.cpp b/src/ui/pages/settings_page.cpp index 637692f..fa66313 100644 --- a/src/ui/pages/settings_page.cpp +++ b/src/ui/pages/settings_page.cpp @@ -2496,6 +2496,12 @@ void RenderSettingsPage(App* app) { ImGui::SameLine(); if (TactileButton(TR("screenshot_open_dir"), ImVec2(0, 0), S.resolveFont("button"))) util::Platform::openFolder(app->screenshotDir()); + if (chat::hushChatFeatureEnabledAtBuild()) { + // Populate the Chat tab with demo conversations so the sweep captures its real UI. + ImGui::SameLine(); + if (TactileButton("Seed demo chat", ImVec2(0, 0), S.resolveFont("button"))) + app->seedChatDemoData(); + } ImGui::Dummy(ImVec2(0, Layout::spacingSm())); ImGui::Separator(); ImGui::Dummy(ImVec2(0, Layout::spacingSm()));