mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 22:25:20 +00:00
PeerID 30/n: Update some leftovers + case normalization (#839)
* PeerID 28/n: `ChatViewModel.getShortIDForNoiseKey` * PeerID 29/n: `BLEService` + remove dupe funcs from #823 * `handleFileTransfer` to use PeerID * `sendMessage` and `sendPrivateMessage` * PeerID 30/n: Update some leftovers * `lowercased()` inside PeerID for normalization --------- Co-authored-by: jack <212554440+jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -35,7 +35,7 @@ struct PeerID: Equatable, Hashable {
|
|||||||
// Private so the callers have to go through a convenience init
|
// Private so the callers have to go through a convenience init
|
||||||
private init(prefix: Prefix, bare: any StringProtocol) {
|
private init(prefix: Prefix, bare: any StringProtocol) {
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.bare = String(bare)
|
self.bare = String(bare).lowercased()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2360,7 +2360,6 @@ extension BLEService {
|
|||||||
|
|
||||||
private func configureNoiseServiceCallbacks(for service: NoiseEncryptionService) {
|
private func configureNoiseServiceCallbacks(for service: NoiseEncryptionService) {
|
||||||
service.onPeerAuthenticated = { [weak self] peerID, fingerprint in
|
service.onPeerAuthenticated = { [weak self] peerID, fingerprint in
|
||||||
let peerID = PeerID(str: peerID)
|
|
||||||
SecureLogger.debug("🔐 Noise session authenticated with \(peerID), fingerprint: \(fingerprint.prefix(16))...")
|
SecureLogger.debug("🔐 Noise session authenticated with \(peerID), fingerprint: \(fingerprint.prefix(16))...")
|
||||||
self?.messageQueue.async { [weak self] in
|
self?.messageQueue.async { [weak self] in
|
||||||
self?.sendPendingMessagesAfterHandshake(for: peerID)
|
self?.sendPendingMessagesAfterHandshake(for: peerID)
|
||||||
@@ -3612,7 +3611,7 @@ extension BLEService {
|
|||||||
|
|
||||||
private func checkPeerConnectivity() {
|
private func checkPeerConnectivity() {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
var disconnectedPeers: [String] = []
|
var disconnectedPeers: [PeerID] = []
|
||||||
let peerIDsForLinkState: [PeerID] = collectionsQueue.sync { Array(peers.keys) }
|
let peerIDsForLinkState: [PeerID] = collectionsQueue.sync { Array(peers.keys) }
|
||||||
var cachedLinkStates: [PeerID: (hasPeripheral: Bool, hasCentral: Bool)] = [:]
|
var cachedLinkStates: [PeerID: (hasPeripheral: Bool, hasCentral: Bool)] = [:]
|
||||||
for peerID in peerIDsForLinkState {
|
for peerID in peerIDsForLinkState {
|
||||||
@@ -3635,7 +3634,7 @@ extension BLEService {
|
|||||||
var updated = peer
|
var updated = peer
|
||||||
updated.isConnected = false
|
updated.isConnected = false
|
||||||
peers[peerID] = updated
|
peers[peerID] = updated
|
||||||
disconnectedPeers.append(peerID.id)
|
disconnectedPeers.append(peerID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cleanup: remove peers that are not connected and past reachability retention
|
// Cleanup: remove peers that are not connected and past reachability retention
|
||||||
@@ -3660,7 +3659,7 @@ extension BLEService {
|
|||||||
let currentPeerIDs = self.collectionsQueue.sync { self.currentPeerIDs }
|
let currentPeerIDs = self.collectionsQueue.sync { self.currentPeerIDs }
|
||||||
|
|
||||||
for peerID in disconnectedPeers {
|
for peerID in disconnectedPeers {
|
||||||
self.delegate?.didDisconnectFromPeer(PeerID(str: peerID))
|
self.delegate?.didDisconnectFromPeer(peerID)
|
||||||
}
|
}
|
||||||
// Publish snapshots so UnifiedPeerService updates connection/reachability icons
|
// Publish snapshots so UnifiedPeerService updates connection/reachability icons
|
||||||
self.requestPeerDataPublish()
|
self.requestPeerDataPublish()
|
||||||
|
|||||||
@@ -177,18 +177,18 @@ final class NoiseEncryptionService {
|
|||||||
private let rekeyCheckInterval: TimeInterval = 60.0 // Check every minute
|
private let rekeyCheckInterval: TimeInterval = 60.0 // Check every minute
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
private var onPeerAuthenticatedHandlers: [((String, String) -> Void)] = [] // Array of handlers for peer authentication
|
private var onPeerAuthenticatedHandlers: [((PeerID, String) -> Void)] = [] // Array of handlers for peer authentication
|
||||||
var onHandshakeRequired: ((PeerID) -> Void)? // peerID needs handshake
|
var onHandshakeRequired: ((PeerID) -> Void)? // peerID needs handshake
|
||||||
|
|
||||||
// Add a handler for peer authentication
|
// Add a handler for peer authentication
|
||||||
func addOnPeerAuthenticatedHandler(_ handler: @escaping (String, String) -> Void) {
|
func addOnPeerAuthenticatedHandler(_ handler: @escaping (PeerID, String) -> Void) {
|
||||||
serviceQueue.async(flags: .barrier) { [weak self] in
|
serviceQueue.async(flags: .barrier) { [weak self] in
|
||||||
self?.onPeerAuthenticatedHandlers.append(handler)
|
self?.onPeerAuthenticatedHandlers.append(handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy support - setting this will add to the handlers array
|
// Legacy support - setting this will add to the handlers array
|
||||||
var onPeerAuthenticated: ((String, String) -> Void)? {
|
var onPeerAuthenticated: ((PeerID, String) -> Void)? {
|
||||||
get { nil } // Always return nil for backward compatibility
|
get { nil } // Always return nil for backward compatibility
|
||||||
set {
|
set {
|
||||||
if let handler = newValue {
|
if let handler = newValue {
|
||||||
@@ -546,7 +546,7 @@ final class NoiseEncryptionService {
|
|||||||
// Notify all handlers about authentication
|
// Notify all handlers about authentication
|
||||||
serviceQueue.async { [weak self] in
|
serviceQueue.async { [weak self] in
|
||||||
self?.onPeerAuthenticatedHandlers.forEach { handler in
|
self?.onPeerAuthenticatedHandlers.forEach { handler in
|
||||||
handler(peerID.id, fingerprint)
|
handler(peerID, fingerprint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ final class NotificationService {
|
|||||||
sendLocalNotification(title: title, body: body, identifier: identifier)
|
sendLocalNotification(title: title, body: body, identifier: identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendPrivateMessageNotification(from sender: String, message: String, peerID: String) {
|
func sendPrivateMessageNotification(from sender: String, message: String, peerID: PeerID) {
|
||||||
let title = "🔒 DM from \(sender)"
|
let title = "🔒 DM from \(sender)"
|
||||||
let body = message
|
let body = message
|
||||||
let identifier = "private-\(UUID().uuidString)"
|
let identifier = "private-\(UUID().uuidString)"
|
||||||
let userInfo = ["peerID": peerID, "senderName": sender]
|
let userInfo = ["peerID": peerID.id, "senderName": sender]
|
||||||
|
|
||||||
sendLocalNotification(title: title, body: body, identifier: identifier, userInfo: userInfo)
|
sendLocalNotification(title: title, body: body, identifier: identifier, userInfo: userInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ final class GossipSyncManager {
|
|||||||
// Storage: broadcast messages (ordered by insert), and latest announce per sender
|
// Storage: broadcast messages (ordered by insert), and latest announce per sender
|
||||||
private var messages: [String: BitchatPacket] = [:] // idHex -> packet
|
private var messages: [String: BitchatPacket] = [:] // idHex -> packet
|
||||||
private var messageOrder: [String] = []
|
private var messageOrder: [String] = []
|
||||||
private var latestAnnouncementByPeer: [String: (id: String, packet: BitchatPacket)] = [:]
|
private var latestAnnouncementByPeer: [PeerID: (id: String, packet: BitchatPacket)] = [:]
|
||||||
|
|
||||||
// Timer
|
// Timer
|
||||||
private var periodicTimer: DispatchSourceTimer?
|
private var periodicTimer: DispatchSourceTimer?
|
||||||
@@ -101,8 +101,8 @@ final class GossipSyncManager {
|
|||||||
|
|
||||||
if isAnnounce {
|
if isAnnounce {
|
||||||
guard isAnnouncementFresh(packet) else {
|
guard isAnnouncementFresh(packet) else {
|
||||||
let sender = packet.senderID.hexEncodedString().lowercased()
|
let sender = PeerID(hexData: packet.senderID)
|
||||||
removeState(forNormalizedPeerID: sender)
|
removeState(for: sender)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ final class GossipSyncManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if isAnnounce {
|
} else if isAnnounce {
|
||||||
let sender = packet.senderID.hexEncodedString().lowercased()
|
let sender = PeerID(hexData: packet.senderID)
|
||||||
latestAnnouncementByPeer[sender] = (id: idHex, packet: packet)
|
latestAnnouncementByPeer[sender] = (id: idHex, packet: packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,33 +270,28 @@ final class GossipSyncManager {
|
|||||||
let nowMs = UInt64(now.timeIntervalSince1970 * 1000)
|
let nowMs = UInt64(now.timeIntervalSince1970 * 1000)
|
||||||
guard nowMs >= timeoutMs else { return }
|
guard nowMs >= timeoutMs else { return }
|
||||||
let cutoff = nowMs - timeoutMs
|
let cutoff = nowMs - timeoutMs
|
||||||
let stalePeerIDs = latestAnnouncementByPeer.compactMap { (peerHex, pair) -> String? in
|
let stalePeerIDs = latestAnnouncementByPeer.compactMap { peerID, pair in
|
||||||
pair.packet.timestamp < cutoff ? peerHex.lowercased() : nil
|
pair.packet.timestamp < cutoff ? peerID : nil
|
||||||
}
|
}
|
||||||
guard !stalePeerIDs.isEmpty else { return }
|
guard !stalePeerIDs.isEmpty else { return }
|
||||||
for peerKey in stalePeerIDs {
|
for peerKey in stalePeerIDs {
|
||||||
removeState(forNormalizedPeerID: peerKey)
|
removeState(for: peerKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicit removal hook for LEAVE/stale peer
|
// Explicit removal hook for LEAVE/stale peer
|
||||||
func removeAnnouncementForPeer(_ peerID: PeerID) {
|
func removeAnnouncementForPeer(_ peerID: PeerID) {
|
||||||
queue.async { [weak self] in
|
queue.async { [weak self] in
|
||||||
self?._removeAnnouncementForPeer(peerID)
|
self?.removeState(for: peerID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func _removeAnnouncementForPeer(_ peerID: PeerID) {
|
private func removeState(for peerID: PeerID) {
|
||||||
let normalizedPeerID = peerID.id.lowercased()
|
_ = latestAnnouncementByPeer.removeValue(forKey: peerID)
|
||||||
removeState(forNormalizedPeerID: normalizedPeerID)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func removeState(forNormalizedPeerID normalizedPeerID: String) {
|
|
||||||
_ = latestAnnouncementByPeer.removeValue(forKey: normalizedPeerID)
|
|
||||||
// Remove messages from this peer
|
// Remove messages from this peer
|
||||||
// Collect IDs to remove first to avoid concurrent modification
|
// Collect IDs to remove first to avoid concurrent modification
|
||||||
let messageIdsToRemove = messages.compactMap { (id, message) -> String? in
|
let messageIdsToRemove = messages.compactMap { (id, message) -> String? in
|
||||||
message.senderID.hexEncodedString().lowercased() == normalizedPeerID ? id : nil
|
PeerID(hexData: message.senderID) == peerID ? id : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove messages and update messageOrder
|
// Remove messages and update messageOrder
|
||||||
@@ -317,13 +312,13 @@ extension GossipSyncManager {
|
|||||||
|
|
||||||
func _hasAnnouncement(for peerID: PeerID) -> Bool {
|
func _hasAnnouncement(for peerID: PeerID) -> Bool {
|
||||||
queue.sync {
|
queue.sync {
|
||||||
latestAnnouncementByPeer[peerID.id.lowercased()] != nil
|
latestAnnouncementByPeer[peerID] != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _messageCount(for peerID: PeerID) -> Int {
|
func _messageCount(for peerID: PeerID) -> Int {
|
||||||
queue.sync {
|
queue.sync {
|
||||||
messages.values.filter { $0.senderID.hexEncodedString().lowercased() == peerID.id.lowercased() }.count
|
messages.values.filter { PeerID(hexData: $0.senderID) == peerID }.count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1155,7 +1155,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
NotificationService.shared.sendPrivateMessageNotification(
|
NotificationService.shared.sendPrivateMessageNotification(
|
||||||
from: senderName,
|
from: senderName,
|
||||||
message: pm.content,
|
message: pm.content,
|
||||||
peerID: convKey.id
|
peerID: convKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1876,7 +1876,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
NotificationService.shared.sendPrivateMessageNotification(
|
NotificationService.shared.sendPrivateMessageNotification(
|
||||||
from: senderName,
|
from: senderName,
|
||||||
message: pm.content,
|
message: pm.content,
|
||||||
peerID: convKey.id
|
peerID: convKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1956,8 +1956,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
func isSelfSender(peerID: PeerID?, displayName: String?) -> Bool {
|
func isSelfSender(peerID: PeerID?, displayName: String?) -> Bool {
|
||||||
guard let peerID else { return false }
|
guard let peerID else { return false }
|
||||||
if peerID == meshService.myPeerID { return true }
|
if peerID == meshService.myPeerID { return true }
|
||||||
let lowerPeer = peerID.id.lowercased()
|
guard peerID.isGeoDM || peerID.isGeoChat else { return false }
|
||||||
guard lowerPeer.hasPrefix("nostr") else { return false }
|
|
||||||
|
|
||||||
if let mapped = nostrKeyMapping[peerID]?.lowercased(),
|
if let mapped = nostrKeyMapping[peerID]?.lowercased(),
|
||||||
let gh = currentGeohash,
|
let gh = currentGeohash,
|
||||||
@@ -1967,10 +1966,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
|
|
||||||
if let gh = currentGeohash,
|
if let gh = currentGeohash,
|
||||||
let myIdentity = try? idBridge.deriveIdentity(forGeohash: gh) {
|
let myIdentity = try? idBridge.deriveIdentity(forGeohash: gh) {
|
||||||
let myLower = myIdentity.publicKeyHex.lowercased()
|
if peerID == PeerID(nostr: myIdentity.publicKeyHex) { return true }
|
||||||
let shortLen = TransportConfig.nostrShortKeyDisplayLength
|
|
||||||
let shortKey = "nostr:" + myLower.prefix(shortLen)
|
|
||||||
if lowerPeer == shortKey { return true }
|
|
||||||
let suffix = myIdentity.publicKeyHex.suffix(4)
|
let suffix = myIdentity.publicKeyHex.suffix(4)
|
||||||
let expected = (nickname + "#" + suffix).lowercased()
|
let expected = (nickname + "#" + suffix).lowercased()
|
||||||
if let display = displayName?.lowercased(), display == expected { return true }
|
if let display = displayName?.lowercased(), display == expected { return true }
|
||||||
@@ -2453,7 +2449,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let targetPeer = selectedPrivateChatPeer
|
let targetPeer = selectedPrivateChatPeer
|
||||||
let message = enqueueMediaMessage(content: "[voice] \(url.lastPathComponent)", targetPeer: targetPeer?.id)
|
let message = enqueueMediaMessage(content: "[voice] \(url.lastPathComponent)", targetPeer: targetPeer)
|
||||||
let messageID = message.id
|
let messageID = message.id
|
||||||
let transferId = makeTransferID(messageID: messageID)
|
let transferId = makeTransferID(messageID: messageID)
|
||||||
|
|
||||||
@@ -2532,7 +2528,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
)
|
)
|
||||||
guard packet.encode() != nil else { throw MediaSendError.encodingFailed }
|
guard packet.encode() != nil else { throw MediaSendError.encodingFailed }
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
let message = self.enqueueMediaMessage(content: "[image] \(outputURL.lastPathComponent)", targetPeer: targetPeer?.id)
|
let message = self.enqueueMediaMessage(content: "[image] \(outputURL.lastPathComponent)", targetPeer: targetPeer)
|
||||||
let messageID = message.id
|
let messageID = message.id
|
||||||
let transferId = self.makeTransferID(messageID: messageID)
|
let transferId = self.makeTransferID(messageID: messageID)
|
||||||
self.registerTransfer(transferId: transferId, messageID: messageID)
|
self.registerTransfer(transferId: transferId, messageID: messageID)
|
||||||
@@ -2574,7 +2570,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func enqueueMediaMessage(content: String, targetPeer: String?) -> BitchatMessage {
|
private func enqueueMediaMessage(content: String, targetPeer: PeerID?) -> BitchatMessage {
|
||||||
let timestamp = Date()
|
let timestamp = Date()
|
||||||
let message: BitchatMessage
|
let message: BitchatMessage
|
||||||
|
|
||||||
@@ -2591,7 +2587,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
deliveryStatus: .sending
|
deliveryStatus: .sending
|
||||||
)
|
)
|
||||||
var chats = privateChats
|
var chats = privateChats
|
||||||
chats[PeerID(str: peerID), default: []].append(message)
|
chats[peerID, default: []].append(message)
|
||||||
privateChats = chats
|
privateChats = chats
|
||||||
trimMessagesIfNeeded()
|
trimMessagesIfNeeded()
|
||||||
} else {
|
} else {
|
||||||
@@ -2604,7 +2600,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
originalSender: nil,
|
originalSender: nil,
|
||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
recipientNickname: nil,
|
recipientNickname: nil,
|
||||||
senderPeerID: PeerID(str: senderPeerID),
|
senderPeerID: senderPeerID,
|
||||||
deliveryStatus: .sending
|
deliveryStatus: .sending
|
||||||
)
|
)
|
||||||
messages.append(message)
|
messages.append(message)
|
||||||
@@ -2629,29 +2625,28 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
private func currentPublicSender() -> (name: String, peerID: String) {
|
private func currentPublicSender() -> (name: String, peerID: PeerID) {
|
||||||
var displaySender = nickname
|
var displaySender = nickname
|
||||||
var senderPeerID = meshService.myPeerID
|
var senderPeerID = meshService.myPeerID
|
||||||
if case .location(let ch) = activeChannel,
|
if case .location(let ch) = activeChannel,
|
||||||
let identity = try? idBridge.deriveIdentity(forGeohash: ch.geohash) {
|
let identity = try? idBridge.deriveIdentity(forGeohash: ch.geohash) {
|
||||||
let suffix = String(identity.publicKeyHex.suffix(4))
|
let suffix = String(identity.publicKeyHex.suffix(4))
|
||||||
displaySender = nickname + "#" + suffix
|
displaySender = nickname + "#" + suffix
|
||||||
let shortKey = identity.publicKeyHex.prefix(TransportConfig.nostrShortKeyDisplayLength)
|
senderPeerID = PeerID(nostr: identity.publicKeyHex)
|
||||||
senderPeerID = PeerID(str: "nostr:\(shortKey)")
|
|
||||||
}
|
}
|
||||||
return (displaySender, senderPeerID.id)
|
return (displaySender, senderPeerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private func nicknameForPeer(_ peerID: String) -> String {
|
private func nicknameForPeer(_ peerID: PeerID) -> String {
|
||||||
if let name = meshService.peerNickname(peerID: PeerID(str: peerID)) {
|
if let name = meshService.peerNickname(peerID: peerID) {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
if let favorite = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: PeerID(str: peerID)),
|
if let favorite = FavoritesPersistenceService.shared.getFavoriteStatus(forPeerID: peerID),
|
||||||
!favorite.peerNickname.isEmpty {
|
!favorite.peerNickname.isEmpty {
|
||||||
return favorite.peerNickname
|
return favorite.peerNickname
|
||||||
}
|
}
|
||||||
if let noiseKey = Data(hexString: peerID),
|
if let noiseKey = Data(hexString: peerID.id),
|
||||||
let favorite = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey),
|
let favorite = FavoritesPersistenceService.shared.getFavoriteStatus(for: noiseKey),
|
||||||
!favorite.peerNickname.isEmpty {
|
!favorite.peerNickname.isEmpty {
|
||||||
return favorite.peerNickname
|
return favorite.peerNickname
|
||||||
@@ -4881,7 +4876,6 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
noiseService.onPeerAuthenticated = { [weak self] peerID, fingerprint in
|
noiseService.onPeerAuthenticated = { [weak self] peerID, fingerprint in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let peerID = PeerID(str: peerID)
|
|
||||||
|
|
||||||
SecureLogger.debug("🔐 Authenticated: \(peerID)", category: .security)
|
SecureLogger.debug("🔐 Authenticated: \(peerID)", category: .security)
|
||||||
|
|
||||||
@@ -5874,7 +5868,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
NotificationService.shared.sendPrivateMessageNotification(
|
NotificationService.shared.sendPrivateMessageNotification(
|
||||||
from: senderNickname,
|
from: senderNickname,
|
||||||
message: messageContent,
|
message: messageContent,
|
||||||
peerID: targetPeerID.id
|
peerID: targetPeerID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6267,7 +6261,7 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
|||||||
NotificationService.shared.sendPrivateMessageNotification(
|
NotificationService.shared.sendPrivateMessageNotification(
|
||||||
from: message.sender,
|
from: message.sender,
|
||||||
message: message.content,
|
message: message.content,
|
||||||
peerID: peerID.id
|
peerID: peerID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ struct ContentView: View {
|
|||||||
@State private var commandSuggestions: [String] = []
|
@State private var commandSuggestions: [String] = []
|
||||||
@State private var showMessageActions = false
|
@State private var showMessageActions = false
|
||||||
@State private var selectedMessageSender: String?
|
@State private var selectedMessageSender: String?
|
||||||
@State private var selectedMessageSenderID: String?
|
@State private var selectedMessageSenderID: PeerID?
|
||||||
@FocusState private var isNicknameFieldFocused: Bool
|
@FocusState private var isNicknameFieldFocused: Bool
|
||||||
@State private var isAtBottomPublic: Bool = true
|
@State private var isAtBottomPublic: Bool = true
|
||||||
@State private var isAtBottomPrivate: Bool = true
|
@State private var isAtBottomPrivate: Bool = true
|
||||||
@@ -285,12 +285,12 @@ 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.isGeoChat {
|
||||||
if let full = viewModel.fullNostrHex(forSenderPeerID: PeerID(str: peerID)) {
|
if let full = viewModel.fullNostrHex(forSenderPeerID: peerID) {
|
||||||
viewModel.startGeohashDM(withPubkeyHex: full)
|
viewModel.startGeohashDM(withPubkeyHex: full)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.startPrivateChat(with: PeerID(str: peerID))
|
viewModel.startPrivateChat(with: peerID)
|
||||||
}
|
}
|
||||||
withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) {
|
withAnimation(.easeInOut(duration: TransportConfig.uiAnimationMediumSeconds)) {
|
||||||
showSidebar = true
|
showSidebar = true
|
||||||
@@ -312,8 +312,8 @@ 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.isGeoChat,
|
||||||
let full = viewModel.fullNostrHex(forSenderPeerID: PeerID(str: peerID)),
|
let full = viewModel.fullNostrHex(forSenderPeerID: 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 {
|
||||||
@@ -794,7 +794,7 @@ struct ContentView: View {
|
|||||||
case "user":
|
case "user":
|
||||||
let id = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
let id = url.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
|
||||||
let peerID = PeerID(str: id.removingPercentEncoding ?? id)
|
let peerID = PeerID(str: id.removingPercentEncoding ?? id)
|
||||||
selectedMessageSenderID = peerID.id
|
selectedMessageSenderID = peerID
|
||||||
|
|
||||||
if peerID.isGeoDM || peerID.isGeoChat {
|
if peerID.isGeoDM || peerID.isGeoChat {
|
||||||
selectedMessageSender = viewModel.geohashDisplayName(for: peerID)
|
selectedMessageSender = viewModel.geohashDisplayName(for: peerID)
|
||||||
|
|||||||
Reference in New Issue
Block a user