From 8a2af872d68dc682f2444431917c09ba4d683b2e Mon Sep 17 00:00:00 2001 From: wt Date: Fri, 18 Sep 2026 11:59:56 +0700 Subject: [PATCH] fix self-chat read state: mark own outgoing messages as read locally Self-chat returned early in sendDisplayedMarkerIfNeeded, so outgoing messages never reached markRead and never showed the Read status. --- Scripts/verify.sh | 4 ++++ Sources/Shared/Models/AppModel.swift | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Scripts/verify.sh b/Scripts/verify.sh index caf0323..1376dbd 100755 --- a/Scripts/verify.sh +++ b/Scripts/verify.sh @@ -425,6 +425,10 @@ grep -q 'markersPublisher' Sources/Shared/XMPP/XMPPService.swift || { echo "XEP-0333 displayed markers must mark messages as read" exit 1 } +grep -q 'markRead(at: index, cameFromPeer: false)' Sources/Shared/Models/AppModel.swift || { + echo "Self-chat must mark its own outgoing messages as read locally" + exit 1 +} grep -q 'case read(conversationJID' Sources/Shared/XMPP/XMPPService.swift || { echo "Read receipts must reference the conversation" exit 1 diff --git a/Sources/Shared/Models/AppModel.swift b/Sources/Shared/Models/AppModel.swift index 5c99b44..50b1490 100644 --- a/Sources/Shared/Models/AppModel.swift +++ b/Sources/Shared/Models/AppModel.swift @@ -2534,11 +2534,25 @@ final class AppModel: ObservableObject { /// Sends an XEP-0333 `` marker for the newest incoming 1:1 /// message once the chat is opened, so the peer's client can show it as /// read. MUC rooms never get markers (XEP-0333); deduped per message so - /// repeated SwiftUI appearances do not resend. + /// repeated SwiftUI appearances do not resend. Self-chat has no peer, so + /// its own outgoing messages are promoted to `.read` locally instead of + /// sending a marker to our own bare JID. private func sendDisplayedMarkerIfNeeded(for conversationID: String) { guard let account else { return } let normalized = conversationID.lowercased() - guard normalized != account.normalizedJID else { return } + if normalized == account.normalizedJID { + for index in messages.indices { + let message = messages[index] + guard message.conversationID == normalized, + message.direction == .outgoing, + message.delivery != .failed, + !message.isRetracted, + message.kind != .system + else { continue } + markRead(at: index, cameFromPeer: false) + } + return + } guard let latest = messages .filter({ $0.conversationID == normalized && $0.direction == .incoming }) .max(by: { $0.timestamp < $1.timestamp }),