Fix room message routing and improve room UI

- Fix room field not being properly set in BluetoothMeshService sendMessage
- Make room name header tappable to open sidebar
- Show member count in parentheses next to room name
- Display room members including self with "(you)" indicator
- Show self in room member list with dot indicator
- Disable favorite/chat actions for self in member list
- Fix empty room detection logic
This commit is contained in:
jack
2025-07-05 19:35:37 +02:00
parent eee97881e9
commit d0a465f05f
2 changed files with 74 additions and 37 deletions
@@ -520,6 +520,9 @@ class BluetoothMeshService: NSObject {
timestamp: Date(), timestamp: Date(),
isRelay: false, isRelay: false,
originalSender: nil, originalSender: nil,
isPrivate: false,
recipientNickname: nil,
senderPeerID: self.myPeerID,
mentions: mentions.isEmpty ? nil : mentions, mentions: mentions.isEmpty ? nil : mentions,
room: room room: room
) )
+71 -37
View File
@@ -206,9 +206,18 @@ struct ContentView: View {
} else if let currentRoom = viewModel.currentRoom { } else if let currentRoom = viewModel.currentRoom {
// Room header // Room header
HStack(spacing: 4) { HStack(spacing: 4) {
Text(currentRoom) let memberCount = (viewModel.roomMembers[currentRoom]?.count ?? 0) + 1 // +1 for self
.font(.system(size: 18, weight: .medium, design: .monospaced)) Button(action: {
.foregroundColor(Color.orange) withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {
showSidebar.toggle()
sidebarDragOffset = 0
}
}) {
Text("\(currentRoom) (\(memberCount))")
.font(.system(size: 18, weight: .medium, design: .monospaced))
.foregroundColor(Color.orange)
}
.buttonStyle(.plain)
Spacer() Spacer()
@@ -568,7 +577,8 @@ struct ContentView: View {
.foregroundColor(secondaryTextColor) .foregroundColor(secondaryTextColor)
.padding(.horizontal) .padding(.horizontal)
} else if let currentRoom = viewModel.currentRoom, } else if let currentRoom = viewModel.currentRoom,
(viewModel.roomMembers[currentRoom]?.isEmpty ?? true) { viewModel.roomMembers[currentRoom]?.isEmpty ?? true,
!viewModel.connectedPeers.contains(viewModel.meshService.myPeerID) {
Text("No one in this room yet") Text("No one in this room yet")
.font(.system(size: 14, design: .monospaced)) .font(.system(size: 14, design: .monospaced))
.foregroundColor(secondaryTextColor) .foregroundColor(secondaryTextColor)
@@ -579,14 +589,21 @@ struct ContentView: View {
let myPeerID = viewModel.meshService.myPeerID let myPeerID = viewModel.meshService.myPeerID
// Filter peers based on current room // Filter peers based on current room
let peersToShow = if let currentRoom = viewModel.currentRoom, let peersToShow: [String] = {
let roomMemberIDs = viewModel.roomMembers[currentRoom] { if let currentRoom = viewModel.currentRoom,
// Show only peers who have sent messages to this room let roomMemberIDs = viewModel.roomMembers[currentRoom] {
viewModel.connectedPeers.filter { roomMemberIDs.contains($0) && $0 != myPeerID } // Show only peers who have sent messages to this room (including self)
} else { var memberPeers = viewModel.connectedPeers.filter { roomMemberIDs.contains($0) }
// Show all connected peers in main chat // Always include ourselves if we're connected
viewModel.connectedPeers.filter { $0 != myPeerID } if viewModel.connectedPeers.contains(myPeerID) {
} memberPeers.append(myPeerID)
}
return Array(Set(memberPeers)) // Remove duplicates
} else {
// Show all connected peers in main chat
return viewModel.connectedPeers
}
}()
// Sort peers: favorites first, then alphabetically by nickname // Sort peers: favorites first, then alphabetically by nickname
let sortedPeers = peersToShow.sorted { peer1, peer2 in let sortedPeers = peersToShow.sorted { peer1, peer2 in
@@ -603,13 +620,18 @@ struct ContentView: View {
} }
ForEach(sortedPeers, id: \.self) { peerID in ForEach(sortedPeers, id: \.self) { peerID in
let displayName = peerNicknames[peerID] ?? "person-\(peerID.prefix(4))" let displayName = peerID == myPeerID ? viewModel.nickname : (peerNicknames[peerID] ?? "person-\(peerID.prefix(4))")
let rssi = peerRSSI[peerID]?.intValue ?? -100 let rssi = peerRSSI[peerID]?.intValue ?? -100
let isFavorite = viewModel.isFavorite(peerID: peerID) let isFavorite = viewModel.isFavorite(peerID: peerID)
let isMe = peerID == myPeerID
HStack(spacing: 8) { HStack(spacing: 8) {
// Signal strength indicator or unread message icon // Signal strength indicator or unread message icon
if viewModel.unreadPrivateMessages.contains(peerID) { if isMe {
Text("")
.font(.system(size: 12))
.foregroundColor(textColor)
} else if viewModel.unreadPrivateMessages.contains(peerID) {
Image(systemName: "envelope.fill") Image(systemName: "envelope.fill")
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(Color.orange) .foregroundColor(Color.orange)
@@ -619,36 +641,48 @@ struct ContentView: View {
.frame(width: 8, height: 8) .frame(width: 8, height: 8)
} }
// Favorite star // Favorite star (not for self)
Button(action: { if !isMe {
viewModel.toggleFavorite(peerID: peerID) Button(action: {
}) { viewModel.toggleFavorite(peerID: peerID)
Image(systemName: isFavorite ? "star.fill" : "star") }) {
.font(.system(size: 12)) Image(systemName: isFavorite ? "star.fill" : "star")
.foregroundColor(isFavorite ? Color.yellow : secondaryTextColor) .font(.system(size: 12))
} .foregroundColor(isFavorite ? Color.yellow : secondaryTextColor)
.buttonStyle(.plain)
// Peer name button
Button(action: {
if peerNicknames[peerID] != nil {
viewModel.startPrivateChat(with: peerID)
withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {
showSidebar = false
sidebarDragOffset = 0
}
} }
}) { .buttonStyle(.plain)
}
// Peer name
if isMe {
HStack { HStack {
Text(displayName) Text(displayName + " (you)")
.font(.system(size: 14, design: .monospaced)) .font(.system(size: 14, design: .monospaced))
.foregroundColor(peerNicknames[peerID] != nil ? textColor : secondaryTextColor) .foregroundColor(textColor)
Spacer() Spacer()
} }
} else {
Button(action: {
if peerNicknames[peerID] != nil {
viewModel.startPrivateChat(with: peerID)
withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {
showSidebar = false
sidebarDragOffset = 0
}
}
}) {
HStack {
Text(displayName)
.font(.system(size: 14, design: .monospaced))
.foregroundColor(peerNicknames[peerID] != nil ? textColor : secondaryTextColor)
Spacer()
}
}
.buttonStyle(.plain)
.disabled(peerNicknames[peerID] == nil)
} }
.buttonStyle(.plain)
.disabled(peerNicknames[peerID] == nil)
} }
.padding(.horizontal) .padding(.horizontal)
.padding(.vertical, 8) .padding(.vertical, 8)