Remove up and downlink from QR codes

Open node details view from new node notification
Fix speed
Simple deep linking structure
This commit is contained in:
Garth Vander Houwen 2024-05-14 22:39:07 -07:00
parent 8e07453afd
commit a4c1fc4fe6
13 changed files with 123 additions and 216 deletions

View file

@ -128,7 +128,6 @@
DDA9515A2BC6624100CEA535 /* TelemetryWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA951592BC6624100CEA535 /* TelemetryWeather.swift */; };
DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA9515B2BC6631200CEA535 /* TelemetryEnums.swift */; };
DDA9515E2BC6F56F00CEA535 /* IndoorAirQuality.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */; };
DDAA632E2BE7F84E00CC22D3 /* DeepLinkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAA632D2BE7F84E00CC22D3 /* DeepLinkManager.swift */; };
DDAB580D2B0DAA9E00147258 /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAB580C2B0DAA9E00147258 /* Routes.swift */; };
DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAB580E2B0DAFBC00147258 /* LocationEntityExtension.swift */; };
DDAD49ED2AFB39DC00B4425D /* MeshMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAD49EC2AFB39DC00B4425D /* MeshMap.swift */; };
@ -387,7 +386,6 @@
DDA951592BC6624100CEA535 /* TelemetryWeather.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelemetryWeather.swift; sourceTree = "<group>"; };
DDA9515B2BC6631200CEA535 /* TelemetryEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryEnums.swift; sourceTree = "<group>"; };
DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndoorAirQuality.swift; sourceTree = "<group>"; };
DDAA632D2BE7F84E00CC22D3 /* DeepLinkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkManager.swift; sourceTree = "<group>"; };
DDAB580B2B0D913500147258 /* MeshtasticDataModelV20.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV20.xcdatamodel; sourceTree = "<group>"; };
DDAB580C2B0DAA9E00147258 /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Routes.swift; sourceTree = "<group>"; };
DDAB580E2B0DAFBC00147258 /* LocationEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEntityExtension.swift; sourceTree = "<group>"; };
@ -766,14 +764,6 @@
path = Channels;
sourceTree = "<group>";
};
DDAA632C2BE7F83400CC22D3 /* DeepLinks */ = {
isa = PBXGroup;
children = (
DDAA632D2BE7F84E00CC22D3 /* DeepLinkManager.swift */,
);
path = DeepLinks;
sourceTree = "<group>";
};
DDAD49EB2AFAE82500B4425D /* Map */ = {
isa = PBXGroup;
children = (
@ -835,7 +825,6 @@
children = (
DD7709392AA1ABA1007A8BF0 /* Tips */,
DD90860A26F645B700DC5189 /* Meshtastic.entitlements */,
DDAA632C2BE7F83400CC22D3 /* DeepLinks */,
DD8ED9C6289CE4A100B3B0AB /* Enums */,
DD86D40D2881BDB300BAEB7A /* Export */,
DDDB443E29F79A9400EE2349 /* Extensions */,
@ -1253,7 +1242,6 @@
DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */,
DD15E4F32B8BA56E00654F61 /* PaxCounterConfig.swift in Sources */,
DDDB445229F8ACF900EE2349 /* Date.swift in Sources */,
DDAA632E2BE7F84E00CC22D3 /* DeepLinkManager.swift in Sources */,
DDC4D568275499A500A4208E /* Persistence.swift in Sources */,
DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */,
DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */,

View file

@ -1,100 +0,0 @@
//
// DeepLinkManager.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 5/5/24.
//
import Foundation
protocol DeepLinkTabManager {
func handle(deepLink: String, selectedTab: inout Tab) -> Bool
}
@available(iOS 17.0, *)
@Observable
class DeepLinkManager {
var selectedTab: Tab = .ble
var features: [DeepLinkTabManager]
init() {
self.features = [
DeepLinkManagerMessages(),
DeepLinkManagerBluetooth(),
DeepLinkManagerNodes(),
DeepLinkManagerMap(),
DeepLinkManagerSettings()
]
}
func handleDeepLink(deepLink: String) {
for handler in features {
if handler.handle(deepLink: deepLink, selectedTab: &selectedTab) {
return
}
}
}
}
class DeepLinkManagerBluetooth: DeepLinkTabManager {
func handle(deepLink: String, selectedTab: inout Tab) -> Bool {
if deepLink.contains("bluetooth") {
selectedTab = .ble
return true
}
return false
}
}
class DeepLinkManagerMessages: DeepLinkTabManager {
var channel: String = ""
var messageId: String = ""
func handle(deepLink: String, selectedTab: inout Tab) -> Bool {
if deepLink.contains("messages") {
selectedTab = .messages
extractData(from: deepLink)
return true
}
return false
}
private func extractData(from deepLink: String) {
let temp = deepLink.replacingOccurrences(of: "meshtastic://messages?", with: "")
let params = temp.components(separatedBy: "&")
guard params.count == 2 else { return }
channel = params[0].replacingOccurrences(of: "channel=", with: "")
messageId = params[1].replacingOccurrences(of: "messageId=", with: "")
}
}
class DeepLinkManagerMap: DeepLinkTabManager {
func handle(deepLink: String, selectedTab: inout Tab) -> Bool {
if deepLink.contains("map") {
selectedTab = .map
return true
}
return false
}
}
class DeepLinkManagerNodes: DeepLinkTabManager {
func handle(deepLink: String, selectedTab: inout Tab) -> Bool {
if deepLink.contains("nodes") {
selectedTab = .nodes
return true
}
return false
}
}
class DeepLinkManagerSettings: DeepLinkTabManager {
func handle(deepLink: String, selectedTab: inout Tab) -> Bool {
if deepLink.contains("settings") {
selectedTab = .settings
return true
}
return false
}
}

View file

@ -1008,52 +1008,45 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
public func getPositionFromPhoneGPS(destNum: Int64) -> Position? {
var positionPacket = Position()
do {
if #available(iOS 17.0, macOS 14.0, *) {
if #available(iOS 17.0, macOS 14.0, *) {
if let lastLocation = LocationsHandler.shared.locationsArray.last {
positionPacket.latitudeI = Int32(lastLocation.coordinate.latitude * 1e7)
positionPacket.longitudeI = Int32(lastLocation.coordinate.longitude * 1e7)
let timestamp = lastLocation.timestamp
positionPacket.time = UInt32(timestamp.timeIntervalSince1970)
positionPacket.timestamp = UInt32(timestamp.timeIntervalSince1970)
positionPacket.altitude = Int32(lastLocation.altitude)
positionPacket.satsInView = UInt32(LocationsHandler.satsInView)
let currentSpeed = lastLocation.speed
if currentSpeed > 0 && (!currentSpeed.isNaN || !currentSpeed.isInfinite) {
positionPacket.groundSpeed = UInt32(currentSpeed * 3.6)
}
let currentHeading = lastLocation.course
if currentHeading > 0 && (!currentHeading.isNaN || !currentHeading.isInfinite) {
positionPacket.groundTrack = UInt32(currentHeading)
}
}
if let lastLocation = LocationsHandler.shared.locationsArray.last {
} else {
if destNum <= 0 || LocationHelper.currentLocation.distance(from: LocationHelper.DefaultLocation) == 0.0 {
return nil
}
positionPacket.latitudeI = Int32(LocationHelper.currentLocation.latitude * 1e7)
positionPacket.longitudeI = Int32(LocationHelper.currentLocation.longitude * 1e7)
let timestamp = LocationHelper.shared.locationManager.location?.timestamp ?? Date()
positionPacket.latitudeI = Int32(lastLocation.coordinate.latitude * 1e7)
positionPacket.longitudeI = Int32(lastLocation.coordinate.longitude * 1e7)
let timestamp = lastLocation.timestamp
positionPacket.time = UInt32(timestamp.timeIntervalSince1970)
positionPacket.timestamp = UInt32(timestamp.timeIntervalSince1970)
positionPacket.altitude = Int32(LocationHelper.shared.locationManager.location?.altitude ?? 0)
positionPacket.satsInView = UInt32(LocationHelper.satsInView)
let currentSpeed = LocationHelper.shared.locationManager.location?.speed ?? 0
positionPacket.altitude = Int32(lastLocation.altitude)
positionPacket.satsInView = UInt32(LocationsHandler.satsInView)
let currentSpeed = lastLocation.speed
if currentSpeed > 0 && (!currentSpeed.isNaN || !currentSpeed.isInfinite) {
positionPacket.groundSpeed = UInt32(currentSpeed * 3.6)
positionPacket.groundSpeed = UInt32(currentSpeed)
}
let currentHeading = LocationHelper.shared.locationManager.location?.course ?? 0
if currentHeading > 0 && (!currentHeading.isNaN || !currentHeading.isInfinite) {
let currentHeading = lastLocation.course
if (currentHeading > 0 && currentHeading <= 360) && (!currentHeading.isNaN || !currentHeading.isInfinite) {
positionPacket.groundTrack = UInt32(currentHeading)
}
}
} catch {
return nil
} else {
positionPacket.latitudeI = Int32(LocationHelper.currentLocation.latitude * 1e7)
positionPacket.longitudeI = Int32(LocationHelper.currentLocation.longitude * 1e7)
let timestamp = LocationHelper.shared.locationManager.location?.timestamp ?? Date()
positionPacket.time = UInt32(timestamp.timeIntervalSince1970)
positionPacket.timestamp = UInt32(timestamp.timeIntervalSince1970)
positionPacket.altitude = Int32(LocationHelper.shared.locationManager.location?.altitude ?? 0)
positionPacket.satsInView = UInt32(LocationHelper.satsInView)
let currentSpeed = LocationHelper.shared.locationManager.location?.speed ?? 0
if currentSpeed > 0 && (!currentSpeed.isNaN || !currentSpeed.isInfinite) {
positionPacket.groundSpeed = UInt32(currentSpeed)
}
let currentHeading = LocationHelper.shared.locationManager.location?.course ?? 0
if (currentHeading > 0 && currentHeading <= 360) && (!currentHeading.isNaN || !currentHeading.isInfinite) {
positionPacket.groundTrack = UInt32(currentHeading)
}
}
return positionPacket
}

View file

@ -315,7 +315,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
position.speed = Int32(nodeInfo.position.groundSpeed * UInt32(3.6))
position.speed = Int32(nodeInfo.position.groundSpeed)
position.heading = Int32(nodeInfo.position.groundTrack)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
var newPostions = [PositionEntity]()
@ -738,7 +738,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
subtitle: "AKA \(telemetry.nodeTelemetry?.user?.shortName ?? "UNK")",
content: "Time to charge your radio, there is \(telemetry.batteryLevel)% battery remaining.",
target: "nodes",
path: "meshtastic://nodes/\(telemetry.nodeTelemetry?.num ?? 0)/devicetelemetrylog"
path: "meshtastic://nodes?nodenum=\(telemetry.nodeTelemetry?.num ?? 0)"
)
]
manager.schedule()
@ -972,9 +972,10 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
subtitle: "\(icon) \(waypoint.name ?? "Dropped Pin")",
content: "\(waypoint.longDescription ?? "\(latitude), \(longitude)")",
target: "map",
path: "meshtastic://open-waypoint?id=\(waypoint.id)"
path: "meshtastic://map?waypontid=\(waypoint.id)"
)
]
print("meshtastic://map?waypontid=\(waypoint.id)")
manager.schedule()
} catch {
context.rollback()

View file

@ -9,9 +9,7 @@ import TipKit
@available(iOS 17.0, *)
@main
struct MeshtasticAppleApp: App {
let deepLinkManager = DeepLinkManager()
@UIApplicationDelegateAdaptor(MeshtasticAppDelegate.self) var appDelegate
let persistenceController = PersistenceController.shared
@ObservedObject private var bleManager: BLEManager = BLEManager.shared
@ -26,7 +24,7 @@ struct MeshtasticAppleApp: App {
var body: some Scene {
WindowGroup {
ContentView(deepLinkManager: deepLinkManager)
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environmentObject(bleManager)
.sheet(isPresented: $saveChannels) {
@ -56,10 +54,6 @@ struct MeshtasticAppleApp: App {
}
}
.onOpenURL(perform: { (url) in
if url.absoluteString.lowercased().contains("meshtastic://") {
deepLinkManager.handleDeepLink(deepLink: url.absoluteString.lowercased())
}
print("Some sort of URL was received \(url)")
self.incomingUrl = url
@ -70,7 +64,15 @@ struct MeshtasticAppleApp: App {
self.saveChannels = true
print("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")")
} else if url.absoluteString.lowercased().contains("meshtastic://") {
deepLinkManager.handleDeepLink(deepLink: url.absoluteString.lowercased())
appState.navigationPath = url.absoluteString
let path = appState.navigationPath ?? ""
if path.starts(with: "meshtastic://map") {
AppState.shared.tabSelection = Tab.map
} else if path.starts(with: "meshtastic://nodes") {
AppState.shared.tabSelection = Tab.nodes
}
} else {
saveChannels = false
print("User wants to import a MBTILES offline map file: \(self.incomingUrl?.absoluteString ?? "No Tiles link")")
@ -166,6 +168,6 @@ class AppState: ObservableObject {
@Published var unreadDirectMessages: Int = 0
@Published var unreadChannelMessages: Int = 0
@Published var firmwareVersion: String = "0.0.0"
@Published var connectedNode: NodeInfoEntity?
//@Published var connectedNode: NodeInfoEntity?
@Published var navigationPath: String?
}

View file

@ -33,13 +33,14 @@ class MeshtasticAppDelegate: NSObject, UIApplicationDelegate, UNUserNotification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
let targetValue = userInfo["target"] as? String
AppState.shared.navigationPath = userInfo["path"] as? String
print("\(AppState.shared.navigationPath ?? "EMPTY")")
let deepLink = userInfo["path"] as? String
AppState.shared.navigationPath = deepLink
if targetValue == "map" {
AppState.shared.tabSelection = Tab.map
} else if targetValue == "message" {
AppState.shared.tabSelection = Tab.messages
} else if targetValue == "node" {
} else if targetValue == "nodes" {
AppState.shared.tabSelection = Tab.nodes
}
completionHandler()

View file

@ -196,8 +196,8 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
title: "New Node",
subtitle: "\(newUser.longName ?? "unknown".localized)",
content: "New Node has been discovered",
target: "nodeInfo",
path: "meshtastic://nodes?num=\(newUser.num)"
target: "nodes",
path: "meshtastic://nodes?nodenum=\(newUser.num)"
)
]
manager.schedule()
@ -345,7 +345,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
position.longitudeI = positionMessage.longitudeI
position.altitude = positionMessage.altitude
position.satsInView = Int32(positionMessage.satsInView)
position.speed = Int32(positionMessage.groundSpeed * UInt32(3.6))
position.speed = Int32(positionMessage.groundSpeed)
position.heading = Int32(positionMessage.groundTrack)
position.precisionBits = Int32(positionMessage.precisionBits)
if positionMessage.timestamp != 0 {

View file

@ -6,12 +6,11 @@ import SwiftUI
@available(iOS 17.0, *)
struct ContentView: View {
@State var deepLinkManager: DeepLinkManager
@StateObject var appState = AppState.shared
var body: some View {
TabView(selection: $appState.tabSelection) {
Messages(deepLinkManager: deepLinkManager.features[0] as? DeepLinkManagerMessages)
Messages()
.tabItem {
Label("messages", systemImage: "message")
}
@ -22,7 +21,7 @@ struct ContentView: View {
Label("bluetooth", systemImage: "antenna.radiowaves.left.and.right")
}
.tag(Tab.ble)
NodeList(deepLinkManager: deepLinkManager.features[2] as? DeepLinkManagerNodes)
NodeList()
.tabItem {
Label("nodes", systemImage: "flipphone")
}

View file

@ -13,8 +13,6 @@ import TipKit
struct Messages: View {
@State var deepLinkManager: DeepLinkManagerMessages
@StateObject var appState = AppState.shared
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@ -29,10 +27,6 @@ struct Messages: View {
case groupMessages
case directMessages
}
init (deepLinkManager: DeepLinkManagerMessages? = nil) {
self.deepLinkManager = deepLinkManager ?? .init()
}
var body: some View {

View file

@ -35,9 +35,11 @@ struct MeshMap: View {
@State var selectedPosition: PositionEntity?
@State var editingWaypoint: WaypointEntity?
@State var selectedWaypoint: WaypointEntity?
@State var selectedWaypointId: String?
@State var newWaypointCoord: CLLocationCoordinate2D?
@State var isMeshMap = true
var body: some View {
NavigationStack {
@ -106,33 +108,33 @@ struct MeshMap: View {
.sheet(isPresented: $isEditingSettings) {
MapSettingsForm(traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap)
}
.onChange(of: (appState.navigationPath)) { newPath in
if ((newPath?.hasPrefix("meshtastic://open-waypoint")) != nil) {
guard let url = URL(string: appState.navigationPath ?? "NONE") else {
print("Invalid URL")
return
}
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
print("Invalid URL Components")
return
}
guard let action = components.host, action == "open-waypoint" else {
print("Unknown waypoint URL action")
return
}
guard let waypointId = components.queryItems?.first(where: { $0.name == "id" })?.value else {
print("Waypoint id not found")
return
}
// guard let waypoint = waypoints.first(where: { $0.id == Int64(waypointId) }) else {
// print("Waypoint not found")
// .onChange(of: (appState.navigationPath)) { newPath in
//
// if ((newPath?.hasPrefix("meshtastic://open-waypoint")) != nil) {
// guard let url = URL(string: appState.navigationPath ?? "NONE") else {
// print("Invalid URL")
// return
// }
// guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
// print("Invalid URL Components")
// return
// }
//showWaypoints = true
//position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 1000, heading: 0, pitch: 60))
}
}
// guard let action = components.host, action == "open-waypoint" else {
// print("Unknown waypoint URL action")
// return
// }
// guard let waypointId = components.queryItems?.first(where: { $0.name == "id" })?.value else {
// print("Waypoint id not found")
// return
// }
//// guard let waypoint = waypoints.first(where: { $0.id == Int64(waypointId) }) else {
//// print("Waypoint not found")
//// return
//// }
// //showWaypoints = true
// //position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 1000, heading: 0, pitch: 60))
// }
// }
.onChange(of: (selectedMapLayer)) { newMapLayer in
switch selectedMapLayer {
case .standard:
@ -174,6 +176,14 @@ struct MeshMap: View {
if self.bleManager.context == nil {
self.bleManager.context = context
}
// if deepLinkManager.waypointId.length > 0 {
// let wayPointEntity = getWaypoint(id: Int64(deepLinkManager.waypointId) ?? -1, context: context)
//if wayPointEntity.id > 0 {
// position = .camera(MapCamera(centerCoordinate: wayPointEntity.coordinate, distance: 1000, heading: 0, pitch: 60))
//}
switch selectedMapLayer {
case .standard:
mapStyle = MapStyle.standard(elevation: .realistic, pointsOfInterest: showPointsOfInterest ? .all : .excludingAll, showsTraffic: showTraffic)

View file

@ -9,7 +9,7 @@ import CoreLocation
struct NodeList: View {
@State var deepLinkManager: DeepLinkManagerNodes
@StateObject var appState = AppState.shared
@State private var columnVisibility = NavigationSplitViewVisibility.all
@State private var selectedNode: NodeInfoEntity?
@State private var isPresentingTraceRouteSentAlert = false
@ -42,13 +42,17 @@ struct NodeList: View {
var nodes: FetchedResults<NodeInfoEntity>
init (deepLinkManager: DeepLinkManagerNodes? = nil) {
self.deepLinkManager = deepLinkManager ?? .init()
}
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
// HStack {
// Button("Open Node") {
// UIApplication
// .shared
// .open(URL(string: "meshtastic://nodes?nodeNum=530606484")!)
// }
// }
let connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
List(nodes, id: \.self, selection: $selectedNode) { node in
@ -208,6 +212,7 @@ struct NodeList: View {
.disableAutocorrection(true)
.scrollDismissesKeyboard(.immediately)
.navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count)))
.listStyle(.plain)
.confirmationDialog(
@ -218,12 +223,11 @@ struct NodeList: View {
Button("Delete Node") {
let deleteNode = getNodeInfo(id: deleteNodeId, context: context)
if connectedNode != nil {
}
if deleteNode != nil {
let success = bleManager.removeNode(node: deleteNode!, connectedNodeNum: Int64(connectedNodeNum))
if !success {
print("Failed to delete node \(deleteNode?.user?.longName ?? "unknown".localized)")
if deleteNode != nil {
let success = bleManager.removeNode(node: deleteNode!, connectedNodeNum: Int64(connectedNodeNum))
if !success {
print("Failed to delete node \(deleteNode?.user?.longName ?? "unknown".localized)")
}
}
}
}
@ -310,6 +314,23 @@ struct NodeList: View {
.onChange(of: distanceFilter) { _ in
searchNodeList()
}
.onChange(of: (appState.navigationPath)) { newPath in
if ((newPath?.hasPrefix("meshtastic://nodes")) != nil) {
if let urlComponent = URLComponents(string: newPath ?? "") {
let queryItems = urlComponent.queryItems
let nodeNum = queryItems?.first(where: { $0.name == "nodenum" })?.value
if nodeNum == nil {
print("nodeNum not found")
}
else {
selectedNode = nodes.first(where: { $0.num == Int64(nodeNum ?? "-1") })
AppState.shared.navigationPath = nil
}
}
}
}
.onAppear {
if self.bleManager.context == nil {
self.bleManager.context = context

View file

@ -278,8 +278,6 @@ struct ShareChannels: View {
channelSettings.name = ch.name!
channelSettings.psk = ch.psk!
channelSettings.id = UInt32(ch.id)
channelSettings.uplinkEnabled = ch.uplinkEnabled
channelSettings.downlinkEnabled = ch.downlinkEnabled
channelSet.settings.append(channelSettings)
}
}

@ -1 +1 @@
Subproject commit f92900c5f884b04388fb7abf61d4df66783015e4
Subproject commit dd7d64cc038a6365c119ec7508762cc45f405948