diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 7964d860..424f7dda 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -26,7 +26,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { @Published var connectedPeripheral: Peripheral! @Published var lastConnectionError: String @Published var invalidVersion = false - @Published var preferredPeripheral = false @Published var isSwitchedOn: Bool = false @Published var automaticallyReconnect: Bool = true @@ -166,11 +165,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { isConnected = true if userSettings?.preferredPeripheralId.count ?? 0 < 1 { userSettings?.preferredPeripheralId = peripheral.identifier.uuidString - preferredPeripheral = true + // preferredPeripheral = true } else if userSettings!.preferredPeripheralId == peripheral.identifier.uuidString { - preferredPeripheral = true + // preferredPeripheral = true } else { - preferredPeripheral = false + // preferredPeripheral = false print("Trying to connect a non prefered peripheral") } UserDefaults.standard.synchronize() @@ -448,8 +447,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, peripheralId: self.connectedPeripheral.id, context: context!) - userSettings?.preferredNodeNum = myInfo?.myNodeNum ?? 0 - if myInfo != nil { connectedPeripheral.num = myInfo!.myNodeNum connectedPeripheral.firmwareVersion = myInfo?.firmwareVersion ?? NSLocalizedString("unknown", comment: "Unknown") diff --git a/Meshtastic/Model/UserSettings.swift b/Meshtastic/Model/UserSettings.swift index 026306bc..0f759ee8 100644 --- a/Meshtastic/Model/UserSettings.swift +++ b/Meshtastic/Model/UserSettings.swift @@ -19,12 +19,6 @@ class UserSettings: ObservableObject { UserDefaults.standard.synchronize() } } - @Published var preferredNodeNum: Int64 { - didSet { - UserDefaults.standard.set(preferredNodeNum, forKey: "preferredNodeNum") - UserDefaults.standard.synchronize() - } - } @Published var provideLocation: Bool { didSet { UserDefaults.standard.set(provideLocation, forKey: "provideLocation") @@ -73,7 +67,6 @@ class UserSettings: ObservableObject { self.meshtasticUsername = UserDefaults.standard.object(forKey: "meshtasticusername") as? String ?? "" self.preferredPeripheralId = UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" - self.preferredNodeNum = UserDefaults.standard.object(forKey: "preferredNodeNum") as? Int64 ?? 0 self.provideLocation = UserDefaults.standard.object(forKey: "provideLocation") as? Bool ?? false self.provideLocationInterval = UserDefaults.standard.object(forKey: "provideLocationInterval") as? Int ?? 900 self.keyboardType = UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0 diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 0f7affb4..43a0ebf5 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -12,186 +12,152 @@ import CoreLocation import CoreBluetooth struct Connect: View { - + @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @EnvironmentObject var userSettings: UserSettings @State var node: NodeInfoEntity? = nil - - @State var isPreferredRadio: Bool = false @State var isUnsetRegion = false @State var invalidFirmwareVersion = false - - var body: some View { + @State var presentingSwitchPreferredPeripheral = false + @State var selectedPeripherialId = "" + var body: some View { + NavigationStack { VStack { List { if bleManager.isSwitchedOn { - Section(header: Text("connected.radio").font(.title)) { - if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected { - HStack { - Image(systemName: "antenna.radiowaves.left.and.right") - .symbolRenderingMode(.hierarchical) - .imageScale(.large).foregroundColor(.green) - .padding(.trailing) - VStack(alignment: .leading) { - if node != nil { - Text(bleManager.connectedPeripheral.longName).font(.title2) - } - Text("ble.name").font(.caption)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? NSLocalizedString("unknown", comment: "Unknown"))") - .font(.caption).foregroundColor(Color.gray) - if node != nil { - Text("firmware.version").font(.caption)+Text(": \(node?.myInfo?.firmwareVersion ?? NSLocalizedString("unknown", comment: "Unknown"))") - .font(.caption).foregroundColor(Color.gray) - } - if bleManager.isSubscribed { - Text("subscribed").font(.caption) - .foregroundColor(.green) - } else { - Text("communicating").font(.caption) - .foregroundColor(.orange) + Section(header: Text("connected.radio").font(.title)) { + if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected { + HStack { + Image(systemName: "antenna.radiowaves.left.and.right") + .resizable() + .symbolRenderingMode(.hierarchical) + .foregroundColor(.green) + .frame(width: 60, height: 60) + .padding(.trailing) + VStack(alignment: .leading) { + if node != nil { + Text(bleManager.connectedPeripheral.longName).font(.title) + } + Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? NSLocalizedString("unknown", comment: "Unknown"))") + .font(.callout).foregroundColor(Color.gray) + if node != nil { + Text("firmware.version").font(.callout)+Text(": \(node?.myInfo?.firmwareVersion ?? NSLocalizedString("unknown", comment: "Unknown"))") + .font(.callout).foregroundColor(Color.gray) + } + if bleManager.isSubscribed { + Text("subscribed").font(.callout) + .foregroundColor(.green) + } else { + Text("communicating").font(.callout) + .foregroundColor(.orange) + } } } - Spacer() - VStack(alignment: .center) { - Text("preferred.radio").font(.caption2) - .multilineTextAlignment(.center) - .frame(width: 75) - Toggle("preferred.radio", isOn: $bleManager.preferredPeripheral) - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - .labelsHidden() - .onChange(of: bleManager.preferredPeripheral) { value in - if value { - if bleManager.connectedPeripheral != nil { - userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString - userSettings.preferredNodeNum = bleManager.connectedPeripheral!.num - bleManager.preferredPeripheral = true - isPreferredRadio = true - } - } else { - - if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.identifier.uuidString == userSettings.preferredPeripheralId { - - userSettings.preferredPeripheralId = "" - userSettings.preferredNodeNum = 0 - bleManager.preferredPeripheral = false - isPreferredRadio = false + .font(.caption).foregroundColor(Color.gray) + .padding([.top, .bottom]) + .swipeActions { + + Button(role: .destructive) { + if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected { + bleManager.disconnectPeripheral(reconnect: false) + } + } label: { + Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash") + } + } + .contextMenu{ + + if node != nil { + + Text("Num: \(String(node!.num))") + Text("Short Name: \(node?.user?.shortName ?? "????")") + Text("Long Name: \(node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))") + Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))") + Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))") + Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") + + } + } + if isUnsetRegion { + HStack { + NavigationLink { + LoRaConfig(node: node) + } label: { + Label("set.region", systemImage: "globe.americas.fill") + .foregroundColor(.red) + .font(.title) + } + } + } + } else { + + if bleManager.isConnecting { + HStack { + Image(systemName: "antenna.radiowaves.left.and.right") + .symbolRenderingMode(.hierarchical) + .imageScale(.large).foregroundColor(.orange) + .padding(.trailing) + if bleManager.timeoutTimerCount == 0 { + Text("connecting") + .font(.title3) + .foregroundColor(.orange) + } else { + VStack { + + Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10") + .font(.callout) + .foregroundColor(.orange) } } } - } - } - .font(.caption).foregroundColor(Color.gray) - .padding([.top, .bottom]) - .swipeActions { - - Button(role: .destructive) { - if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected { - bleManager.disconnectPeripheral(reconnect: false) - isPreferredRadio = false - } - } label: { - Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash") - } - } - .contextMenu{ - - if node != nil { + .padding() - Text("Num: \(String(node!.num))") - Text("Short Name: \(node?.user?.shortName ?? "????")") - Text("Long Name: \(node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))") - Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))") - Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))") - Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") + } else { - } - } - if isUnsetRegion { - HStack { - NavigationLink { - LoRaConfig(node: node) - } label: { - Label("set.region", systemImage: "globe.americas.fill") - .foregroundColor(.red) - .font(.title) + if bleManager.lastConnectionError.count > 0 { + Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red) } - } - } - } else { - - if bleManager.isConnecting { - HStack { - Image(systemName: "antenna.radiowaves.left.and.right") - .symbolRenderingMode(.hierarchical) - .imageScale(.large).foregroundColor(.orange) - .padding(.trailing) - if bleManager.timeoutTimerCount == 0 { - Text("connecting") - .font(.title3) - .foregroundColor(.orange) - } else { - VStack { - - Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10") - .font(.callout) - .foregroundColor(.orange) - } + HStack { + Image(systemName: "antenna.radiowaves.left.and.right.slash") + .symbolRenderingMode(.hierarchical) + .imageScale(.large).foregroundColor(.red) + .padding(.trailing) + Text("not.connected").font(.title3) } + .padding() } - .padding() - - } else { - - if bleManager.lastConnectionError.count > 0 { - Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red) - } - HStack { - Image(systemName: "antenna.radiowaves.left.and.right.slash") - .symbolRenderingMode(.hierarchical) - .imageScale(.large).foregroundColor(.red) - .padding(.trailing) - Text("not.connected").font(.title3) - } - .padding() } } - } - .textCase(nil) - - if !self.bleManager.isConnected { - Section(header: Text("available.radios").font(.title)) { - ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name > $1.name })) { peripheral in - HStack { - Image(systemName: "circle.fill") - .imageScale(.large).foregroundColor(.gray) - .padding(.trailing) - Button(action: { - self.bleManager.stopScanning() - if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected { - - self.bleManager.disconnectPeripheral() + .textCase(nil) + + if !self.bleManager.isConnected { + Section(header: Text("available.radios").font(.title)) { + ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.name > $1.name })) { peripheral in + HStack { + Image(systemName: "circle.fill") + .imageScale(.large).foregroundColor(.gray) + .padding(.trailing) + Button(action: { + if userSettings.preferredPeripheralId.count > 0 && peripheral.peripheral.identifier.uuidString != userSettings.preferredPeripheralId { + presentingSwitchPreferredPeripheral = true + selectedPeripherialId = peripheral.peripheral.identifier.uuidString + } else { + self.bleManager.connectTo(peripheral: peripheral.peripheral) + } + }) { + Text(peripheral.name).font(.title3) } - self.bleManager.connectTo(peripheral: peripheral.peripheral) - if userSettings.preferredPeripheralId == peripheral.peripheral.identifier.uuidString { - - isPreferredRadio = true - } else { - - isPreferredRadio = false + Spacer() + VStack { + SignalStrengthIndicator(signalStrength: peripheral.getSignalStrength()) } - }) { - Text(peripheral.name).font(.title3) - } - Spacer() - VStack { - SignalStrengthIndicator(signalStrength: peripheral.getSignalStrength()) - } - }.padding([.bottom, .top]) - } - }.textCase(nil) - } + }.padding([.bottom, .top]) + } + }.textCase(nil) + } } else { Text("bluetooth.off") @@ -199,12 +165,28 @@ struct Connect: View { .font(.title) } } - + .confirmationDialog("Connecting to a new radio will clear all local app data on the phone.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) { + + Button("Connect to new radio?", role: .destructive) { + bleManager.stopScanning() + bleManager.connectedPeripheral = nil + userSettings.preferredPeripheralId = "" + if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected { + bleManager.disconnectPeripheral() + } + + clearCoreDataDatabase(context: context) + let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId} ) + bleManager.connectTo(peripheral: radio!.peripheral) + presentingSwitchPreferredPeripheral = false + selectedPeripherialId = "" + } + } + HStack(alignment: .center) { Spacer() - + #if targetEnvironment(macCatalyst) - if bleManager.connectedPeripheral != nil { Button(role: .destructive, action: { @@ -217,7 +199,7 @@ struct Connect: View { }) { Label("disconnect", systemImage: "antenna.radiowaves.left.and.right.slash") - + } .buttonStyle(.bordered) .buttonBorderShape(.capsule) @@ -225,15 +207,15 @@ struct Connect: View { .padding() } #endif - Spacer() - } - .padding(.bottom, 10) + Spacer() + } + .padding(.bottom, 10) } .navigationTitle("bluetooth") .navigationBarItems(leading: MeshtasticLogo(), trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") - }) + ZStack { + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") + }) } .sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) { InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion) @@ -245,10 +227,10 @@ struct Connect: View { } .onChange(of: (self.bleManager.isSubscribed)) { sub in - if userSettings.preferredNodeNum > 0 && sub { + if userSettings.preferredPeripheralId.count > 0 && sub { let fetchNodeInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") - fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(userSettings.preferredNodeNum)) + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(bleManager.connectedPeripheral.num)) do { @@ -270,7 +252,7 @@ struct Connect: View { .onAppear(perform: { self.bleManager.context = context self.bleManager.userSettings = userSettings - + // Ask for notification permission UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in if success { @@ -279,11 +261,6 @@ struct Connect: View { print(error.localizedDescription) } } - if self.bleManager.connectedPeripheral != nil && userSettings.preferredPeripheralId == self.bleManager.connectedPeripheral.id { - isPreferredRadio = true - } else { - isPreferredRadio = false - } }) } func didDismissSheet() { diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 31f71bbe..613961d0 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -38,7 +38,7 @@ struct ChannelMessageList: View { ScrollView { LazyVStack { ForEach( channel.allPrivateMessages ) { (message: MessageEntity) in - let currentUser: Bool = (userSettings.preferredNodeNum == message.fromUser?.num ? true : false) + let currentUser: Bool = (bleManager.connectedPeripheral.num == message.fromUser?.num ? true : false) if message.replyID > 0 { let messageReply = channel.allPrivateMessages.first(where: { $0.messageId == message.replyID }) HStack { diff --git a/Meshtastic/Views/Messages/Contacts.swift b/Meshtastic/Views/Messages/Contacts.swift index 241a694e..8a4ae653 100644 --- a/Meshtastic/Views/Messages/Contacts.swift +++ b/Meshtastic/Views/Messages/Contacts.swift @@ -141,7 +141,7 @@ struct Contacts: View { } Section(header: Text("direct.messages")) { ForEach(users) { (user: UserEntity) in - if user.num != bleManager.userSettings?.preferredNodeNum ?? 0 { + if user.num != bleManager.connectedPeripheral?.num ?? 0 { NavigationLink(destination: UserMessageList(user: user)) { let mostRecent = user.messageList.last let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64((mostRecent?.messageTimestamp ?? 0 )))) @@ -255,10 +255,10 @@ struct Contacts: View { self.bleManager.userSettings = userSettings self.bleManager.context = context - if userSettings.preferredNodeNum > 0 { + if userSettings.preferredPeripheralId.count > 0 { let fetchNodeInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") - fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(userSettings.preferredNodeNum)) + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(bleManager.connectedPeripheral.num)) do { diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index d696714e..50cb5451 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -37,8 +37,8 @@ struct UserMessageList: View { ScrollView { LazyVStack { ForEach( user.messageList ) { (message: MessageEntity) in - if user.num != userSettings.preferredNodeNum { - let currentUser: Bool = (userSettings.preferredNodeNum == message.fromUser?.num ? true : false) + if user.num != bleManager.connectedPeripheral.num { + let currentUser: Bool = (bleManager.connectedPeripheral.num == message.fromUser?.num ?? -1 ? true : false) if message.replyID > 0 { let messageReply = user.messageList.first(where: { $0.messageId == message.replyID })