Bossy linter

This commit is contained in:
Garth Vander Houwen 2024-10-05 15:50:57 -07:00
parent 26e917df48
commit a4d5aefca3
43 changed files with 191 additions and 232 deletions

View file

@ -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:

View file

@ -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")

View file

@ -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.")
}

View file

@ -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")
}
}
}

View file

@ -177,7 +177,6 @@ enum Iaq: Int, CaseIterable, Identifiable {
}
}
// Default of 0 is Client
enum MetricsTypes: Int, CaseIterable, Identifiable {

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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")

View file

@ -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
}

View file

@ -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) {

View file

@ -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 {

View file

@ -43,7 +43,7 @@ struct ContentView: View {
Label("map", systemImage: "map")
}
.tag(NavigationState.Tab.map)
Settings(
router: appState.router
)

View file

@ -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")

View file

@ -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(

View file

@ -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()
}
}

View file

@ -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) {

View file

@ -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()
}

View file

@ -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(

View file

@ -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
}

View file

@ -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) {

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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)")

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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) {

View file

@ -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 }
}

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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() {

View file

@ -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
}
}

View file

@ -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))