mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 01:45:20 +00:00
Show Bluetooth permission alerts on launch and foreground (#765)
* Fix test suite peer ID collisions Use unique peer IDs for each test suite to prevent global registry collisions when Swift Testing runs suites in parallel. - PrivateChatE2ETests: PRIV_* prefix - PublicChatE2ETests: PUB_* prefix - Update all peer ID references to use actual instance IDs This fixes the race condition where simplePublicMessage() was receiving duplicate deliveries due to registry contamination. * Add Bluetooth permission & state alerts on launch and foreground Wire up existing Bluetooth alert infrastructure to show notifications when Bluetooth is off, unauthorized, or unsupported. Changes: - Add didUpdateBluetoothState() to BitchatDelegate protocol - BLEService now notifies delegate when Bluetooth state changes - ChatViewModel implements delegate method to show alerts - Check Bluetooth state on app launch (after 100ms delay) - Check Bluetooth state when app comes to foreground - Add getCurrentBluetoothState() method to BLEService The UI alert already existed but wasn't wired up. Now users will see appropriate alerts for: - Bluetooth turned off - Bluetooth permission denied - Bluetooth unsupported on device Alert includes a button to open Settings on iOS. --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
|
||||
// MARK: - Message Types
|
||||
|
||||
@@ -164,14 +165,17 @@ protocol BitchatDelegate: AnyObject {
|
||||
func didConnectToPeer(_ peerID: String)
|
||||
func didDisconnectFromPeer(_ peerID: String)
|
||||
func didUpdatePeerList(_ peers: [String])
|
||||
|
||||
|
||||
// Optional method to check if a fingerprint belongs to a favorite peer
|
||||
func isFavorite(fingerprint: String) -> Bool
|
||||
|
||||
|
||||
func didUpdateMessageDeliveryStatus(_ messageID: String, status: DeliveryStatus)
|
||||
|
||||
// Low-level events for better separation of concerns
|
||||
func didReceiveNoisePayload(from peerID: String, type: NoisePayloadType, payload: Data, timestamp: Date)
|
||||
|
||||
// Bluetooth state updates for user notifications
|
||||
func didUpdateBluetoothState(_ state: CBManagerState)
|
||||
func didReceivePublicMessage(from peerID: String, nickname: String, content: String, timestamp: Date)
|
||||
}
|
||||
|
||||
|
||||
@@ -552,7 +552,11 @@ final class BLEService: NSObject {
|
||||
func getNoiseService() -> NoiseEncryptionService {
|
||||
return noiseService
|
||||
}
|
||||
|
||||
|
||||
func getCurrentBluetoothState() -> CBManagerState {
|
||||
return centralManager?.state ?? .unknown
|
||||
}
|
||||
|
||||
// MARK: Messaging
|
||||
|
||||
// Transport protocol conformance helper: simplified public message send
|
||||
@@ -694,6 +698,11 @@ extension BLEService: GossipSyncManager.Delegate {
|
||||
|
||||
extension BLEService: CBCentralManagerDelegate {
|
||||
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
// Notify delegate about state change on main thread
|
||||
Task { @MainActor in
|
||||
self.delegate?.didUpdateBluetoothState(central.state)
|
||||
}
|
||||
|
||||
if central.state == .poweredOn {
|
||||
// Start scanning - use allow duplicates for faster discovery when active
|
||||
startScanning()
|
||||
|
||||
@@ -549,7 +549,16 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
// Start mesh service immediately
|
||||
meshService.startServices()
|
||||
|
||||
|
||||
// Check initial Bluetooth state after a brief delay to allow centralManager initialization
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let bleService = self.meshService as? BLEService {
|
||||
let state = bleService.getCurrentBluetoothState()
|
||||
self.updateBluetoothState(state)
|
||||
}
|
||||
}
|
||||
|
||||
// Announce Tor status (geohash-only; do not show in mesh chat). Only when auto-start is allowed.
|
||||
if TorManager.shared.torEnforced && !torStatusAnnounced && TorManager.shared.isAutoStartAllowed() {
|
||||
torStatusAnnounced = true
|
||||
@@ -2834,6 +2843,12 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
|
||||
@MainActor
|
||||
@objc private func appDidBecomeActive() {
|
||||
// Check Bluetooth state and show alert if needed
|
||||
if let bleService = meshService as? BLEService {
|
||||
let currentState = bleService.getCurrentBluetoothState()
|
||||
updateBluetoothState(currentState)
|
||||
}
|
||||
|
||||
// When app becomes active, send read receipts for visible private chat
|
||||
if let peerID = selectedPrivateChatPeer {
|
||||
// Try immediately
|
||||
@@ -4597,8 +4612,16 @@ final class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
}
|
||||
|
||||
// Mention parsing moved from BLE – use the existing non-optional helper below
|
||||
// MARK: - Bluetooth State Monitoring
|
||||
|
||||
func didUpdateBluetoothState(_ state: CBManagerState) {
|
||||
Task { @MainActor in
|
||||
updateBluetoothState(state)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Peer Connection Events
|
||||
|
||||
|
||||
func didConnectToPeer(_ peerID: String) {
|
||||
SecureLogger.debug("🤝 Peer connected: \(peerID)", category: .session)
|
||||
|
||||
|
||||
@@ -286,4 +286,7 @@ private final class MockBitchatDelegate: BitchatDelegate {
|
||||
func didUpdatePeerList(_ peers: [String]) {}
|
||||
func isFavorite(fingerprint: String) -> Bool { return false }
|
||||
func didUpdateMessageDeliveryStatus(_ messageID: String, status: DeliveryStatus) {}
|
||||
func didReceiveNoisePayload(from peerID: String, type: NoisePayloadType, payload: Data, timestamp: Date) {}
|
||||
func didUpdateBluetoothState(_ state: CBManagerState) {}
|
||||
func didReceivePublicMessage(from peerID: String, nickname: String, content: String, timestamp: Date) {}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import Testing
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
@testable import bitchat
|
||||
|
||||
struct FragmentationTests {
|
||||
@@ -134,6 +135,7 @@ extension FragmentationTests {
|
||||
func isFavorite(fingerprint: String) -> Bool { false }
|
||||
func didUpdateMessageDeliveryStatus(_ messageID: String, status: DeliveryStatus) {}
|
||||
func didReceiveNoisePayload(from peerID: String, type: NoisePayloadType, payload: Data, timestamp: Date) {}
|
||||
func didUpdateBluetoothState(_ state: CBManagerState) {}
|
||||
func didReceivePublicMessage(from peerID: String, nickname: String, content: String, timestamp: Date) {
|
||||
publicMessages.append((peerID, nickname, content))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user