From 13686b3ce937db5905d3b04781c0e659ac8c256e Mon Sep 17 00:00:00 2001 From: jack Date: Wed, 2 Jul 2025 21:19:32 +0200 Subject: [PATCH] Fix private message notifications and chat updates - Remove self-notification when sending private messages - Clear unread indicator when viewing active chat - Properly update UI when private messages are sent/received - Prevent duplicate messages in chat history - Use objectWillChange to force SwiftUI updates --- bitchat/Services/BluetoothMeshService.swift | 5 +-- bitchat/ViewModels/ChatViewModel.swift | 37 ++++++++++++++++----- bitchat/Views/ContentView.swift | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/bitchat/Services/BluetoothMeshService.swift b/bitchat/Services/BluetoothMeshService.swift index c7fcf9f2..f9ab0b86 100644 --- a/bitchat/Services/BluetoothMeshService.swift +++ b/bitchat/Services/BluetoothMeshService.swift @@ -226,10 +226,7 @@ class BluetoothMeshService: NSObject { print("[DEBUG] Sending private message to \(recipientNickname): \(content)") self.broadcastPacket(packet) - // Also show the message locally - DispatchQueue.main.async { - self.delegate?.didReceiveMessage(message) - } + // Don't call didReceiveMessage here - let the view model handle it directly } } } diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index 98746670..df084a61 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -76,6 +76,27 @@ class ChatViewModel: ObservableObject { guard !content.isEmpty else { return } guard let recipientNickname = meshService.getPeerNicknames()[peerID] else { return } + // Create the message locally + let message = BitchatMessage( + sender: nickname, + content: content, + timestamp: Date(), + isRelay: false, + originalSender: nil, + isPrivate: true, + recipientNickname: recipientNickname, + senderPeerID: meshService.myPeerID + ) + + // Add to our private chat history + if privateChats[peerID] == nil { + privateChats[peerID] = [] + } + privateChats[peerID]?.append(message) + + // Trigger UI update + objectWillChange.send() + // Send via mesh meshService.sendPrivateMessage(content, to: peerID, recipientNickname: recipientNickname) } @@ -182,6 +203,9 @@ extension ChatViewModel: BitchatDelegate { } privateChats[peerID]?.append(message) + // Trigger UI update for private chats + objectWillChange.send() + // Mark as unread if not currently viewing this chat if selectedPrivateChatPeer != peerID { unreadPrivateMessages.insert(peerID) @@ -189,16 +213,13 @@ extension ChatViewModel: BitchatDelegate { // Show notification banner showPrivateMessageNotification(from: message.sender, content: message.content) + } else { + // We're viewing this chat, make sure unread is cleared + unreadPrivateMessages.remove(peerID) } } else if message.sender == nickname { - // Our own message - find recipient by nickname - if let recipientNickname = message.recipientNickname, - let recipientPeerID = getPeerIDForNickname(recipientNickname) { - if privateChats[recipientPeerID] == nil { - privateChats[recipientPeerID] = [] - } - privateChats[recipientPeerID]?.append(message) - } + // Our own message that was echoed back - ignore it since we already added it locally + print("[DEBUG] Ignoring our own private message echo") } } else { // Regular public message diff --git a/bitchat/Views/ContentView.swift b/bitchat/Views/ContentView.swift index 948e72a0..a909b428 100644 --- a/bitchat/Views/ContentView.swift +++ b/bitchat/Views/ContentView.swift @@ -61,7 +61,7 @@ struct ContentView: View { } .padding(.top, 60) .transition(.move(edge: .top).combined(with: .opacity)) - .animation(.easeInOut, value: viewModel.privateMessageNotification) + .animation(.easeInOut, value: viewModel.privateMessageNotification != nil) } } #if os(macOS)