diff --git a/bitchat/ViewModels/ChatViewModel.swift b/bitchat/ViewModels/ChatViewModel.swift index 4cb934ec..519ef0df 100644 --- a/bitchat/ViewModels/ChatViewModel.swift +++ b/bitchat/ViewModels/ChatViewModel.swift @@ -3144,7 +3144,8 @@ class ChatViewModel: ObservableObject, BitchatDelegate { return hash } - private func colorForPeerSeed(_ seed: String, isDark: Bool) -> Color { + @MainActor + func colorForPeerSeed(_ seed: String, isDark: Bool) -> Color { if let cached = peerColorCache[seed] { return cached } var hue = Double(djb2(seed) % 360) / 360.0 // Avoid orange (~30°) reserved for self @@ -3175,6 +3176,21 @@ class ChatViewModel: ObservableObject, BitchatDelegate { return colorForPeerSeed(seed, isDark: isDark) } + // Public helpers for views to color peers consistently in lists + @MainActor + func colorForNostrPubkey(_ pubkeyHexLowercased: String, isDark: Bool) -> Color { + return colorForPeerSeed("nostr:" + pubkeyHexLowercased.lowercased(), isDark: isDark) + } + + @MainActor + func colorForMeshPeer(id peerID: String, isDark: Bool) -> Color { + if let peer = unifiedPeerService.getPeer(by: peerID) { + let full = peer.noisePublicKey.hexEncodedString().lowercased() + return colorForPeerSeed("noise:" + full, isDark: isDark) + } + return colorForPeerSeed(peerID.lowercased(), isDark: isDark) + } + private func trimMeshTimelineIfNeeded() { if meshTimeline.count > meshTimelineCap { let removeCount = meshTimeline.count - meshTimelineCap diff --git a/bitchat/Views/GeohashPeopleList.swift b/bitchat/Views/GeohashPeopleList.swift index e8604b97..69528c61 100644 --- a/bitchat/Views/GeohashPeopleList.swift +++ b/bitchat/Views/GeohashPeopleList.swift @@ -6,6 +6,7 @@ struct GeohashPeopleList: View { let textColor: Color let secondaryTextColor: Color let onTapPerson: () -> Void + @Environment(\.colorScheme) var colorScheme var body: some View { Group { @@ -51,14 +52,15 @@ struct GeohashPeopleList: View { } let (base, suffix) = splitSuffix(from: person.displayName) let isMe = person.id == myHex + let assignedColor = viewModel.colorForNostrPubkey(person.id, isDark: colorScheme == .dark) HStack(spacing: 0) { - let rowColor: Color = isMe ? .orange : textColor + let rowColor: Color = isMe ? .orange : assignedColor Text(base) .font(.system(size: 14, design: .monospaced)) .fontWeight(isMe ? .bold : .regular) .foregroundColor(rowColor) if !suffix.isEmpty { - let suffixColor = isMe ? Color.orange.opacity(0.6) : textColor.opacity(0.6) + let suffixColor = isMe ? Color.orange.opacity(0.6) : rowColor.opacity(0.6) Text(suffix) .font(.system(size: 14, design: .monospaced)) .foregroundColor(suffixColor) diff --git a/bitchat/Views/MeshPeerList.swift b/bitchat/Views/MeshPeerList.swift index 14ca6a1b..ccc62fa3 100644 --- a/bitchat/Views/MeshPeerList.swift +++ b/bitchat/Views/MeshPeerList.swift @@ -7,6 +7,7 @@ struct MeshPeerList: View { let onTapPeer: (String) -> Void let onToggleFavorite: (String) -> Void let onShowFingerprint: (String) -> Void + @Environment(\.colorScheme) var colorScheme var body: some View { Group { @@ -61,7 +62,8 @@ struct MeshPeerList: View { let displayName = isMe ? viewModel.nickname : peer.nickname let (base, suffix) = splitSuffix(from: displayName) - let baseColor = ((peer.favoriteStatus?.isFavorite ?? false) || peerNicknames[peer.id] != nil) ? textColor : secondaryTextColor + let assigned = viewModel.colorForMeshPeer(id: peer.id, isDark: colorScheme == .dark) + let baseColor = isMe ? Color.orange : assigned HStack(spacing: 0) { Text(base) .font(.system(size: 14, design: .monospaced))