mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 19:45:20 +00:00
UI improvements and rename rooms to channels
- Changed system messages from green to grey with consistent 12pt font - Fixed text wrapping to flow naturally under timestamps - Changed default nickname to anonXXXX format - Replaced text with icon representations in status bar - Added icons to sidebar section headers - Made autocomplete UI consistent between commands and @mentions - Added welcome message for new users (3 second delay) - Changed sidebar header to 'YOUR NETWORK' - Added command aliases (/join, /msg) - Implemented /hug and /slap commands with haptic feedback - Improved command help display with alphabetization - Renamed 'rooms' to 'channels' throughout entire codebase
This commit is contained in:
@@ -489,7 +489,7 @@ class BluetoothMeshService: NSObject {
|
||||
self.characteristic = characteristic
|
||||
}
|
||||
|
||||
func sendMessage(_ content: String, mentions: [String] = [], room: String? = nil, to recipientID: String? = nil) {
|
||||
func sendMessage(_ content: String, mentions: [String] = [], channel: String? = nil, to recipientID: String? = nil) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
@@ -506,7 +506,7 @@ class BluetoothMeshService: NSObject {
|
||||
recipientNickname: nil,
|
||||
senderPeerID: self.myPeerID,
|
||||
mentions: mentions.isEmpty ? nil : mentions,
|
||||
room: room
|
||||
channel: channel
|
||||
)
|
||||
|
||||
if let messageData = message.toBinaryPayload() {
|
||||
@@ -653,17 +653,17 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func sendRoomLeaveNotification(_ room: String) {
|
||||
func sendChannelLeaveNotification(_ channel: String) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
// Create a leave packet with room hashtag as payload
|
||||
// Create a leave packet with channel 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
|
||||
payload: Data(channel.utf8), // Channel hashtag as payload
|
||||
signature: nil,
|
||||
ttl: 3 // Short TTL for leave notifications
|
||||
)
|
||||
@@ -738,53 +738,53 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func announcePasswordProtectedRoom(_ room: String, isProtected: Bool = true, creatorID: String? = nil, keyCommitment: String? = nil) {
|
||||
func announcePasswordProtectedChannel(_ channel: String, isProtected: Bool = true, creatorID: String? = nil, keyCommitment: String? = nil) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
// Payload format: room|isProtected|creatorID|keyCommitment
|
||||
// Payload format: channel|isProtected|creatorID|keyCommitment
|
||||
let protectedFlag = isProtected ? "1" : "0"
|
||||
let creator = creatorID ?? self.myPeerID
|
||||
let commitment = keyCommitment ?? ""
|
||||
let payload = "\(room)|\(protectedFlag)|\(creator)|\(commitment)"
|
||||
let payload = "\(channel)|\(protectedFlag)|\(creator)|\(commitment)"
|
||||
|
||||
let packet = BitchatPacket(
|
||||
type: MessageType.roomAnnounce.rawValue,
|
||||
type: MessageType.channelAnnounce.rawValue,
|
||||
senderID: Data(self.myPeerID.utf8),
|
||||
recipientID: SpecialRecipients.broadcast,
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: Data(payload.utf8),
|
||||
signature: nil,
|
||||
ttl: 5 // Allow wider propagation for room announcements
|
||||
ttl: 5 // Allow wider propagation for channel announcements
|
||||
)
|
||||
|
||||
self.broadcastPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
func sendRoomRetentionAnnouncement(_ room: String, enabled: Bool) {
|
||||
func sendChannelRetentionAnnouncement(_ channel: String, enabled: Bool) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
// Payload format: room|enabled|creatorID
|
||||
// Payload format: channel|enabled|creatorID
|
||||
let enabledFlag = enabled ? "1" : "0"
|
||||
let payload = "\(room)|\(enabledFlag)|\(self.myPeerID)"
|
||||
let payload = "\(channel)|\(enabledFlag)|\(self.myPeerID)"
|
||||
|
||||
let packet = BitchatPacket(
|
||||
type: MessageType.roomRetention.rawValue,
|
||||
type: MessageType.channelRetention.rawValue,
|
||||
senderID: Data(self.myPeerID.utf8),
|
||||
recipientID: SpecialRecipients.broadcast,
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: Data(payload.utf8),
|
||||
signature: nil,
|
||||
ttl: 5 // Allow wider propagation for room announcements
|
||||
ttl: 5 // Allow wider propagation for channel announcements
|
||||
)
|
||||
|
||||
self.broadcastPacket(packet)
|
||||
}
|
||||
}
|
||||
|
||||
func sendEncryptedRoomMessage(_ content: String, mentions: [String], room: String, roomKey: SymmetricKey) {
|
||||
func sendEncryptedChannelMessage(_ content: String, mentions: [String], channel: String, channelKey: SymmetricKey) {
|
||||
messageQueue.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
@@ -797,7 +797,7 @@ class BluetoothMeshService: NSObject {
|
||||
// Debug logging removed
|
||||
|
||||
do {
|
||||
let sealedBox = try AES.GCM.seal(contentData, using: roomKey)
|
||||
let sealedBox = try AES.GCM.seal(contentData, using: channelKey)
|
||||
let encryptedData = sealedBox.combined!
|
||||
|
||||
// Create message with encrypted content
|
||||
@@ -811,7 +811,7 @@ class BluetoothMeshService: NSObject {
|
||||
recipientNickname: nil,
|
||||
senderPeerID: self.myPeerID,
|
||||
mentions: mentions.isEmpty ? nil : mentions,
|
||||
room: room,
|
||||
channel: channel,
|
||||
encryptedContent: encryptedData,
|
||||
isEncrypted: true
|
||||
)
|
||||
@@ -1244,7 +1244,7 @@ class BluetoothMeshService: NSObject {
|
||||
MessageRetryService.shared.addMessageForRetry(
|
||||
content: message.content,
|
||||
mentions: message.mentions,
|
||||
room: message.room,
|
||||
channel: message.channel,
|
||||
isPrivate: message.isPrivate,
|
||||
recipientPeerID: nil,
|
||||
recipientNickname: message.recipientNickname
|
||||
@@ -1298,24 +1298,24 @@ class BluetoothMeshService: NSObject {
|
||||
if sentToPeripherals == 0 && sentToCentrals == 0 {
|
||||
if packet.type == MessageType.message.rawValue,
|
||||
let message = BitchatMessage.fromBinaryPayload(packet.payload) {
|
||||
// For encrypted room messages, we need to preserve the room key
|
||||
var roomKeyData: Data? = nil
|
||||
if let room = message.room, message.isEncrypted {
|
||||
// This is an encrypted room message
|
||||
// For encrypted channel messages, we need to preserve the channel key
|
||||
var channelKeyData: Data? = nil
|
||||
if let channel = message.channel, message.isEncrypted {
|
||||
// This is an encrypted channel message
|
||||
if let viewModel = delegate as? ChatViewModel,
|
||||
let roomKey = viewModel.roomKeys[room] {
|
||||
roomKeyData = roomKey.withUnsafeBytes { Data($0) }
|
||||
let channelKey = viewModel.channelKeys[channel] {
|
||||
channelKeyData = channelKey.withUnsafeBytes { Data($0) }
|
||||
}
|
||||
}
|
||||
|
||||
MessageRetryService.shared.addMessageForRetry(
|
||||
content: message.content,
|
||||
mentions: message.mentions,
|
||||
room: message.room,
|
||||
channel: message.channel,
|
||||
isPrivate: message.isPrivate,
|
||||
recipientPeerID: nil,
|
||||
recipientNickname: message.recipientNickname,
|
||||
roomKey: roomKeyData
|
||||
channelKey: channelKeyData
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1430,11 +1430,11 @@ class BluetoothMeshService: NSObject {
|
||||
peerNicknames[senderID] = message.sender
|
||||
peerNicknamesLock.unlock()
|
||||
|
||||
// Handle encrypted room messages
|
||||
// Handle encrypted channel messages
|
||||
var finalContent = message.content
|
||||
if message.isEncrypted, let room = message.room, let encryptedData = message.encryptedContent {
|
||||
if message.isEncrypted, let channel = message.channel, let encryptedData = message.encryptedContent {
|
||||
// Try to decrypt the content
|
||||
if let decryptedContent = self.delegate?.decryptRoomMessage(encryptedData, room: room) {
|
||||
if let decryptedContent = self.delegate?.decryptChannelMessage(encryptedData, channel: channel) {
|
||||
finalContent = decryptedContent
|
||||
} else {
|
||||
// Unable to decrypt - show placeholder
|
||||
@@ -1453,7 +1453,7 @@ class BluetoothMeshService: NSObject {
|
||||
recipientNickname: nil,
|
||||
senderPeerID: senderID,
|
||||
mentions: message.mentions,
|
||||
room: message.room,
|
||||
channel: message.channel,
|
||||
encryptedContent: message.encryptedContent,
|
||||
isEncrypted: message.isEncrypted
|
||||
)
|
||||
@@ -1467,10 +1467,10 @@ class BluetoothMeshService: NSObject {
|
||||
self.delegate?.didReceiveMessage(messageWithPeerID)
|
||||
}
|
||||
|
||||
// Generate and send ACK for room messages if we're mentioned or it's a small room
|
||||
// Generate and send ACK for channel messages if we're mentioned or it's a small channel
|
||||
let viewModel = self.delegate as? ChatViewModel
|
||||
let myNickname = viewModel?.nickname ?? self.myPeerID
|
||||
if let _ = message.room,
|
||||
if let _ = message.channel,
|
||||
let mentions = message.mentions,
|
||||
(mentions.contains(myNickname) || self.activePeers.count < 10) {
|
||||
if let ack = DeliveryTracker.shared.generateAck(
|
||||
@@ -1575,7 +1575,7 @@ class BluetoothMeshService: NSObject {
|
||||
recipientNickname: message.recipientNickname,
|
||||
senderPeerID: senderID,
|
||||
mentions: message.mentions,
|
||||
room: message.room,
|
||||
channel: message.channel,
|
||||
deliveryStatus: nil // Will be set to .delivered in ChatViewModel
|
||||
)
|
||||
|
||||
@@ -1867,13 +1867,13 @@ class BluetoothMeshService: NSObject {
|
||||
|
||||
case .leave:
|
||||
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
|
||||
// Check if payload contains a channel hashtag
|
||||
if let channel = String(data: packet.payload, encoding: .utf8),
|
||||
channel.hasPrefix("#") {
|
||||
// Channel leave notification
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didReceiveRoomLeave(room, from: senderID)
|
||||
self.delegate?.didReceiveChannelLeave(channel, from: senderID)
|
||||
}
|
||||
|
||||
// Relay if TTL > 0
|
||||
@@ -1924,19 +1924,19 @@ class BluetoothMeshService: NSObject {
|
||||
self.broadcastPacket(relayPacket)
|
||||
}
|
||||
|
||||
case .roomAnnounce:
|
||||
case .channelAnnounce:
|
||||
if let payloadStr = String(data: packet.payload, encoding: .utf8) {
|
||||
// Parse payload: room|isProtected|creatorID|keyCommitment
|
||||
// Parse payload: channel|isProtected|creatorID|keyCommitment
|
||||
let components = payloadStr.split(separator: "|").map(String.init)
|
||||
if components.count >= 3 {
|
||||
let room = components[0]
|
||||
let channel = components[0]
|
||||
let isProtected = components[1] == "1"
|
||||
let creatorID = components[2]
|
||||
let keyCommitment = components.count >= 4 ? components[3] : nil
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didReceivePasswordProtectedRoomAnnouncement(room, isProtected: isProtected, creatorID: creatorID, keyCommitment: keyCommitment)
|
||||
self.delegate?.didReceivePasswordProtectedChannelAnnouncement(channel, isProtected: isProtected, creatorID: creatorID, keyCommitment: keyCommitment)
|
||||
}
|
||||
|
||||
// Relay announcement
|
||||
@@ -1977,18 +1977,18 @@ class BluetoothMeshService: NSObject {
|
||||
self.broadcastPacket(relayPacket)
|
||||
}
|
||||
|
||||
case .roomRetention:
|
||||
case .channelRetention:
|
||||
if let payloadStr = String(data: packet.payload, encoding: .utf8) {
|
||||
// Parse payload: room|enabled|creatorID
|
||||
// Parse payload: channel|enabled|creatorID
|
||||
let components = payloadStr.split(separator: "|").map(String.init)
|
||||
if components.count >= 3 {
|
||||
let room = components[0]
|
||||
let channel = components[0]
|
||||
let enabled = components[1] == "1"
|
||||
let creatorID = components[2]
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.didReceiveRoomRetentionAnnouncement(room, enabled: enabled, creatorID: creatorID)
|
||||
self.delegate?.didReceiveChannelRetentionAnnouncement(channel, enabled: enabled, creatorID: creatorID)
|
||||
}
|
||||
|
||||
// Relay announcement
|
||||
|
||||
Reference in New Issue
Block a user