From b582d0d4bf824f04f3265ea7178a2b1e3dd4281a Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Thu, 13 Mar 2025 21:45:47 -0700 Subject: [PATCH 01/14] Read all messages when one in the channel is read --- Meshtastic/Views/Messages/ChannelMessageList.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 573a7dc8..c1350ce4 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -115,6 +115,9 @@ struct ChannelMessageList: View { if !message.read { message.read = true do { + for unreadMessage in channel.allPrivateMessages.filter({ !$0.read }) { + unreadMessage.read = true + } try context.save() Logger.data.info("📖 [App] Read message \(message.messageId) ") appState.unreadChannelMessages = myInfo.unreadMessages From ff81f77aa6491819795515e6b3de8f5873598e1d Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Thu, 13 Mar 2025 21:43:13 -0700 Subject: [PATCH 02/14] Read all messages in channel at once --- Meshtastic/Views/Messages/ChannelMessageList.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index c1350ce4..7753ddbb 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -113,7 +113,6 @@ struct ChannelMessageList: View { .id(message.messageId) .onAppear { if !message.read { - message.read = true do { for unreadMessage in channel.allPrivateMessages.filter({ !$0.read }) { unreadMessage.read = true From d33e7007835a86b45f50f57aceb9c66133a9ab21 Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Sat, 15 Mar 2025 00:02:43 -0700 Subject: [PATCH 03/14] Overhaul Store and Forward --- Localizable.xcstrings | 23 +++++++ Meshtastic/Helpers/BLEManager.swift | 6 +- Meshtastic/Helpers/MeshPackets.swift | 14 ++-- .../contents | 5 +- Meshtastic/Persistence/UpdateCoreData.swift | 1 + Meshtastic/Views/Messages/MessageText.swift | 23 +++++-- .../Config/Module/StoreForwardConfig.swift | 68 ++++++++----------- 7 files changed, 85 insertions(+), 55 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 6c2731d1..1357bbd4 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -9313,6 +9313,9 @@ } } } + }, + "Enable this device as a Store and Forward server. Requires an ESP32 device with PSRAM." : { + }, "enabled" : { "localizations" : { @@ -9409,8 +9412,12 @@ } } } + }, + "Enables the store and forward module." : { + }, "Enables the store and forward module. Store and forward must be enabled on both client and router devices." : { + "extractionState" : "stale", "localizations" : { "sr" : { "stringUnit" : { @@ -25056,6 +25063,7 @@ } }, "Router" : { + "extractionState" : "stale", "localizations" : { "sr" : { "stringUnit" : { @@ -25066,6 +25074,7 @@ } }, "Router Options" : { + "extractionState" : "stale", "localizations" : { "sr" : { "stringUnit" : { @@ -27139,6 +27148,9 @@ } } } + }, + "Send a heartbeat to advertise the server's presence." : { + }, "Send a message to a certain meshtastic channel" : { "localizations" : { @@ -27888,6 +27900,9 @@ } } } + }, + "Server Option" : { + }, "Set" : { "localizations" : { @@ -28046,6 +28061,9 @@ } } } + }, + "Settings" : { + }, "Share QR Code & Link" : { "localizations" : { @@ -28883,6 +28901,7 @@ } }, "Store and forward clients can request history from routers on the network." : { + "extractionState" : "stale", "localizations" : { "sr" : { "stringUnit" : { @@ -28893,6 +28912,7 @@ } }, "Store and forward router devices require a ESP32 device with PSRAM." : { + "extractionState" : "stale", "localizations" : { "sr" : { "stringUnit" : { @@ -28901,6 +28921,9 @@ } } } + }, + "Store and forward servers require an ESP32 device with PSRAM or Linux Native." : { + }, "storeforward.heartbeat" : { "localizations" : { diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 47db7ebd..64cb2b9f 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -811,11 +811,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate case .serialApp: Logger.mesh.info("🕸️ MESH PACKET received for Serial App UNHANDLED UNHANDLED") case .storeForwardApp: - if wantStoreAndForwardPackets { - storeAndForwardPacket(packet: decodedInfo.packet, connectedNodeNum: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context) - } else { - Logger.mesh.info("🕸️ MESH PACKET received for Store and Forward App - Store and Forward is disabled.") - } + storeAndForwardPacket(packet: decodedInfo.packet, connectedNodeNum: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context) case .rangeTestApp: if wantRangeTestPackets { textMessageAppPacket( diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 093066ef..e47f462f 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -898,11 +898,14 @@ func textMessageAppPacket( if packet.decoded.replyID > 0 { newMessage.replyID = Int64(packet.decoded.replyID) } + // Updated logic for handling toUser if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != Constants.maximumNodeNum { if !storeForwardBroadcast { newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to }) + } else if storeForwardBroadcast { + // For S&F broadcast messages, treat as a channel message (not a DM) + newMessage.toUser = nil } else { - /// Make a new to user if they are unknown newMessage.toUser = createUser(num: Int64(truncatingIfNeeded: packet.to), context: context) } } @@ -961,7 +964,7 @@ func textMessageAppPacket( appState.unreadDirectMessages = newMessage.toUser?.unreadMessages ?? 0 } if !(newMessage.fromUser?.mute ?? false) { - // Create an iOS Notification for the received DM message and schedule it immediately + // Create an iOS Notification for the received DM message let manager = LocalNotificationManager() manager.notifications = [ Notification( @@ -983,18 +986,16 @@ func textMessageAppPacket( } else if newMessage.fromUser != nil && newMessage.toUser == nil { let fetchMyInfoRequest = MyInfoEntity.fetchRequest() fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode)) - do { let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) if !fetchedMyInfo.isEmpty { appState.unreadChannelMessages = fetchedMyInfo[0].unreadMessages - for channel in (fetchedMyInfo[0].channels?.array ?? []) as? [ChannelEntity] ?? [] { if channel.index == newMessage.channel { context.refresh(channel, mergeChanges: true) } if channel.index == newMessage.channel && !channel.mute && UserDefaults.channelMessageNotifications { - // Create an iOS Notification for the received private channel message and schedule it immediately + // Create an iOS Notification for the received channel message let manager = LocalNotificationManager() manager.notifications = [ Notification( @@ -1007,7 +1008,8 @@ func textMessageAppPacket( messageId: newMessage.messageId, channel: newMessage.channel, userNum: Int64(newMessage.fromUser?.userId ?? "0"), - critical: critical) + critical: critical + ) ] manager.schedule() Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)") diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 49.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 49.xcdatamodel/contents index 9e23de8a..03e88490 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 49.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 49.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -373,7 +373,8 @@ - + + diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 0c367968..3a169b17 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -1363,6 +1363,7 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi newConfig.records = Int32(config.records) newConfig.historyReturnMax = Int32(config.historyReturnMax) newConfig.historyReturnWindow = Int32(config.historyReturnWindow) + newConfig.isServer = config.isServer fetchedNode[0].storeForwardConfig = newConfig } else { fetchedNode[0].storeForwardConfig?.enabled = config.enabled diff --git a/Meshtastic/Views/Messages/MessageText.swift b/Meshtastic/Views/Messages/MessageText.swift index df5b1f3d..f444b8d8 100644 --- a/Meshtastic/Views/Messages/MessageText.swift +++ b/Meshtastic/Views/Messages/MessageText.swift @@ -37,14 +37,28 @@ struct MessageText: View { HStack { Spacer() Image(systemName: "lock.circle.fill") - .symbolRenderingMode(.palette) - .foregroundStyle(.white, .green) - .font(.system(size: 20)) - .offset(x: 8, y: 8) + .symbolRenderingMode(.palette) + .foregroundStyle(.white, .green) + .font(.system(size: 20)) + .offset(x: 8, y: 8) } } } + let isStoreAndForward = message.portNum == Int32(PortNum.storeForwardApp.rawValue) let isDetectionSensorMessage = message.portNum == Int32(PortNum.detectionSensorApp.rawValue) + if isStoreAndForward { + VStack(alignment: .trailing) { + Spacer() + HStack { + Spacer() + Image(systemName: "envelope.circle.fill") + .symbolRenderingMode(.palette) + .foregroundStyle(.white, .gray) + .font(.system(size: 20)) + .offset(x: 8, y: 8) + } + } + } if tapBackDestination.overlaySensorMessage { VStack { isDetectionSensorMessage ? Image(systemName: "sensor.fill") @@ -59,6 +73,7 @@ struct MessageText: View { } else { EmptyView() } + } .contextMenu { MessageContextMenuItems( diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index f0718ac2..ee1359c1 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -18,8 +18,8 @@ struct StoreForwardConfig: View { @State var hasChanges: Bool = false /// Enable the Store and Forward Module @State var enabled = false - /// Is a S&F Router - @State var isRouter = false + /// Is a S&F Server + @State var isServer = false /// Send a Heartbeat @State var heartbeat: Bool = false /// Number of Records @@ -35,43 +35,19 @@ struct StoreForwardConfig: View { ConfigHeader(title: "Store & Forward", config: \.storeForwardConfig, node: node, onAppear: setStoreAndForwardValues) Section(header: Text("options")) { - Toggle(isOn: $enabled) { Label("enabled", systemImage: "envelope.arrow.triangle.branch") - Text("Enables the store and forward module. Store and forward must be enabled on both client and router devices.") + Text("Enables the store and forward module.") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) .listRowSeparator(.visible) - if enabled { - HStack { - Picker(selection: $isRouter, label: Text("Role")) { - Text("Client") - .tag(false) - Text("Router") - .tag(true) - } - .pickerStyle(SegmentedPickerStyle()) - .padding(.top, 5) - .padding(.bottom, 5) - } - VStack { - if isRouter { - Text("Store and forward router devices require a ESP32 device with PSRAM.") - .foregroundColor(.gray) - .font(.callout) - } else { - Text("Store and forward clients can request history from routers on the network.") - .foregroundColor(.gray) - .font(.callout) - } - } - } } - if isRouter { - Section(header: Text("Router Options")) { + if enabled { + Section(header: Text("Settings")) { Toggle(isOn: $heartbeat) { Label("storeforward.heartbeat", systemImage: "waveform.path.ecg") + Text("Send a heartbeat to advertise the server's presence.") } Picker("Number of records", selection: $records) { Text("unset").tag(0) @@ -81,7 +57,7 @@ struct StoreForwardConfig: View { Text("100").tag(100) } .pickerStyle(DefaultPickerStyle()) - Picker("History Return Max", selection: $historyReturnMax ) { + Picker("History Return Max", selection: $historyReturnMax) { Text("unset").tag(0) Text("25").tag(25) Text("50").tag(50) @@ -89,7 +65,7 @@ struct StoreForwardConfig: View { Text("100").tag(100) } .pickerStyle(DefaultPickerStyle()) - Picker("History Return Window", selection: $historyReturnWindow ) { + Picker("History Return Window", selection: $historyReturnWindow) { Text("unset").tag(0) Text("One Minute").tag(60) Text("Five Minutes").tag(300) @@ -101,6 +77,20 @@ struct StoreForwardConfig: View { } .pickerStyle(DefaultPickerStyle()) } + + Section(header: Text("Server Option")) { + Toggle(isOn: $isServer) { + Label("Server", systemImage: "server.rack") + Text("Enable this device as a Store and Forward server. Requires an ESP32 device with PSRAM.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .listRowSeparator(.visible) + if isServer { + Text("Store and forward servers require an ESP32 device with PSRAM or Linux Native.") + .foregroundColor(.gray) + .font(.callout) + } + } } } .scrollDismissesKeyboard(.interactively) @@ -110,18 +100,19 @@ struct StoreForwardConfig: View { SaveConfigButton(node: node, hasChanges: $hasChanges) { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context) if connectedNode != nil { - /// Let the user set isRouter for the connected node, for nodes on the mesh set isRouter based + /// Let the user set isServer for the connected node, for nodes on the mesh set isServer based /// on receipt of a primary heartbeat if connectedNode?.num ?? 0 == node?.num ?? -1 { - connectedNode?.storeForwardConfig?.isRouter = isRouter + connectedNode?.storeForwardConfig?.isServer = isServer do { try context.save() } catch { - Logger.mesh.error("Failed to save isRouter: \(error.localizedDescription)") + Logger.mesh.error("Failed to save isServer: \(error.localizedDescription)") } } var sfc = ModuleConfig.StoreForwardConfig() + sfc.isServer = isServer sfc.enabled = self.enabled sfc.heartbeat = self.heartbeat sfc.records = UInt32(self.records) @@ -171,8 +162,8 @@ struct StoreForwardConfig: View { .onChange(of: enabled) { oldEnabled, newEnabled in if oldEnabled != newEnabled && newEnabled != node!.storeForwardConfig!.enabled { hasChanges = true } } - .onChange(of: isRouter) { oldIsRouter, newIsRouter in - if oldIsRouter != newIsRouter && newIsRouter != node!.storeForwardConfig!.isRouter { hasChanges = true } + .onChange(of: isServer) { oldIsServer, newIsServer in + if oldIsServer != newIsServer && newIsServer != node!.storeForwardConfig!.isServer { hasChanges = true } } .onChange(of: heartbeat) { oldHeartbeat, newHeartbeat in if oldHeartbeat != newHeartbeat && newHeartbeat != node?.storeForwardConfig?.heartbeat ?? true { hasChanges = true } @@ -187,9 +178,10 @@ struct StoreForwardConfig: View { if oldHistoryReturnWindow != newHistoryReturnWindow && newHistoryReturnWindow != node!.storeForwardConfig?.historyReturnWindow ?? -1 { hasChanges = true } } } + func setStoreAndForwardValues() { self.enabled = (node?.storeForwardConfig?.enabled ?? false) - self.isRouter = (node?.storeForwardConfig?.isRouter ?? false) + self.isServer = (node?.storeForwardConfig?.isServer ?? false) self.heartbeat = (node?.storeForwardConfig?.heartbeat ?? true) self.records = Int(node?.storeForwardConfig?.records ?? 50) self.historyReturnMax = Int(node?.storeForwardConfig?.historyReturnMax ?? 100) From 360906f31d35c627af057e7c8bba94042f8dbf20 Mon Sep 17 00:00:00 2001 From: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Date: Sat, 15 Mar 2025 00:05:09 -0700 Subject: [PATCH 04/14] Revert read all --- Meshtastic/Views/Messages/ChannelMessageList.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 7753ddbb..573a7dc8 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -113,10 +113,8 @@ struct ChannelMessageList: View { .id(message.messageId) .onAppear { if !message.read { + message.read = true do { - for unreadMessage in channel.allPrivateMessages.filter({ !$0.read }) { - unreadMessage.read = true - } try context.save() Logger.data.info("📖 [App] Read message \(message.messageId) ") appState.unreadChannelMessages = myInfo.unreadMessages From 0d647616e2f6e8acf67af1db96636f6fa4cc0e06 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 30 Mar 2025 22:25:32 -0700 Subject: [PATCH 05/14] Bump version back --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 3156850d..e5e362e5 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1845,7 +1845,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.21; + MARKETING_VERSION = 2.5.22; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1879,7 +1879,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.21; + MARKETING_VERSION = 2.5.22; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1911,7 +1911,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.21; + MARKETING_VERSION = 2.5.22; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1944,7 +1944,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.21; + MARKETING_VERSION = 2.5.22; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From ea39adac26826fca5084cb856ed388c3b71d1c02 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 31 Mar 2025 22:06:00 -0700 Subject: [PATCH 06/14] Add OSLog Redacttion attributes --- Meshtastic.xcodeproj/project.pbxproj | 40 -- Meshtastic/AppIntents/AppIntentErrors.swift | 2 +- Meshtastic/Helpers/BLEManager.swift | 54 +-- .../Helpers/LocalNotificationManager.swift | 2 +- Meshtastic/Helpers/LocationsHandler.swift | 2 +- Meshtastic/Helpers/MeshPackets.swift | 58 +-- Meshtastic/MeshtasticApp.swift | 12 +- Meshtastic/MeshtasticAppDelegate.swift | 4 +- .../MetricsSeriesList.swift | 2 - Meshtastic/Persistence/Persistence.swift | 6 +- Meshtastic/Persistence/UpdateCoreData.swift | 54 +-- Meshtastic/Router/Router.swift | 2 +- Meshtastic/Views/Bluetooth/Connect.swift | 6 +- .../Weather/LocalWeatherConditions.swift | 2 +- .../Helpers/Weather/NodeWeatherForecast.swift | 2 +- .../Views/MapKitMap/Custom/MapButtons.swift | 64 --- .../Custom/MapViewFitExtension.swift | 37 -- .../MapKitMap/Custom/MapViewSwiftUI.swift | 434 ------------------ .../MapKitMap/Custom/TileDownloadStatus.swift | 14 - .../Views/MapKitMap/NodeMapMapkit.swift | 164 ------- .../Views/MapKitMap/WaypointFormMapKit.swift | 266 ----------- .../Views/Messages/ChannelMessageList.swift | 4 +- Meshtastic/Views/Messages/MessageText.swift | 2 +- Meshtastic/Views/Messages/RetryButton.swift | 4 +- .../Views/Messages/TapbackResponses.swift | 4 +- .../Views/Messages/UserMessageList.swift | 4 +- .../Views/Nodes/DetectionSensorLog.swift | 2 +- Meshtastic/Views/Nodes/DeviceMetricsLog.swift | 4 +- .../Views/Nodes/EnvironmentMetricsLog.swift | 2 +- .../Helpers/Actions/DeleteNodeButton.swift | 4 +- .../Helpers/Actions/NavigateToButton.swift | 18 +- Meshtastic/Views/Nodes/MeshMap.swift | 2 +- Meshtastic/Views/Nodes/NodeList.swift | 2 +- Meshtastic/Views/Nodes/PaxCounterLog.swift | 4 +- Meshtastic/Views/Nodes/PositionLog.swift | 2 +- Meshtastic/Views/Nodes/PowerMetricsLog.swift | 4 +- Meshtastic/Views/Nodes/TraceRouteLog.swift | 2 +- Meshtastic/Views/Settings/AppLog.swift | 2 +- Meshtastic/Views/Settings/Channels.swift | 8 +- .../Views/Settings/Config/LoRaConfig.swift | 1 - .../Settings/Config/Module/MQTTConfig.swift | 2 +- .../Config/Module/StoreForwardConfig.swift | 2 +- .../Settings/Config/PositionConfig.swift | 4 +- Meshtastic/Views/Settings/FirmwareApi.swift | 4 +- Meshtastic/Views/Settings/RouteRecorder.swift | 7 +- Meshtastic/Views/Settings/Routes.swift | 14 +- 46 files changed, 154 insertions(+), 1181 deletions(-) delete mode 100644 Meshtastic/Views/MapKitMap/Custom/MapButtons.swift delete mode 100644 Meshtastic/Views/MapKitMap/Custom/MapViewFitExtension.swift delete mode 100644 Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift delete mode 100644 Meshtastic/Views/MapKitMap/Custom/TileDownloadStatus.swift delete mode 100644 Meshtastic/Views/MapKitMap/NodeMapMapkit.swift delete mode 100644 Meshtastic/Views/MapKitMap/WaypointFormMapKit.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index e5e362e5..58e2baa5 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -73,7 +73,6 @@ D93068DB2B81C85E0066FBC8 /* PowerConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068DA2B81C85E0066FBC8 /* PowerConfig.swift */; }; D93068DD2B81CA820066FBC8 /* ConfigHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068DC2B81CA820066FBC8 /* ConfigHeader.swift */; }; D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93069072B81DF040066FBC8 /* SaveConfigButton.swift */; }; - D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9BC22DA2B7DE8E2006A37D5 /* TileDownloadStatus.swift */; }; D9C9839D2B79CFD700BDBE6A /* TextMessageSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */; }; D9C983A02B79D0E800BDBE6A /* AlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C9839F2B79D0E800BDBE6A /* AlertButton.swift */; }; D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C983A12B79D1A600BDBE6A /* RequestPositionButton.swift */; }; @@ -99,7 +98,6 @@ DD2553572855B02500E55709 /* LoRaConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553562855B02500E55709 /* LoRaConfig.swift */; }; DD2553592855B52700E55709 /* PositionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553582855B52700E55709 /* PositionConfig.swift */; }; DD268D8E2BCC90E2008073AE /* RouteEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD268D8D2BCC90E2008073AE /* RouteEnums.swift */; }; - DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */; }; DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD33DB612B3D27C7003E1EA0 /* FirmwareApi.swift */; }; DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; }; DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD354FD82BD96A0B0061A25F /* IAQScale.swift */; }; @@ -153,9 +151,7 @@ DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD93800D2BA74D0C008BEC06 /* ChannelForm.swift */; }; DD94B7402ACCE3BE00DCD1D1 /* MapSettingsForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD94B73F2ACCE3BE00DCD1D1 /* MapSettingsForm.swift */; }; DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FBC296E6B01007C176F /* EmojiOnlyTextField.swift */; }; - DD964FBF296E76EF007C176F /* WaypointFormMapKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FBE296E76EF007C176F /* WaypointFormMapKit.swift */; }; DD964FC2297272AE007C176F /* WaypointEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */; }; - DD964FC42974767D007C176F /* MapViewFitExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC32974767D007C176F /* MapViewFitExtension.swift */; }; DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC52975DBFD007C176F /* QueryCoreData.swift */; }; DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */; }; DD97E96828EFE9A00056DDA4 /* About.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96728EFE9A00056DDA4 /* About.swift */; }; @@ -212,8 +208,6 @@ DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26412AABF655003AFCB7 /* NodeListItem.swift */; }; DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */; }; DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */; }; - DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26472AACD6D1003AFCB7 /* NodeMapMapkit.swift */; }; - DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443529F6287000EE2349 /* MapButtons.swift */; }; DDDB444029F79AB000EE2349 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443F29F79AB000EE2349 /* UserDefaults.swift */; }; DDDB444229F8A88700EE2349 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB444129F8A88700EE2349 /* Double.swift */; }; DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB444329F8A8DD00EE2349 /* Float.swift */; }; @@ -344,7 +338,6 @@ D93068DC2B81CA820066FBC8 /* ConfigHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigHeader.swift; sourceTree = ""; }; D93069062B81D8900066FBC8 /* MeshtasticDataModelV 27.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 27.xcdatamodel"; sourceTree = ""; }; D93069072B81DF040066FBC8 /* SaveConfigButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveConfigButton.swift; sourceTree = ""; }; - D9BC22DA2B7DE8E2006A37D5 /* TileDownloadStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileDownloadStatus.swift; sourceTree = ""; }; D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageSize.swift; sourceTree = ""; }; D9C9839F2B79D0E800BDBE6A /* AlertButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertButton.swift; sourceTree = ""; }; D9C983A12B79D1A600BDBE6A /* RequestPositionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestPositionButton.swift; sourceTree = ""; }; @@ -379,7 +372,6 @@ DD268D8D2BCC90E2008073AE /* RouteEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteEnums.swift; sourceTree = ""; }; DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = ""; }; DD2984A82C5AEF7500B1268D /* MeshtasticDataModelV 41.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 41.xcdatamodel"; sourceTree = ""; }; - DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = ""; }; DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = ""; }; DD31B04D2BDC6FD30024FA63 /* MeshtasticDataModelV 36.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 36.xcdatamodel"; sourceTree = ""; }; DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 23.xcdatamodel"; sourceTree = ""; }; @@ -451,10 +443,8 @@ DD93800D2BA74D0C008BEC06 /* ChannelForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelForm.swift; sourceTree = ""; }; DD94B73F2ACCE3BE00DCD1D1 /* MapSettingsForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapSettingsForm.swift; sourceTree = ""; }; DD964FBC296E6B01007C176F /* EmojiOnlyTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiOnlyTextField.swift; sourceTree = ""; }; - DD964FBE296E76EF007C176F /* WaypointFormMapKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointFormMapKit.swift; sourceTree = ""; }; DD964FC029724F6D007C176F /* MeshtasticDataModelV6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV6.xcdatamodel; sourceTree = ""; }; DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointEntityExtension.swift; sourceTree = ""; }; - DD964FC32974767D007C176F /* MapViewFitExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewFitExtension.swift; sourceTree = ""; }; DD964FC52975DBFD007C176F /* QueryCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryCoreData.swift; sourceTree = ""; }; DD9681A22BBB22BE00FD2C47 /* MeshtasticDataModelV32.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV32.xcdatamodel; sourceTree = ""; }; DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticLogo.swift; sourceTree = ""; }; @@ -528,9 +518,7 @@ DDDB26412AABF655003AFCB7 /* NodeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListItem.swift; sourceTree = ""; }; DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = ""; }; DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoItem.swift; sourceTree = ""; }; - DDDB26472AACD6D1003AFCB7 /* NodeMapMapkit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMapMapkit.swift; sourceTree = ""; }; DDDB26492AAD743E003AFCB7 /* MeshtasticDataModelV18.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV18.xcdatamodel; sourceTree = ""; }; - DDDB443529F6287000EE2349 /* MapButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapButtons.swift; sourceTree = ""; }; DDDB443F29F79AB000EE2349 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; DDDB444129F8A88700EE2349 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; }; DDDB444329F8A8DD00EE2349 /* Float.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = ""; }; @@ -702,27 +690,6 @@ path = AppIntents; sourceTree = ""; }; - C9483F6B2773016700998F6B /* MapKitMap */ = { - isa = PBXGroup; - children = ( - C9A7BC0E27759A6800760B50 /* Custom */, - DDDB26472AACD6D1003AFCB7 /* NodeMapMapkit.swift */, - DD964FBE296E76EF007C176F /* WaypointFormMapKit.swift */, - ); - path = MapKitMap; - sourceTree = ""; - }; - C9A7BC0E27759A6800760B50 /* Custom */ = { - isa = PBXGroup; - children = ( - DD964FC32974767D007C176F /* MapViewFitExtension.swift */, - DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */, - DDDB443529F6287000EE2349 /* MapButtons.swift */, - D9BC22DA2B7DE8E2006A37D5 /* TileDownloadStatus.swift */, - ); - path = Custom; - sourceTree = ""; - }; D9C9839E2B79D0C600BDBE6A /* TextMessageField */ = { isa = PBXGroup; children = ( @@ -1023,7 +990,6 @@ isa = PBXGroup; children = ( DD6D5A312CA1176A00ED3032 /* Layouts */, - C9483F6B2773016700998F6B /* MapKitMap */, DDC2E18D26CE25CB0042C5E4 /* Helpers */, DD47E3D726F2F21A00029299 /* Bluetooth */, DDC2E18B26CE25A70042C5E4 /* Messages */, @@ -1415,11 +1381,9 @@ DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */, D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */, DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */, - DD964FBF296E76EF007C176F /* WaypointFormMapKit.swift in Sources */, DDD5BB182C2F9C36007E03CA /* OSLogEntryLog.swift in Sources */, DD3501892852FC3B000FC853 /* Settings.swift in Sources */, DDDC22382BA92344002C44F1 /* MeshMapContent.swift in Sources */, - DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */, DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */, 6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */, DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */, @@ -1464,7 +1428,6 @@ DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */, DDDB445429F8AD1600EE2349 /* Data.swift in Sources */, DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */, - DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */, DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */, DD6193792863875F00E59241 /* SerialConfig.swift in Sources */, DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */, @@ -1474,7 +1437,6 @@ B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */, DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */, 233E99C32D849D7A00CC3A77 /* WeightCompactWidget.swift in Sources */, - DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */, DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */, DD1BD0F32C63C65E008C0C70 /* SecurityConfig.swift in Sources */, DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */, @@ -1518,7 +1480,6 @@ D93068DB2B81C85E0066FBC8 /* PowerConfig.swift in Sources */, D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */, DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */, - DD964FC42974767D007C176F /* MapViewFitExtension.swift in Sources */, BCE2D3C72C7B0D0A008E6199 /* ShortcutsProvider.swift in Sources */, DD47E3D626F17ED900029299 /* CircleText.swift in Sources */, DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */, @@ -1537,7 +1498,6 @@ D93068DD2B81CA820066FBC8 /* ConfigHeader.swift in Sources */, 251926872C3BAE2200249DF5 /* NodeAlertsButton.swift in Sources */, DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */, - D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */, DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */, BC5EBA3C2D002A2000C442FF /* MessageNodeIntent.swift in Sources */, DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */, diff --git a/Meshtastic/AppIntents/AppIntentErrors.swift b/Meshtastic/AppIntents/AppIntentErrors.swift index 427c30ae..9732de12 100644 --- a/Meshtastic/AppIntents/AppIntentErrors.swift +++ b/Meshtastic/AppIntents/AppIntentErrors.swift @@ -16,7 +16,7 @@ class AppIntentErrors { var localizedStringResource: LocalizedStringResource { switch self { case let .message(message): - Logger.services.error("App Intent: \(message)") + Logger.services.error("App Intent: \(message,privacy: .public)") return "Error: \(message)" case .notConnected: Logger.services.error("App Intent: No Connected Node") diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 7077a26d..2d42094c 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -119,7 +119,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate self.isConnected = false self.isConnecting = false self.lastConnectionError = "🚨 " + String.localizedStringWithFormat("Connection failed after %d attempts to connect to %@. You may need to forget your device under Settings > Bluetooth.".localized, timeoutTimerCount, name) - Logger.services.error("\(self.lastConnectionError)") + Logger.services.error("\(self.lastConnectionError, privacy: .public)") self.timeoutTimerCount = 0 self.startScanning() } else { @@ -295,7 +295,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } else { // Disconnected without error which indicates user intent to disconnect // Happens when swiping to disconnect - Logger.services.info("ℹ️ [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public): \(String(describing: "User Initiated Disconnect".localized))") + Logger.services.info("ℹ️ [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public): \(String(describing: "User Initiated Disconnect".localized), privacy: .public)") } // Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake self.startScanning() @@ -485,7 +485,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } let logString = String.localizedStringWithFormat("mesh.log.traceroute.sent %@".localized, destNum.toHex()) - Logger.mesh.info("🪧 \(logString)") + Logger.mesh.info("🪧 \(logString, privacy: .public)") } catch { @@ -498,14 +498,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate guard connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected else { return } if FROMRADIO_characteristic == nil { - Logger.mesh.error("🚨 \("firmware.version.unsupported".localized)") + Logger.mesh.error("🚨 \("firmware.version.unsupported".localized, privacy: .public)") invalidVersion = true return } else { let nodeName = connectedPeripheral?.peripheral.name ?? "unknown".localized let logString = String.localizedStringWithFormat("mesh.log.wantconfig %@".localized, nodeName) - Logger.mesh.info("🛎️ \(logString)") + Logger.mesh.info("🛎️ \(logString, privacy: .public)") // BLE Characteristics discovered, issue wantConfig var toRadio: ToRadio = ToRadio() configNonce += 1 @@ -750,7 +750,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } } // Log any other unknownApp calls - if !nowKnown { Logger.mesh.info("🕸️ MESH PACKET received for Unknown App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") } + if !nowKnown { Logger.mesh.info("🕸️ MESH PACKET received for Unknown App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") } case .textMessageApp, .detectionSensorApp: textMessageAppPacket( packet: decodedInfo.packet, @@ -769,7 +769,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate appState: appState ) case .remoteHardwareApp: - Logger.mesh.info("🕸️ MESH PACKET received for Remote Hardware App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received for Remote Hardware App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") case .positionApp: upsertPositionPacket(packet: decodedInfo.packet, context: context) case .waypointApp: @@ -971,33 +971,33 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate Logger.data.error("Error Updating Core Data TraceRouteHop: \(nsError, privacy: .public)") } let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.route %@".localized, routeString) - Logger.mesh.info("🪧 \(logString)") + Logger.mesh.info("🪧 \(logString, privacy: .public)") } case .neighborinfoApp: if let neighborInfo = try? NeighborInfo(serializedBytes: decodedInfo.packet.decoded.payload) { - Logger.mesh.info("🕸️ MESH PACKET received for Neighbor Info App UNHANDLED \((try? neighborInfo.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received for Neighbor Info App UNHANDLED \((try? neighborInfo.jsonString()) ?? "JSON Decode Failure", privacy: .public)") } case .paxcounterApp: paxCounterPacket(packet: decodedInfo.packet, context: context) case .mapReportApp: - Logger.mesh.info("🕸️ MESH PACKET received Map Report App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received Map Report App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") case .UNRECOGNIZED: - Logger.mesh.info("🕸️ MESH PACKET received UNRECOGNIZED App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received UNRECOGNIZED App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") case .max: Logger.services.info("MAX PORT NUM OF 511") case .atakPlugin: - Logger.mesh.info("🕸️ MESH PACKET received for ATAK Plugin App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received for ATAK Plugin App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") case .powerstressApp: - Logger.mesh.info("🕸️ MESH PACKET received for Power Stress App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received for Power Stress App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") case .reticulumTunnelApp: - Logger.mesh.info("🕸️ MESH PACKET received for Reticulum Tunnel App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.info("🕸️ MESH PACKET received for Reticulum Tunnel App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)") } if decodedInfo.configCompleteID != 0 && decodedInfo.configCompleteID == configNonce { invalidVersion = false lastConnectionError = "" isSubscribed = true - Logger.mesh.info("🤜 [BLE] Want Config Complete. ID:\(decodedInfo.configCompleteID)") + Logger.mesh.info("🤜 [BLE] Want Config Complete. ID:\(decodedInfo.configCompleteID, privacy: .public)") if sendTime() { } peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected }) @@ -1031,7 +1031,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } } catch { - Logger.data.error("Failed to find a node info for the connected node \(error.localizedDescription)") + Logger.data.error("Failed to find a node info for the connected node \(error.localizedDescription, privacy: .public)") } } @@ -1075,7 +1075,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } let nodeName = connectedPeripheral?.peripheral.name ?? "unknown".localized let logString = String.localizedStringWithFormat("mesh.log.textmessage.send.failed %@".localized, nodeName) - Logger.mesh.info("🚫 \(logString)") + Logger.mesh.info("🚫 \(logString, privacy: .public)") success = false } else if message.count < 1 { @@ -1162,7 +1162,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) let logString = String.localizedStringWithFormat("mesh.log.textmessage.sent %@ %@ %@".localized, String(newMessage.messageId), fromUserNum.toHex(), toUserNum.toHex()) - Logger.mesh.info("💬 \(logString)") + Logger.mesh.info("💬 \(logString, privacy: .public)") do { try context.save() Logger.data.info("💾 Saved a new sent message from \(self.connectedPeripheral.num.toHex(), privacy: .public) to \(toUserNum.toHex(), privacy: .public)") @@ -1209,7 +1209,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate return false } let logString = String.localizedStringWithFormat("mesh.log.waypoint.sent %@".localized, String(fromNodeNum)) - Logger.mesh.info("📍 \(logString)") + Logger.mesh.info("📍 \(logString, privacy: .public)") if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) success = true @@ -1373,7 +1373,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) let logString = String.localizedStringWithFormat("mesh.log.sharelocation %@".localized, String(fromNodeNum)) - Logger.services.debug("📍 \(logString)") + Logger.services.debug("📍 \(logString, privacy: .public)") return true } else { Logger.services.error("Device no longer connected. Unable to send position information.") @@ -1689,7 +1689,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } } } catch { - Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription)") + Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription, privacy: .public)") } } @@ -1728,7 +1728,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse) let logString = String.localizedStringWithFormat("mesh.log.channel.sent %@ %d".localized, String(connectedPeripheral.num), chan.index) - Logger.mesh.info("🎛️ \(logString)") + Logger.mesh.info("🎛️ \(logString, privacy: .public)") } } // Save the LoRa Config and the device will reboot @@ -1757,7 +1757,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse) let logString = String.localizedStringWithFormat("mesh.log.lora.config.sent %@".localized, String(connectedPeripheral.num)) - Logger.mesh.info("📻 \(logString)") + Logger.mesh.info("📻 \(logString, privacy: .public)") } if self.connectedPeripheral != nil { @@ -1834,7 +1834,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } catch { context.rollback() let nsError = error as NSError - Logger.data.error("🚫 Error deleting node from core data: \(nsError)") + Logger.data.error("🚫 Error deleting node from core data: \(nsError, privacy: .public)") } } return false @@ -2677,7 +2677,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.get %@".localized, String(connectedPeripheral.num)) - Logger.mesh.info("🥫 \(logString)") + Logger.mesh.info("🥫 \(logString, privacy: .public)") return true } @@ -3257,7 +3257,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected { connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) - Logger.mesh.debug("\(adminDescription)") + Logger.mesh.debug("\(adminDescription, privacy: .public)") return true } return false @@ -3454,7 +3454,7 @@ extension BLEManager: CBCentralManagerDelegate { default: status = "default" } - Logger.services.info("📜 [BLE] Bluetooth status: \(status)") + Logger.services.info("📜 [BLE] Bluetooth status: \(status, privacy: .public)") } // Called each time a peripheral is discovered diff --git a/Meshtastic/Helpers/LocalNotificationManager.swift b/Meshtastic/Helpers/LocalNotificationManager.swift index d5f25749..c51a2af3 100644 --- a/Meshtastic/Helpers/LocalNotificationManager.swift +++ b/Meshtastic/Helpers/LocalNotificationManager.swift @@ -75,7 +75,7 @@ class LocalNotificationManager { UNUserNotificationCenter.current().add(request) { error in if let error { - Logger.services.error("Error Scheduling Notification: \(error.localizedDescription)") + Logger.services.error("Error Scheduling Notification: \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index 6754891c..5d4293a8 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -69,7 +69,7 @@ import OSLog } } } catch { - Logger.services.error("💥 [App] Could not start location updates: \(error.localizedDescription)") + Logger.services.error("💥 [App] Could not start location updates: \(error.localizedDescription, privacy: .public)") } return } diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index a52580df..15580c4e 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -104,7 +104,7 @@ func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNu func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedObjectContext) -> MyInfoEntity? { let logString = String.localizedStringWithFormat("mesh.log.myinfo %@".localized, String(myInfo.myNodeNum)) - Logger.mesh.info("ℹ️ \(logString)") + Logger.mesh.info("ℹ️ \(logString, privacy: .public)") let fetchMyInfoRequest = MyInfoEntity.fetchRequest() fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum)) @@ -155,7 +155,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled { let logString = String.localizedStringWithFormat("mesh.log.channel.received %d %@".localized, channel.index, String(fromNum)) - Logger.mesh.info("🎛️ \(logString)") + Logger.mesh.info("🎛️ \(logString, privacy: .public)") let fetchedMyInfoRequest = MyInfoEntity.fetchRequest() fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum) @@ -194,7 +194,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo } catch { Logger.data.error("💥 Failed to save channel: \(error.localizedDescription, privacy: .public)") } - Logger.data.info("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)") + Logger.data.info("💾 Updated MyInfo channel \(channel.index, privacy: .public) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum, privacy: .public)") } else if channel.role.rawValue > 0 { Logger.data.error("💥Trying to save a channel to a MyInfo that does not exist: \(fromNum.toHex(), privacy: .public)") } @@ -210,7 +210,7 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, sessionPass if metadata.isInitialized { let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, fromNum.toHex()) - Logger.mesh.info("🏷️ \(logString)") + Logger.mesh.info("🏷️ \(logString, privacy: .public)") let fetchedNodeRequest = NodeInfoEntity.fetchRequest() fetchedNodeRequest.predicate = NSPredicate(format: "num == %lld", fromNum) @@ -262,7 +262,7 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, sessionPass func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? { let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, String(nodeInfo.num)) - Logger.mesh.info("📟 \(logString)") + Logger.mesh.info("📟 \(logString, privacy: .public)") guard nodeInfo.num > 0 else { return nil } @@ -350,12 +350,12 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje } do { try context.save() - Logger.data.info("💾 Saved a new Node Info For: \(String(nodeInfo.num))") + Logger.data.info("💾 Saved a new Node Info For: \(String(nodeInfo.num), privacy: .public)") return newNode } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError)") + Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError, privacy: .public)") } } catch { Logger.data.error("Fetch MyInfo Error") @@ -473,7 +473,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { if !cmmc.messages.isEmpty { let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, packet.from.toHex()) - Logger.mesh.info("🥫 \(logString)") + Logger.mesh.info("🥫 \(logString, privacy: .public)") let fetchNodeRequest = NodeInfoEntity.fetchRequest() fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from)) @@ -548,7 +548,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { let ringtone = adminMessage.getRingtoneResponse upsertRtttlConfigPacket(ringtone: ringtone, nodeNum: Int64(packet.from), context: context) } else { - Logger.mesh.error("🕸️ MESH PACKET received Admin App UNHANDLED \((try? packet.decoded.jsonString()) ?? "JSON Decode Failure")") + Logger.mesh.error("🕸️ MESH PACKET received Admin App UNHANDLED \((try? packet.decoded.jsonString()) ?? "JSON Decode Failure", privacy: .public)") } // Save an ack for the admin message log for each admin message response received as we stopped sending acks if there is also a response to reduce airtime. adminResponseAck(packet: packet, context: context) @@ -573,17 +573,17 @@ func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) { do { try context.save() } catch { - Logger.data.error("Failed to save admin message response as an ack: \(error.localizedDescription)") + Logger.data.error("Failed to save admin message response as an ack: \(error.localizedDescription, privacy: .public)") } } } catch { - Logger.data.error("Failed to fetch admin message by requestID: \(error.localizedDescription)") + Logger.data.error("Failed to fetch admin message by requestID: \(error.localizedDescription, privacy: .public)") } } func paxCounterPacket (packet: MeshPacket, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.paxcounter %@".localized, String(packet.from)) - Logger.mesh.info("🧑‍🤝‍🧑 \(logString)") + Logger.mesh.info("🧑‍🤝‍🧑 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from)) @@ -608,7 +608,7 @@ func paxCounterPacket (packet: MeshPacket, context: NSManagedObjectContext) { do { try context.save() } catch { - Logger.data.error("Failed to save pax: \(error.localizedDescription)") + Logger.data.error("Failed to save pax: \(error.localizedDescription, privacy: .public)") } } else { Logger.data.info("Node Info Not Found") @@ -627,7 +627,7 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana let routingErrorString = routingError?.display ?? "unknown".localized let logString = String.localizedStringWithFormat("mesh.log.routing.message %@ %@".localized, String(packet.decoded.requestID), routingErrorString) - Logger.mesh.info("🕸️ \(logString)") + Logger.mesh.info("🕸️ \(logString, privacy: .public)") let fetchMessageRequest = MessageEntity.fetchRequest() fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID)) @@ -674,11 +674,11 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana return } try context.save() - Logger.data.info("💾 ACK Saved for Message: \(packet.decoded.requestID)") + Logger.data.info("💾 ACK Saved for Message: \(packet.decoded.requestID, privacy: .public)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving ACK for message: \(packet.id) Error: \(nsError)") + Logger.data.error("Error Saving ACK for message: \(packet.id, privacy: .public) Error: \(nsError, privacy: .public)") } } } @@ -688,7 +688,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage if let telemetryMessage = try? Telemetry(serializedBytes: packet.decoded.payload) { let logString = String.localizedStringWithFormat("mesh.log.telemetry.received %@".localized, String(packet.from)) - Logger.mesh.info("📈 \(logString)") + Logger.mesh.info("📈 \(logString, privacy: .public)") if telemetryMessage.variant != Telemetry.OneOf_Variant.deviceMetrics(telemetryMessage.deviceMetrics) && telemetryMessage.variant != Telemetry.OneOf_Variant.environmentMetrics(telemetryMessage.environmentMetrics) && telemetryMessage.variant != Telemetry.OneOf_Variant.localStats(telemetryMessage.localStats) && telemetryMessage.variant != Telemetry.OneOf_Variant.powerMetrics(telemetryMessage.powerMetrics) { /// Other unhandled telemetry packets @@ -782,7 +782,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage } try context.save() - Logger.data.info("💾 [TelemetryEntity] of type \(MetricsTypes(rawValue: Int(telemetry.metricsType))?.name ?? "Unknown Metrics Type") Saved for Node: \(packet.from.toHex())") + Logger.data.info("💾 [TelemetryEntity] of type \(MetricsTypes(rawValue: Int(telemetry.metricsType))?.name ?? "Unknown Metrics Type", privacy: .public) Saved for Node: \(packet.from.toHex(), privacy: .public)") if telemetry.metricsType == 0 { // Connected Device Metrics // ------------------------ @@ -883,7 +883,7 @@ func textMessageAppPacket( } if messageText?.count ?? 0 > 0 { - Logger.mesh.info("💬 \("mesh.log.textmessage.received".localized)") + Logger.mesh.info("💬 \("mesh.log.textmessage.received".localized, privacy: .public)") let messageUsers = UserEntity.fetchRequest() messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from]) do { @@ -959,7 +959,7 @@ func textMessageAppPacket( var messageSaved = false do { try context.save() - Logger.data.info("💾 Saved a new message for \(newMessage.messageId)") + Logger.data.info("💾 Saved a new message for \(newMessage.messageId, privacy: .public)") messageSaved = true if messageSaved { @@ -989,7 +989,7 @@ func textMessageAppPacket( ) ] manager.schedule() - Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)") + Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized, privacy: .public)") } } else if newMessage.fromUser != nil && newMessage.toUser == nil { let fetchMyInfoRequest = MyInfoEntity.fetchRequest() @@ -1021,7 +1021,7 @@ func textMessageAppPacket( critical: critical) ] manager.schedule() - Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)") + Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized, privacy: .public)") } } } @@ -1033,7 +1033,7 @@ func textMessageAppPacket( } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Failed to save new MessageEntity \(nsError)") + Logger.data.error("Failed to save new MessageEntity \(nsError, privacy: .public)") } } catch { Logger.data.error("Fetch Message To and From Users Error") @@ -1044,7 +1044,7 @@ func textMessageAppPacket( func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.waypoint.received %@".localized, String(packet.from)) - Logger.mesh.info("📍 \(logString)") + Logger.mesh.info("📍 \(logString, privacy: .public)") let fetchWaypointRequest = WaypointEntity.fetchRequest() fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(packet.id)) @@ -1071,7 +1071,7 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) { waypoint.created = Date() do { try context.save() - Logger.data.info("💾 Added Node Waypoint App Packet For: \(waypoint.id)") + Logger.data.info("💾 Added Node Waypoint App Packet For: \(waypoint.id, privacy: .public)") let manager = LocalNotificationManager() let icon = String(UnicodeScalar(Int(waypoint.icon)) ?? "📍") let latitude = Double(waypoint.latitudeI) / 1e7 @@ -1086,12 +1086,12 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) { path: "meshtastic:///map?waypointid=\(waypoint.id)" ) ] - Logger.data.debug("meshtastic:///map?waypointid=\(waypoint.id)") + Logger.data.debug("meshtastic:///map?waypointid=\(waypoint.id, privacy: .public)") manager.schedule() } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving WaypointEntity from WAYPOINT_APP \(nsError)") + Logger.data.error("Error Saving WaypointEntity from WAYPOINT_APP \(nsError, privacy: .public)") } } else { fetchedWaypoint[0].id = Int64(packet.id) @@ -1109,11 +1109,11 @@ func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) { fetchedWaypoint[0].lastUpdated = Date() do { try context.save() - Logger.data.info("💾 Updated Node Waypoint App Packet For: \(fetchedWaypoint[0].id)") + Logger.data.info("💾 Updated Node Waypoint App Packet For: \(fetchedWaypoint[0].id, privacy: .public)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving WaypointEntity from WAYPOINT_APP \(nsError)") + Logger.data.error("Error Saving WaypointEntity from WAYPOINT_APP \(nsError, privacy: .public)") } } } diff --git a/Meshtastic/MeshtasticApp.swift b/Meshtastic/MeshtasticApp.swift index b7b28f35..3569a292 100644 --- a/Meshtastic/MeshtasticApp.swift +++ b/Meshtastic/MeshtasticApp.swift @@ -55,7 +55,7 @@ struct MeshtasticAppleApp: App { .presentationDragIndicator(.visible) } .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in - Logger.mesh.debug("URL received \(userActivity)") + Logger.mesh.debug("URL received \(userActivity, privacy: .public)") self.incomingUrl = userActivity.webpageURL if (self.incomingUrl?.absoluteString.lowercased().contains("meshtastic.org/e/#")) != nil { @@ -72,18 +72,18 @@ struct MeshtasticAppleApp: App { } self.channelSettings = cs } - Logger.services.debug("Add Channel \(self.addChannels)") + Logger.services.debug("Add Channel \(self.addChannels, privacy: .public)") } self.saveChannels = true Logger.mesh.debug("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")") } if self.saveChannels { - Logger.mesh.debug("User wants to open Channel Settings URL: \(String(describing: self.incomingUrl!.relativeString))") + Logger.mesh.debug("User wants to open Channel Settings URL: \(String(describing: self.incomingUrl!.relativeString), privacy: .public)") } } .onOpenURL(perform: { (url) in - Logger.mesh.debug("Some sort of URL was received \(url)") + Logger.mesh.debug("Some sort of URL was received \(url, privacy: .public)") self.incomingUrl = url if url.absoluteString.lowercased().contains("meshtastic.org/e/#") { if let components = self.incomingUrl?.absoluteString.components(separatedBy: "#") { @@ -99,10 +99,10 @@ struct MeshtasticAppleApp: App { } self.channelSettings = cs } - Logger.services.debug("Add Channel \(self.addChannels)") + Logger.services.debug("Add Channel \(self.addChannels, privacy: .public)") } self.saveChannels = true - Logger.mesh.debug("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link")") + Logger.mesh.debug("User wants to open a Channel Settings URL: \(self.incomingUrl?.absoluteString ?? "No QR Code Link", privacy: .public)") } else if url.absoluteString.lowercased().contains("meshtastic:///") { appState.router.route(url: url) } diff --git a/Meshtastic/MeshtasticAppDelegate.swift b/Meshtastic/MeshtasticAppDelegate.swift index 801fa955..365faef4 100644 --- a/Meshtastic/MeshtasticAppDelegate.swift +++ b/Meshtastic/MeshtasticAppDelegate.swift @@ -97,10 +97,10 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat if let targetValue = userInfo["target"] as? String, let deepLink = userInfo["path"] as? String, let url = URL(string: deepLink) { - Logger.services.info("userNotificationCenter didReceiveResponse \(targetValue) \(deepLink)") + Logger.services.info("userNotificationCenter didReceiveResponse \(targetValue, privacy: .public) \(deepLink, privacy: .public)") router?.route(url: url) } else { - Logger.services.error("Failed to handle notification response: \(userInfo)") + Logger.services.error("Failed to handle notification response: \(userInfo, privacy: .public)") } completionHandler() } diff --git a/Meshtastic/Model/Metrics Visualization/MetricsSeriesList.swift b/Meshtastic/Model/Metrics Visualization/MetricsSeriesList.swift index 46ec6258..fb68af92 100644 --- a/Meshtastic/Model/Metrics Visualization/MetricsSeriesList.swift +++ b/Meshtastic/Model/Metrics Visualization/MetricsSeriesList.swift @@ -94,7 +94,6 @@ class MetricsSeriesList: ObservableObject, RandomAccessCollection, RangeReplacea if let minimumSpan = aSeries.minumumYAxisSpan, let currentRange = range[aSeries] { let currentSpan = currentRange.upperBound - currentRange.lowerBound - //Logger.data.info("Updated \(aSeries.id) to \(range[aSeries] ?? 0...0) span=\(currentSpan)") if currentSpan < minimumSpan { // Calculate the center of the range let centerOfRange = currentRange.lowerBound + (currentSpan / 2) @@ -118,7 +117,6 @@ class MetricsSeriesList: ObservableObject, RandomAccessCollection, RangeReplacea return globalLower...globalUpper } - // Collection conformance typealias Index = Int typealias Element = MetricsChartSeries diff --git a/Meshtastic/Persistence/Persistence.swift b/Meshtastic/Persistence/Persistence.swift index e86278e3..f18a8566 100644 --- a/Meshtastic/Persistence/Persistence.swift +++ b/Meshtastic/Persistence/Persistence.swift @@ -48,7 +48,7 @@ class PersistenceController { if let error = error as NSError? { - Logger.data.error("CoreData Error: \(error.localizedDescription). Now attempting to truncate CoreData database. All app data will be lost.") + Logger.data.error("CoreData Error: \(error.localizedDescription, privacy: .public). Now attempting to truncate CoreData database. All app data will be lost.") self.clearDatabase() } }) @@ -65,11 +65,11 @@ class PersistenceController { do { try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil) } catch let error { - Logger.data.error("Failed to re-create CoreData database: \(error.localizedDescription)") + Logger.data.error("Failed to re-create CoreData database: \(error.localizedDescription, privacy: .public)") } } catch let error { - Logger.data.error("Failed to destroy CoreData database, delete the app and re-install to clear data. Attempted to clear persistent store: \(error.localizedDescription)") + Logger.data.error("Failed to destroy CoreData database, delete the app and re-install to clear data. Attempted to clear persistent store: \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 5e90cd9e..0b7af975 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -85,7 +85,7 @@ public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObje } try context.save() } catch let error as NSError { - Logger.data.error("\(error.localizedDescription)") + Logger.data.error("\(error.localizedDescription, privacy: .public)") } } @@ -98,7 +98,7 @@ public func deleteUserMessages(user: UserEntity, context: NSManagedObjectContext } try context.save() } catch let error as NSError { - Logger.data.error("\(error.localizedDescription)") + Logger.data.error("\(error.localizedDescription, privacy: .public)") } } @@ -122,7 +122,7 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext, includeRoutes do { try context.executeAndMergeChanges(using: deleteRequest) } catch { - Logger.data.error("\(error.localizedDescription)") + Logger.data.error("\(error.localizedDescription, privacy: .public)") } } } @@ -130,7 +130,7 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext, includeRoutes func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, packet.from.toHex()) - Logger.mesh.info("📟 \(logString)") + Logger.mesh.info("📟 \(logString, privacy: .public)") guard packet.from > 0 else { return } @@ -313,7 +313,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.position.received %@".localized, String(packet.from)) - Logger.mesh.info("📍 \(logString)") + Logger.mesh.info("📍 \(logString, privacy: .public)") let fetchNodePositionRequest = NodeInfoEntity.fetchRequest() fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from)) @@ -407,7 +407,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.bluetooth.config %@".localized, String(nodeNum)) - Logger.mesh.info("📶 \(logString)") + Logger.mesh.info("📶 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -451,7 +451,7 @@ func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.device.config %@".localized, String(nodeNum)) - Logger.mesh.info("📟 \(logString)") + Logger.mesh.info("📟 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -506,7 +506,7 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessi func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.display.config %@".localized, nodeNum.toHex()) - Logger.data.info("🖥️ \(logString)") + Logger.data.info("🖥️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -551,19 +551,15 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses Logger.data.info("💾 [DisplayConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") } catch { - context.rollback() - let nsError = error as NSError Logger.data.error("💥 [DisplayConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)") } } else { - - Logger.data.error("💥 [DisplayConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex()) unable to save Display Config") + Logger.data.error("💥 [DisplayConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Display Config") } } catch { - let nsError = error as NSError Logger.data.error("💥 [DisplayConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)") } @@ -572,7 +568,7 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.lora.config %@".localized, nodeNum.toHex()) - Logger.data.info("📻 \(logString)") + Logger.data.info("📻 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", nodeNum) @@ -643,7 +639,7 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPa func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.network.config %@".localized, String(nodeNum)) - Logger.data.info("🌐 \(logString)") + Logger.data.info("🌐 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -692,7 +688,7 @@ func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, ses func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.position.config %@".localized, String(nodeNum)) - Logger.data.info("🗺️ \(logString)") + Logger.data.info("🗺️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -755,7 +751,7 @@ func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, s func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.power.config %@".localized, String(nodeNum)) - Logger.data.info("🗺️ \(logString)") + Logger.data.info("🗺️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -807,7 +803,7 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, session func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.security.config %@".localized, String(nodeNum)) - Logger.data.info("🛡️ \(logString)") + Logger.data.info("🛡️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -868,7 +864,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, s func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightingConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.ambientlighting.config %@".localized, String(nodeNum)) - Logger.data.info("🏮 \(logString)") + Logger.data.info("🏮 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -921,7 +917,7 @@ func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightin func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.cannedmessage.config %@".localized, String(nodeNum)) - Logger.data.info("🥫 \(logString)") + Logger.data.info("🥫 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -980,7 +976,7 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSensorConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.detectionsensor.config %@".localized, String(nodeNum)) - Logger.data.info("🕵️ \(logString)") + Logger.data.info("🕵️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1037,7 +1033,7 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.externalnotification.config %@".localized, String(nodeNum)) - Logger.data.info("📣 \(logString)") + Logger.data.info("📣 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1106,7 +1102,7 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.paxcounter.config %@".localized, String(nodeNum)) - Logger.data.info("🧑‍🤝‍🧑 \(logString)") + Logger.data.info("🧑‍🤝‍🧑 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1148,7 +1144,7 @@ func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, n func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.ringtone.config %@".localized, String(nodeNum)) - Logger.data.info("⛰️ \(logString)") + Logger.data.info("⛰️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1188,7 +1184,7 @@ func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, sessionPasskey: D func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.mqtt.config %@".localized, String(nodeNum)) - Logger.data.info("🌉 \(logString)") + Logger.data.info("🌉 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1250,7 +1246,7 @@ func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int6 func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.rangetest.config %@".localized, String(nodeNum)) - Logger.data.info("⛰️ \(logString)") + Logger.data.info("⛰️ \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1294,7 +1290,7 @@ func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nod func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.serial.config %@".localized, String(nodeNum)) - Logger.data.info("🤖 \(logString)") + Logger.data.info("🤖 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1349,7 +1345,7 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.storeforward.config %@".localized, String(nodeNum)) - Logger.data.info("📬 \(logString)") + Logger.data.info("📬 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -1397,7 +1393,7 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.telemetry.config %@".localized, String(nodeNum)) - Logger.data.info("📈 \(logString)") + Logger.data.info("📈 \(logString, privacy: .public)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) diff --git a/Meshtastic/Router/Router.swift b/Meshtastic/Router/Router.swift index 718c71b1..8ba39609 100644 --- a/Meshtastic/Router/Router.swift +++ b/Meshtastic/Router/Router.swift @@ -44,7 +44,7 @@ class Router: ObservableObject { } else if components.path.hasPrefix("/settings") { routeSettings(components) } else { - Logger.services.warning("Failed to route url: \(url)") + Logger.services.warning("Failed to route url: \(url, privacy: .public)") } } diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 81672c10..880faf8d 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -35,7 +35,7 @@ struct Connect: View { if success { Logger.services.info("Notifications are all set!") } else if let error = error { - Logger.services.error("\(error.localizedDescription)") + Logger.services.error("\(error.localizedDescription, privacy: .public)") } } } @@ -324,7 +324,7 @@ struct Connect: View { isUnsetRegion = false } } catch { - Logger.data.error("💥 Error fetching node info: \(error.localizedDescription)") + Logger.data.error("💥 Error fetching node info: \(error.localizedDescription, privacy: .public)") } } } @@ -361,7 +361,7 @@ struct Connect: View { pushType: nil) Logger.services.info("Requested MyActivity live activity. ID: \(myActivity.id)") } catch { - Logger.services.error("Error requesting live activity: \(error.localizedDescription)") + Logger.services.error("Error requesting live activity: \(error.localizedDescription, privacy: .public)") } } diff --git a/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift b/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift index c2879aec..6682f18c 100644 --- a/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift +++ b/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift @@ -64,7 +64,7 @@ struct LocalWeatherConditions: View { attributionLogo = colorScheme == .light ? attribution.combinedMarkLightURL : attribution.combinedMarkDarkURL } } catch { - Logger.services.error("Could not gather weather information: \(error.localizedDescription)") + Logger.services.error("Could not gather weather information: \(error.localizedDescription, privacy: .public)") condition = .clear symbolName = "cloud.fill" } diff --git a/Meshtastic/Views/Helpers/Weather/NodeWeatherForecast.swift b/Meshtastic/Views/Helpers/Weather/NodeWeatherForecast.swift index 5fec377e..53f19a0f 100644 --- a/Meshtastic/Views/Helpers/Weather/NodeWeatherForecast.swift +++ b/Meshtastic/Views/Helpers/Weather/NodeWeatherForecast.swift @@ -35,7 +35,7 @@ struct NodeWeatherForecastView: View { ) }) } catch { - Logger.services.error("Could not load weather: \(error.localizedDescription)") + Logger.services.error("Could not load weather: \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Views/MapKitMap/Custom/MapButtons.swift b/Meshtastic/Views/MapKitMap/Custom/MapButtons.swift deleted file mode 100644 index 89959f74..00000000 --- a/Meshtastic/Views/MapKitMap/Custom/MapButtons.swift +++ /dev/null @@ -1,64 +0,0 @@ -// -//// MapButtons.swift -//// Meshtastic -//// -//// Copyright © Garth Vander Houwen 4/23/23. -//// -// -//import SwiftUI -// -//struct MapButtons: View { -// let buttonWidth: CGFloat = 22 -// let width: CGFloat = 45 -// @Binding var tracking: UserTrackingModes -// @Binding var isPresentingInfoSheet: Bool -// var body: some View { -// VStack { -// let impactLight = UIImpactFeedbackGenerator(style: .light) -// Button(action: { -// self.isPresentingInfoSheet.toggle() -// }) { -// Image(systemName: isPresentingInfoSheet ? "info.circle.fill" : "info.circle") -// .resizable() -// .frame(width: buttonWidth, height: buttonWidth, alignment: .center) -// .offset(y: -2) -// } -// Divider() -// Button(action: { -// switch self.tracking { -// case .none: -// self.tracking = .follow -// case .follow: -// self.tracking = .followWithHeading -// case .followWithHeading: -// self.tracking = .none -// } -// impactLight.impactOccurred() -// }) { -// Image(systemName: tracking.icon) -// .frame(width: buttonWidth, height: buttonWidth, alignment: .center) -// .offset(y: 3) -// } -// } -// .frame(width: width, height: width*2, alignment: .center) -// .background(Color(UIColor.systemBackground)) -// .cornerRadius(8) -// .shadow(radius: 1) -// .offset(x: 3, y: 25) -// } -//} -// -//// MARK: Previews -//// struct MapControl_Previews: PreviewProvider { -//// @State static var tracking: UserTrackingModes = .none -//// @State static var isPresentingInfoSheet = false -//// static var previews: some View { -//// Group { -//// MapButtons(tracking: $tracking, isPresentingInfoSheet: $isPresentingInfoSheet) -//// .environment(\.colorScheme, .light) -//// MapButtons(tracking: $tracking, isPresentingInfoSheet: $isPresentingInfoSheet) -//// .environment(\.colorScheme, .dark) -//// } -//// .previewLayout(.fixed(width: 60, height: 100)) -//// } -//// } diff --git a/Meshtastic/Views/MapKitMap/Custom/MapViewFitExtension.swift b/Meshtastic/Views/MapKitMap/Custom/MapViewFitExtension.swift deleted file mode 100644 index a5c8ef63..00000000 --- a/Meshtastic/Views/MapKitMap/Custom/MapViewFitExtension.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// MapViewFitExtension.swift -// Meshtastic -// -// Created by Garth Vander Houwen on 1/15/23. -// - -import MapKit - -extension MKMapView { - - func fitAllAnnotations(with padding: UIEdgeInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)) { - var zoomRect: MKMapRect = .null - annotations.forEach({ - let annotationPoint = MKMapPoint($0.coordinate) - let pointRect = MKMapRect(x: annotationPoint.x, y: annotationPoint.y, width: 0.01, height: 0.01) - zoomRect = zoomRect.union(pointRect) - }) - - setVisibleMapRect(zoomRect, edgePadding: padding, animated: true) - } - - func fit(annotations: [MKAnnotation], andShow show: Bool, with padding: UIEdgeInsets = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)) { - var zoomRect: MKMapRect = .null - annotations.forEach({ - let aPoint = MKMapPoint($0.coordinate) - let rect = MKMapRect(x: aPoint.x, y: aPoint.y, width: 0.1, height: 0.1) - zoomRect = zoomRect.isNull ? rect : zoomRect.union(rect) - }) - - if show { - addAnnotations(annotations) - } - - setVisibleMapRect(zoomRect, edgePadding: padding, animated: true) - } -} diff --git a/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift deleted file mode 100644 index 8cdf6d84..00000000 --- a/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift +++ /dev/null @@ -1,434 +0,0 @@ -//// -//// MapViewSwitUI.swift -//// Meshtastic -//// -//// Copyright(c) Josh Pirihi & Garth Vander Houwen 1/16/22. -// -//import Foundation -//import SwiftUI -//import MapKit -//import OSLog -// -//struct PolygonInfo: Codable { -// let stroke: String? -// let strokeWidth, strokeOpacity: Int? -// let fill: String? -// let fillOpacity: Double? -// let title, subtitle: String? -//} -// -//func degreesToRadians(_ number: Double) -> Double { -// return number * .pi / 180 -//} -//var currentMapLayer: MapLayer? -// -//struct MapViewSwiftUI: UIViewRepresentable { -// var onLongPress: (_ waypointCoordinate: CLLocationCoordinate2D) -> Void -// var onWaypointEdit: (_ waypointId: Int ) -> Void -// let mapView = MKMapView() -// // Parameters -// let selectedMapLayer: MapLayer -// let selectedWeatherLayer: MapOverlayServer = UserDefaults.mapOverlayServer -// let positions: [PositionEntity] -// let waypoints: [WaypointEntity] -// let userTrackingMode: MKUserTrackingMode -// let showNodeHistory: Bool -// let showRouteLines: Bool -// let mapViewType: MKMapType = MKMapType.standard -// // Offline Map Tiles -// @AppStorage("lastUpdatedLocalMapFile") private var lastUpdatedLocalMapFile = 0 -// @State private var loadedLastUpdatedLocalMapFile = 0 -// var customMapOverlay: CustomMapOverlay? -// @State private var presentCustomMapOverlayHash: CustomMapOverlay? -// // MARK: Private methods -// private func configureMap(mapView: MKMapView) { -// // Map View Parameters -// mapView.mapType = mapViewType -// mapView.addAnnotations(waypoints) -// // Do the initial map centering -// let latest = positions -// .filter { $0.latest == true } -// .sorted { $0.nodePosition?.num ?? 0 > $1.nodePosition?.num ?? -1 } -// let span = MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003) -// let center = (latest.count > 0 && userTrackingMode == MKUserTrackingMode.none) ? latest[0].coordinate : LocationHelper.currentLocation -// let region = MKCoordinateRegion(center: center, span: span) -// mapView.addAnnotations(showNodeHistory ? positions : latest) -// mapView.setRegion(region, animated: true) -// // Set user (phone gps) tracking options -// mapView.setUserTrackingMode(userTrackingMode, animated: true) -// if userTrackingMode == MKUserTrackingMode.none { -// if latest.count == 1 { -// mapView.fit(annotations: showNodeHistory ? positions: latest, andShow: false) -// } else { -// mapView.fitAllAnnotations() -// } -// mapView.showsUserLocation = false -// } else { -// mapView.showsUserLocation = true -// } -// // Other MKMapView Settings -// mapView.preferredConfiguration.elevationStyle = .realistic// .flat -// mapView.pointOfInterestFilter = MKPointOfInterestFilter.excludingAll -// mapView.isPitchEnabled = true -// mapView.isRotateEnabled = true -// mapView.isScrollEnabled = true -// mapView.isZoomEnabled = true -// mapView.showsBuildings = true -// mapView.showsScale = true -// mapView.showsTraffic = true -// -// mapView.showsCompass = false -// let compass = MKCompassButton(mapView: mapView) -// compass.translatesAutoresizingMaskIntoConstraints = false -// #if targetEnvironment(macCatalyst) -// // Show the default always visible compass and the mac only controls -// compass.compassVisibility = .visible -// mapView.addSubview(compass) -// mapView.showsZoomControls = true -// mapView.showsPitchControl = true -// compass.trailingAnchor.constraint(equalTo: mapView.trailingAnchor, constant: -115).isActive = true -// compass.bottomAnchor.constraint(equalTo: mapView.bottomAnchor, constant: -5).isActive = true -// #else -// compass.compassVisibility = .adaptive -// mapView.addSubview(compass) -// compass.trailingAnchor.constraint(equalTo: mapView.trailingAnchor, constant: -5).isActive = true -// compass.topAnchor.constraint(equalTo: mapView.topAnchor, constant: 145).isActive = true -// #endif -// } -// private func setMapBaseLayer(mapView: MKMapView) { -// // Avoid refreshing UI if selectedLayer has not changed -// guard currentMapLayer != selectedMapLayer else { return } -// currentMapLayer = selectedMapLayer -// for overlay in mapView.overlays where overlay is MKTileOverlay { -// mapView.removeOverlay(overlay) -// } -// switch selectedMapLayer { -// case .offline: -// mapView.mapType = .standard -// let overlay = TileOverlay() -// overlay.canReplaceMapContent = false -// overlay.minimumZ = UserDefaults.mapTileServer.zoomRange.startIndex -// overlay.maximumZ = UserDefaults.mapTileServer.zoomRange.endIndex -// mapView.addOverlay(overlay, level: UserDefaults.mapTilesAboveLabels ? .aboveLabels : .aboveRoads) -// case .satellite: -// mapView.mapType = .satellite -// case .hybrid: -// mapView.mapType = .hybrid -// default: -// mapView.mapType = .standard -// } -// } -// private func setMapOverlays(mapView: MKMapView) { -// // Weather radar -// if UserDefaults.enableOverlayServer { -// let locale = Locale.current -// if locale.region?.identifier ?? "no locale" == "US" { -// let overlay = MKTileOverlay(urlTemplate: selectedWeatherLayer.tileUrl) -// overlay.canReplaceMapContent = false -// overlay.minimumZ = selectedWeatherLayer.zoomRange.startIndex -// overlay.maximumZ = selectedWeatherLayer.zoomRange.endIndex -// mapView.addOverlay(overlay, level: .aboveLabels) -// } -// } -// } -// -// func makeUIView(context: Context) -> MKMapView { -// currentMapLayer = nil -// mapView.delegate = context.coordinator -// self.configureMap(mapView: mapView) -// return mapView -// } -// func updateUIView(_ mapView: MKMapView, context: Context) { -// // Set selected map base layer -// setMapBaseLayer(mapView: mapView) -// // Set map tile server and weather overlay layers -// setMapOverlays(mapView: mapView) -// let latest = positions -// .filter { $0.latest == true } -// .sorted { $0.nodePosition?.num ?? 0 > $1.nodePosition?.num ?? -1 } -// // Node Route Lines -// if showRouteLines { -// // Remove all existing PolyLine Overlays -// for overlay in mapView.overlays where overlay is MKPolyline { -// mapView.removeOverlay(overlay) -// } -// var lineIndex = 0 -// for position in latest { -// let nodePositions = positions.filter { $0.nodeCoordinate != nil && $0.nodePosition?.num ?? 0 == position.nodePosition?.num ?? -1 } -// let lineCoords = nodePositions.compactMap({(position) -> CLLocationCoordinate2D in -// return position.nodeCoordinate ?? LocationHelper.DefaultLocation -// }) -// let polyline = MKPolyline(coordinates: lineCoords, count: nodePositions.count) -// polyline.title = "\(String(position.nodePosition?.num ?? 0))" -// mapView.addOverlay(polyline, level: .aboveLabels) -// lineIndex += 1 -// // There are 18 colors for lines, start over if we are at index 17 -// if lineIndex > 17 { -// lineIndex = 0 -// } -// } -// } else { -// // Remove all existing PolyLine Overlays -// for overlay in mapView.overlays where overlay is MKPolyline { -// mapView.removeOverlay(overlay) -// } -// } -// let annotationCount = waypoints.count + (showNodeHistory ? positions.count : latest.count) -// if annotationCount != mapView.annotations.count { -// Logger.services.info("Annotation Count: \(annotationCount) Map Annotations: \(mapView.annotations.count)") -// mapView.removeAnnotations(mapView.annotations) -// mapView.addAnnotations(waypoints) -// } -// mapView.addAnnotations(showNodeHistory ? positions : latest) -// if userTrackingMode == MKUserTrackingMode.none { -// mapView.showsUserLocation = false -// if UserDefaults.enableMapRecentering { -// if latest.count == 1 { -// mapView.fit(annotations: showNodeHistory ? positions : latest, andShow: true) -// } else { -// mapView.fitAllAnnotations() -// } -// } -// } else { -// mapView.showsUserLocation = true -// } -// mapView.setUserTrackingMode(userTrackingMode, animated: true) -// } -// func makeCoordinator() -> MapCoordinator { -// return Coordinator(self) -// } -// final class MapCoordinator: NSObject, MKMapViewDelegate, UIGestureRecognizerDelegate { -// var parent: MapViewSwiftUI -// var longPressRecognizer = UILongPressGestureRecognizer() -// init(_ parent: MapViewSwiftUI) { -// self.parent = parent -// super.init() -// self.longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler)) -// self.longPressRecognizer.minimumPressDuration = 0.5 -// self.longPressRecognizer.cancelsTouchesInView = true -// self.longPressRecognizer.delegate = self -// self.parent.mapView.addGestureRecognizer(longPressRecognizer) -// } -// func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { -// switch annotation { -// case let positionAnnotation as PositionEntity: -// let reuseID = String(positionAnnotation.nodePosition?.num ?? 0) + "-" + String(positionAnnotation.time?.timeIntervalSince1970 ?? 0) -// let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "node") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: reuseID ) -// annotationView.tag = -1 -// annotationView.canShowCallout = true -// if positionAnnotation.latest { -// annotationView.markerTintColor = UIColor(hex: UInt32(positionAnnotation.nodePosition?.num ?? 0)).darker() -// annotationView.displayPriority = .required -// annotationView.titleVisibility = .visible -// } else { -// annotationView.markerTintColor = UIColor(hex: UInt32(positionAnnotation.nodePosition?.num ?? 0)).lighter() -// annotationView.displayPriority = .defaultHigh -// annotationView.titleVisibility = .adaptive -// } -// annotationView.tag = -1 -// annotationView.canShowCallout = true -// annotationView.titleVisibility = .adaptive -// let leftIcon = UIImageView(image: annotationView.glyphText?.image()) -// leftIcon.backgroundColor = UIColor(.indigo) -// annotationView.leftCalloutAccessoryView = leftIcon -// let subtitle = UILabel() -// subtitle.text = "Long Name: \(positionAnnotation.nodePosition?.user?.longName ?? "Unknown") \n" -// subtitle.text? += "Latitude: \(String(format: "%.5f", positionAnnotation.coordinate.latitude)) \n" -// subtitle.text! += "Longitude: \(String(format: "%.5f", positionAnnotation.coordinate.longitude)) \n" -// let distanceFormatter = MKDistanceFormatter() -// subtitle.text! += "Altitude: \(distanceFormatter.string(fromDistance: Double(positionAnnotation.altitude))) \n" -// if positionAnnotation.nodePosition?.metadata != nil { -// if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.client || -// DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.clientMute || -// DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.routerClient { -// annotationView.glyphImage = UIImage(systemName: "flipphone") -// } else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.repeater { -// annotationView.glyphImage = UIImage(systemName: "repeat") -// } else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.router { -// annotationView.glyphImage = UIImage(systemName: "wifi.router.fill") -// } else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.tracker { -// annotationView.glyphImage = UIImage(systemName: "location.viewfinder") -// } else if DeviceRoles(rawValue: Int(positionAnnotation.nodePosition!.metadata?.role ?? 0)) == DeviceRoles.sensor { -// annotationView.glyphImage = UIImage(systemName: "sensor") -// } -// let pf = PositionFlags(rawValue: Int(positionAnnotation.nodePosition?.metadata?.positionFlags ?? 3)) -// if pf.contains(.Satsinview) { -// subtitle.text! += "Sats in view: \(String(positionAnnotation.satsInView)) \n" -// } -// if pf.contains(.SeqNo) { -// subtitle.text! += "Sequence: \(String(positionAnnotation.seqNo)) \n" -// } -// if pf.contains(.Heading) { -// if parent.userTrackingMode != MKUserTrackingMode.followWithHeading { -// annotationView.glyphImage = UIImage(systemName: "location.north.fill")?.rotate(radians: Float(degreesToRadians(Double(positionAnnotation.heading)))) -// subtitle.text! += "Heading: \(String(positionAnnotation.heading)) \n" -// } else { -// annotationView.glyphImage = UIImage(systemName: "flipphone") -// } -// } -// if pf.contains(.Speed) { -// let formatter = MeasurementFormatter() -// formatter.locale = Locale.current -// if positionAnnotation.speed <= 1 { -// annotationView.glyphImage = UIImage(systemName: "hexagon") -// } -// subtitle.text! += "Speed: \(formatter.string(from: Measurement(value: Double(positionAnnotation.speed), unit: UnitSpeed.kilometersPerHour))) \n" -// } -// } else { -// // node metadata is nil -// annotationView.glyphImage = UIImage(systemName: "flipphone") -// } -// if LocationHelper.currentLocation.distance(from: LocationHelper.DefaultLocation) > 0.0 { -// let metersAway = positionAnnotation.coordinate.distance(from: LocationHelper.currentLocation) -// subtitle.text! += "distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway))) \n" -// } -// subtitle.text! += positionAnnotation.time?.formatted() ?? "Unknown \n" -// subtitle.numberOfLines = 0 -// annotationView.detailCalloutAccessoryView = subtitle -// let detailsIcon = UIButton(type: .detailDisclosure) -// detailsIcon.setImage(UIImage(systemName: "trash"), for: .normal) -// annotationView.rightCalloutAccessoryView = detailsIcon -// return annotationView -// case let waypointAnnotation as WaypointEntity: -// let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "waypoint") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: String(waypointAnnotation.id)) -// annotationView.tag = Int(waypointAnnotation.id) -// annotationView.isEnabled = true -// annotationView.canShowCallout = true -// if waypointAnnotation.icon == 0 { -// annotationView.glyphText = "📍" -// } else { -// annotationView.glyphText = String(UnicodeScalar(Int(waypointAnnotation.icon)) ?? "📍") -// } -// annotationView.markerTintColor = UIColor(.accentColor) -// annotationView.displayPriority = .required -// annotationView.titleVisibility = .adaptive -// let leftIcon = UIImageView(image: annotationView.glyphText?.image()) -// leftIcon.backgroundColor = UIColor(.accentColor) -// annotationView.leftCalloutAccessoryView = leftIcon -// let subtitle = UILabel() -// if waypointAnnotation.longDescription?.count ?? 0 > 0 { -// subtitle.text = (waypointAnnotation.longDescription ?? "") + "\n" -// } else { -// subtitle.text = "" -// } -// if LocationHelper.currentLocation.distance(from: LocationHelper.DefaultLocation) > 0.0 { -// let metersAway = waypointAnnotation.coordinate.distance(from: LocationHelper.currentLocation) -// let distanceFormatter = MKDistanceFormatter() -// subtitle.text! += "distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway))) \n" -// } -// if waypointAnnotation.created != nil { -// subtitle.text! += "Created: \(waypointAnnotation.created?.formatted() ?? "Unknown") \n" -// } -// if waypointAnnotation.lastUpdated != nil { -// subtitle.text! += "Updated: \(waypointAnnotation.lastUpdated?.formatted() ?? "Unknown") \n" -// } -// if waypointAnnotation.expire != nil { -// subtitle.text! += "Expires: \(waypointAnnotation.expire?.formatted() ?? "Unknown") \n" -// } -// subtitle.numberOfLines = 0 -// annotationView.detailCalloutAccessoryView = subtitle -// let editIcon = UIButton(type: .detailDisclosure) -// editIcon.setImage(UIImage(systemName: "square.and.pencil"), for: .normal) -// annotationView.rightCalloutAccessoryView = editIcon -// return annotationView -// default: return nil -// } -// } -// func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { -// switch view.annotation { -// case _ as WaypointEntity: -// // Only Allow Edit for waypoint annotations with a id -// if view.tag > 0 { -// parent.onWaypointEdit(view.tag) -// } -// default: break -// } -// } -// @objc func longPressHandler(_ gesture: UILongPressGestureRecognizer) { -// if gesture.state != UIGestureRecognizer.State.ended { -// return -// } else if gesture.state != UIGestureRecognizer.State.began { -// // Screen Position - CGPoint -// let location = longPressRecognizer.location(in: self.parent.mapView) -// // Map Coordinate - CLLocationCoordinate2D -// let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView) -// let annotation = MKPointAnnotation() -// annotation.title = "Dropped Pin" -// annotation.coordinate = coordinate -// parent.mapView.addAnnotation(annotation) -// UINotificationFeedbackGenerator().notificationOccurred(.success) -// parent.onLongPress(coordinate) -// } -// } -// public func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { -// if let tileOverlay = overlay as? MKTileOverlay { -// return MKTileOverlayRenderer(tileOverlay: tileOverlay) -// } else { -// if let routePolyline = overlay as? MKPolyline { -// let titleString = routePolyline.title ?? "0" -// let renderer = MKPolylineRenderer(polyline: routePolyline) -// renderer.strokeColor = UIColor(hex: UInt32(titleString) ?? 0).lighter() -// renderer.lineWidth = 8 -// return renderer -// } -// if let polygon = overlay as? MKPolygon { -// let renderer = MKPolygonRenderer(polygon: polygon) -// renderer.fillColor = UIColor.purple.withAlphaComponent(0.2) -// renderer.strokeColor = .purple.withAlphaComponent(0.7) -// return renderer -// } -// return MKOverlayRenderer(overlay: overlay) -// } -// } -// } -// /// is supposed to be located in the folder with the map name -// public struct DefaultTile: Hashable { -// let tileName: String -// let tileType: String -// public init(tileName: String, tileType: String) { -// self.tileName = tileName -// self.tileType = tileType -// } -// } -// public struct CustomMapOverlay: Equatable, Hashable { -// let mapName: String -// let tileType: String -// var canReplaceMapContent: Bool -// var minimumZoomLevel: Int? -// var maximumZoomLevel: Int? -// let defaultTile: DefaultTile? -// public init( -// mapName: String, -// tileType: String, -// canReplaceMapContent: Bool = true, // false for transparent tiles -// minimumZoomLevel: Int? = nil, -// maximumZoomLevel: Int? = nil, -// defaultTile: DefaultTile? = nil -// ) { -// self.mapName = mapName -// self.tileType = tileType -// self.canReplaceMapContent = canReplaceMapContent -// self.minimumZoomLevel = minimumZoomLevel -// self.maximumZoomLevel = maximumZoomLevel -// self.defaultTile = defaultTile -// } -// public init?( -// mapName: String?, -// tileType: String, -// canReplaceMapContent: Bool = true, // false for transparent tiles -// minimumZoomLevel: Int? = nil, -// maximumZoomLevel: Int? = nil, -// defaultTile: DefaultTile? = nil -// ) { -// if mapName == nil || mapName! == "" { -// return nil -// } -// self.mapName = mapName! -// self.tileType = tileType -// self.canReplaceMapContent = canReplaceMapContent -// self.minimumZoomLevel = minimumZoomLevel -// self.maximumZoomLevel = maximumZoomLevel -// self.defaultTile = defaultTile -// } -// } -//} diff --git a/Meshtastic/Views/MapKitMap/Custom/TileDownloadStatus.swift b/Meshtastic/Views/MapKitMap/Custom/TileDownloadStatus.swift deleted file mode 100644 index 07cddcb8..00000000 --- a/Meshtastic/Views/MapKitMap/Custom/TileDownloadStatus.swift +++ /dev/null @@ -1,14 +0,0 @@ -import SwiftUI - -struct TileDownloadStatus: View { - @ObservedObject var tileManager = OfflineTileManager.shared - - var body: some View { - if tileManager.status == .downloading { - Image(systemName: "arrow.down.circle.fill") - .foregroundColor(.gray) - } else { - EmptyView() - } - } -} diff --git a/Meshtastic/Views/MapKitMap/NodeMapMapkit.swift b/Meshtastic/Views/MapKitMap/NodeMapMapkit.swift deleted file mode 100644 index f9593585..00000000 --- a/Meshtastic/Views/MapKitMap/NodeMapMapkit.swift +++ /dev/null @@ -1,164 +0,0 @@ -//// -//// NodeMapControl.swift -//// Meshtastic -//// -//// Created by Garth Vander Houwen on 9/9/23. -//// -//import SwiftUI -//import CoreLocation -//import MapKit -//import WeatherKit -//import OSLog -// -//struct NodeMapMapkit: View { -// -// @Environment(\.managedObjectContext) var context -// @EnvironmentObject var bleManager: BLEManager -// /// Weather -// /// The current weather condition for the city. -// @State private var condition: WeatherCondition? -// @State private var temperature: Measurement? -// @State private var humidity: Int? -// @State private var symbolName: String = "cloud.fill" -// @State private var attributionLink: URL? -// @State private var attributionLogo: URL? -// -// @Environment(\.colorScheme) var colorScheme: ColorScheme -// @AppStorage("meshMapType") private var meshMapType = 0 -// @AppStorage("meshMapShowNodeHistory") private var meshMapShowNodeHistory = false -// @AppStorage("meshMapShowRouteLines") private var meshMapShowRouteLines = false -// @State private var selectedMapLayer: MapLayer = .standard -// @State var waypointCoordinate: WaypointCoordinate? -// @State var editingWaypoint: Int = 0 -// @State private var customMapOverlay: MapViewSwiftUI.CustomMapOverlay? = MapViewSwiftUI.CustomMapOverlay( -// mapName: "offlinemap", -// tileType: "png", -// canReplaceMapContent: true -// ) -// @FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: false)], -// predicate: NSPredicate( -// format: "expire == nil || expire >= %@", Date() as NSDate -// ), animation: .none) -// private var waypoints: FetchedResults -// @ObservedObject var node: NodeInfoEntity -// -// var body: some View { -// -// NavigationStack { -// GeometryReader { bounds in -// VStack { -// if node.hasPositions { -// ZStack { -// let positionArray = node.positions?.array as? [PositionEntity] ?? [] -// let lastTenThousand = Array(positionArray.prefix(10000)) -// // let todaysPositions = positionArray.filter { $0.time! >= Calendar.current.startOfDay(for: Date()) } -// ZStack { -// MapViewSwiftUI(onLongPress: { coord in -// waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: coord, waypointId: 0) -// }, onWaypointEdit: { wpId in -// if wpId > 0 { -// waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: nil, waypointId: Int64(wpId)) -// } -// }, -// selectedMapLayer: selectedMapLayer, -// positions: lastTenThousand, -// waypoints: Array(waypoints), -// userTrackingMode: MKUserTrackingMode.none, -// showNodeHistory: meshMapShowNodeHistory, -// showRouteLines: meshMapShowRouteLines, -// customMapOverlay: self.customMapOverlay -// ) -// VStack(alignment: .leading) { -// Spacer() -// HStack(alignment: .bottom, spacing: 1) { -// Picker("Map Type", selection: $selectedMapLayer) { -// ForEach(MapLayer.allCases, id: \.self) { layer in -// if layer == MapLayer.offline && UserDefaults.enableOfflineMaps { -// Text(layer.localized) -// } else if layer != MapLayer.offline { -// Text(layer.localized) -// } -// } -// } -// .onChange(of: (selectedMapLayer)) { newMapLayer in -// UserDefaults.mapLayer = newMapLayer -// } -// .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12, style: .continuous)) -// .pickerStyle(.menu) -// .padding(5) -// VStack { -// VStack { -// Label(temperature?.formatted(.measurement(width: .narrow)) ?? "??", systemImage: symbolName) -// .font(.caption) -// -// Label("\(humidity ?? 0)%", systemImage: "humidity") -// .font(.caption2) -// -// AsyncImage(url: attributionLogo) { image in -// image -// .resizable() -// .scaledToFit() -// } placeholder: { -// ProgressView() -// .controlSize(.mini) -// } -// .frame(height: 10) -// -// Link("Other data sources", destination: attributionLink ?? URL(string: "https://weather-data.apple.com/legal-attribution.html")!) -// .font(.caption2) -// } -// .padding(5) -// -// } -// .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12, style: .continuous)) -// .padding(5) -// .task { -// do { -// if node.hasPositions { -// let mostRecent = node.positions?.lastObject as? PositionEntity -// let weather = try await WeatherService.shared.weather(for: mostRecent?.nodeLocation ?? CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude)) -// condition = weather.currentWeather.condition -// temperature = weather.currentWeather.temperature -// humidity = Int(weather.currentWeather.humidity * 100) -// symbolName = weather.currentWeather.symbolName -// let attribution = try await WeatherService.shared.attribution -// attributionLink = attribution.legalPageURL -// attributionLogo = colorScheme == .light ? attribution.combinedMarkLightURL : attribution.combinedMarkDarkURL -// } -// } catch { -// Logger.services.error("Could not gather weather information: \(error.localizedDescription)") -// condition = .clear -// symbolName = "cloud.fill" -// } -// } -// } -// } -// } -// .ignoresSafeArea(.all, edges: [.top, .leading, .trailing]) -// .frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 1.65) -// } -// } else { -// HStack { -// } -// .padding([.top], 20) -// } -// } -// .edgesIgnoringSafeArea([.leading, .trailing]) -// .sheet(item: $waypointCoordinate, content: { wpc in -// WaypointFormMapKit(coordinate: wpc) -// .presentationDetents([.medium, .large]) -// .presentationDragIndicator(.automatic) -// }) -// .navigationBarTitle(String(node.user?.longName ?? "unknown".localized), displayMode: .inline) -// .navigationBarItems(trailing: -// ZStack { -// ConnectedDevice( -// bluetoothOn: bleManager.isSwitchedOn, -// deviceConnected: bleManager.connectedPeripheral != nil, -// name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") -// }) -// } -// .padding(.bottom, 2) -// } -// } -//} diff --git a/Meshtastic/Views/MapKitMap/WaypointFormMapKit.swift b/Meshtastic/Views/MapKitMap/WaypointFormMapKit.swift deleted file mode 100644 index 456472e0..00000000 --- a/Meshtastic/Views/MapKitMap/WaypointFormMapKit.swift +++ /dev/null @@ -1,266 +0,0 @@ -//// -//// WaypointFormView.swift -//// Meshtastic -//// -//// Copyright Garth Vander Houwen 1/10/23. -//// -// -//import CoreLocation -//import MeshtasticProtobufs -//import OSLog -//import SwiftUI -// -//struct WaypointFormMapKit: View { -// -// @EnvironmentObject var bleManager: BLEManager -// @Environment(\.dismiss) private var dismiss -// @State var coordinate: WaypointCoordinate -// @FocusState private var iconIsFocused: Bool -// @State private var name: String = "" -// @State private var description: String = "" -// @State private var icon: String = "📍" -// @State private var latitude: Double = 0 -// @State private var longitude: Double = 0 -// @State private var expires: Bool = false -// @State private var expire: Date = Date.now.addingTimeInterval(60 * 480) // 1 minute * 480 = 8 Hours -// @State private var locked: Bool = false -// @State private var lockedTo: Int64 = 0 -// -// var body: some View { -// -// Form { -// let distance = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude).distance(from: CLLocation(latitude: coordinate.coordinate?.latitude ?? 0, longitude: coordinate.coordinate?.longitude ?? 0)) -// Section(header: Text((coordinate.waypointId > 0) ? "Editing Waypoint" : "Create Waypoint")) { -// HStack { -// Text("Location: \(String(format: "%.5f", latitude) + "," + String(format: "%.5f", longitude))") -// .textSelection(.enabled) -// .foregroundColor(Color.gray) -// .font(.caption2) -// if coordinate.coordinate?.latitude ?? 0 != 0 && coordinate.coordinate?.longitude ?? 0 != 0 { -// DistanceText(meters: distance) -// .foregroundColor(Color.gray) -// .font(.caption2) -// } -// } -// HStack { -// Text("Name") -// Spacer() -// TextField( -// "Name", -// text: $name, -// axis: .vertical -// ) -// .foregroundColor(Color.gray) -// .onChange(of: name) { -// var totalBytes = name.utf8.count -// // Only mess with the value if it is too big -// while totalBytes > 30 { -// name = String(name.dropLast()) -// totalBytes = name.utf8.count -// } -// if totalBytes > 30 { -// name = String(name.dropLast()) -// } -// } -// } -// HStack { -// Text("Description") -// Spacer() -// TextField( -// "Description", -// text: $description, -// axis: .vertical -// ) -// .foregroundColor(Color.gray) -// .onChange(of: description) { -// var totalBytes = description.utf8.count -// // Only mess with the value if it is too big -// while totalBytes > 100 { -// description = String(description.dropLast()) -// totalBytes = description.utf8.count -// } -// } -// } -// HStack { -// Text("Icon") -// Spacer() -// EmojiOnlyTextField(text: $icon, placeholder: "Select an emoji") -// .font(.title) -// .focused($iconIsFocused) -// .onChange(of: icon) { _, value in -// -// // If you have anything other than emojis in your string make it empty -// if !value.onlyEmojis() { -// icon = "" -// } -// // If a second emoji is entered delete the first one -// if value.count >= 1 { -// -// if value.count > 1 { -// let index = value.index(value.startIndex, offsetBy: 1) -// icon = String(value[index]) -// } -// iconIsFocused = false -// } -// } -// -// } -// Toggle(isOn: $expires) { -// Label("Expires", systemImage: "clock.badge.xmark") -// } -// .toggleStyle(SwitchToggleStyle(tint: .accentColor)) -// if expires { -// DatePicker("Expire", selection: $expire, in: Date.now...) -// .datePickerStyle(.compact) -// .font(.callout) -// } -// Toggle(isOn: $locked) { -// Label("Locked", systemImage: "lock") -// } -// .toggleStyle(SwitchToggleStyle(tint: .accentColor)) -// } -// } -// HStack { -// Button { -// -// var newWaypoint = Waypoint() -// // Loading a waypoint from edit -// if coordinate.waypointId > 0 { -// newWaypoint.id = UInt32(coordinate.waypointId) -// let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context) -// newWaypoint.latitudeI = waypoint.latitudeI -// newWaypoint.longitudeI = waypoint.longitudeI -// } else { -// // New waypoint -// newWaypoint.id = UInt32.random(in: UInt32(UInt8.max).. 0 ? name : "Dropped Pin" -// newWaypoint.description_p = description -// // Unicode scalar value for the icon emoji string -// let unicodeScalers = icon.unicodeScalars -// // First element as an UInt32 -// let unicode = unicodeScalers[unicodeScalers.startIndex].value -// newWaypoint.icon = unicode -// if locked { -// if lockedTo == 0 { -// newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num) -// } else { -// newWaypoint.lockedTo = UInt32(lockedTo) -// } -// } -// if expires { -// newWaypoint.expire = UInt32(expire.timeIntervalSince1970) -// } else { -// newWaypoint.expire = 0 -// } -// if bleManager.sendWaypoint(waypoint: newWaypoint) { -// dismiss() -// } else { -// dismiss() -// Logger.mesh.error("Send waypoint failed") -// } -// } label: { -// Label("Send", systemImage: "arrow.up") -// } -// .buttonStyle(.bordered) -// .buttonBorderShape(.capsule) -// .controlSize(.regular) -// .disabled(bleManager.connectedPeripheral == nil) -// .padding(.bottom) -// -// Button(role: .cancel) { -// dismiss() -// } label: { -// Label("cancel", systemImage: "x.circle") -// } -// .buttonStyle(.bordered) -// .buttonBorderShape(.capsule) -// .controlSize(.regular) -// .padding(.bottom) -// -// if coordinate.waypointId > 0 { -// -// Menu { -// Button("For me", action: { -// let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context) -// bleManager.context.delete(waypoint) -// do { -// try bleManager.context.save() -// } catch { -// bleManager.context.rollback() -// } -// dismiss() }) -// Button("For everyone", action: { -// var newWaypoint = Waypoint() -// -// if coordinate.waypointId > 0 { -// newWaypoint.id = UInt32(coordinate.waypointId) -// } -// newWaypoint.name = name.count > 0 ? name : "Dropped Pin" -// newWaypoint.description_p = description -// newWaypoint.latitudeI = Int32(coordinate.coordinate?.latitude ?? 0 * 1e7) -// newWaypoint.longitudeI = Int32(coordinate.coordinate?.longitude ?? 0 * 1e7) -// // Unicode scalar value for the icon emoji string -// let unicodeScalers = icon.unicodeScalars -// // First element as an UInt32 -// let unicode = unicodeScalers[unicodeScalers.startIndex].value -// newWaypoint.icon = unicode -// if locked { -// if lockedTo == 0 { -// newWaypoint.lockedTo = UInt32(bleManager.connectedPeripheral!.num) -// } else { -// newWaypoint.lockedTo = UInt32(lockedTo) -// } -// } -// newWaypoint.expire = 1 -// if bleManager.sendWaypoint(waypoint: newWaypoint) { -// dismiss() -// } else { -// dismiss() -// Logger.mesh.error("Send waypoint failed") -// } -// }) -// } -// label: { -// Label("delete", systemImage: "trash") -// .foregroundColor(.red) -// } -// .buttonStyle(.bordered) -// .buttonBorderShape(.capsule) -// .controlSize(.regular) -// .padding(.bottom) -// } -// } -// .onAppear { -// if coordinate.waypointId > 0 { -// let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context) -// name = waypoint.name ?? "Dropped Pin" -// description = waypoint.longDescription ?? "" -// icon = String(UnicodeScalar(Int(waypoint.icon)) ?? "📍") -// latitude = Double(waypoint.latitudeI) / 1e7 -// longitude = Double(waypoint.longitudeI) / 1e7 -// if waypoint.expire != nil { -// expires = true -// expire = waypoint.expire ?? Date() -// } else { -// expires = false -// } -// if waypoint.locked > 0 { -// locked = true -// lockedTo = waypoint.locked -// } -// } else { -// name = "" -// description = "" -// locked = false -// expires = false -// expire = Date.now.addingTimeInterval(60 * 480) -// icon = "📍" -// latitude = coordinate.coordinate?.latitude ?? 0 -// longitude = coordinate.coordinate?.longitude ?? 0 -// } -// } -// } -//} diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 573a7dc8..704ac452 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -116,11 +116,11 @@ struct ChannelMessageList: View { message.read = true do { try context.save() - Logger.data.info("📖 [App] Read message \(message.messageId) ") + Logger.data.info("📖 [App] Read message \(message.messageId, privacy: .public) ") appState.unreadChannelMessages = myInfo.unreadMessages context.refresh(myInfo, mergeChanges: true) } catch { - Logger.data.error("Failed to read message \(message.messageId): \(error.localizedDescription)") + Logger.data.error("Failed to read message \(message.messageId, privacy: .public): \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Views/Messages/MessageText.swift b/Meshtastic/Views/Messages/MessageText.swift index df5b1f3d..95fcd839 100644 --- a/Meshtastic/Views/Messages/MessageText.swift +++ b/Meshtastic/Views/Messages/MessageText.swift @@ -79,7 +79,7 @@ struct MessageText: View { do { try context.save() } catch { - Logger.data.error("Failed to delete message \(message.messageId): \(error.localizedDescription)") + Logger.data.error("Failed to delete message \(message.messageId, privacy: .public): \(error.localizedDescription, privacy: .public)") } } Button("Cancel", role: .cancel) {} diff --git a/Meshtastic/Views/Messages/RetryButton.swift b/Meshtastic/Views/Messages/RetryButton.swift index afda173a..6964f1b5 100644 --- a/Meshtastic/Views/Messages/RetryButton.swift +++ b/Meshtastic/Views/Messages/RetryButton.swift @@ -37,7 +37,7 @@ struct RetryButton: View { do { try context.save() } catch { - Logger.data.error("Failed to delete message \(messageID): \(error.localizedDescription)") + Logger.data.error("Failed to delete message \(messageID, privacy: .public): \(error.localizedDescription, privacy: .public)") } if !bleManager.sendMessage( message: payload, @@ -47,7 +47,7 @@ struct RetryButton: View { replyID: replyID ) { // Best effort, unlikely since we already checked BLE state - Logger.services.warning("Failed to resend message \(messageID)") + Logger.services.warning("Failed to resend message \(messageID, privacy: .public)") } else { switch destination { case .user: diff --git a/Meshtastic/Views/Messages/TapbackResponses.swift b/Meshtastic/Views/Messages/TapbackResponses.swift index 77310184..b46e65f3 100644 --- a/Meshtastic/Views/Messages/TapbackResponses.swift +++ b/Meshtastic/Views/Messages/TapbackResponses.swift @@ -31,10 +31,10 @@ struct TapbackResponses: View { tapback.read = true do { try context.save() - Logger.data.info("📖 Read tapback \(tapback.messageId) ") + Logger.data.info("📖 Read tapback \(tapback.messageId, privacy: .public) ") onRead() } catch { - Logger.data.error("Failed to read tapback \(tapback.messageId): \(error.localizedDescription)") + Logger.data.error("Failed to read tapback \(tapback.messageId, privacy: .public): \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 68db6280..dea4586f 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -103,11 +103,11 @@ struct UserMessageList: View { message.read = true do { try context.save() - Logger.data.info("📖 [App] Read message \(message.messageId) ") + Logger.data.info("📖 [App] Read message \(message.messageId, privacy: .public) ") appState.unreadDirectMessages = user.unreadMessages } catch { - Logger.data.error("Failed to read message \(message.messageId): \(error.localizedDescription)") + Logger.data.error("Failed to read message \(message.messageId, privacy: .public): \(error.localizedDescription, privacy: .public)") } } } diff --git a/Meshtastic/Views/Nodes/DetectionSensorLog.swift b/Meshtastic/Views/Nodes/DetectionSensorLog.swift index 1eeb499e..89c62be3 100644 --- a/Meshtastic/Views/Nodes/DetectionSensorLog.swift +++ b/Meshtastic/Views/Nodes/DetectionSensorLog.swift @@ -135,7 +135,7 @@ struct DetectionSensorLog: View { self.isExporting = false Logger.services.info("Detection Sensor metrics log download succeeded.") case .failure(let error): - Logger.services.error("Detection Sensor log download failed: \(error.localizedDescription).") + Logger.services.error("Detection Sensor log download failed: \(error.localizedDescription, privacy: .public).") } } ) diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 9132d068..9ebce292 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -211,7 +211,7 @@ struct DeviceMetricsLog: View { ) { Button("device.metrics.delete", role: .destructive) { if clearTelemetry(destNum: node.num, metricsType: 0, context: context) { - Logger.data.notice("Cleared Device Metrics for \(node.num)") + Logger.data.notice("Cleared Device Metrics for \(node.num, privacy: .public)") } else { Logger.data.error("Clear Device Metrics Log Failed") } @@ -257,7 +257,7 @@ struct DeviceMetricsLog: View { self.isExporting = false Logger.services.info("Device metrics log download succeeded.") case .failure(let error): - Logger.services.error("Device metrics log download failed: \(error.localizedDescription)") + Logger.services.error("Device metrics log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index bdd544c8..7ae9bc50 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -177,7 +177,7 @@ struct EnvironmentMetricsLog: View { self.isExporting = false Logger.services.info("Environment metrics log download succeeded.") case .failure(let error): - Logger.services.error("Environment metrics log download failed: \(error.localizedDescription)") + Logger.services.error("Environment metrics log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Nodes/Helpers/Actions/DeleteNodeButton.swift b/Meshtastic/Views/Nodes/Helpers/Actions/DeleteNodeButton.swift index d6adc165..127a31d7 100644 --- a/Meshtastic/Views/Nodes/Helpers/Actions/DeleteNodeButton.swift +++ b/Meshtastic/Views/Nodes/Helpers/Actions/DeleteNodeButton.swift @@ -41,7 +41,7 @@ struct DeleteNodeButton: View { id: node.num, context: context ) else { - Logger.data.error("Unable to find node info to delete node \(node.num)") + Logger.data.error("Unable to find node info to delete node \(node.num, privacy: .public)") return } let success = bleManager.removeNode( @@ -49,7 +49,7 @@ struct DeleteNodeButton: View { connectedNodeNum: connectedNode.num ) if !success { - Logger.data.error("Failed to delete node \(deleteNode.user?.longName ?? "unknown".localized)") + Logger.data.error("Failed to delete node \(deleteNode.user?.longName ?? "unknown".localized, privacy: .public)") } else { dismiss() } diff --git a/Meshtastic/Views/Nodes/Helpers/Actions/NavigateToButton.swift b/Meshtastic/Views/Nodes/Helpers/Actions/NavigateToButton.swift index e7a3567e..78917082 100644 --- a/Meshtastic/Views/Nodes/Helpers/Actions/NavigateToButton.swift +++ b/Meshtastic/Views/Nodes/Helpers/Actions/NavigateToButton.swift @@ -19,20 +19,20 @@ struct NavigateToButton: View { Logger.services.error("NavigateToAction: Selected node does not exist") return } - - Logger.services.info("Fetching NodeInfoEntity for userNum: \(userNum)") - + + Logger.services.info("Fetching NodeInfoEntity for userNum: \(userNum, privacy: .public)") + let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "NodeInfoEntity") fetchRequest.predicate = NSPredicate(format: "num == %lld", Int64(userNum)) - + do { let fetchedNodes = try PersistenceController.shared.container.viewContext.fetch(fetchRequest) - + guard let nodeInfo = fetchedNodes.first else { - Logger.services.error("NavigateToAction: Node with userNum \(userNum) not found in Core Data") + Logger.services.error("NavigateToAction: Node with userNum \(userNum, privacy: .public) not found in Core Data") return } - + if let latitude = nodeInfo.latestPosition?.latitude, let longitude = nodeInfo.latestPosition?.longitude { if let url = URL(string: "maps://?saddr=&daddr=\(latitude),\(longitude)") { @@ -41,10 +41,10 @@ struct NavigateToButton: View { Logger.services.error("Failed to create URL for navigation") } } else { - Logger.services.warning("NavigateToAction: Node \(userNum) has invalid or missing coordinates") + Logger.services.warning("NavigateToAction: Node \(userNum, privacy: .public) has invalid or missing coordinates") } } catch { - Logger.services.error("NavigateToAction: Failed to fetch node with userNum \(userNum): \(error.localizedDescription)") + Logger.services.error("NavigateToAction: Failed to fetch node with userNum \(userNum, privacy: .public): \(error.localizedDescription, privacy: .public)") } } label: { Label { diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index 65928ba3..a0650c41 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -115,7 +115,7 @@ struct MeshMap: View { editingWaypoint!.longitudeI = Int32((newWaypointCoord?.longitude ?? 0) * 1e7) editingWaypoint!.expire = Date.now.addingTimeInterval(60 * 480) editingWaypoint!.id = 0 - Logger.services.debug("Long press occured at Lat: \(coordinate.latitude) Long: \(coordinate.longitude)") + Logger.services.debug("Long press occured at Lat: \(coordinate.latitude, privacy: .public) Long: \(coordinate.longitude, privacy: .public)") default: return } }) diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 002fc695..34dbd475 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -237,7 +237,7 @@ struct NodeList: View { if deleteNode != nil { let success = bleManager.removeNode(node: deleteNode!, connectedNodeNum: Int64(bleManager.connectedPeripheral?.num ?? -1)) if !success { - Logger.data.error("Failed to delete node \(deleteNode?.user?.longName ?? "unknown".localized)") + Logger.data.error("Failed to delete node \(deleteNode?.user?.longName ?? "unknown".localized, privacy: .public)") } } } diff --git a/Meshtastic/Views/Nodes/PaxCounterLog.swift b/Meshtastic/Views/Nodes/PaxCounterLog.swift index 6be95332..37ca7c30 100644 --- a/Meshtastic/Views/Nodes/PaxCounterLog.swift +++ b/Meshtastic/Views/Nodes/PaxCounterLog.swift @@ -176,7 +176,7 @@ struct PaxCounterLog: View { ) { Button("paxcounter.delete", role: .destructive) { if clearPax(destNum: node.num, context: context) { - Logger.services.info("Cleared Pax Counter for \(node.num)") + Logger.services.info("Cleared Pax Counter for \(node.num, privacy: .public)") } else { Logger.services.error("Clear Pax Counter Log Failed") } @@ -216,7 +216,7 @@ struct PaxCounterLog: View { self.isExporting = false Logger.services.info("PAX Counter log download succeeded") case .failure(let error): - Logger.services.error("PAX Counter log download failed: \(error.localizedDescription)") + Logger.services.error("PAX Counter log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index d5972a27..6c78d1c3 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -163,7 +163,7 @@ struct PositionLog: View { Logger.services.info("Position log download succeeded.") self.isExporting = false case .failure(let error): - Logger.services.error("Position log download failed: \(error.localizedDescription)") + Logger.services.error("Position log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Nodes/PowerMetricsLog.swift b/Meshtastic/Views/Nodes/PowerMetricsLog.swift index 3fd5582a..f3fb410a 100644 --- a/Meshtastic/Views/Nodes/PowerMetricsLog.swift +++ b/Meshtastic/Views/Nodes/PowerMetricsLog.swift @@ -243,7 +243,7 @@ struct PowerMetricsLog: View { ) { Button("Delete Power metrics?", role: .destructive) { if clearTelemetry(destNum: node.num, metricsType: 2, context: context) { - Logger.data.notice("Cleared Power Metrics for \(node.num)") + Logger.data.notice("Cleared Power Metrics for \(node.num, privacy: .public)") } else { Logger.data.error("Clear Power Metrics Log Failed") } @@ -289,7 +289,7 @@ struct PowerMetricsLog: View { self.isExporting = false Logger.services.info("Power metrics log download succeeded.") case .failure(let error): - Logger.services.error("Power metrics log download failed: \(error.localizedDescription)") + Logger.services.error("Power metrics log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Nodes/TraceRouteLog.swift b/Meshtastic/Views/Nodes/TraceRouteLog.swift index f10dad58..e4ad4add 100644 --- a/Meshtastic/Views/Nodes/TraceRouteLog.swift +++ b/Meshtastic/Views/Nodes/TraceRouteLog.swift @@ -64,7 +64,7 @@ struct TraceRouteLog: View { do { try context.save() } catch let error as NSError { - Logger.data.error("\(error.localizedDescription)") + Logger.data.error("\(error.localizedDescription, privacy: .public)") } } label: { Label("delete", systemImage: "trash") diff --git a/Meshtastic/Views/Settings/AppLog.swift b/Meshtastic/Views/Settings/AppLog.swift index b96ed806..53a32e07 100644 --- a/Meshtastic/Views/Settings/AppLog.swift +++ b/Meshtastic/Views/Settings/AppLog.swift @@ -178,7 +178,7 @@ struct AppLog: View { self.isExporting = false Logger.services.info("Application log download succeeded.") case .failure(let error): - Logger.services.error("Application log download failed: \(error.localizedDescription)") + Logger.services.error("Application log download failed: \(error.localizedDescription, privacy: .public)") } } ) diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index 6d439194..551b9ab4 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -186,11 +186,11 @@ struct Channels: View { if channel.role != Channel.Role.disabled { do { try context.save() - Logger.data.info("💾 Saved Channel: \(channel.settings.name)") + Logger.data.info("💾 Saved Channel: \(channel.settings.name, privacy: .public)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Unresolved Core Data error in the channel editor. Error: \(nsError)") + Logger.data.error("Unresolved Core Data error in the channel editor. Error: \(nsError, privacy: .public)") } } else { let objects = selectedChannel?.allPrivateMessages ?? [] @@ -203,11 +203,11 @@ struct Channels: View { context.delete(selectedChannel!) do { try context.save() - Logger.data.info("💾 Deleted Channel: \(channel.settings.name)") + Logger.data.info("💾 Deleted Channel: \(channel.settings.name, privacy: .public)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Unresolved Core Data error in the channel editor. Error: \(nsError)") + Logger.data.error("Unresolved Core Data error in the channel editor. Error: \(nsError, privacy: .public)") } } let adminMessageId = bleManager.saveChannel(channel: channel, fromUser: node!.user!, toUser: node!.user!) diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 0948f36f..20371f31 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -249,7 +249,6 @@ struct LoRaConfig: View { let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.loRaConfig == nil { Logger.mesh.info("⚙️ Empty or expired lora config requesting via PKI admin") - _ = bleManager.requestLoRaConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 765a8cab..29b06464 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -357,7 +357,7 @@ struct MQTTConfig: View { defaultTopic = "msh/" + (region?.topic ?? "UNSET") geocoder.reverseGeocodeLocation(LocationsHandler.shared.locationsArray.first!, completionHandler: {(placemarks, error) in if let error { - Logger.services.error("Failed to reverse geocode location: \(error.localizedDescription)") + Logger.services.error("Failed to reverse geocode location: \(error.localizedDescription, privacy: .public)") return } diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index f0718ac2..aa3812a9 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -117,7 +117,7 @@ struct StoreForwardConfig: View { do { try context.save() } catch { - Logger.mesh.error("Failed to save isRouter: \(error.localizedDescription)") + Logger.mesh.error("Failed to save isRouter: \(error.localizedDescription, privacy: .public)") } } diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index f963b02b..db0574c7 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -530,7 +530,7 @@ struct PositionConfig: View { } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving Position Config Entity \(nsError)") + Logger.data.error("Error Saving Position Config Entity \(nsError, privacy: .public)") } } @@ -550,7 +550,7 @@ struct PositionConfig: View { } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving Position Config Entity \(nsError)") + Logger.data.error("Error Saving Position Config Entity \(nsError, privacy: .public)") } } } diff --git a/Meshtastic/Views/Settings/FirmwareApi.swift b/Meshtastic/Views/Settings/FirmwareApi.swift index 3b64c1e9..9daae230 100644 --- a/Meshtastic/Views/Settings/FirmwareApi.swift +++ b/Meshtastic/Views/Settings/FirmwareApi.swift @@ -62,7 +62,7 @@ class Api: ObservableObject { completion(deviceHardware) } } catch { - Logger.services.error("JSON decode failure: \(error.localizedDescription)") + Logger.services.error("JSON decode failure: \(error.localizedDescription, privacy: .public)") } return } @@ -82,7 +82,7 @@ class Api: ObservableObject { completion(firmwareReleases) } } catch { - Logger.services.error("JSON decode failure: \(error.localizedDescription)") + Logger.services.error("JSON decode failure: \(error.localizedDescription, privacy: .public)") } return } diff --git a/Meshtastic/Views/Settings/RouteRecorder.swift b/Meshtastic/Views/Settings/RouteRecorder.swift index 9a5b90c5..8cee2eeb 100644 --- a/Meshtastic/Views/Settings/RouteRecorder.swift +++ b/Meshtastic/Views/Settings/RouteRecorder.swift @@ -188,7 +188,7 @@ struct RouteRecorder: View { } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving RouteEntity from the Route Recorder \(nsError)") + Logger.data.error("Error Saving RouteEntity from the Route Recorder \(nsError, privacy: .public)") } } label: { Label("start", systemImage: "play") @@ -246,7 +246,7 @@ struct RouteRecorder: View { } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving RouteEntity from the Route Recorder \(nsError)") + Logger.data.error("Error Saving RouteEntity from the Route Recorder \(nsError, privacy: .public)") } isShowingDetails = false } label: { @@ -298,11 +298,10 @@ struct RouteRecorder: View { do { try context.save() Logger.data.info("💾 Saved a new route location") - // logger.info("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving LocationEntity from the Route Recorder \(nsError)") + Logger.data.error("Error Saving LocationEntity from the Route Recorder \(nsError, privacy: .public)") } } } diff --git a/Meshtastic/Views/Settings/Routes.swift b/Meshtastic/Views/Settings/Routes.swift index 91638ab6..52b00fa0 100644 --- a/Meshtastic/Views/Settings/Routes.swift +++ b/Meshtastic/Views/Settings/Routes.swift @@ -64,7 +64,7 @@ struct Routes: View { var latIndex = -1 var longIndex = -1 for index in headers!.indices { - Logger.services.debug("\(index): \( headers![index])") + Logger.services.debug("\(index, privacy: .public): \( headers![index], privacy: .public)") if headers![index].trimmingCharacters(in: .whitespaces) == "Latitude" { latIndex = index } else if headers![index].trimmingCharacters(in: .whitespaces) == "Longitude" { @@ -94,7 +94,7 @@ struct Routes: View { do { try context.save() } catch let error as NSError { - Logger.services.error("\(error.localizedDescription)") + Logger.services.error("\(error.localizedDescription, privacy: .public)") isShowingBadFileAlert = true } } else { @@ -103,11 +103,11 @@ struct Routes: View { } catch { // TODO: deal with errors - Logger.services.error("\(error.localizedDescription)") + Logger.services.error("\(error.localizedDescription, privacy: .public)") } } catch { - Logger.services.error("CSV Import Error: \(error.localizedDescription)") + Logger.services.error("CSV Import Error: \(error.localizedDescription, privacy: .public)") } } List(routes, id: \.self, selection: $selectedRoute) { route in @@ -151,7 +151,7 @@ struct Routes: View { do { try context.save() } catch let error as NSError { - Logger.data.error("\(error.localizedDescription)") + Logger.data.error("\(error.localizedDescription, privacy: .public)") } } label: { Label("delete", systemImage: "trash") @@ -227,7 +227,7 @@ struct Routes: View { } catch { context.rollback() let nsError = error as NSError - Logger.data.error("Error Saving RouteEntity from the Route Editor \(nsError)") + Logger.data.error("Error Saving RouteEntity from the Route Editor \(nsError, privacy: .public)") } } .buttonStyle(.bordered) @@ -300,7 +300,7 @@ struct Routes: View { self.isExporting = false Logger.services.info("Route log download succeeded.") case .failure(let error): - Logger.services.error("Route log download failed: \(error.localizedDescription).") + Logger.services.error("Route log download failed: \(error.localizedDescription, privacy: .public).") } } ) From 9de106a10ce3a206d37bbb8b2b42f768aedb5928 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 31 Mar 2025 22:20:10 -0700 Subject: [PATCH 07/14] Mask coordinates --- Meshtastic/Helpers/LocationsHandler.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index 5d4293a8..de712346 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -88,11 +88,11 @@ import OSLog return false } if location.horizontalAccuracy < 0 { - Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") + Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .hash))") return false } if location.horizontalAccuracy > 5 { - Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") + Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .hash))") return false } } From fc96c894917110dcabb8e884a28c96a25ebd7866 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 31 Mar 2025 22:37:51 -0700 Subject: [PATCH 08/14] Make store and forward config build --- Meshtastic/Persistence/UpdateCoreData.swift | 2 +- .../Views/Settings/Config/Module/StoreForwardConfig.swift | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index c9c08e40..e5e7bd87 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -1361,7 +1361,7 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi newConfig.records = Int32(config.records) newConfig.historyReturnMax = Int32(config.historyReturnMax) newConfig.historyReturnWindow = Int32(config.historyReturnWindow) - newConfig.isServer = config.isServer + newConfig.isRouter = config.isServer fetchedNode[0].storeForwardConfig = newConfig } else { fetchedNode[0].storeForwardConfig?.enabled = config.enabled diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index 20b08bf4..fe6abcd1 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -103,7 +103,7 @@ struct StoreForwardConfig: View { /// Let the user set isServer for the connected node, for nodes on the mesh set isServer based /// on receipt of a primary heartbeat if connectedNode?.num ?? 0 == node?.num ?? -1 { - connectedNode?.storeForwardConfig?.isServer = isServer + connectedNode?.storeForwardConfig?.isRouter = isServer do { try context.save() } catch { @@ -163,7 +163,7 @@ struct StoreForwardConfig: View { if oldEnabled != newEnabled && newEnabled != node!.storeForwardConfig!.enabled { hasChanges = true } } .onChange(of: isServer) { oldIsServer, newIsServer in - if oldIsServer != newIsServer && newIsServer != node!.storeForwardConfig!.isServer { hasChanges = true } + if oldIsServer != newIsServer && newIsServer != node!.storeForwardConfig!.isRouter { hasChanges = true } } .onChange(of: heartbeat) { oldHeartbeat, newHeartbeat in if oldHeartbeat != newHeartbeat && newHeartbeat != node?.storeForwardConfig?.heartbeat ?? true { hasChanges = true } @@ -181,7 +181,7 @@ struct StoreForwardConfig: View { func setStoreAndForwardValues() { self.enabled = (node?.storeForwardConfig?.enabled ?? false) - self.isServer = (node?.storeForwardConfig?.isServer ?? false) + self.isServer = (node?.storeForwardConfig?.isRouter ?? false) self.heartbeat = (node?.storeForwardConfig?.heartbeat ?? true) self.records = Int(node?.storeForwardConfig?.records ?? 50) self.historyReturnMax = Int(node?.storeForwardConfig?.historyReturnMax ?? 100) From 46bf02c89c51e5a0d48bdd4810ca5d2d0a8c63a9 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 31 Mar 2025 23:11:40 -0700 Subject: [PATCH 09/14] Make public key read only --- Meshtastic/Helpers/LocationsHandler.swift | 4 +-- .../Settings/Config/SecurityConfig.swift | 25 +++++++------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index de712346..3e9f92d2 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -88,11 +88,11 @@ import OSLog return false } if location.horizontalAccuracy < 0 { - Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .hash))") + Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .none))") return false } if location.horizontalAccuracy > 5 { - Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .hash))") + Logger.services.info("📍 [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private(mask: .none))") return false } } diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index c3d493c1..938a9202 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -22,7 +22,6 @@ struct SecurityConfig: View { @State var hasChanges = false @State var publicKey = "" - @State var hasValidPublicKey: Bool = false @State var privateKey = "" @State var hasValidPrivateKey: Bool = false @State var adminKey: String = "" @@ -45,11 +44,14 @@ struct SecurityConfig: View { Section(header: Text("Admin & Direct Message Keys")) { VStack(alignment: .leading) { Label("Public Key", systemImage: "key") - SecureInput("Public Key", text: $publicKey, isValid: $hasValidPublicKey) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(hasValidPublicKey ? Color.clear : Color.red, lineWidth: 2.0) - ) + Text(publicKey) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() + .keyboardType(.alphabet) + .foregroundStyle(.tertiary) + .disableAutocorrection(true) + .textSelection(.enabled) Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) @@ -144,15 +146,6 @@ struct SecurityConfig: View { .onChange(of: adminChannelEnabled) { _, newAdminChannelEnabled in if newAdminChannelEnabled != node?.securityConfig?.adminChannelEnabled { hasChanges = true } } - .onChange(of: publicKey) { - let tempKey = Data(base64Encoded: publicKey) ?? Data() - if tempKey.count == 32 { - hasValidPublicKey = true - } else { - hasValidPublicKey = false - } - hasChanges = true - } .onChange(of: privateKey) { let tempKey = Data(base64Encoded: privateKey) ?? Data() if tempKey.count == 32 { @@ -222,7 +215,7 @@ struct SecurityConfig: View { SaveConfigButton(node: node, hasChanges: $hasChanges) { - if !hasValidPublicKey || !hasValidPrivateKey || !hasValidAdminKey { + if !hasValidPrivateKey || !hasValidAdminKey || !hasValidAdminKey2 || !hasValidAdminKey3 { return } From ebbe7c2dccb55f54ce1097afb509762461d9b3e5 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 1 Apr 2025 09:26:03 -0700 Subject: [PATCH 10/14] Show tips on app launch --- Meshtastic/MeshtasticApp.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Meshtastic/MeshtasticApp.swift b/Meshtastic/MeshtasticApp.swift index 3569a292..5c82c257 100644 --- a/Meshtastic/MeshtasticApp.swift +++ b/Meshtastic/MeshtasticApp.swift @@ -38,6 +38,8 @@ struct MeshtasticAppleApp: App { // Wire up router self.appDelegate.router = appState.router + // Show Tips + try? Tips.resetDatastore() } var body: some Scene { @@ -108,12 +110,6 @@ struct MeshtasticAppleApp: App { } }) .task { - #if DEBUG - /// Optionally, call `Tips.resetDatastore()` before `Tips.configure()` to reset the state of all tips. This will allow tips to re-appear even after they have been dismissed by the user. - /// This is for testing only, and should not be enabled in release builds. - try? Tips.resetDatastore() - #endif - try? Tips.configure( [ // Reset which tips have been shown and what parameters have been tracked, useful during testing and for this sample project From 6c6e2e17fff42ed810094da37ba367f6fa7cfc64 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 1 Apr 2025 09:32:51 -0700 Subject: [PATCH 11/14] Reset the tip datastore on app launch --- Localizable.xcstrings | 195 +--------------------------- Meshtastic/Tips/BluetoothTips.swift | 4 +- 2 files changed, 8 insertions(+), 191 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 4dcb2899..08f7b2ae 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -5717,6 +5717,9 @@ } } } + }, + "Connected Radio" : { + }, "connected.radio" : { "localizations" : { @@ -9417,23 +9420,6 @@ }, "Enables the store and forward module." : { - }, - "Enables the store and forward module. Store and forward must be enabled on both client and router devices." : { - "extractionState" : "stale", - "localizations" : { - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Омогућава модул за чување и пренос. Чување и пренос мора бити омогућено на оба уређаја, клијенту и рутеру." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用存储和转发模块。客户端和路由器设备都必须启用存储和转发功能。" - } - } - } }, "Enabling Ethernet will disable the bluetooth connection to the app." : { "localizations" : { @@ -24959,28 +24945,6 @@ } } }, - "Router" : { - "extractionState" : "stale", - "localizations" : { - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Рутер" - } - } - } - }, - "Router Options" : { - "extractionState" : "stale", - "localizations" : { - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Опције рутера" - } - } - } - }, "Routes" : { "localizations" : { "sr" : { @@ -28313,6 +28277,9 @@ } } } + }, + "Shows information for the Lora radio connected via bluetooth. You can swipe left to disconnect the radio and long press start the live activity." : { + }, "Shut Down" : { "localizations" : { @@ -28803,28 +28770,6 @@ } } }, - "Store and forward clients can request history from routers on the network." : { - "extractionState" : "stale", - "localizations" : { - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Клијенти за складиштење и прослеђивање могу затражити историју од рутера на мрежи." - } - } - } - }, - "Store and forward router devices require a ESP32 device with PSRAM." : { - "extractionState" : "stale", - "localizations" : { - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Рутер за складиштење и прослеђивање захтева ESP32 уређај са PSRAM." - } - } - } - }, "Store and forward servers require an ESP32 device with PSRAM or Linux Native." : { }, @@ -30524,134 +30469,6 @@ } } }, - "tip.bluetooth.connect.message" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Shows information for the Lora radio currently connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity." - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Shows information for the Lora radio connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity." - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Affiche les informations de la radio Lora connectée via le bluetooth. Vous pouvez faire un glissé vers la gauche pour déconnecter la radio et un appui long pour voir les statistiques ou démarrer l'activité en direct." - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "מראה מידע אודות מכשיר המשטסטיק המחובר כעת לבלוטוס. ניתן לגרור שמאלה להתנתקות או לחיצה ארוכה לראות סטטיסטיקה או להתחיל פעילות." - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Shows information for the Lora radio currently connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity." - } - }, - "pt-PT" : { - "stringUnit" : { - "state" : "translated", - "value" : "Mostra informações para o rádio LoRa conectado via bluetooth. Você pode deslizar para a esquerda para desconectar o rádio e pressionar por um longo período para ver estatísticas ou iniciar a atividade ao vivo." - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Visar information för LoRa-radion ansluten via bluetooth. Du kan svepa åt vänster för att koppla från radion och långtryck för att visa statistik eller starta liveaktivitet." - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Приказује информације за LoRA радио повезан преко Блутута. Можете превући лево да бисте одспојили радио и дуго притиснути да бисте погледали статистику или започели активност у реалном времену." - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示当前通过蓝牙连接的 Lora 电台的信息。您可以向左滑动断开电台,长按查看统计信息或开始实时活动。" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "顯示目前通過藍芽連接的 Lora 電台的信息。您可以向左滑動斷開電台,長按查看統計訊息或開始即時活動。" - } - } - } - }, - "tip.bluetooth.connect.title" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Connected LoRa Radio" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Connected Radio" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Radio connectée" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "מכשיר מחובר" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Connected LoRa Radio" - } - }, - "pt-PT" : { - "stringUnit" : { - "state" : "translated", - "value" : "Rádio Conectado" - } - }, - "se" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ansluten Radio" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Радио повезан" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "电台已连接" - } - }, - "zh-Hant-TW" : { - "stringUnit" : { - "state" : "translated", - "value" : "連接到 LoRa 電台" - } - } - } - }, "tip.channel.admin.message" : { "localizations" : { "de" : { diff --git a/Meshtastic/Tips/BluetoothTips.swift b/Meshtastic/Tips/BluetoothTips.swift index 02d2af53..838d29fc 100644 --- a/Meshtastic/Tips/BluetoothTips.swift +++ b/Meshtastic/Tips/BluetoothTips.swift @@ -13,10 +13,10 @@ struct BluetoothConnectionTip: Tip { return "tip.bluetooth.connect" } var title: Text { - Text("tip.bluetooth.connect.title") + Text("Connected Radio") } var message: Text? { - Text("tip.bluetooth.connect.message") + Text("Shows information for the Lora radio connected via bluetooth. You can swipe left to disconnect the radio and long press start the live activity.") } var image: Image? { Image(systemName: "flipphone") From 5d9ea157679b6acc2e16afaa9c77a05fdcf8370c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 1 Apr 2025 17:33:39 -0700 Subject: [PATCH 12/14] Masks for a couple of coordinate logs --- Meshtastic/Helpers/BLEManager.swift | 2 +- Meshtastic/Helpers/LocationsHandler.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 4828a30e..9f633f30 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -537,7 +537,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if let coordsMatch = try CommonRegex.COORDS_REGEX.firstMatch(in: logString) { log = "\(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces))" log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression) - Logger.radio.debug("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)") + Logger.radio.debug("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private(mask: .none)) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)") } else { log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression) Logger.radio.debug("🕵🏻‍♂️ \(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)") diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index 3e9f92d2..75830805 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -84,7 +84,7 @@ import OSLog if smartPostion { let age = -location.timestamp.timeIntervalSinceNow if age > 10 { - Logger.services.info("📍 [App] Smart Position - Bad Location: Too Old \(age, privacy: .public) seconds ago \(location, privacy: .private)") + Logger.services.info("📍 [App] Smart Position - Bad Location: Too Old \(age, privacy: .public) seconds ago \(location, privacy: .private(mask: .none))") return false } if location.horizontalAccuracy < 0 { From 8650ce839c100561c4d78e24a34bb357a842ad6b Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 1 Apr 2025 20:07:31 -0700 Subject: [PATCH 13/14] Add lost commit back --- Meshtastic/Views/Messages/ChannelMessageList.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index 704ac452..bf5be325 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -115,6 +115,9 @@ struct ChannelMessageList: View { if !message.read { message.read = true do { + for unreadMessage in channel.allPrivateMessages.filter({ !$0.read }) { + unreadMessage.read = true + } try context.save() Logger.data.info("📖 [App] Read message \(message.messageId, privacy: .public) ") appState.unreadChannelMessages = myInfo.unreadMessages From a722c176cb35e427e8fc4b85860bff6b8745718d Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 1 Apr 2025 20:15:35 -0700 Subject: [PATCH 14/14] Remove extra brace --- Meshtastic/Views/Nodes/PowerMetricsLog.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Views/Nodes/PowerMetricsLog.swift b/Meshtastic/Views/Nodes/PowerMetricsLog.swift index f3fb410a..489184da 100644 --- a/Meshtastic/Views/Nodes/PowerMetricsLog.swift +++ b/Meshtastic/Views/Nodes/PowerMetricsLog.swift @@ -272,7 +272,7 @@ struct PowerMetricsLog: View { ContentUnavailableView("No Power Metrics", systemImage: "slash.circle") } } - .navigationTitle("Power Metrics Log}") + .navigationTitle("Power Metrics Log") .navigationBarTitleDisplayMode(.inline) .navigationBarItems(trailing: ZStack {