mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 22:05:21 +00:00
PeerID 23/n: ChatViewModel + its dependences (#801)
This commit is contained in:
@@ -221,7 +221,7 @@ final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
|
|||||||
// Get peer ID from userInfo
|
// Get peer ID from userInfo
|
||||||
if let peerID = userInfo["peerID"] as? String {
|
if let peerID = userInfo["peerID"] as? String {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.chatViewModel?.startPrivateChat(with: peerID)
|
self.chatViewModel?.startPrivateChat(with: PeerID(str: peerID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,9 +148,9 @@ final class CommandProcessor {
|
|||||||
|
|
||||||
if chatViewModel?.selectedPrivateChatPeer != nil {
|
if chatViewModel?.selectedPrivateChatPeer != nil {
|
||||||
// In private chat
|
// In private chat
|
||||||
if let peerNickname = meshService?.peerNickname(peerID: PeerID(str: targetPeerID)) {
|
if let peerNickname = meshService?.peerNickname(peerID: targetPeerID) {
|
||||||
let personalMessage = "* \(emoji) \(myNickname) \(action) you\(suffix) *"
|
let personalMessage = "* \(emoji) \(myNickname) \(action) you\(suffix) *"
|
||||||
meshService?.sendPrivateMessage(personalMessage, to: PeerID(str: targetPeerID),
|
meshService?.sendPrivateMessage(personalMessage, to: targetPeerID,
|
||||||
recipientNickname: peerNickname,
|
recipientNickname: peerNickname,
|
||||||
messageID: UUID().uuidString)
|
messageID: UUID().uuidString)
|
||||||
// Also add a local system message so the sender sees a natural-language confirmation
|
// Also add a local system message so the sender sees a natural-language confirmation
|
||||||
@@ -214,7 +214,7 @@ final class CommandProcessor {
|
|||||||
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
||||||
|
|
||||||
if let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
if let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
||||||
let fingerprint = meshService?.getFingerprint(for: PeerID(str: peerID)) {
|
let fingerprint = meshService?.getFingerprint(for: peerID) {
|
||||||
if identityManager.isBlocked(fingerprint: fingerprint) {
|
if identityManager.isBlocked(fingerprint: fingerprint) {
|
||||||
return .success(message: "\(nickname) is already blocked")
|
return .success(message: "\(nickname) is already blocked")
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ final class CommandProcessor {
|
|||||||
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
||||||
|
|
||||||
if let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
if let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
||||||
let fingerprint = meshService?.getFingerprint(for: PeerID(str: peerID)) {
|
let fingerprint = meshService?.getFingerprint(for: peerID) {
|
||||||
if !identityManager.isBlocked(fingerprint: fingerprint) {
|
if !identityManager.isBlocked(fingerprint: fingerprint) {
|
||||||
return .success(message: "\(nickname) is not blocked")
|
return .success(message: "\(nickname) is not blocked")
|
||||||
}
|
}
|
||||||
@@ -285,7 +285,7 @@ final class CommandProcessor {
|
|||||||
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
let nickname = targetName.hasPrefix("@") ? String(targetName.dropFirst()) : targetName
|
||||||
|
|
||||||
guard let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
guard let peerID = chatViewModel?.getPeerIDForNickname(nickname),
|
||||||
let noisePublicKey = Data(hexString: peerID) else {
|
let noisePublicKey = Data(hexString: peerID.id) else {
|
||||||
return .error(message: "can't find peer: \(nickname)")
|
return .error(message: "can't find peer: \(nickname)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,10 +235,10 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get peer ID for nickname
|
/// Get peer ID for nickname
|
||||||
func getPeerID(for nickname: String) -> String? {
|
func getPeerID(for nickname: String) -> PeerID? {
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
if peer.displayName == nickname || peer.nickname == nickname {
|
if peer.displayName == nickname || peer.nickname == nickname {
|
||||||
return peer.peerID.id
|
return peer.peerID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -347,7 +347,7 @@ final class UnifiedPeerService: ObservableObject, TransportPeerEventsDelegate {
|
|||||||
// MARK: - Compatibility Methods (for easy migration)
|
// MARK: - Compatibility Methods (for easy migration)
|
||||||
|
|
||||||
var allPeers: [BitchatPeer] { peers }
|
var allPeers: [BitchatPeer] { peers }
|
||||||
var connectedPeers: [PeerID] { Array(connectedPeerIDs) }
|
var connectedPeers: Set<PeerID> { connectedPeerIDs }
|
||||||
var favoritePeers: Set<String> {
|
var favoritePeers: Set<String> {
|
||||||
Set(favorites.compactMap { getFingerprint(for: $0.peerID) })
|
Set(favorites.compactMap { getFingerprint(for: $0.peerID) })
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -207,7 +207,7 @@ struct ContentView: View {
|
|||||||
set: { _ in viewModel.showingFingerprintFor = nil }
|
set: { _ in viewModel.showingFingerprintFor = nil }
|
||||||
)) {
|
)) {
|
||||||
if let peerID = viewModel.showingFingerprintFor {
|
if let peerID = viewModel.showingFingerprintFor {
|
||||||
FingerprintView(viewModel: viewModel, peerID: peerID)
|
FingerprintView(viewModel: viewModel, peerID: peerID.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@@ -262,11 +262,11 @@ struct ContentView: View {
|
|||||||
Button("content.actions.direct_message") {
|
Button("content.actions.direct_message") {
|
||||||
if let peerID = selectedMessageSenderID {
|
if let peerID = selectedMessageSenderID {
|
||||||
if peerID.hasPrefix("nostr:") {
|
if peerID.hasPrefix("nostr:") {
|
||||||
if let full = viewModel.fullNostrHex(forSenderPeerID: peerID) {
|
if let full = viewModel.fullNostrHex(forSenderPeerID: PeerID(str: peerID)) {
|
||||||
viewModel.startGeohashDM(withPubkeyHex: full)
|
viewModel.startGeohashDM(withPubkeyHex: full)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.startPrivateChat(with: peerID)
|
viewModel.startPrivateChat(with: PeerID(str: peerID))
|
||||||
}
|
}
|
||||||
withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) {
|
withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) {
|
||||||
showSidebar = true
|
showSidebar = true
|
||||||
@@ -289,7 +289,7 @@ struct ContentView: View {
|
|||||||
Button("content.actions.block", role: .destructive) {
|
Button("content.actions.block", role: .destructive) {
|
||||||
// Prefer direct geohash block when we have a Nostr sender ID
|
// Prefer direct geohash block when we have a Nostr sender ID
|
||||||
if let peerID = selectedMessageSenderID, peerID.hasPrefix("nostr:"),
|
if let peerID = selectedMessageSenderID, peerID.hasPrefix("nostr:"),
|
||||||
let full = viewModel.fullNostrHex(forSenderPeerID: peerID),
|
let full = viewModel.fullNostrHex(forSenderPeerID: PeerID(str: peerID)),
|
||||||
let sender = selectedMessageSender {
|
let sender = selectedMessageSender {
|
||||||
viewModel.blockGeohashUser(pubkeyHexLowercased: full, displayName: sender)
|
viewModel.blockGeohashUser(pubkeyHexLowercased: full, displayName: sender)
|
||||||
} else if let sender = selectedMessageSender {
|
} else if let sender = selectedMessageSender {
|
||||||
@@ -322,8 +322,8 @@ struct ContentView: View {
|
|||||||
|
|
||||||
private func messagesView(privatePeer: String?, isAtBottom: Binding<Bool>) -> some View {
|
private func messagesView(privatePeer: String?, isAtBottom: Binding<Bool>) -> some View {
|
||||||
let messages: [BitchatMessage] = {
|
let messages: [BitchatMessage] = {
|
||||||
if let privatePeer = privatePeer {
|
if let privatePeer {
|
||||||
return viewModel.getPrivateChatMessages(for: privatePeer)
|
return viewModel.getPrivateChatMessages(for: PeerID(str: privatePeer))
|
||||||
}
|
}
|
||||||
return viewModel.messages
|
return viewModel.messages
|
||||||
}()
|
}()
|
||||||
@@ -517,7 +517,7 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Also check when view appears
|
// Also check when view appears
|
||||||
if let peerID = privatePeer {
|
if let peerID = PeerID(str: privatePeer) {
|
||||||
// Try multiple times to ensure read receipts are sent
|
// Try multiple times to ensure read receipts are sent
|
||||||
viewModel.markPrivateMessagesAsRead(from: peerID)
|
viewModel.markPrivateMessagesAsRead(from: peerID)
|
||||||
|
|
||||||
@@ -767,20 +767,20 @@ struct ContentView: View {
|
|||||||
private func handleOpenURL(_ url: URL) {
|
private func handleOpenURL(_ url: URL) {
|
||||||
guard url.scheme == "bitchat", url.host == "user" else { return }
|
guard url.scheme == "bitchat", url.host == "user" else { return }
|
||||||
let id = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
let id = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
||||||
let peerID = id.removingPercentEncoding ?? id
|
let peerID = PeerID(str: id.removingPercentEncoding ?? id)
|
||||||
selectedMessageSenderID = peerID
|
selectedMessageSenderID = peerID.id
|
||||||
|
|
||||||
if peerID.hasPrefix("nostr") {
|
if peerID.isGeoDM || peerID.isGeoChat {
|
||||||
selectedMessageSender = viewModel.geohashDisplayName(for: peerID)
|
selectedMessageSender = viewModel.geohashDisplayName(for: peerID)
|
||||||
} else {
|
} else {
|
||||||
if let name = viewModel.meshService.peerNickname(peerID: PeerID(str: peerID)) {
|
if let name = viewModel.meshService.peerNickname(peerID: peerID) {
|
||||||
selectedMessageSender = name
|
selectedMessageSender = name
|
||||||
} else {
|
} else {
|
||||||
selectedMessageSender = viewModel.messages.last(where: { $0.senderPeerID == peerID && $0.sender != "system" })?.sender
|
selectedMessageSender = viewModel.messages.last(where: { $0.senderPeerID == peerID && $0.sender != "system" })?.sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if viewModel.isSelfSender(peerID: selectedMessageSenderID, displayName: selectedMessageSender) {
|
if viewModel.isSelfSender(peerID: peerID, displayName: selectedMessageSender) {
|
||||||
selectedMessageSender = nil
|
selectedMessageSender = nil
|
||||||
selectedMessageSenderID = nil
|
selectedMessageSenderID = nil
|
||||||
} else {
|
} else {
|
||||||
@@ -793,7 +793,7 @@ struct ContentView: View {
|
|||||||
isAtBottom: Binding<Bool>) {
|
isAtBottom: Binding<Bool>) {
|
||||||
let targetID: String? = {
|
let targetID: String? = {
|
||||||
if let peer = privatePeer,
|
if let peer = privatePeer,
|
||||||
let last = viewModel.getPrivateChatMessages(for: peer).suffix(300).last?.id {
|
let last = viewModel.getPrivateChatMessages(for: PeerID(str: peer)).suffix(300).last?.id {
|
||||||
return "dm:\(peer)|\(last)"
|
return "dm:\(peer)|\(last)"
|
||||||
}
|
}
|
||||||
let contextKey: String = {
|
let contextKey: String = {
|
||||||
@@ -931,14 +931,14 @@ struct ContentView: View {
|
|||||||
textColor: textColor,
|
textColor: textColor,
|
||||||
secondaryTextColor: secondaryTextColor,
|
secondaryTextColor: secondaryTextColor,
|
||||||
onTapPeer: { peerID in
|
onTapPeer: { peerID in
|
||||||
viewModel.startPrivateChat(with: peerID)
|
viewModel.startPrivateChat(with: PeerID(str: peerID))
|
||||||
showSidebar = true
|
showSidebar = true
|
||||||
},
|
},
|
||||||
onToggleFavorite: { peerID in
|
onToggleFavorite: { peerID in
|
||||||
viewModel.toggleFavorite(peerID: peerID)
|
viewModel.toggleFavorite(peerID: PeerID(str: peerID))
|
||||||
},
|
},
|
||||||
onShowFingerprint: { peerID in
|
onShowFingerprint: { peerID in
|
||||||
viewModel.showFingerprint(for: peerID)
|
viewModel.showFingerprint(for: PeerID(str: peerID))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -977,18 +977,20 @@ struct ContentView: View {
|
|||||||
|
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
privateHeaderInfo(context: headerContext, privatePeerID: privatePeerID)
|
privateHeaderInfo(context: headerContext, privatePeerID: privatePeerID)
|
||||||
|
let peerID = PeerID(str: headerContext.headerPeerID)
|
||||||
|
let isFavorite = viewModel.isFavorite(peerID: peerID)
|
||||||
|
|
||||||
if !privatePeerID.hasPrefix("nostr_") {
|
if !privatePeerID.hasPrefix("nostr_") {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
viewModel.toggleFavorite(peerID: headerContext.headerPeerID)
|
viewModel.toggleFavorite(peerID: peerID)
|
||||||
}) {
|
}) {
|
||||||
Image(systemName: viewModel.isFavorite(peerID: headerContext.headerPeerID) ? "star.fill" : "star")
|
Image(systemName: isFavorite ? "star.fill" : "star")
|
||||||
.font(.bitchatSystem(size: 14))
|
.font(.bitchatSystem(size: 14))
|
||||||
.foregroundColor(viewModel.isFavorite(peerID: headerContext.headerPeerID) ? Color.yellow : textColor)
|
.foregroundColor(isFavorite ? Color.yellow : textColor)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.accessibilityLabel(
|
.accessibilityLabel(
|
||||||
viewModel.isFavorite(peerID: headerContext.headerPeerID)
|
isFavorite
|
||||||
? String(localized: "content.accessibility.remove_favorite", comment: "Accessibility label to remove a favorite")
|
? String(localized: "content.accessibility.remove_favorite", comment: "Accessibility label to remove a favorite")
|
||||||
: String(localized: "content.accessibility.add_favorite", comment: "Accessibility label to add a favorite")
|
: String(localized: "content.accessibility.add_favorite", comment: "Accessibility label to add a favorite")
|
||||||
)
|
)
|
||||||
@@ -1043,7 +1045,7 @@ struct ContentView: View {
|
|||||||
|
|
||||||
private func privateHeaderInfo(context: PrivateHeaderContext, privatePeerID: String) -> some View {
|
private func privateHeaderInfo(context: PrivateHeaderContext, privatePeerID: String) -> some View {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
viewModel.showFingerprint(for: context.headerPeerID)
|
viewModel.showFingerprint(for: PeerID(str: context.headerPeerID))
|
||||||
}) {
|
}) {
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
if let connectionState = context.peer?.connectionState {
|
if let connectionState = context.peer?.connectionState {
|
||||||
@@ -1076,7 +1078,7 @@ struct ContentView: View {
|
|||||||
.font(.bitchatSystem(size: 14))
|
.font(.bitchatSystem(size: 14))
|
||||||
.foregroundColor(.purple)
|
.foregroundColor(.purple)
|
||||||
.accessibilityLabel(String(localized: "content.accessibility.available_nostr", comment: "Accessibility label for Nostr-available peer indicator"))
|
.accessibilityLabel(String(localized: "content.accessibility.available_nostr", comment: "Accessibility label for Nostr-available peer indicator"))
|
||||||
} else if viewModel.meshService.isPeerConnected(PeerID(str: context.headerPeerID)) || viewModel.connectedPeers.contains(context.headerPeerID) {
|
} else if viewModel.meshService.isPeerConnected(PeerID(str: context.headerPeerID)) || viewModel.connectedPeers.contains(PeerID(str: context.headerPeerID)) {
|
||||||
Image(systemName: "dot.radiowaves.left.and.right")
|
Image(systemName: "dot.radiowaves.left.and.right")
|
||||||
.font(.bitchatSystem(size: 14))
|
.font(.bitchatSystem(size: 14))
|
||||||
.foregroundColor(textColor)
|
.foregroundColor(textColor)
|
||||||
@@ -1090,11 +1092,11 @@ struct ContentView: View {
|
|||||||
if !privatePeerID.hasPrefix("nostr_") {
|
if !privatePeerID.hasPrefix("nostr_") {
|
||||||
let statusPeerID: String = {
|
let statusPeerID: String = {
|
||||||
if privatePeerID.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
if privatePeerID.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
||||||
return short
|
return short.id
|
||||||
}
|
}
|
||||||
return context.headerPeerID
|
return context.headerPeerID
|
||||||
}()
|
}()
|
||||||
let encryptionStatus = viewModel.getEncryptionStatus(for: statusPeerID)
|
let encryptionStatus = viewModel.getEncryptionStatus(for: PeerID(str: statusPeerID))
|
||||||
if let icon = encryptionStatus.icon {
|
if let icon = encryptionStatus.icon {
|
||||||
Image(systemName: icon)
|
Image(systemName: icon)
|
||||||
.font(.bitchatSystem(size: 14))
|
.font(.bitchatSystem(size: 14))
|
||||||
@@ -1129,16 +1131,16 @@ struct ContentView: View {
|
|||||||
private func makePrivateHeaderContext(for privatePeerID: String) -> PrivateHeaderContext {
|
private func makePrivateHeaderContext(for privatePeerID: String) -> PrivateHeaderContext {
|
||||||
let headerPeerID: String = {
|
let headerPeerID: String = {
|
||||||
if privatePeerID.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
if privatePeerID.count == 64, let short = viewModel.getShortIDForNoiseKey(privatePeerID) {
|
||||||
return short
|
return short.id
|
||||||
}
|
}
|
||||||
return privatePeerID
|
return privatePeerID
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let peer = viewModel.getPeer(byID: headerPeerID)
|
let peer = viewModel.getPeer(byID: PeerID(str: headerPeerID))
|
||||||
|
|
||||||
let displayName: String = {
|
let displayName: String = {
|
||||||
if privatePeerID.hasPrefix("nostr_"), case .location(let ch) = locationManager.selectedChannel {
|
if privatePeerID.hasPrefix("nostr_"), case .location(let ch) = locationManager.selectedChannel {
|
||||||
let disp = viewModel.geohashDisplayName(for: privatePeerID)
|
let disp = viewModel.geohashDisplayName(for: PeerID(str: privatePeerID))
|
||||||
return "#\(ch.geohash)/@\(disp)"
|
return "#\(ch.geohash)/@\(disp)"
|
||||||
}
|
}
|
||||||
if let name = peer?.displayName { return name }
|
if let name = peer?.displayName { return name }
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ struct FingerprintView: View {
|
|||||||
VStack(alignment: .leading, spacing: 16) {
|
VStack(alignment: .leading, spacing: 16) {
|
||||||
// Prefer short mesh ID for session/encryption status
|
// Prefer short mesh ID for session/encryption status
|
||||||
let statusPeerID: String = {
|
let statusPeerID: String = {
|
||||||
if peerID.count == 64, let short = viewModel.getShortIDForNoiseKey(peerID) { return short }
|
if peerID.count == 64, let short = viewModel.getShortIDForNoiseKey(peerID) { return short.id }
|
||||||
return peerID
|
return peerID
|
||||||
}()
|
}()
|
||||||
// Resolve a friendly name
|
// Resolve a friendly name
|
||||||
let peerNickname: String = {
|
let peerNickname: String = {
|
||||||
if let p = viewModel.getPeer(byID: statusPeerID) { return p.displayName }
|
if let p = viewModel.getPeer(byID: PeerID(str: statusPeerID)) { return p.displayName }
|
||||||
if let name = viewModel.meshService.peerNickname(peerID: PeerID(str: statusPeerID)) { return name }
|
if let name = viewModel.meshService.peerNickname(peerID: PeerID(str: statusPeerID)) { return name }
|
||||||
if peerID.count == 64, let data = Data(hexString: peerID) {
|
if peerID.count == 64, let data = Data(hexString: peerID) {
|
||||||
if let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: data), !fav.peerNickname.isEmpty { return fav.peerNickname }
|
if let fav = FavoritesPersistenceService.shared.getFavoriteStatus(for: data), !fav.peerNickname.isEmpty { return fav.peerNickname }
|
||||||
@@ -84,7 +84,7 @@ struct FingerprintView: View {
|
|||||||
return Strings.unknownPeer()
|
return Strings.unknownPeer()
|
||||||
}()
|
}()
|
||||||
// Accurate encryption state based on short ID session
|
// Accurate encryption state based on short ID session
|
||||||
let encryptionStatus = viewModel.getEncryptionStatus(for: statusPeerID)
|
let encryptionStatus = viewModel.getEncryptionStatus(for: PeerID(str: statusPeerID))
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
if let icon = encryptionStatus.icon {
|
if let icon = encryptionStatus.icon {
|
||||||
@@ -115,7 +115,7 @@ struct FingerprintView: View {
|
|||||||
.font(.bitchatSystem(size: 12, weight: .bold, design: .monospaced))
|
.font(.bitchatSystem(size: 12, weight: .bold, design: .monospaced))
|
||||||
.foregroundColor(textColor.opacity(0.7))
|
.foregroundColor(textColor.opacity(0.7))
|
||||||
|
|
||||||
if let fingerprint = viewModel.getFingerprint(for: statusPeerID) {
|
if let fingerprint = viewModel.getFingerprint(for: PeerID(str: statusPeerID)) {
|
||||||
Text(formatFingerprint(fingerprint))
|
Text(formatFingerprint(fingerprint))
|
||||||
.font(.bitchatSystem(size: 14, design: .monospaced))
|
.font(.bitchatSystem(size: 14, design: .monospaced))
|
||||||
.foregroundColor(textColor)
|
.foregroundColor(textColor)
|
||||||
@@ -176,6 +176,7 @@ struct FingerprintView: View {
|
|||||||
// Verification status
|
// Verification status
|
||||||
if encryptionStatus == .noiseSecured || encryptionStatus == .noiseVerified {
|
if encryptionStatus == .noiseSecured || encryptionStatus == .noiseVerified {
|
||||||
let isVerified = encryptionStatus == .noiseVerified
|
let isVerified = encryptionStatus == .noiseVerified
|
||||||
|
let peerID = PeerID(str: peerID)
|
||||||
|
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
Text(isVerified ? Strings.verifiedBadge : Strings.notVerifiedBadge)
|
Text(isVerified ? Strings.verifiedBadge : Strings.notVerifiedBadge)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ struct MeshPeerList: View {
|
|||||||
let myPeerID = viewModel.meshService.myPeerID
|
let myPeerID = viewModel.meshService.myPeerID
|
||||||
let mapped: [(peer: BitchatPeer, isMe: Bool, hasUnread: Bool, enc: EncryptionStatus)] = viewModel.allPeers.map { peer in
|
let mapped: [(peer: BitchatPeer, isMe: Bool, hasUnread: Bool, enc: EncryptionStatus)] = viewModel.allPeers.map { peer in
|
||||||
let isMe = peer.peerID == myPeerID
|
let isMe = peer.peerID == myPeerID
|
||||||
let hasUnread = viewModel.hasUnreadMessages(for: peer.peerID.id)
|
let hasUnread = viewModel.hasUnreadMessages(for: peer.peerID)
|
||||||
let enc = viewModel.getEncryptionStatus(for: peer.peerID.id)
|
let enc = viewModel.getEncryptionStatus(for: peer.peerID)
|
||||||
return (peer, isMe, hasUnread, enc)
|
return (peer, isMe, hasUnread, enc)
|
||||||
}
|
}
|
||||||
// Stable visual order without mutating state here
|
// Stable visual order without mutating state here
|
||||||
@@ -47,7 +47,7 @@ struct MeshPeerList: View {
|
|||||||
let peer = item.peer
|
let peer = item.peer
|
||||||
let isMe = item.isMe
|
let isMe = item.isMe
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
let assigned = viewModel.colorForMeshPeer(id: peer.peerID.id, isDark: colorScheme == .dark)
|
let assigned = viewModel.colorForMeshPeer(id: peer.peerID, isDark: colorScheme == .dark)
|
||||||
let baseColor = isMe ? Color.orange : assigned
|
let baseColor = isMe ? Color.orange : assigned
|
||||||
if isMe {
|
if isMe {
|
||||||
Image(systemName: "person.fill")
|
Image(systemName: "person.fill")
|
||||||
@@ -89,7 +89,7 @@ struct MeshPeerList: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isMe, viewModel.isPeerBlocked(peer.peerID.id) {
|
if !isMe, viewModel.isPeerBlocked(peer.peerID) {
|
||||||
Image(systemName: "nosign")
|
Image(systemName: "nosign")
|
||||||
.font(.bitchatSystem(size: 10))
|
.font(.bitchatSystem(size: 10))
|
||||||
.foregroundColor(.red)
|
.foregroundColor(.red)
|
||||||
@@ -105,7 +105,7 @@ struct MeshPeerList: View {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Offline: prefer showing verified badge from persisted fingerprints
|
// Offline: prefer showing verified badge from persisted fingerprints
|
||||||
if let fp = viewModel.getFingerprint(for: peer.peerID.id),
|
if let fp = viewModel.getFingerprint(for: peer.peerID),
|
||||||
viewModel.verifiedFingerprints.contains(fp) {
|
viewModel.verifiedFingerprints.contains(fp) {
|
||||||
Image(systemName: "checkmark.seal.fill")
|
Image(systemName: "checkmark.seal.fill")
|
||||||
.font(.bitchatSystem(size: 10))
|
.font(.bitchatSystem(size: 10))
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ struct VerificationSheetView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Remove verification for selected peer (if verified)
|
// Optional: Remove verification for selected peer (if verified)
|
||||||
if let pid = viewModel.selectedPrivateChatPeer?.id,
|
if let pid = viewModel.selectedPrivateChatPeer,
|
||||||
let fp = viewModel.getFingerprint(for: pid),
|
let fp = viewModel.getFingerprint(for: pid),
|
||||||
viewModel.verifiedFingerprints.contains(fp) {
|
viewModel.verifiedFingerprints.contains(fp) {
|
||||||
Button(action: { viewModel.unverifyFingerprint(for: pid) }) {
|
Button(action: { viewModel.unverifyFingerprint(for: pid) }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user