feat(chat): per-conversation delete (revive + block); memoize chat/badge render
Adds a per-conversation "delete" with two modes, and removes the per-frame rescans of the chat history that shared these files. Delete conversation (header trash icon → confirm dialog): - Delete (revive-on-new-message): clears local history and tombstones the messages (new chat_deleted table, keyed dedup hashes) so the every-few- seconds memo re-scan can't re-import them; a genuinely NEW message (new txid) revives the thread. - Delete & block: removes history WITHOUT a tombstone and records the cid as blocked (settings); ChatService::ingest drops that conversation's messages — old and future — until unblocked from the "Blocked" manager, which then re-imports the conversation from chain. - Local-only (messages remain on-chain; the peer keeps their copy). deleteConversation() deletes the DB rows FIRST and only then mutates the store, so a failed write can't leave the two diverged. Unit-tested (revive / tombstone-survives-reload / block / unblock) and adversarially reviewed (store/DB divergence, half-open DB, revive-unread). Performance (chat + badge hot paths, from the perf audit): - ChatStore gains revision(); the Chat unread badge is now a single O(N) no-alloc pass cached on it (was O(conversations x messages) copy+sort every frame). The conversation list and open thread are memoized on revision() (+ show-hidden and AddressBook::revision() for peer-name resolution). - AddressBook gains revision() so an in-place contact rename invalidates the chat memo (an edit keeps entries().size() constant). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -259,6 +259,23 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["chat_emoji_search"] = "Search emoji";
|
||||
strings_["chat_hide_hidden"] = "Hide hidden";
|
||||
strings_["chat_hidden_toast"] = "Conversation hidden — a new message brings it back";
|
||||
// Delete conversation (local cache) — revive-on-new-message vs delete & block
|
||||
strings_["chat_delete"] = "Delete conversation";
|
||||
strings_["chat_delete_title"] = "Delete conversation?";
|
||||
strings_["chat_delete_body_prefix"] = "Delete your local copy of the conversation with ";
|
||||
strings_["chat_delete_body_suffix"] = "?";
|
||||
strings_["chat_delete_revive_note"] = "\"Delete\" clears the history on this device. If they message you again, the conversation comes back.";
|
||||
strings_["chat_delete_local_note"] = "This only affects this device — the messages stay on the blockchain and the other person keeps their copy.";
|
||||
strings_["chat_delete_confirm"] = "Delete";
|
||||
strings_["chat_delete_block"] = "Delete & block";
|
||||
strings_["chat_deleted_toast"] = "Conversation deleted";
|
||||
strings_["chat_delete_failed"] = "Couldn't delete the conversation — nothing was changed.";
|
||||
strings_["chat_blocked_toast"] = "Conversation deleted & blocked";
|
||||
strings_["chat_blocked_manage"] = "Blocked";
|
||||
strings_["chat_blocked_title"] = "Blocked conversations";
|
||||
strings_["chat_blocked_desc"] = "Blocked conversations are removed and their messages are dropped — old and new — until you unblock. Unblocking re-imports the conversation from the chain.";
|
||||
strings_["chat_unblock"] = "Unblock";
|
||||
strings_["chat_unblocked_toast"] = "Conversation unblocked";
|
||||
strings_["chat_pick_contact"] = "Choose from contacts\xE2\x80\xA6";
|
||||
strings_["chat_no_z_contacts"] = "No shielded-address contacts yet";
|
||||
strings_["chat_copy_address_tip"] = "Click to copy address";
|
||||
|
||||
Reference in New Issue
Block a user