feat(chat): hide conversations + contact address picker for new conversation

Hide conversations:
- A "Hide" action in the thread header drops a conversation from the list. The
  messages stay in the seed-encrypted store (on-chain history can't be deleted);
  a new INCOMING message un-hides it (you can't un-receive), so nothing is lost.
- Hidden cids persist in settings (mirrors the mute list) and are skipped by both
  the conversation list and the unread badge.

New-conversation address picker:
- A "Choose from contacts" dropdown lists the address book's shielded (z-address)
  contacts and fills the recipient field on selection; manual paste still works.

8-language strings + CJK subset (+1 glyph 届).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 23:26:04 -05:00
parent fce873936e
commit fc414eeed4
14 changed files with 105 additions and 0 deletions

View File

@@ -1262,6 +1262,7 @@ int App::chatUnreadCount() const
const auto& store = chat_service_.store();
for (const auto& cid : store.conversationIds()) {
if (settings_ && settings_->isChatMuted(cid)) continue; // muted conversations don't badge (Q10)
if (settings_ && settings_->isChatHidden(cid)) continue; // hidden conversations don't badge
std::int64_t seen = 0;
const auto it = chat_seen_watermark_.find(cid);
if (it != chat_seen_watermark_.end()) seen = it->second;
@@ -1719,6 +1720,13 @@ void App::refreshTransactionData()
for (const auto& tx : result.transactions) chatTxTimes[tx.txid] = tx.timestamp;
std::vector<std::string> newChatCids;
chat_service_.ingest(result.hushChatMetadata, chatTxTimes, std::time(nullptr), &newChatCids);
// A new message un-hides a hidden conversation (you can't un-receive), so nothing is lost.
if (settings_) {
bool unhid = false;
for (const auto& cid : newChatCids)
if (settings_->isChatHidden(cid)) { settings_->setChatHidden(cid, false); unhid = true; }
if (unhid) settings_->save();
}
// Toast when a NON-muted conversation received a new message and we're off the Chat tab.
// Gate on the ingest-reported cids, not a seen-watermark delta — the latter can be swallowed
// by block-time vs wall-clock (echo) skew (Q10 + Q4).
@@ -1785,6 +1793,13 @@ void App::refreshRecentTransactionData()
for (const auto& tx : result.transactions) chatTxTimes[tx.txid] = tx.timestamp;
std::vector<std::string> newChatCids;
chat_service_.ingest(result.hushChatMetadata, chatTxTimes, std::time(nullptr), &newChatCids);
// A new message un-hides a hidden conversation (you can't un-receive), so nothing is lost.
if (settings_) {
bool unhid = false;
for (const auto& cid : newChatCids)
if (settings_->isChatHidden(cid)) { settings_->setChatHidden(cid, false); unhid = true; }
if (unhid) settings_->save();
}
// Toast when a NON-muted conversation received a new message and we're off the Chat tab.
// Gate on the ingest-reported cids, not a seen-watermark delta — the latter can be swallowed
// by block-time vs wall-clock (echo) skew (Q10 + Q4).