mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Bossy linter
This commit is contained in:
parent
26e917df48
commit
a4d5aefca3
43 changed files with 191 additions and 232 deletions
|
|
@ -15,7 +15,7 @@ class AppIntentErrors {
|
|||
|
||||
var localizedStringResource: LocalizedStringResource {
|
||||
switch self {
|
||||
case let .message(message):
|
||||
case let .message(message):
|
||||
Logger.services.error("App Intent: \(message)")
|
||||
return "Error: \(message)"
|
||||
case .notConnected:
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import AppIntents
|
|||
struct FactoryResetNodeIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Factory Reset"
|
||||
static var description: IntentDescription = "Perform a factory reset on the node you are connected to"
|
||||
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
// Request user confirmation before performing the factory reset
|
||||
try await requestConfirmation(result: .result(dialog: "Are you sure you want to factory reset the node?"),confirmationActionName: ConfirmationActionName
|
||||
try await requestConfirmation(result: .result(dialog: "Are you sure you want to factory reset the node?"), confirmationActionName: ConfirmationActionName
|
||||
.custom(acceptLabel: "Factory Reset", acceptAlternatives: [], denyLabel: "Cancel", denyAlternatives: [], destructive: true))
|
||||
|
||||
// Ensure the node is connected
|
||||
|
|
@ -27,7 +27,7 @@ struct FactoryResetNodeIntent: AppIntent {
|
|||
let connectedNode = getNodeInfo(id: connectedPeripheralNum, context: PersistenceController.shared.container.viewContext),
|
||||
let fromUser = connectedNode.user,
|
||||
let toUser = connectedNode.user {
|
||||
|
||||
|
||||
// Attempt to send a factory reset command, throw an error if it fails
|
||||
if !BLEManager.shared.sendFactoryReset(fromUser: fromUser, toUser: toUser) {
|
||||
throw AppIntentErrors.AppIntentError.message("Failed to perform factory reset")
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct MessageChannelIntent: AppIntent {
|
|||
guard let messageData = messageContent.data(using: .utf8) else {
|
||||
throw AppIntentErrors.AppIntentError.message("Failed to encode message content")
|
||||
}
|
||||
|
||||
|
||||
if messageData.count > 200 {
|
||||
throw $messageContent.needsValueError("Message content exceeds 200 bytes.")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,44 +14,38 @@ struct NodePositionIntent: AppIntent {
|
|||
|
||||
@Parameter(title: "Node Number")
|
||||
var nodeNum: Int
|
||||
|
||||
|
||||
static var title: LocalizedStringResource = "Get Node Position"
|
||||
static var description: IntentDescription = "Fetch the latest position of a cetain node"
|
||||
|
||||
|
||||
|
||||
func perform() async throws -> some IntentResult & ReturnsValue<CLPlacemark> {
|
||||
if (!BLEManager.shared.isConnected) {
|
||||
if !BLEManager.shared.isConnected {
|
||||
throw AppIntentErrors.AppIntentError.notConnected
|
||||
}
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
do {
|
||||
guard let fetchedNode = try PersistenceController.shared.container.viewContext.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity], fetchedNode.count == 1 else {
|
||||
throw $nodeNum.needsValueError("Could not find node")
|
||||
}
|
||||
|
||||
let nodeInfo = fetchedNode[0]
|
||||
nodeInfo.latestEnvironmentMetrics?.batteryLevel
|
||||
if let latitude = nodeInfo.latestPosition?.coordinate.latitude,
|
||||
let longitude = nodeInfo.latestPosition?.coordinate.longitude {
|
||||
let nodeLocation = CLLocation(latitude: latitude, longitude: longitude)
|
||||
|
||||
// Reverse geocode the CLLocation to get a CLPlacemark
|
||||
let geocoder = CLGeocoder()
|
||||
let placemarks = try await geocoder.reverseGeocodeLocation(nodeLocation)
|
||||
|
||||
if let placemark = placemarks.first {
|
||||
return .result(value: placemark)
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Error Reverse Geocoding Location")
|
||||
}
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Node does not have positions")
|
||||
}
|
||||
} catch {
|
||||
throw AppIntentErrors.AppIntentError.message("Fetch Failure")
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
|
||||
do {
|
||||
guard let fetchedNode = try PersistenceController.shared.container.viewContext.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity], fetchedNode.count == 1 else {
|
||||
throw $nodeNum.needsValueError("Could not find node")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
let nodeInfo = fetchedNode[0]
|
||||
if let latitude = nodeInfo.latestPosition?.coordinate.latitude,
|
||||
let longitude = nodeInfo.latestPosition?.coordinate.longitude {
|
||||
let nodeLocation = CLLocation(latitude: latitude, longitude: longitude)
|
||||
// Reverse geocode the CLLocation to get a CLPlacemark
|
||||
let geocoder = CLGeocoder()
|
||||
let placemarks = try await geocoder.reverseGeocodeLocation(nodeLocation)
|
||||
|
||||
if let placemark = placemarks.first {
|
||||
return .result(value: placemark)
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Error Reverse Geocoding Location")
|
||||
}
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Node does not have positions")
|
||||
}
|
||||
} catch {
|
||||
throw AppIntentErrors.AppIntentError.message("Fetch Failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ enum Iaq: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Default of 0 is Client
|
||||
enum MetricsTypes: Int, CaseIterable, Identifiable {
|
||||
|
||||
|
|
|
|||
|
|
@ -54,31 +54,28 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
let LOGRADIO_UUID = CBUUID(string: "0x5a3d6e49-06e6-4423-9944-e9de8cdf9547")
|
||||
|
||||
// MARK: init
|
||||
|
||||
private override init() {
|
||||
// Default initialization should not be used
|
||||
fatalError("Use setup(appState:context:) to initialize the singleton")
|
||||
}
|
||||
// Default initialization should not be used
|
||||
fatalError("Use setup(appState:context:) to initialize the singleton")
|
||||
}
|
||||
|
||||
static func setup(appState: AppState, context: NSManagedObjectContext) {
|
||||
guard shared == nil else {
|
||||
print("BLEManager already initialized")
|
||||
return
|
||||
}
|
||||
shared = BLEManager(appState: appState, context: context)
|
||||
static func setup(appState: AppState, context: NSManagedObjectContext) {
|
||||
guard shared == nil else {
|
||||
Logger.services.warning("[BLE] BLEManager already initialized")
|
||||
return
|
||||
}
|
||||
shared = BLEManager(appState: appState, context: context)
|
||||
}
|
||||
|
||||
private init(appState: AppState, context: NSManagedObjectContext) {
|
||||
self.appState = appState
|
||||
self.context = context
|
||||
self.lastConnectionError = ""
|
||||
self.connectedVersion = "0.0.0"
|
||||
super.init()
|
||||
centralManager = CBCentralManager(delegate: self, queue: nil)
|
||||
mqttManager.delegate = self
|
||||
}
|
||||
|
||||
|
||||
private init(appState: AppState, context: NSManagedObjectContext) {
|
||||
self.appState = appState
|
||||
self.context = context
|
||||
self.lastConnectionError = ""
|
||||
self.connectedVersion = "0.0.0"
|
||||
super.init()
|
||||
centralManager = CBCentralManager(delegate: self, queue: nil)
|
||||
mqttManager.delegate = self
|
||||
}
|
||||
|
||||
// MARK: Scanning for BLE Devices
|
||||
// Scan for nearby BLE devices using the Meshtastic BLE service ID
|
||||
|
|
@ -464,7 +461,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
do {
|
||||
let fetchedNodes = try context.fetch(nodes)
|
||||
let receivingNode = fetchedNodes.first(where: { $0.num == destNum })
|
||||
let connectedNode = fetchedNodes.first(where: { $0.num == self.connectedPeripheral.num })
|
||||
traceRoute.id = Int64(meshPacket.id)
|
||||
traceRoute.time = Date()
|
||||
traceRoute.node = receivingNode
|
||||
|
|
@ -1617,7 +1613,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
let decodedString = base64UrlString.base64urlToBase64()
|
||||
if let decodedData = Data(base64Encoded: decodedString) {
|
||||
do {
|
||||
let channelSet: ChannelSet = try ChannelSet(serializedData: decodedData)
|
||||
let channelSet: ChannelSet = try ChannelSet(serializedBytes: decodedData)
|
||||
for cs in channelSet.settings {
|
||||
if addChannels {
|
||||
// We are trying to add a channel so lets get the last index
|
||||
|
|
@ -1989,10 +1985,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
let messageDescription = "🛟 Saved LoRa Config for \(toUser.longName ?? "unknown".localized)"
|
||||
|
||||
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
|
||||
upsertLoRaConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey,context: context)
|
||||
upsertLoRaConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey, context: context)
|
||||
return Int64(meshPacket.id)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -3195,7 +3190,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
}
|
||||
|
||||
func storeAndForwardPacket(packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
|
||||
if let storeAndForwardMessage = try? StoreAndForward(serializedData: packet.decoded.payload) {
|
||||
if let storeAndForwardMessage = try? StoreAndForward(serializedBytes: packet.decoded.payload) {
|
||||
// Handle each of the store and forward request / response messages
|
||||
switch storeAndForwardMessage.rr {
|
||||
case .unset:
|
||||
|
|
@ -3321,7 +3316,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
// MARK: - CB Central Manager implmentation
|
||||
extension BLEManager: CBCentralManagerDelegate {
|
||||
|
||||
|
||||
// MARK: Bluetooth enabled/disabled
|
||||
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
if central.state == CBManagerState.poweredOn {
|
||||
|
|
@ -3331,9 +3326,8 @@ extension BLEManager: CBCentralManagerDelegate {
|
|||
} else {
|
||||
isSwitchedOn = false
|
||||
}
|
||||
|
||||
|
||||
var status = ""
|
||||
|
||||
switch central.state {
|
||||
case .poweredOff:
|
||||
status = "BLE is powered off"
|
||||
|
|
@ -3352,10 +3346,9 @@ extension BLEManager: CBCentralManagerDelegate {
|
|||
}
|
||||
Logger.services.info("📜 [BLE] Bluetooth status: \(status)")
|
||||
}
|
||||
|
||||
|
||||
// Called each time a peripheral is discovered
|
||||
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
|
||||
|
||||
if self.automaticallyReconnect && peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" {
|
||||
self.connectTo(peripheral: peripheral)
|
||||
Logger.services.info("✅ [BLE] Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown", privacy: .public)")
|
||||
|
|
@ -3363,7 +3356,6 @@ extension BLEManager: CBCentralManagerDelegate {
|
|||
let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
||||
let device = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: name ?? "Unknown", shortName: "?", longName: name ?? "Unknown", firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral)
|
||||
let index = peripherals.map { $0.peripheral }.firstIndex(of: peripheral)
|
||||
|
||||
if let peripheralIndex = index {
|
||||
peripherals[peripheralIndex] = device
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,16 +5,9 @@ import OSLog
|
|||
class LocalNotificationManager {
|
||||
|
||||
var notifications = [Notification]()
|
||||
|
||||
let thumbsUpAction = UNNotificationAction(identifier: "messageNotification.thumbsUpAction", title:
|
||||
"👍 \(Tapbacks.thumbsUp.description)", options: [])
|
||||
let thumbsDownAction = UNNotificationAction(identifier: "messageNotification.thumbsDownAction", title:
|
||||
"👎 \(Tapbacks.thumbsDown.description)", options: [])
|
||||
let replyInputAction = UNTextInputNotificationAction(
|
||||
identifier: "messageNotification.replyInputAction",
|
||||
title: "reply".localized,
|
||||
options: [])
|
||||
|
||||
let thumbsUpAction = UNNotificationAction(identifier: "messageNotification.thumbsUpAction", title: "👍 \(Tapbacks.thumbsUp.description)", options: [])
|
||||
let thumbsDownAction = UNNotificationAction(identifier: "messageNotification.thumbsDownAction", title: "👎 \(Tapbacks.thumbsDown.description)", options: [])
|
||||
let replyInputAction = UNTextInputNotificationAction(identifier: "messageNotification.replyInputAction", title: "reply".localized, options: [])
|
||||
|
||||
// Step 1 Request Permissions for notifications
|
||||
private func requestAuthorization() {
|
||||
|
|
@ -43,13 +36,13 @@ class LocalNotificationManager {
|
|||
private func scheduleNotifications() {
|
||||
let messageNotificationCategory = UNNotificationCategory(
|
||||
identifier: "messageNotificationCategory",
|
||||
actions: [thumbsUpAction, thumbsDownAction,replyInputAction],
|
||||
actions: [thumbsUpAction, thumbsDownAction, replyInputAction],
|
||||
intentIdentifiers: [],
|
||||
options: .customDismissAction
|
||||
)
|
||||
|
||||
UNUserNotificationCenter.current().setNotificationCategories([messageNotificationCategory])
|
||||
|
||||
|
||||
for notification in notifications {
|
||||
let content = UNMutableNotificationContent()
|
||||
content.subtitle = notification.subtitle
|
||||
|
|
@ -75,7 +68,6 @@ class LocalNotificationManager {
|
|||
content.userInfo["userNum"] = notification.userNum
|
||||
}
|
||||
|
||||
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
||||
let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger)
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ func generateMessageMarkdown (message: String) -> String {
|
|||
|
||||
func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
let remote = nodeNum != UserDefaults.preferredPeripheralNum
|
||||
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
||||
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context)
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
|
||||
|
|
@ -454,11 +453,11 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
|
||||
func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
|
||||
if let adminMessage = try? AdminMessage(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
|
||||
|
||||
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
|
||||
if let cmmc = try? CannedMessageModuleConfig(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
if !cmmc.messages.isEmpty {
|
||||
|
||||
|
|
@ -581,7 +580,7 @@ func paxCounterPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
do {
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoRequest)
|
||||
|
||||
if let paxMessage = try? Paxcount(serializedData: packet.decoded.payload) {
|
||||
if let paxMessage = try? Paxcount(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
let newPax = PaxCounterEntity(context: context)
|
||||
newPax.ble = Int32(truncatingIfNeeded: paxMessage.ble)
|
||||
|
|
@ -611,7 +610,7 @@ func paxCounterPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
|
||||
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {
|
||||
if let routingMessage = try? Routing(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
let routingError = RoutingError(rawValue: routingMessage.errorReason.rawValue)
|
||||
|
||||
|
|
@ -833,7 +832,7 @@ func textMessageAppPacket(
|
|||
}
|
||||
var storeForwardBroadcast = false
|
||||
if storeForward {
|
||||
if let storeAndForwardMessage = try? StoreAndForward(serializedData: packet.decoded.payload) {
|
||||
if let storeAndForwardMessage = try? StoreAndForward(serializedBytes: packet.decoded.payload) {
|
||||
messageText = String(bytes: storeAndForwardMessage.text, encoding: .utf8)
|
||||
if storeAndForwardMessage.rr == .routerTextBroadcast {
|
||||
storeForwardBroadcast = true
|
||||
|
|
@ -993,7 +992,6 @@ func textMessageAppPacket(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
let logString = String.localizedStringWithFormat("mesh.log.waypoint.received %@".localized, String(packet.from))
|
||||
|
|
@ -1004,7 +1002,7 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
|
||||
do {
|
||||
|
||||
if let waypointMessage = try? Waypoint(serializedData: packet.decoded.payload) {
|
||||
if let waypointMessage = try? Waypoint(serializedBytes: packet.decoded.payload) {
|
||||
let fetchedWaypoint = try context.fetch(fetchWaypointRequest)
|
||||
if fetchedWaypoint.isEmpty {
|
||||
let waypoint = WaypointEntity(context: context)
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ struct MeshtasticAppleApp: App {
|
|||
)
|
||||
}
|
||||
}
|
||||
.onChange(of: scenePhase) { (newScenePhase) in
|
||||
.onChange(of: scenePhase) { (_, newScenePhase) in
|
||||
switch newScenePhase {
|
||||
case .background:
|
||||
Logger.services.info("🎬 [App] Scene is in the background")
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
} else {
|
||||
Logger.services.error("Failed to retrieve channel or messageId from userInfo")
|
||||
}
|
||||
break
|
||||
case "messageNotification.thumbsDownAction":
|
||||
if let channel = userInfo["channel"] as? Int32,
|
||||
let replyID = userInfo["messageId"] as? Int64 {
|
||||
|
|
@ -76,7 +75,6 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
} else {
|
||||
Logger.services.error("Failed to retrieve channel or messageId from userInfo")
|
||||
}
|
||||
break
|
||||
case "messageNotification.replyInputAction":
|
||||
if let userInput = (response as? UNTextInputNotificationResponse)?.userText,
|
||||
let channel = userInfo["channel"] as? Int32,
|
||||
|
|
@ -92,7 +90,6 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat
|
|||
} else {
|
||||
Logger.services.error("Failed to retrieve user input, channel, or messageId from userInfo")
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,12 +159,12 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
if packet.to == Constants.maximumNodeNum || packet.to == UserDefaults.preferredPeripheralNum {
|
||||
newNode.channel = Int32(packet.channel)
|
||||
}
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedBytes: packet.decoded.payload) {
|
||||
newNode.hopsAway = Int32(nodeInfoMessage.hopsAway)
|
||||
newNode.favorite = nodeInfoMessage.isFavorite
|
||||
}
|
||||
|
||||
if let newUserMessage = try? User(serializedData: packet.decoded.payload) {
|
||||
if let newUserMessage = try? User(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
if newUserMessage.id.isEmpty {
|
||||
if packet.from > Constants.minimumNodeNum {
|
||||
|
|
@ -254,7 +254,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
fetchedNode[0].channel = Int32(packet.channel)
|
||||
}
|
||||
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
fetchedNode[0].hopsAway = Int32(nodeInfoMessage.hopsAway)
|
||||
fetchedNode[0].favorite = nodeInfoMessage.isFavorite
|
||||
|
|
@ -320,7 +320,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
|
||||
do {
|
||||
|
||||
if let positionMessage = try? Position(serializedData: packet.decoded.payload) {
|
||||
if let positionMessage = try? Position(serializedBytes: packet.decoded.payload) {
|
||||
|
||||
/// Don't save empty position packets from null island or apple park
|
||||
if (positionMessage.longitudeI != 0 && positionMessage.latitudeI != 0) && (positionMessage.latitudeI != 373346000 && positionMessage.longitudeI != -1220090000) {
|
||||
|
|
|
|||
|
|
@ -301,10 +301,10 @@ struct Connect: View {
|
|||
.presentationDetents([.large])
|
||||
.presentationDragIndicator(.automatic)
|
||||
}
|
||||
.onChange(of: (self.bleManager.invalidVersion)) { _ in
|
||||
.onChange(of: self.bleManager.invalidVersion) {
|
||||
invalidFirmwareVersion = self.bleManager.invalidVersion
|
||||
}
|
||||
.onChange(of: (self.bleManager.isSubscribed)) { sub in
|
||||
.onChange(of: self.bleManager.isSubscribed) { _, sub in
|
||||
|
||||
if UserDefaults.preferredPeripheralId.count > 0 && sub {
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct ContentView: View {
|
|||
Label("map", systemImage: "map")
|
||||
}
|
||||
.tag(NavigationState.Tab.map)
|
||||
|
||||
|
||||
Settings(
|
||||
router: appState.router
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ struct WaypointFormMapKit: View {
|
|||
axis: .vertical
|
||||
)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: name, perform: { _ in
|
||||
.onChange(of: name) {
|
||||
var totalBytes = name.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 30 {
|
||||
|
|
@ -61,7 +61,7 @@ struct WaypointFormMapKit: View {
|
|||
if totalBytes > 30 {
|
||||
name = String(name.dropLast())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Text("Description")
|
||||
|
|
|
|||
|
|
@ -134,11 +134,11 @@ struct ChannelMessageList: View {
|
|||
scrollView.scrollTo(channel.allPrivateMessages.last?.messageId ?? 0, anchor: .bottom)
|
||||
}
|
||||
}
|
||||
.onChange(of: channel.allPrivateMessages, perform: { _ in
|
||||
.onChange(of: channel.allPrivateMessages) {
|
||||
withAnimation {
|
||||
scrollView.scrollTo(channel.allPrivateMessages.last?.messageId ?? 0, anchor: .bottom)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
TextMessageField(
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ struct Messages: View {
|
|||
} else if case .directMessages = router.navigationState.messages {
|
||||
Text("Select a conversation")
|
||||
}
|
||||
}.onChange(of: router.navigationState) { _ in
|
||||
}.onChange(of: router.navigationState) {
|
||||
setupNavigationState()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ struct TextMessageField: View {
|
|||
HStack(alignment: .top) {
|
||||
ZStack {
|
||||
TextField("message", text: $typingMessage, axis: .vertical)
|
||||
.onChange(of: typingMessage, perform: { value in
|
||||
.onChange(of: typingMessage) { _, value in
|
||||
totalBytes = value.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > Self.maxbytes {
|
||||
typingMessage = String(typingMessage.dropLast())
|
||||
totalBytes = typingMessage.utf8.count
|
||||
}
|
||||
})
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
|
|
|
|||
|
|
@ -199,12 +199,12 @@ struct UserList: View {
|
|||
.sheet(isPresented: $showingHelp) {
|
||||
DirectMessagesHelp()
|
||||
}
|
||||
.onChange(of: searchText) { _ in
|
||||
.onChange(of: searchText) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: viaLora) { _ in
|
||||
.onChange(of: viaLora) {
|
||||
if !viaLora && !viaMqtt {
|
||||
viaMqtt = true
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ struct UserList: View {
|
|||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: viaMqtt) { _ in
|
||||
.onChange(of: viaMqtt) {
|
||||
if !viaLora && !viaMqtt {
|
||||
viaLora = true
|
||||
}
|
||||
|
|
@ -220,27 +220,27 @@ struct UserList: View {
|
|||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: [deviceRoles]) { _ in
|
||||
.onChange(of: [deviceRoles]) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: hopsAway) { _ in
|
||||
.onChange(of: hopsAway) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: [boolFilters]) { _ in
|
||||
.onChange(of: [boolFilters]) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: maxDistance) { _ in
|
||||
.onChange(of: maxDistance) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
}
|
||||
.onChange(of: isPkiEncrypted) { _ in
|
||||
.onChange(of: isPkiEncrypted) {
|
||||
Task {
|
||||
await searchUserList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,11 +122,11 @@ struct UserMessageList: View {
|
|||
scrollView.scrollTo(user.messageList.last?.messageId ?? 0, anchor: .bottom)
|
||||
}
|
||||
}
|
||||
.onChange(of: user.messageList, perform: { _ in
|
||||
.onChange(of: user.messageList) {
|
||||
withAnimation {
|
||||
scrollView.scrollTo(user.messageList.last?.messageId ?? 0, anchor: .bottom)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
TextMessageField(
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ struct DeviceMetricsLog: View {
|
|||
.padding(.bottom)
|
||||
.padding(.trailing)
|
||||
}
|
||||
.onChange(of: selection) { newSelection in
|
||||
.onChange(of: selection) { _, newSelection in
|
||||
guard let metrics = deviceMetrics.first(where: { $0.id == newSelection }) else {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct MapSettingsForm: View {
|
|||
.pickerStyle(SegmentedPickerStyle())
|
||||
.padding(.top, 5)
|
||||
.padding(.bottom, 5)
|
||||
.onChange(of: mapLayer) { newMapLayer in
|
||||
.onChange(of: mapLayer) { _, newMapLayer in
|
||||
UserDefaults.mapLayer = newMapLayer
|
||||
}
|
||||
if meshMap {
|
||||
|
|
@ -50,7 +50,7 @@ struct MapSettingsForm: View {
|
|||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
}
|
||||
.onChange(of: meshMapDistance) { newMeshMapDistance in
|
||||
.onChange(of: meshMapDistance) { _, newMeshMapDistance in
|
||||
UserDefaults.meshMapDistance = newMeshMapDistance
|
||||
}
|
||||
Toggle(isOn: $waypoints) {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ struct NodeMapSwiftUI: View {
|
|||
}
|
||||
.sheet(isPresented: $isEditingSettings) {
|
||||
MapSettingsForm(traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap)
|
||||
.onChange(of: (selectedMapLayer)) { newMapLayer in
|
||||
.onChange(of: (selectedMapLayer)) { _, newMapLayer in
|
||||
switch selectedMapLayer {
|
||||
case .standard:
|
||||
UserDefaults.mapLayer = newMapLayer
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ struct PositionPopover: View {
|
|||
}
|
||||
/// Altitude
|
||||
Label {
|
||||
let formatter = MeasurementFormatter()
|
||||
let distanceInMeters = Measurement(value: Double(position.altitude), unit: UnitLength.meters)
|
||||
let distanceInFeet = distanceInMeters.converted(to: UnitLength.feet)
|
||||
if Locale.current.measurementSystem == .metric {
|
||||
|
|
|
|||
|
|
@ -280,12 +280,12 @@ struct NodeList: View {
|
|||
ContentUnavailableView("", systemImage: "line.3.horizontal")
|
||||
}
|
||||
.navigationSplitViewStyle(.balanced)
|
||||
.onChange(of: searchText) { _ in
|
||||
.onChange(of: searchText) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: viaLora) { _ in
|
||||
.onChange(of: viaLora) {
|
||||
if !viaLora && !viaMqtt {
|
||||
viaMqtt = true
|
||||
}
|
||||
|
|
@ -293,7 +293,7 @@ struct NodeList: View {
|
|||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: viaMqtt) { _ in
|
||||
.onChange(of: viaMqtt) {
|
||||
if !viaLora && !viaMqtt {
|
||||
viaLora = true
|
||||
}
|
||||
|
|
@ -301,32 +301,32 @@ struct NodeList: View {
|
|||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: [boolFilters]) { _ in
|
||||
.onChange(of: [boolFilters]) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: [deviceRoles]) { _ in
|
||||
.onChange(of: [deviceRoles]) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: hopsAway) { _ in
|
||||
.onChange(of: hopsAway) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: maxDistance) { _ in
|
||||
.onChange(of: maxDistance) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: distanceFilter) { _ in
|
||||
.onChange(of: distanceFilter) {
|
||||
Task {
|
||||
await searchNodeList()
|
||||
}
|
||||
}
|
||||
.onChange(of: router.navigationState) { _ in
|
||||
.onChange(of: router.navigationState) {
|
||||
if let selected = router.navigationState.nodeListSelectedNodeNum {
|
||||
self.selectedNode = getNodeInfo(id: selected, context: context)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -67,8 +67,6 @@ struct AppData: View {
|
|||
let container = NSPersistentContainer(name: "Meshtastic")
|
||||
do {
|
||||
try container.restorePersistentStore(from: file.absoluteURL)
|
||||
let request = MyInfoEntity.fetchRequest()
|
||||
try context.fetch(request)
|
||||
UserDefaults.preferredPeripheralId = ""
|
||||
UserDefaults.preferredPeripheralNum = Int(file.pathComponents[(idiom == .phone || idiom == .pad) ? 9 : 10]) ?? 0
|
||||
Logger.data.notice("🗂️ Restored a core data backup to backup/\(UserDefaults.preferredPeripheralNum, privacy: .public)")
|
||||
|
|
|
|||
|
|
@ -131,25 +131,25 @@ struct AppLog: View {
|
|||
logs.sort(using: sortOrder)
|
||||
}
|
||||
}
|
||||
.onChange(of: searchText) { _ in
|
||||
.onChange(of: searchText) {
|
||||
Task {
|
||||
await logs = searchAppLogs()
|
||||
logs.sort(using: sortOrder)
|
||||
}
|
||||
}
|
||||
.onChange(of: [categories]) { _ in
|
||||
.onChange(of: [categories]) {
|
||||
Task {
|
||||
await logs = searchAppLogs()
|
||||
logs.sort(using: sortOrder)
|
||||
}
|
||||
}
|
||||
.onChange(of: [levels]) { _ in
|
||||
.onChange(of: [levels]) {
|
||||
Task {
|
||||
await logs = searchAppLogs()
|
||||
logs.sort(using: sortOrder)
|
||||
}
|
||||
}
|
||||
.onChange(of: selection) { newSelection in
|
||||
.onChange(of: selection) { _, newSelection in
|
||||
presentingErrorDetails = true
|
||||
let log = logs.first {
|
||||
$0.id == newSelection
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ struct ChannelForm: View {
|
|||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: channelName, perform: { _ in
|
||||
.onChange(of: channelName) {
|
||||
channelName = channelName.replacing(" ", with: "")
|
||||
var totalBytes = channelName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
|
|
@ -48,7 +48,7 @@ struct ChannelForm: View {
|
|||
totalBytes = channelName.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
}
|
||||
HStack {
|
||||
Picker("Key Size", selection: $channelKeySize) {
|
||||
|
|
@ -97,7 +97,7 @@ struct ChannelForm: View {
|
|||
, lineWidth: 2.0)
|
||||
|
||||
)
|
||||
.onChange(of: channelKey, perform: { _ in
|
||||
.onChange(of: channelKey) {
|
||||
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1 {
|
||||
|
|
@ -106,7 +106,7 @@ struct ChannelForm: View {
|
|||
hasValidKey = false
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.disabled(channelKeySize <= 0)
|
||||
}
|
||||
HStack {
|
||||
|
|
@ -146,7 +146,7 @@ struct ChannelForm: View {
|
|||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.disabled(!supportedVersion)
|
||||
.listRowSeparator(.visible)
|
||||
.onChange(of: preciseLocation) { pl in
|
||||
.onChange(of: preciseLocation) { _, pl in
|
||||
if pl == false {
|
||||
positionPrecision = 14
|
||||
}
|
||||
|
|
@ -184,10 +184,10 @@ struct ChannelForm: View {
|
|||
.listRowSeparator(.visible)
|
||||
}
|
||||
}
|
||||
.onChange(of: channelName) { _ in
|
||||
.onChange(of: channelName) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
.onChange(of: channelKeySize) {
|
||||
if channelKeySize == -1 {
|
||||
channelKey = "AQ=="
|
||||
} else {
|
||||
|
|
@ -196,10 +196,10 @@ struct ChannelForm: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKey) { _ in
|
||||
.onChange(of: channelKey) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: channelKeySize) { _ in
|
||||
.onChange(of: channelKeySize) {
|
||||
if channelKeySize == -1 {
|
||||
if channelRole == 0 {
|
||||
preciseLocation = false
|
||||
|
|
@ -207,10 +207,10 @@ struct ChannelForm: View {
|
|||
channelKey = "AQ=="
|
||||
}
|
||||
}
|
||||
.onChange(of: channelRole) { _ in
|
||||
.onChange(of: channelRole) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: preciseLocation) { loc in
|
||||
.onChange(of: preciseLocation) { _, loc in
|
||||
if loc == true {
|
||||
if channelKey == "AQ==" {
|
||||
preciseLocation = false
|
||||
|
|
@ -223,10 +223,10 @@ struct ChannelForm: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionPrecision) { _ in
|
||||
.onChange(of: positionPrecision) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: positionsEnabled) { pe in
|
||||
.onChange(of: positionsEnabled) { _, pe in
|
||||
if pe {
|
||||
if positionPrecision == 0 {
|
||||
positionPrecision = 14
|
||||
|
|
@ -236,10 +236,10 @@ struct ChannelForm: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: uplink) { _ in
|
||||
.onChange(of: uplink) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: downlink) { _ in
|
||||
.onChange(of: downlink) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onFirstAppear {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ struct BluetoothConfig: View {
|
|||
Label("bluetooth.mode.fixedpin", systemImage: "wallet.pass")
|
||||
TextField("bluetooth.mode.fixedpin", text: $fixedPin)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: fixedPin, perform: { _ in
|
||||
.onChange(of: fixedPin) {
|
||||
// Don't let the first character be 0 because it will get stripped when saving a UInt32
|
||||
if fixedPin.first == "0" {
|
||||
fixedPin = fixedPin.replacing("0", with: "")
|
||||
|
|
@ -59,7 +59,7 @@ struct BluetoothConfig: View {
|
|||
} else if fixedPin.utf8.count < pinLength {
|
||||
shortPin = true
|
||||
}
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.decimalPad)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ struct DeviceConfig: View {
|
|||
Label("Time Zone", systemImage: "clock.badge.exclamationmark")
|
||||
TextField("Time Zone", text: $tzdef, axis: .vertical)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: tzdef) { _ in
|
||||
.onChange(of: tzdef) {
|
||||
var totalBytes = tzdef.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 63 {
|
||||
|
|
|
|||
|
|
@ -71,8 +71,7 @@ struct CannedMessagesConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: messages, perform: { _ in
|
||||
|
||||
.onChange(of: messages) {
|
||||
var totalBytes = messages.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 198 {
|
||||
|
|
@ -80,7 +79,7 @@ struct CannedMessagesConfig: View {
|
|||
totalBytes = messages.utf8.count
|
||||
}
|
||||
hasMessagesChanges = true
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
|
|||
|
|
@ -123,14 +123,14 @@ struct MQTTConfig: View {
|
|||
Label("Root Topic", systemImage: "tree")
|
||||
TextField("Root Topic", text: $root)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: root, perform: { _ in
|
||||
.onChange(of: root) {
|
||||
var totalBytes = root.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 30 {
|
||||
root = String(root.dropLast())
|
||||
totalBytes = root.utf8.count
|
||||
}
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.asciiCapable)
|
||||
|
|
@ -162,7 +162,7 @@ struct MQTTConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: address, perform: { _ in
|
||||
.onChange(of: address) {
|
||||
var totalBytes = address.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 62 {
|
||||
|
|
@ -170,7 +170,7 @@ struct MQTTConfig: View {
|
|||
totalBytes = address.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.keyboardType(.default)
|
||||
}
|
||||
.autocorrectionDisabled()
|
||||
|
|
@ -181,7 +181,7 @@ struct MQTTConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: username, perform: { _ in
|
||||
.onChange(of: username) {
|
||||
var totalBytes = username.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 62 {
|
||||
|
|
@ -189,7 +189,7 @@ struct MQTTConfig: View {
|
|||
totalBytes = username.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
@ -200,7 +200,7 @@ struct MQTTConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: password, perform: { _ in
|
||||
.onChange(of: password) {
|
||||
var totalBytes = password.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 62 {
|
||||
|
|
@ -208,7 +208,7 @@ struct MQTTConfig: View {
|
|||
totalBytes = password.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
|
|||
|
|
@ -79,11 +79,11 @@ struct PaxCounterConfig: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: enabled) {
|
||||
if $0 != node?.paxCounterConfig?.enabled { hasChanges = true }
|
||||
.onChange(of: enabled) { oldEnabled, newEnabled in
|
||||
if oldEnabled != newEnabled && newEnabled != node?.paxCounterConfig?.enabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: paxcounterUpdateInterval) {
|
||||
if $0 != node?.paxCounterConfig?.updateInterval ?? -1 { hasChanges = true }
|
||||
.onChange(of: paxcounterUpdateInterval) { oldPaxcounterUpdateInterval, newPaxcounterUpdateInterval in
|
||||
if oldPaxcounterUpdateInterval != newPaxcounterUpdateInterval && newPaxcounterUpdateInterval != node?.paxCounterConfig?.updateInterval ?? -1 { hasChanges = true }
|
||||
}
|
||||
|
||||
SaveConfigButton(node: node, hasChanges: $hasChanges) {
|
||||
|
|
|
|||
|
|
@ -167,32 +167,26 @@ struct StoreForwardConfig: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: enabled) { newEnabled in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newEnabled != node!.storeForwardConfig!.enabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: enabled) { oldEnabled, newEnabled in
|
||||
if oldEnabled != newEnabled && newEnabled != node!.storeForwardConfig!.enabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: isRouter) { newIsRouter in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newIsRouter != node!.storeForwardConfig!.isRouter { hasChanges = true }
|
||||
}
|
||||
.onChange(of: isRouter) { oldIsRouter, newIsRouter in
|
||||
if oldIsRouter != newIsRouter && newIsRouter != node!.storeForwardConfig!.isRouter { hasChanges = true }
|
||||
}
|
||||
.onChange(of: heartbeat) { newHeartbeat in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newHeartbeat != node!.storeForwardConfig!.heartbeat { hasChanges = true }
|
||||
}
|
||||
.onChange(of: heartbeat) { oldHeartbeat, newHeartbeat in
|
||||
if oldHeartbeat != newHeartbeat && newHeartbeat != node!.storeForwardConfig!.heartbeat { hasChanges = true }
|
||||
}
|
||||
.onChange(of: records) { newRecords in
|
||||
.onChange(of: records) { oldRecords, newRecords in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newRecords != node!.storeForwardConfig!.records { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: historyReturnMax) { newHistoryReturnMax in
|
||||
.onChange(of: historyReturnMax) { oldHistoryReturnMax, newHistoryReturnMax in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newHistoryReturnMax != node!.storeForwardConfig!.historyReturnMax { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: historyReturnWindow) { newHistoryReturnWindow in
|
||||
.onChange(of: historyReturnWindow) { oldHistoryReturnWindow, newHistoryReturnWindow in
|
||||
if node != nil && node?.storeForwardConfig != nil {
|
||||
if newHistoryReturnWindow != node!.storeForwardConfig!.historyReturnWindow { hasChanges = true }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ struct NetworkConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: wifiSsid, perform: { _ in
|
||||
.onChange(of: wifiSsid) {
|
||||
var totalBytes = wifiSsid.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 32 {
|
||||
|
|
@ -53,7 +53,7 @@ struct NetworkConfig: View {
|
|||
totalBytes = wifiSsid.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
@ -63,7 +63,7 @@ struct NetworkConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: wifiPsk, perform: { _ in
|
||||
.onChange(of: wifiPsk) {
|
||||
var totalBytes = wifiPsk.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 63 {
|
||||
|
|
@ -71,7 +71,7 @@ struct NetworkConfig: View {
|
|||
totalBytes = wifiPsk.utf8.count
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
@ -154,10 +154,10 @@ struct NetworkConfig: View {
|
|||
.onChange(of: wifiEnabled) {
|
||||
if $0 != node?.networkConfig?.wifiEnabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: wifiSsid) { newSSID in
|
||||
.onChange(of: wifiSsid) { _, newSSID in
|
||||
if newSSID != node?.networkConfig?.wifiSsid { hasChanges = true }
|
||||
}
|
||||
.onChange(of: wifiPsk) { newPsk in
|
||||
.onChange(of: wifiPsk) { _, newPsk in
|
||||
if newPsk != node?.networkConfig?.wifiPsk { hasChanges = true }
|
||||
}
|
||||
.onChange(of: wifiMode) {
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ struct PositionConfig: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: fixedPosition) { newFixed in
|
||||
.onChange(of: fixedPosition) { _, newFixed in
|
||||
if supportedVersion {
|
||||
if let positionConfig = node?.positionConfig {
|
||||
/// Fixed Position is off to start
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ private struct FloatField: View {
|
|||
TextField(title.localized, value: $typingNumber, format: .number)
|
||||
.foregroundColor(.gray)
|
||||
.multilineTextAlignment(.trailing)
|
||||
.onChange(of: typingNumber, perform: { _ in
|
||||
.onChange(of: typingNumber) {
|
||||
if isValid(typingNumber) {
|
||||
number = typingNumber
|
||||
} else {
|
||||
typingNumber = number
|
||||
}
|
||||
})
|
||||
}
|
||||
.keyboardType(.decimalPad)
|
||||
.onAppear {
|
||||
typingNumber = number
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ struct SecurityConfig: View {
|
|||
.onChange(of: adminChannelEnabled) {
|
||||
if $0 != node?.securityConfig?.adminChannelEnabled { hasChanges = true }
|
||||
}
|
||||
.onChange(of: publicKey) { _ in
|
||||
.onChange(of: publicKey) {
|
||||
let tempKey = Data(base64Encoded: publicKey) ?? Data()
|
||||
if tempKey.count == 32 {
|
||||
hasValidPublicKey = true
|
||||
|
|
@ -127,7 +127,7 @@ struct SecurityConfig: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: privateKey) { _ in
|
||||
.onChange(of: privateKey) {
|
||||
let tempKey = Data(base64Encoded: privateKey) ?? Data()
|
||||
if tempKey.count == 32 {
|
||||
hasValidPrivateKey = true
|
||||
|
|
@ -136,7 +136,7 @@ struct SecurityConfig: View {
|
|||
}
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: adminKey) { key in
|
||||
.onChange(of: adminKey) { _, key in
|
||||
let tempKey = Data(base64Encoded: key) ?? Data()
|
||||
if key.isEmpty {
|
||||
hasValidAdminKey = true
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ struct RouteRecorder: View {
|
|||
.onDisappear(perform: {
|
||||
UIApplication.shared.isIdleTimerDisabled = false
|
||||
})
|
||||
.onChange(of: locationsHandler.locationsArray.last) { newLoc in
|
||||
.onChange(of: locationsHandler.locationsArray.last) { _, newLoc in
|
||||
if locationsHandler.isRecording {
|
||||
if let loc = newLoc {
|
||||
if recording != nil {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ struct Routes: View {
|
|||
}
|
||||
|
||||
do {
|
||||
|
||||
guard let fileContent = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
|
||||
let routeName = selectedFile.lastPathComponent.dropLast(4)
|
||||
let lines = fileContent.components(separatedBy: "\n")
|
||||
|
|
@ -175,14 +174,14 @@ struct Routes: View {
|
|||
axis: .vertical
|
||||
)
|
||||
.foregroundColor(Color.gray)
|
||||
.onChange(of: name, perform: { _ in
|
||||
.onChange(of: name) {
|
||||
var totalBytes = name.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > 100 {
|
||||
name = String(name.dropLast())
|
||||
totalBytes = name.utf8.count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Toggle(isOn: $enabled) {
|
||||
Label("enabled", systemImage: "point.topleft.filled.down.to.point.bottomright.curvepath")
|
||||
|
|
@ -236,16 +235,16 @@ struct Routes: View {
|
|||
.controlSize(.large)
|
||||
.disabled(!hasChanges)
|
||||
}
|
||||
.onChange(of: name) { _ in
|
||||
.onChange(of: name) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: notes) { _ in
|
||||
.onChange(of: notes) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: enabled) { _ in
|
||||
.onChange(of: enabled) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: color) { _ in
|
||||
.onChange(of: color) {
|
||||
hasChanges = true
|
||||
}
|
||||
Map {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ struct Settings: View {
|
|||
Image(systemName: "light.max")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NavigationLink(value: SettingsNavigationState.cannedMessages) {
|
||||
Label {
|
||||
Text("canned.messages")
|
||||
|
|
@ -335,7 +335,6 @@ struct Settings: View {
|
|||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !(node?.deviceConfig?.isManaged ?? false) {
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
|
|
@ -387,7 +386,7 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
.pickerStyle(.navigationLink)
|
||||
.onChange(of: selectedNode) { newValue in
|
||||
.onChange(of: selectedNode) { _, newValue in
|
||||
if selectedNode > 0 {
|
||||
let node = nodes.first(where: { $0.num == newValue })
|
||||
let connectedNode = nodes.first(where: { $0.num == preferredNodeNum })
|
||||
|
|
@ -483,7 +482,7 @@ struct Settings: View {
|
|||
Firmware(node: node)
|
||||
}
|
||||
}
|
||||
.onChange(of: UserDefaults.preferredPeripheralNum ) { newConnectedNode in
|
||||
.onChange(of: UserDefaults.preferredPeripheralNum ) { _, newConnectedNode in
|
||||
preferredNodeNum = newConnectedNode
|
||||
if nodes.count > 1 {
|
||||
if selectedNode == 0 {
|
||||
|
|
|
|||
|
|
@ -235,15 +235,15 @@ struct ShareChannels: View {
|
|||
.onAppear {
|
||||
generateChannelSet()
|
||||
}
|
||||
.onChange(of: includeChannel0) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel1) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel2) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel3) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel4) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel5) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel6) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel7) { _ in generateChannelSet() }
|
||||
.onChange(of: replaceChannels) { _ in generateChannelSet() }
|
||||
.onChange(of: includeChannel0) { generateChannelSet() }
|
||||
.onChange(of: includeChannel1) { generateChannelSet() }
|
||||
.onChange(of: includeChannel2) { generateChannelSet() }
|
||||
.onChange(of: includeChannel3) { generateChannelSet() }
|
||||
.onChange(of: includeChannel4) { generateChannelSet() }
|
||||
.onChange(of: includeChannel5) { generateChannelSet() }
|
||||
.onChange(of: includeChannel6) { generateChannelSet() }
|
||||
.onChange(of: includeChannel7) { generateChannelSet() }
|
||||
.onChange(of: replaceChannels) { generateChannelSet() }
|
||||
}
|
||||
}
|
||||
func generateChannelSet() {
|
||||
|
|
|
|||
|
|
@ -49,14 +49,14 @@ struct UserConfig: View {
|
|||
Label(isLicensed ? "Call Sign" : "Long Name", systemImage: "person.crop.rectangle.fill")
|
||||
|
||||
TextField("Long Name", text: $longName)
|
||||
.onChange(of: longName, perform: { _ in
|
||||
.onChange(of: longName) {
|
||||
var totalBytes = longName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
while totalBytes > (isLicensed ? 6 : 36) {
|
||||
longName = String(longName.dropLast())
|
||||
totalBytes = longName.utf8.count
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
|
|
@ -74,14 +74,14 @@ struct UserConfig: View {
|
|||
Label("Short Name", systemImage: "circlebadge.fill")
|
||||
TextField("Short Name", text: $shortName)
|
||||
.foregroundColor(.gray)
|
||||
.onChange(of: shortName, perform: { _ in
|
||||
.onChange(of: shortName) {
|
||||
var totalBytes = shortName.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 4 {
|
||||
shortName = String(shortName.dropLast())
|
||||
totalBytes = shortName.utf8.count
|
||||
}
|
||||
})
|
||||
}
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
|
|
@ -197,17 +197,17 @@ struct UserConfig: View {
|
|||
self.overrideFrequency = node?.loRaConfig?.overrideFrequency ?? 0.00
|
||||
self.hasChanges = false
|
||||
}
|
||||
.onChange(of: shortName) { newShort in
|
||||
.onChange(of: shortName) { _, newShort in
|
||||
if node != nil && node!.user != nil {
|
||||
if newShort != node?.user!.shortName { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: longName) { newLong in
|
||||
.onChange(of: longName) { _, newLong in
|
||||
if node != nil && node!.user != nil {
|
||||
if newLong != node?.user!.longName { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: isLicensed) { newIsLicensed in
|
||||
.onChange(of: isLicensed) { _, newIsLicensed in
|
||||
if node != nil && node!.user != nil {
|
||||
if newIsLicensed != node?.user!.isLicensed {
|
||||
hasChanges = true
|
||||
|
|
@ -219,10 +219,10 @@ struct UserConfig: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: overrideFrequency) { _ in
|
||||
.onChange(of: overrideFrequency) {
|
||||
hasChanges = true
|
||||
}
|
||||
.onChange(of: txPower) { _ in
|
||||
.onChange(of: txPower) {
|
||||
hasChanges = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ struct WidgetsLiveActivity: Widget {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
struct WidgetsLiveActivity_Previews: PreviewProvider {
|
||||
static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "RAK Compact Rotary Handset Gray 8E6G")
|
||||
static let state = MeshActivityAttributes.ContentState(uptimeSeconds: 600, channelUtilization: 1.2, airtime: 3.5, sentPackets: 12587, receivedPackets: 12555, badReceivedPackets: 800, nodesOnline: 99, totalNodes: 100, timerRange: Date.now...Date(timeIntervalSinceNow: 300))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue