mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 23:45:18 +00:00
Implement proper room leave notifications and improve UI
- Send leave notifications when users exit rooms - Update room member lists when peers leave rooms - Change current user icon from dot to person.fill - Handle room-specific leave messages via protocol - Maintain backwards compatibility for general peer disconnection
This commit is contained in:
@@ -155,6 +155,7 @@ protocol BitchatDelegate: AnyObject {
|
||||
func didConnectToPeer(_ peerID: String)
|
||||
func didDisconnectFromPeer(_ peerID: String)
|
||||
func didUpdatePeerList(_ peers: [String])
|
||||
func didReceiveRoomLeave(_ room: String, from peerID: String)
|
||||
|
||||
// Optional method to check if a fingerprint belongs to a favorite peer
|
||||
func isFavorite(fingerprint: String) -> Bool
|
||||
@@ -165,4 +166,8 @@ extension BitchatDelegate {
|
||||
func isFavorite(fingerprint: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func didReceiveRoomLeave(_ room: String, from peerID: String) {
|
||||
// Default empty implementation
|
||||
}
|
||||
}
|
||||
@@ -665,6 +665,26 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func sendRoomLeaveNotification(_ room: String) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
// Create a leave packet with room hashtag as payload
|
||||
let packet = BitchatPacket(
|
||||
type: MessageType.leave.rawValue,
|
||||
senderID: Data(self.myPeerID.utf8),
|
||||
recipientID: SpecialRecipients.broadcast, // Broadcast to all
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: Data(room.utf8), // Room hashtag as payload
|
||||
signature: nil,
|
||||
ttl: 3 // Short TTL for leave notifications
|
||||
)
|
||||
|
||||
bitchatLog("Sending room leave notification for \(room)", category: "room")
|
||||
self.broadcastPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private func sendAnnouncementToPeer(_ peerID: String) {
|
||||
guard let vm = delegate as? ChatViewModel else { return }
|
||||
|
||||
@@ -1585,28 +1605,45 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
|
||||
case .leave:
|
||||
if let nickname = String(data: packet.payload, encoding: .utf8),
|
||||
let senderID = String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) {
|
||||
|
||||
|
||||
// Remove from active peers with proper locking
|
||||
activePeersLock.lock()
|
||||
activePeers.remove(senderID)
|
||||
activePeersLock.unlock()
|
||||
|
||||
announcedPeers.remove(senderID)
|
||||
|
||||
// Show leave message
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didDisconnectFromPeer(nickname)
|
||||
if let senderID = String(data: packet.senderID.trimmingNullBytes(), encoding: .utf8) {
|
||||
// Check if payload contains a room hashtag
|
||||
if let room = String(data: packet.payload, encoding: .utf8),
|
||||
room.hasPrefix("#") {
|
||||
// Room leave notification
|
||||
bitchatLog("Received room leave notification from \(senderID) for room \(room)", category: "room")
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didReceiveRoomLeave(room, from: senderID)
|
||||
}
|
||||
|
||||
// Relay if TTL > 0
|
||||
if packet.ttl > 1 {
|
||||
var relayPacket = packet
|
||||
relayPacket.ttl -= 1
|
||||
self.broadcastPacket(relayPacket)
|
||||
}
|
||||
} else {
|
||||
// Legacy peer disconnect (keeping for backwards compatibility)
|
||||
if let nickname = String(data: packet.payload, encoding: .utf8) {
|
||||
// Remove from active peers with proper locking
|
||||
activePeersLock.lock()
|
||||
activePeers.remove(senderID)
|
||||
activePeersLock.unlock()
|
||||
|
||||
announcedPeers.remove(senderID)
|
||||
|
||||
// Show leave message
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didDisconnectFromPeer(nickname)
|
||||
}
|
||||
self.notifyPeerListUpdate()
|
||||
|
||||
// Clean up peer data
|
||||
peerNicknamesLock.lock()
|
||||
peerNicknames.removeValue(forKey: senderID)
|
||||
peerNicknamesLock.unlock()
|
||||
}
|
||||
}
|
||||
self.notifyPeerListUpdate()
|
||||
|
||||
// Clean up peer data
|
||||
peerNicknamesLock.lock()
|
||||
peerNicknames.removeValue(forKey: senderID)
|
||||
peerNicknamesLock.unlock()
|
||||
} else {
|
||||
}
|
||||
|
||||
case .fragmentStart, .fragmentContinue, .fragmentEnd:
|
||||
|
||||
@@ -132,6 +132,9 @@ class ChatViewModel: ObservableObject {
|
||||
joinedRooms.remove(room)
|
||||
saveJoinedRooms()
|
||||
|
||||
// Send leave notification to other peers
|
||||
meshService.sendRoomLeaveNotification(room)
|
||||
|
||||
// If we're currently in this room, exit to main chat
|
||||
if currentRoom == room {
|
||||
currentRoom = nil
|
||||
@@ -630,6 +633,17 @@ class ChatViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
extension ChatViewModel: BitchatDelegate {
|
||||
func didReceiveRoomLeave(_ room: String, from peerID: String) {
|
||||
// Remove peer from room members
|
||||
if roomMembers[room] != nil {
|
||||
roomMembers[room]?.remove(peerID)
|
||||
bitchatLog("Removed peer \(peerID) from room \(room) members", category: "room")
|
||||
|
||||
// Force UI update
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
|
||||
func didReceiveMessage(_ message: BitchatMessage) {
|
||||
bitchatLog("Received message from \(message.sender), room: \(message.room ?? "nil"), senderPeerID: \(message.senderPeerID ?? "nil")", category: "message")
|
||||
|
||||
|
||||
@@ -644,8 +644,8 @@ struct ContentView: View {
|
||||
HStack(spacing: 8) {
|
||||
// Signal strength indicator or unread message icon
|
||||
if isMe {
|
||||
Text("•")
|
||||
.font(.system(size: 12))
|
||||
Image(systemName: "person.fill")
|
||||
.font(.system(size: 10))
|
||||
.foregroundColor(textColor)
|
||||
} else if viewModel.unreadPrivateMessages.contains(peerID) {
|
||||
Image(systemName: "envelope.fill")
|
||||
|
||||
Reference in New Issue
Block a user