From 85f99984c4cc7d1e4657e5eb963393e15f72fd9a Mon Sep 17 00:00:00 2001 From: jack <212554440+jackjackbits@users.noreply.github.com> Date: Sun, 24 Aug 2025 14:40:06 +0200 Subject: [PATCH] Unify DM notifications and fix geohash self-echo hydration (#505) * feat(notifications): unify DM notifications across transports; notify for unread+recent even in foreground; delegate suppresses if chat open * fix(geohash): include own past geohash messages on channel load; skip only very recent self-echo (<15s) to avoid duplicates --------- Co-authored-by: jack --- bitchat/ViewModels/ChatViewModel.swift | 34 ++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index 72e27c55..d8741b90 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -719,7 +719,11 @@ class ChatViewModel: ObservableObject, BitchatDelegate { self.processedNostrEvents.insert(event.id) if let gh = self.currentGeohash, let myGeoIdentity = try? NostrIdentityBridge.deriveIdentity(forGeohash: gh), - myGeoIdentity.publicKeyHex.lowercased() == event.pubkey.lowercased() { return } + myGeoIdentity.publicKeyHex.lowercased() == event.pubkey.lowercased() { + // Skip very recent self-echo from relay, but allow older events (e.g., after app restart) + let eventTime = Date(timeIntervalSince1970: TimeInterval(event.created_at)) + if Date().timeIntervalSince(eventTime) < 15 { return } + } if let nickTag = event.tags.first(where: { $0.first == "n" }), nickTag.count >= 2 { let nick = nickTag[1] self.geoNicknames[event.pubkey.lowercased()] = nick @@ -833,16 +837,14 @@ class ChatViewModel: ObservableObject, BitchatDelegate { self.sentReadReceipts.insert(messageId) } } else { - // Optionally notify if app backgrounded and message is truly unread - #if os(iOS) - if shouldMarkUnread && UIApplication.shared.applicationState != .active { + // Notify for truly unread and recent messages when not viewing + if shouldMarkUnread { NotificationService.shared.sendPrivateMessageNotification( from: senderName, message: pm.content, peerID: convKey ) } - #endif } self.objectWillChange.send() case .delivered: @@ -1389,11 +1391,12 @@ class ChatViewModel: ObservableObject, BitchatDelegate { category: SecureLogger.session, level: .info) } } - // Skip our own events (we already locally echoed) + // Skip only very recent self-echo from relay; include older self events for hydration if let gh = self.currentGeohash, let myGeoIdentity = try? NostrIdentityBridge.deriveIdentity(forGeohash: gh), myGeoIdentity.publicKeyHex.lowercased() == event.pubkey.lowercased() { - return + let eventTime = Date(timeIntervalSince1970: TimeInterval(event.created_at)) + if Date().timeIntervalSince(eventTime) < 15 { return } } // Cache nickname from tag if present if let nickTag = event.tags.first(where: { $0.first == "n" }), nickTag.count >= 2 { @@ -1521,19 +1524,14 @@ class ChatViewModel: ObservableObject, BitchatDelegate { } else { // pared back: omit defer READ log } - // Notify only when app is backgrounded and not viewing, and only if not already read - #if os(iOS) + // Notify for truly unread and recent messages when not viewing if !isViewing && shouldMarkUnread { - if UIApplication.shared.applicationState != .active { - NotificationService.shared.sendPrivateMessageNotification( - from: senderName, - message: pm.content, - peerID: convKey - ) - // pared back: omit notification log - } + NotificationService.shared.sendPrivateMessageNotification( + from: senderName, + message: pm.content, + peerID: convKey + ) } - #endif self.objectWillChange.send() default: // Handle delivered/read receipts for our sent messages