feat(chat): broadcast self-addressed Control memos (App::sendChatControl)
Adds App::sendChatControl(cid, op, label): composes a self-addressed Control
memo and hands it to the existing chat send coordinator (enqueueChatSend →
pump → the 0-value kChatMinFeeDrgx z_sendmany / lite send) exactly as a message
does — no new fund-path semantics. It carries no UI echo bubble (empty
echoLocalId; resolveOutgoing("") is a no-op), and the memo harvested back to us
is routed to the reducer, never shown as a message.
Phase A, step 4 (broadcast) of on-chain chat delete/restore. UI wiring next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -321,6 +321,10 @@ public:
|
||||
// Send a contact request into an existing conversation (used to retry a failed request in place).
|
||||
void sendContactRequestForCid(const std::string& cid, const std::string& peerZaddr,
|
||||
const std::string& text);
|
||||
// Broadcast a self-addressed Control memo (op "del"/"res") so every device and a fresh seed import
|
||||
// hides/restores this conversation. `label` is a plaintext hint (peer address/name) carried on-chain.
|
||||
// Reuses the chat send coordinator + the 0-value kChatMinFeeDrgx z_sendmany path; no UI echo bubble.
|
||||
void sendChatControl(const std::string& conversationId, const std::string& op, const std::string& label);
|
||||
// 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. Returns true when it had to fabricate the (random) demo identity
|
||||
|
||||
@@ -4675,6 +4675,35 @@ void App::sendChatMessage(const std::string& conversationId, const std::string&
|
||||
enqueueChatSend(LiteOpKind::ChatSend, memos, echo.txid);
|
||||
}
|
||||
|
||||
void App::sendChatControl(const std::string& conversationId, const std::string& op, const std::string& label)
|
||||
{
|
||||
if (!chat::hushChatFeatureEnabledAtBuild() || !chat_service_.hasIdentity()) return;
|
||||
if (conversationId.empty() || op.empty()) return;
|
||||
|
||||
// A control signal is addressed to our OWN reply address — it never reaches the peer; only this
|
||||
// wallet's seed (on any device, including a fresh import) harvests and reduces it.
|
||||
const std::string myReply = chatReplyZaddr();
|
||||
if (myReply.empty()) {
|
||||
ui::Notifications::instance().error(TR("chat_toast_no_zaddr"));
|
||||
return;
|
||||
}
|
||||
const std::string myPubKey = chat_service_.identityPublicKeyHex();
|
||||
if (myPubKey.empty()) return;
|
||||
|
||||
// The label must be a non-empty, non-'{' hint; fall back to the cid if the caller has no name.
|
||||
const std::string hint = label.empty() ? conversationId : label;
|
||||
|
||||
chat::OutgoingChatMemos memos;
|
||||
if (chat::buildOutgoingControl(myPubKey, myReply, conversationId, op, hint, memos)
|
||||
!= chat::ChatComposeStatus::Ok) {
|
||||
return; // never block the local delete/restore on a compose edge case; it is cosmetic cross-device
|
||||
}
|
||||
// Reuse the chat send coordinator exactly as a message does (0-value, kChatMinFeeDrgx fee, two memo
|
||||
// outputs). No echo bubble: pass an empty echoLocalId — resolveOutgoing("") is a no-op, and the memo,
|
||||
// harvested back to us, is routed to the reducer (not shown as a message).
|
||||
enqueueChatSend(LiteOpKind::ChatSend, memos, /*echoLocalId=*/"");
|
||||
}
|
||||
|
||||
void App::startChatConversation(const std::string& peerZaddr, const std::string& text)
|
||||
{
|
||||
if (!chat::hushChatFeatureEnabledAtBuild() || !chat_service_.hasIdentity()) return;
|
||||
|
||||
Reference in New Issue
Block a user