diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 3e446152..9a194160 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -8,9 +8,23 @@ /* Begin PBXBuildFile section */ 25A978592C124FA70003AAE7 /* NodeInfoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978572C124FA70003AAE7 /* NodeInfoExtensions.swift */; }; + 25A978A92C12BD3F0003AAE7 /* WaypointEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789A2C12BD3E0003AAE7 /* WaypointEntityExtension.swift */; }; + 25A978AA2C12BD3F0003AAE7 /* ChannelEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789B2C12BD3E0003AAE7 /* ChannelEntityExtension.swift */; }; + 25A978AB2C12BD3F0003AAE7 /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789C2C12BD3E0003AAE7 /* MessageEntityExtension.swift */; }; + 25A978AC2C12BD3F0003AAE7 /* TraceRouteEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789D2C12BD3E0003AAE7 /* TraceRouteEntityExtension.swift */; }; + 25A978AD2C12BD3F0003AAE7 /* LocationEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789E2C12BD3E0003AAE7 /* LocationEntityExtension.swift */; }; + 25A978AE2C12BD3F0003AAE7 /* RangeTestConfigEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A9789F2C12BD3E0003AAE7 /* RangeTestConfigEntityExtension.swift */; }; + 25A978AF2C12BD3F0003AAE7 /* MQTTConfigEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A02C12BD3E0003AAE7 /* MQTTConfigEntityExtension.swift */; }; + 25A978B02C12BD3F0003AAE7 /* ExternalNotificationConfigEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A12C12BD3E0003AAE7 /* ExternalNotificationConfigEntityExtension.swift */; }; + 25A978B12C12BD3F0003AAE7 /* StoreForwardConfigEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A22C12BD3E0003AAE7 /* StoreForwardConfigEntityExtension.swift */; }; + 25A978B22C12BD3F0003AAE7 /* SerialConfigEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A32C12BD3E0003AAE7 /* SerialConfigEntityExtension.swift */; }; + 25A978B32C12BD3F0003AAE7 /* DeviceMetadataEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A42C12BD3F0003AAE7 /* DeviceMetadataEntityExtension.swift */; }; + 25A978B42C12BD3F0003AAE7 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A52C12BD3F0003AAE7 /* UserEntityExtension.swift */; }; + 25A978B52C12BD3F0003AAE7 /* MyInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A62C12BD3F0003AAE7 /* MyInfoEntityExtension.swift */; }; + 25A978B62C12BD3F0003AAE7 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A72C12BD3F0003AAE7 /* PositionEntityExtension.swift */; }; + 25A978B72C12BD3F0003AAE7 /* NodeInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978A82C12BD3F0003AAE7 /* NodeInfoEntityExtension.swift */; }; 6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; }; 6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; }; - 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; }; B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B399E8A32B6F486400E4488E /* RetryButton.swift */; }; B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; }; C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */; }; @@ -26,8 +40,6 @@ 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 */; }; - DD007BAE2AA4E91200F5FA12 /* MyInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */; }; - DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */; }; DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */ = {isa = PBXBuildFile; productRef = DD0D3D212A55CEB10066DB71 /* CocoaMQTT */; }; DD0E20FC2B87090400F2D100 /* atak.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0E20F92B87090400F2D100 /* atak.pb.swift */; }; DD0E20FD2B87090400F2D100 /* clientonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0E20FA2B87090400F2D100 /* clientonly.pb.swift */; }; @@ -69,8 +81,6 @@ DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; }; DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */; }; DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; }; - DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; }; - DD58C5F22919AD3C00D5BEFB /* ChannelEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */; }; DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5D0A9B2931B9F200F7EA61 /* EthernetModes.swift */; }; DD5E5202298EE33B00D21B61 /* admin.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F0298EE33B00D21B61 /* admin.pb.swift */; }; DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F1298EE33B00D21B61 /* config.pb.swift */; }; @@ -117,7 +127,6 @@ 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 */; }; @@ -130,7 +139,6 @@ DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA9515B2BC6631200CEA535 /* TelemetryEnums.swift */; }; DDA9515E2BC6F56F00CEA535 /* IndoorAirQuality.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */; }; DDAB580D2B0DAA9E00147258 /* Routes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAB580C2B0DAA9E00147258 /* Routes.swift */; }; - DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAB580E2B0DAFBC00147258 /* LocationEntityExtension.swift */; }; DDAD49ED2AFB39DC00B4425D /* MeshMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAD49EC2AFB39DC00B4425D /* MeshMap.swift */; }; DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C5226EB1DF10058C060 /* BLEManager.swift */; }; DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABD528AE742000384BA1 /* BluetoothConfig.swift */; }; @@ -170,7 +178,6 @@ DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */; }; DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD6EEAE29BC024700383354 /* Firmware.swift */; }; DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; }; - DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; }; DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB263E2AABEE20003AFCB7 /* NodeList.swift */; }; DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26412AABF655003AFCB7 /* NodeListItem.swift */; }; DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */; }; @@ -203,7 +210,6 @@ DDDE5A1429AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; }; DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */; }; DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4032B2279A700FCDD05 /* TraceRouteLog.swift */; }; - DDE5B4062B227E3200FCDD05 /* TraceRouteEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */; }; DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */; }; DDF45C342BC1A48E005ED5F2 /* MQTTIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */; }; DDF45C372BC46A5A005ED5F2 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF45C362BC46A5A005ED5F2 /* TimeZone.swift */; }; @@ -242,9 +248,23 @@ /* Begin PBXFileReference section */ 258EE1262C0E833D0025A5FB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 25A978572C124FA70003AAE7 /* NodeInfoExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeInfoExtensions.swift; sourceTree = ""; }; + 25A9789A2C12BD3E0003AAE7 /* WaypointEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaypointEntityExtension.swift; sourceTree = ""; }; + 25A9789B2C12BD3E0003AAE7 /* ChannelEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelEntityExtension.swift; sourceTree = ""; }; + 25A9789C2C12BD3E0003AAE7 /* MessageEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = ""; }; + 25A9789D2C12BD3E0003AAE7 /* TraceRouteEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TraceRouteEntityExtension.swift; sourceTree = ""; }; + 25A9789E2C12BD3E0003AAE7 /* LocationEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationEntityExtension.swift; sourceTree = ""; }; + 25A9789F2C12BD3E0003AAE7 /* RangeTestConfigEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeTestConfigEntityExtension.swift; sourceTree = ""; }; + 25A978A02C12BD3E0003AAE7 /* MQTTConfigEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MQTTConfigEntityExtension.swift; sourceTree = ""; }; + 25A978A12C12BD3E0003AAE7 /* ExternalNotificationConfigEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExternalNotificationConfigEntityExtension.swift; sourceTree = ""; }; + 25A978A22C12BD3E0003AAE7 /* StoreForwardConfigEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoreForwardConfigEntityExtension.swift; sourceTree = ""; }; + 25A978A32C12BD3E0003AAE7 /* SerialConfigEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerialConfigEntityExtension.swift; sourceTree = ""; }; + 25A978A42C12BD3F0003AAE7 /* DeviceMetadataEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceMetadataEntityExtension.swift; sourceTree = ""; }; + 25A978A52C12BD3F0003AAE7 /* UserEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = ""; }; + 25A978A62C12BD3F0003AAE7 /* MyInfoEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyInfoEntityExtension.swift; sourceTree = ""; }; + 25A978A72C12BD3F0003AAE7 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = ""; }; + 25A978A82C12BD3F0003AAE7 /* NodeInfoEntityExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityExtension.swift; sourceTree = ""; }; 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = ""; }; 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = ""; }; - 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = ""; }; A65FA974296876BF00A97686 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; B399E8A32B6F486400E4488E /* RetryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryButton.swift; sourceTree = ""; }; B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = ""; }; @@ -261,8 +281,6 @@ 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 = ""; }; - DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoEntityExtension.swift; sourceTree = ""; }; - DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityExtension.swift; sourceTree = ""; }; DD05296F2B77F454008E44CD /* MeshtasticDataModelV 26.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 26.xcdatamodel"; sourceTree = ""; }; DD0E20F92B87090400F2D100 /* atak.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = atak.pb.swift; sourceTree = ""; }; DD0E20FA2B87090400F2D100 /* clientonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = clientonly.pb.swift; sourceTree = ""; }; @@ -318,8 +336,6 @@ DD4975A42B147BA90026544E /* AmbientLightingConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmbientLightingConfig.swift; sourceTree = ""; }; DD4A911D2708C65400501B7E /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = ""; }; DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentMetricsLog.swift; sourceTree = ""; }; - DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = ""; }; - DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelEntityExtension.swift; sourceTree = ""; }; DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV2.xcdatamodel; sourceTree = ""; }; DD5D0A9B2931B9F200F7EA61 /* EthernetModes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthernetModes.swift; sourceTree = ""; }; DD5E51CC2986643400D21B61 /* MeshtasticDataModelV7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV7.xcdatamodel; sourceTree = ""; }; @@ -370,7 +386,6 @@ 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 = ""; }; @@ -386,7 +401,6 @@ DDA9515D2BC6F56F00CEA535 /* IndoorAirQuality.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndoorAirQuality.swift; sourceTree = ""; }; DDAB580B2B0D913500147258 /* MeshtasticDataModelV20.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV20.xcdatamodel; sourceTree = ""; }; DDAB580C2B0DAA9E00147258 /* Routes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Routes.swift; sourceTree = ""; }; - DDAB580E2B0DAFBC00147258 /* LocationEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEntityExtension.swift; sourceTree = ""; }; DDAD49EC2AFB39DC00B4425D /* MeshMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshMap.swift; sourceTree = ""; }; DDAF8C5226EB1DF10058C060 /* BLEManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEManager.swift; sourceTree = ""; }; DDB234392B5CA9B000DA6FB1 /* MeshtasticDataModelV 24.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 24.xcdatamodel"; sourceTree = ""; }; @@ -437,7 +451,6 @@ DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MqttClientProxyManager.swift; sourceTree = ""; }; DDD6EEAE29BC024700383354 /* Firmware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firmware.swift; sourceTree = ""; }; DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = ""; }; - DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = ""; }; DDDB263E2AABEE20003AFCB7 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = ""; }; DDDB26412AABF655003AFCB7 /* NodeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListItem.swift; sourceTree = ""; }; DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = ""; }; @@ -475,7 +488,6 @@ DDDEE5E229DBE43E00A8E078 /* MeshtasticDataModelV11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV11.xcdatamodel; sourceTree = ""; }; DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsEnums.swift; sourceTree = ""; }; DDE5B4032B2279A700FCDD05 /* TraceRouteLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceRouteLog.swift; sourceTree = ""; }; - DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceRouteEntityExtension.swift; sourceTree = ""; }; DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteRecorder.swift; sourceTree = ""; }; DDEE03EC29544A1000FCAD57 /* MeshtasticDataModelV4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV4.xcdatamodel; sourceTree = ""; }; DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MQTTIcon.swift; sourceTree = ""; }; @@ -559,15 +571,21 @@ DD007BB12AA59B9A00F5FA12 /* CoreData */ = { isa = PBXGroup; children = ( - DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */, - 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */, - DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */, - DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */, - DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */, - DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */, - DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */, - DDAB580E2B0DAFBC00147258 /* LocationEntityExtension.swift */, - DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */, + 25A9789B2C12BD3E0003AAE7 /* ChannelEntityExtension.swift */, + 25A978A42C12BD3F0003AAE7 /* DeviceMetadataEntityExtension.swift */, + 25A978A12C12BD3E0003AAE7 /* ExternalNotificationConfigEntityExtension.swift */, + 25A9789E2C12BD3E0003AAE7 /* LocationEntityExtension.swift */, + 25A9789C2C12BD3E0003AAE7 /* MessageEntityExtension.swift */, + 25A978A02C12BD3E0003AAE7 /* MQTTConfigEntityExtension.swift */, + 25A978A62C12BD3F0003AAE7 /* MyInfoEntityExtension.swift */, + 25A978A82C12BD3F0003AAE7 /* NodeInfoEntityExtension.swift */, + 25A978A72C12BD3F0003AAE7 /* PositionEntityExtension.swift */, + 25A9789F2C12BD3E0003AAE7 /* RangeTestConfigEntityExtension.swift */, + 25A978A32C12BD3E0003AAE7 /* SerialConfigEntityExtension.swift */, + 25A978A22C12BD3E0003AAE7 /* StoreForwardConfigEntityExtension.swift */, + 25A9789D2C12BD3E0003AAE7 /* TraceRouteEntityExtension.swift */, + 25A978A52C12BD3F0003AAE7 /* UserEntityExtension.swift */, + 25A9789A2C12BD3E0003AAE7 /* WaypointEntityExtension.swift */, ); path = CoreData; sourceTree = ""; @@ -1175,7 +1193,6 @@ DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */, DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */, DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */, - DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */, DD77093D2AA1AFA3007A8BF0 /* ChannelTips.swift in Sources */, DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */, DDDB444C29F8AAA600EE2349 /* Color.swift in Sources */, @@ -1193,12 +1210,15 @@ DDDB445229F8ACF900EE2349 /* Date.swift in Sources */, DDC4D568275499A500A4208E /* Persistence.swift in Sources */, DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */, + 25A978B72C12BD3F0003AAE7 /* NodeInfoEntityExtension.swift in Sources */, DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */, + 25A978B22C12BD3F0003AAE7 /* SerialConfigEntityExtension.swift in Sources */, DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */, D9C9839D2B79CFD700BDBE6A /* TextMessageSize.swift in Sources */, DDC94FCE29CF55310082EA6E /* RtttlConfig.swift in Sources */, DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */, DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */, + 25A978B32C12BD3F0003AAE7 /* DeviceMetadataEntityExtension.swift in Sources */, DDC94FC129CE063B0082EA6E /* BatteryLevel.swift in Sources */, DD354FD92BD96A0B0061A25F /* IAQScale.swift in Sources */, DDDB445429F8AD1600EE2349 /* Data.swift in Sources */, @@ -1206,6 +1226,8 @@ DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */, DD5E5213298EE33B00D21B61 /* deviceonly.pb.swift in Sources */, DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */, + 25A978B02C12BD3F0003AAE7 /* ExternalNotificationConfigEntityExtension.swift in Sources */, + 25A978AA2C12BD3F0003AAE7 /* ChannelEntityExtension.swift in Sources */, DD5E5208298EE33B00D21B61 /* rtttl.pb.swift in Sources */, DD6193792863875F00E59241 /* SerialConfig.swift in Sources */, DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */, @@ -1219,7 +1241,7 @@ DD5E5209298EE33B00D21B61 /* module_config.pb.swift in Sources */, DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */, DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */, - 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */, + 25A978B52C12BD3F0003AAE7 /* MyInfoEntityExtension.swift in Sources */, DDDB444229F8A88700EE2349 /* Double.swift in Sources */, DD5E520F298EE33B00D21B61 /* cannedmessages.pb.swift in Sources */, DDF45C342BC1A48E005ED5F2 /* MQTTIcon.swift in Sources */, @@ -1233,17 +1255,18 @@ DDDB444A29F8AA3A00EE2349 /* CLLocationCoordinate2D.swift in Sources */, DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */, DDF45C372BC46A5A005ED5F2 /* TimeZone.swift in Sources */, - DD007BAE2AA4E91200F5FA12 /* MyInfoEntityExtension.swift in Sources */, DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */, DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */, + 25A978AC2C12BD3F0003AAE7 /* TraceRouteEntityExtension.swift in Sources */, DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */, DD5E5207298EE33B00D21B61 /* connection_status.pb.swift in Sources */, DD3CC6C228EB9D4900FA9159 /* UpdateCoreData.swift in Sources */, DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */, + 25A978AD2C12BD3F0003AAE7 /* LocationEntityExtension.swift in Sources */, DDB6ABE628B1406100384BA1 /* LoraConfigEnums.swift in Sources */, DDB8F4142A9EE5F000230ECE /* ChannelList.swift in Sources */, DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */, - DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */, + 25A978B12C12BD3F0003AAE7 /* StoreForwardConfigEntityExtension.swift in Sources */, DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */, DD0E20FC2B87090400F2D100 /* atak.pb.swift in Sources */, DDDB444629F8A96500EE2349 /* Character.swift in Sources */, @@ -1251,7 +1274,7 @@ DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */, DD5E520D298EE33B00D21B61 /* storeforward.pb.swift in Sources */, DD94B7402ACCE3BE00DCD1D1 /* MapSettingsForm.swift in Sources */, - DD964FC2297272AE007C176F /* WaypointEntityExtension.swift in Sources */, + 25A978AF2C12BD3F0003AAE7 /* MQTTConfigEntityExtension.swift in Sources */, 6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */, D93068DB2B81C85E0066FBC8 /* PowerConfig.swift in Sources */, D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */, @@ -1263,7 +1286,6 @@ DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */, DD2553572855B02500E55709 /* LoRaConfig.swift in Sources */, DDB6ABD928B0A4BA00384BA1 /* BluetoothModes.swift in Sources */, - DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */, DD2553592855B52700E55709 /* PositionConfig.swift in Sources */, DD97E96828EFE9A00056DDA4 /* About.swift in Sources */, DDDB444029F79AB000EE2349 /* UserDefaults.swift in Sources */, @@ -1279,8 +1301,11 @@ DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */, DDB75A112A059258006ED576 /* Url.swift in Sources */, DDAD49ED2AFB39DC00B4425D /* MeshMap.swift in Sources */, + 25A978A92C12BD3F0003AAE7 /* WaypointEntityExtension.swift in Sources */, DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */, + 25A978AB2C12BD3F0003AAE7 /* MessageEntityExtension.swift in Sources */, DD1B8F402B35E2F10022AABC /* GPSStatus.swift in Sources */, + 25A978B42C12BD3F0003AAE7 /* UserEntityExtension.swift in Sources */, DD8ED9C52898D51F00B3B0AB /* NetworkConfig.swift in Sources */, DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */, DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */, @@ -1319,7 +1344,6 @@ DDAB580D2B0DAA9E00147258 /* Routes.swift in Sources */, C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */, D93068D52B812B700066FBC8 /* MessageDestination.swift in Sources */, - DD58C5F22919AD3C00D5BEFB /* ChannelEntityExtension.swift in Sources */, DDA9515E2BC6F56F00CEA535 /* IndoorAirQuality.swift in Sources */, DDDB444E29F8AB0E00EE2349 /* Int.swift in Sources */, DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */, @@ -1334,15 +1358,15 @@ DDF6B2482A9AEBF500BA6931 /* StoreForwardConfig.swift in Sources */, DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */, DD93800B2BA3F968008BEC06 /* NodeMapContent.swift in Sources */, + 25A978AE2C12BD3F0003AAE7 /* RangeTestConfigEntityExtension.swift in Sources */, DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */, DD1925B728CDA5A400720036 /* CannedMessagesConfigEnums.swift in Sources */, DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */, - DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */, + 25A978B62C12BD3F0003AAE7 /* PositionEntityExtension.swift in Sources */, B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */, DD5E5211298EE33B00D21B61 /* remote_hardware.pb.swift in Sources */, D93068D72B8146690066FBC8 /* MessageText.swift in Sources */, DD5E5204298EE33B00D21B61 /* xmodem.pb.swift in Sources */, - DDE5B4062B227E3200FCDD05 /* TraceRouteEntityExtension.swift in Sources */, DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Meshtastic/Extensions/CoreData/ChannelEntityExtension.swift b/Meshtastic/Extensions/CoreData/ChannelEntityExtension.swift index 2568943a..84ef3ece 100644 --- a/Meshtastic/Extensions/CoreData/ChannelEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/ChannelEntityExtension.swift @@ -5,9 +5,50 @@ // Copyright(c) Garth Vander Houwen 11/7/22. // import Foundation +import CoreData extension ChannelEntity { + convenience init( + context: NSManagedObjectContext, + id: Int32, + index: Int32, + uplinkEnabled: Bool, + downlinkEnabled: Bool, + name: String?, + role: Int32, + psk: Data, + positionPrecision: Int32 + ) { + self.init(context: context) + self.id = id + self.index = index + self.uplinkEnabled = uplinkEnabled + self.downlinkEnabled = downlinkEnabled + self.name = name + self.role = role + self.psk = psk + self.positionPrecision = positionPrecision + } + + convenience init( + context: NSManagedObjectContext, + channel: Channel + ) { + self.init(context: context) + self.id = Int32(channel.index) + self.index = Int32(channel.index) + self.uplinkEnabled = channel.settings.uplinkEnabled + self.downlinkEnabled = channel.settings.downlinkEnabled + self.name = channel.settings.name + self.role = Int32(channel.role.rawValue) + self.psk = channel.settings.psk + if channel.settings.hasModuleSettings { + self.positionPrecision = Int32(truncatingIfNeeded: channel.settings.moduleSettings.positionPrecision) + self.mute = channel.settings.moduleSettings.isClientMuted + } + } + var allPrivateMessages: [MessageEntity] { self.value(forKey: "allPrivateMessages") as? [MessageEntity] ?? [MessageEntity]() diff --git a/Meshtastic/Extensions/CoreData/DeviceMetadataEntityExtension.swift b/Meshtastic/Extensions/CoreData/DeviceMetadataEntityExtension.swift new file mode 100644 index 00000000..cc0bd37f --- /dev/null +++ b/Meshtastic/Extensions/CoreData/DeviceMetadataEntityExtension.swift @@ -0,0 +1,24 @@ +import Foundation +import CoreData + +extension DeviceMetadataEntity { + convenience init( + context: NSManagedObjectContext, + metadata: DeviceMetadata + ) { + self.init(context: context) + self.time = Date() + self.deviceStateVersion = Int32(metadata.deviceStateVersion) + self.canShutdown = metadata.canShutdown + self.hasWifi = metadata.hasWifi_p + self.hasBluetooth = metadata.hasBluetooth_p + self.hasEthernet = metadata.hasEthernet_p + self.role = Int32(metadata.role.rawValue) + self.positionFlags = Int32(metadata.positionFlags) + // Swift does strings weird, this does work to get the version without the github hash + let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".") + var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))] + version = version.dropLast() + self.firmwareVersion = String(version) + } +} diff --git a/Meshtastic/Extensions/CoreData/ExternalNotificationConfigEntityExtension.swift b/Meshtastic/Extensions/CoreData/ExternalNotificationConfigEntityExtension.swift new file mode 100644 index 00000000..72632308 --- /dev/null +++ b/Meshtastic/Extensions/CoreData/ExternalNotificationConfigEntityExtension.swift @@ -0,0 +1,43 @@ +import CoreData + +extension ExternalNotificationConfigEntity { + convenience init( + context: NSManagedObjectContext, + config: ModuleConfig.ExternalNotificationConfig + ) { + self.init() + self.enabled = config.enabled + self.usePWM = config.usePwm + self.alertBell = config.alertBell + self.alertBellBuzzer = config.alertBellBuzzer + self.alertBellVibra = config.alertBellVibra + self.alertMessage = config.alertMessage + self.alertMessageBuzzer = config.alertMessageBuzzer + self.alertMessageVibra = config.alertMessageVibra + self.active = config.active + self.output = Int32(config.output) + self.outputBuzzer = Int32(config.outputBuzzer) + self.outputVibra = Int32(config.outputVibra) + self.outputMilliseconds = Int32(config.outputMs) + self.nagTimeout = Int32(config.nagTimeout) + self.useI2SAsBuzzer = config.useI2SAsBuzzer + } + + func update(with config: ModuleConfig.ExternalNotificationConfig) { + enabled = config.enabled + usePWM = config.usePwm + alertBell = config.alertBell + alertBellBuzzer = config.alertBellBuzzer + alertBellVibra = config.alertBellVibra + alertMessage = config.alertMessage + alertMessageBuzzer = config.alertMessageBuzzer + alertMessageVibra = config.alertMessageVibra + active = config.active + output = Int32(config.output) + outputBuzzer = Int32(config.outputBuzzer) + outputVibra = Int32(config.outputVibra) + outputMilliseconds = Int32(config.outputMs) + nagTimeout = Int32(config.nagTimeout) + useI2SAsBuzzer = config.useI2SAsBuzzer + } +} diff --git a/Meshtastic/Extensions/CoreData/LocationEntityExtension.swift b/Meshtastic/Extensions/CoreData/LocationEntityExtension.swift index 5b35f620..d66ec017 100644 --- a/Meshtastic/Extensions/CoreData/LocationEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/LocationEntityExtension.swift @@ -11,6 +11,22 @@ import MapKit import SwiftUI extension LocationEntity { + + convenience init( + context: NSManagedObjectContext, + route: RouteEntity, + id: Int32, + location: CLLocation + ) { + self.init(context: context) + self.routeLocation = route + self.id = id + self.altitude = Int32(location.altitude) + self.heading = Int32(location.course) + self.speed = Int32(location.speed) + self.latitudeI = Int32(location.coordinate.latitude * 1e7) + self.longitudeI = Int32(location.coordinate.longitude * 1e7) + } var latitude: Double? { diff --git a/Meshtastic/Extensions/CoreData/MQTTConfigEntityExtension.swift b/Meshtastic/Extensions/CoreData/MQTTConfigEntityExtension.swift new file mode 100644 index 00000000..32744db5 --- /dev/null +++ b/Meshtastic/Extensions/CoreData/MQTTConfigEntityExtension.swift @@ -0,0 +1,37 @@ +import CoreData + +extension MQTTConfigEntity { + convenience init( + context: NSManagedObjectContext, + config: ModuleConfig.MQTTConfig + ) { + self.init(context: context) + self.enabled = config.enabled + self.proxyToClientEnabled = config.proxyToClientEnabled + self.address = config.address + self.username = config.username + self.password = config.password + self.root = config.root + self.encryptionEnabled = config.encryptionEnabled + self.jsonEnabled = config.jsonEnabled + self.tlsEnabled = config.tlsEnabled + self.mapReportingEnabled = config.mapReportingEnabled + self.mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision) + self.mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs) + } + + func update(with config: ModuleConfig.MQTTConfig) { + enabled = config.enabled + proxyToClientEnabled = config.proxyToClientEnabled + address = config.address + username = config.username + password = config.password + root = config.root + encryptionEnabled = config.encryptionEnabled + jsonEnabled = config.jsonEnabled + tlsEnabled = config.tlsEnabled + mapReportingEnabled = config.mapReportingEnabled + mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision) + mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs) + } +} diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index 9258b424..935e35a8 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -9,6 +9,15 @@ import Foundation import CoreData extension NodeInfoEntity { + convenience init( + context: NSManagedObjectContext, + num: Int + ) { + self.init(context: context) + self.id = Int64(num) + self.num = Int64(num) + self.user = UserEntity(context: context, num: num) + } var hasPositions: Bool { return positions?.count ?? 0 > 0 @@ -47,20 +56,3 @@ extension NodeInfoEntity { return false } } - -public func createNodeInfo(num: Int64, context: NSManagedObjectContext) -> NodeInfoEntity { - - let newNode = NodeInfoEntity(context: context) - newNode.id = Int64(num) - newNode.num = Int64(num) - let newUser = UserEntity(context: context) - newUser.num = Int64(num) - let userId = String(format: "%2X", num) - newUser.userId = "!\(userId)" - let last4 = String(userId.suffix(4)) - newUser.longName = "Meshtastic \(last4)" - newUser.shortName = last4 - newUser.hwModel = "UNSET" - newNode.user = newUser - return newNode -} diff --git a/Meshtastic/Extensions/CoreData/RangeTestConfigEntityExtension.swift b/Meshtastic/Extensions/CoreData/RangeTestConfigEntityExtension.swift new file mode 100644 index 00000000..9be459be --- /dev/null +++ b/Meshtastic/Extensions/CoreData/RangeTestConfigEntityExtension.swift @@ -0,0 +1,19 @@ +import CoreData + +extension RangeTestConfigEntity { + convenience init( + context: NSManagedObjectContext, + config: ModuleConfig.RangeTestConfig + ) { + self.init(context: context) + self.sender = Int32(config.sender) + self.enabled = config.enabled + self.save = config.save + } + + func update(with config: ModuleConfig.RangeTestConfig) { + sender = Int32(config.sender) + enabled = config.enabled + save = config.save + } +} diff --git a/Meshtastic/Extensions/CoreData/SerialConfigEntityExtension.swift b/Meshtastic/Extensions/CoreData/SerialConfigEntityExtension.swift new file mode 100644 index 00000000..ac114909 --- /dev/null +++ b/Meshtastic/Extensions/CoreData/SerialConfigEntityExtension.swift @@ -0,0 +1,27 @@ +import CoreData + +extension SerialConfigEntity { + convenience init( + context: NSManagedObjectContext, + config: ModuleConfig.SerialConfig + ) { + self.init(context: context) + self.enabled = config.enabled + self.echo = config.echo + self.rxd = Int32(config.rxd) + self.txd = Int32(config.txd) + self.baudRate = Int32(config.baud.rawValue) + self.timeout = Int32(config.timeout) + self.mode = Int32(config.mode.rawValue) + } + + func update(with config: ModuleConfig.SerialConfig) { + enabled = config.enabled + echo = config.echo + rxd = Int32(config.rxd) + txd = Int32(config.txd) + baudRate = Int32(config.baud.rawValue) + timeout = Int32(config.timeout) + mode = Int32(config.mode.rawValue) + } +} diff --git a/Meshtastic/Extensions/CoreData/StoreForwardConfigEntityExtension.swift b/Meshtastic/Extensions/CoreData/StoreForwardConfigEntityExtension.swift new file mode 100644 index 00000000..2951bb8a --- /dev/null +++ b/Meshtastic/Extensions/CoreData/StoreForwardConfigEntityExtension.swift @@ -0,0 +1,23 @@ +import CoreData + +extension StoreForwardConfigEntity { + convenience init( + context: NSManagedObjectContext, + config: ModuleConfig.StoreForwardConfig + ) { + self.init(context: context) + self.enabled = config.enabled + self.heartbeat = config.heartbeat + self.records = Int32(config.records) + self.historyReturnMax = Int32(config.historyReturnMax) + self.historyReturnWindow = Int32(config.historyReturnWindow) + } + + func update(with config: ModuleConfig.StoreForwardConfig) { + enabled = config.enabled + heartbeat = config.heartbeat + records = Int32(config.records) + historyReturnMax = Int32(config.historyReturnMax) + historyReturnWindow = Int32(config.historyReturnWindow) + } +} diff --git a/Meshtastic/Extensions/CoreData/WaypointEntityExtension.swift b/Meshtastic/Extensions/CoreData/WaypointEntityExtension.swift index b17ccecf..96b5ed5f 100644 --- a/Meshtastic/Extensions/CoreData/WaypointEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/WaypointEntityExtension.swift @@ -10,6 +10,19 @@ import MapKit import SwiftUI extension WaypointEntity { + + convenience init( + context: NSManagedObjectContext, + coordinate: CLLocationCoordinate2D + ) { + self.init(context: context) + self.id = 0 + self.name = "Waypoint Pin" + self.expire = Date.now.addingTimeInterval(60 * 480) + self.latitudeI = Int32(coordinate.latitude * 1e7) + self.longitudeI = Int32(coordinate.longitude * 1e7) + self.expire = Date.now.addingTimeInterval(60 * 480) + } static func allWaypointssFetchRequest() -> NSFetchRequest { let request: NSFetchRequest = WaypointEntity.fetchRequest() diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index fb2c5f29..660021d8 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -685,8 +685,8 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var hopNodes: [TraceRouteHopEntity] = [] for node in routingMessage.route { var hopNode = getNodeInfo(id: Int64(node), context: context!) - if hopNode == nil && hopNode?.num ?? 0 > 0 { - hopNode = createNodeInfo(num: Int64(node), context: context!) + if hopNode == nil { + hopNode = NodeInfoEntity(context: context!, num: Int(node)) } let traceRouteHop = TraceRouteHopEntity(context: context!) traceRouteHop.time = Date() diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 645b52b0..bb4c2e2e 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -156,30 +156,29 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo return } if fetchedMyInfo.count == 1 { - let newChannel = ChannelEntity(context: context) - newChannel.id = Int32(channel.index) - newChannel.index = Int32(channel.index) - newChannel.uplinkEnabled = channel.settings.uplinkEnabled - newChannel.downlinkEnabled = channel.settings.downlinkEnabled - newChannel.name = channel.settings.name - newChannel.role = Int32(channel.role.rawValue) - newChannel.psk = channel.settings.psk - if channel.settings.hasModuleSettings { - newChannel.positionPrecision = Int32(truncatingIfNeeded: channel.settings.moduleSettings.positionPrecision) - newChannel.mute = channel.settings.moduleSettings.isClientMuted - } - guard let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as? NSMutableOrderedSet else { + let newChannel = ChannelEntity( + context: context, + channel: channel + ) + guard let mutableChannels = fetchedMyInfo.first?.channels?.mutableCopy() as? NSMutableOrderedSet else { return } - if let oldChannel = mutableChannels.first(where: {($0 as AnyObject).index == newChannel.index }) as? ChannelEntity { - let index = mutableChannels.index(of: oldChannel as Any) + let oldChannel = mutableChannels.first(where: { + if let channel = $0 as? ChannelEntity { + return channel.index == newChannel.index + } + return false + }) as? ChannelEntity + + if let oldChannel { + let index = mutableChannels.index(of: oldChannel) mutableChannels.replaceObject(at: index, with: newChannel) } else { mutableChannels.add(newChannel) } - fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet + fetchedMyInfo.first?.channels = mutableChannels.copy() as? NSOrderedSet if newChannel.name?.lowercased() == "admin" { - fetchedMyInfo[0].adminIndex = newChannel.index + fetchedMyInfo.first?.adminIndex = newChannel.index } context.refresh(newChannel, mergeChanges: true) do { @@ -212,29 +211,18 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS guard let fetchedNode = try context.fetch(fetchedNodeRequest) as? [NodeInfoEntity] else { return } - let newMetadata = DeviceMetadataEntity(context: context) - newMetadata.time = Date() - newMetadata.deviceStateVersion = Int32(metadata.deviceStateVersion) - newMetadata.canShutdown = metadata.canShutdown - newMetadata.hasWifi = metadata.hasWifi_p - newMetadata.hasBluetooth = metadata.hasBluetooth_p - newMetadata.hasEthernet = metadata.hasEthernet_p - newMetadata.role = Int32(metadata.role.rawValue) - newMetadata.positionFlags = Int32(metadata.positionFlags) - // Swift does strings weird, this does work to get the version without the github hash - let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".") - var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))] - version = version.dropLast() - newMetadata.firmwareVersion = String(version) - if fetchedNode.count > 0 { - fetchedNode[0].metadata = newMetadata - } else { - - if fromNum > 0 { - let newNode = createNodeInfo(num: Int64(fromNum), context: context) - newNode.metadata = newMetadata - } + let newMetadata = DeviceMetadataEntity( + context: context, + metadata: metadata + ) + + if let node = fetchedNode.first { + node.metadata = newMetadata + } else if fromNum > 0 { + let node = NodeInfoEntity(context: context, num: Int(fromNum)) + node.metadata = newMetadata } + do { try context.save() } catch { diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 9472fd05..cb36435c 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -960,56 +960,28 @@ func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfi guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else { return } + + guard let node = fetchedNode.first else { + return Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save External Notification Module Config") + } + // Found a node, save External Notificaitone Config - if !fetchedNode.isEmpty { - - if fetchedNode[0].externalNotificationConfig == nil { - let newExternalNotificationConfig = ExternalNotificationConfigEntity(context: context) - newExternalNotificationConfig.enabled = config.enabled - newExternalNotificationConfig.usePWM = config.usePwm - newExternalNotificationConfig.alertBell = config.alertBell - newExternalNotificationConfig.alertBellBuzzer = config.alertBellBuzzer - newExternalNotificationConfig.alertBellVibra = config.alertBellVibra - newExternalNotificationConfig.alertMessage = config.alertMessage - newExternalNotificationConfig.alertMessageBuzzer = config.alertMessageBuzzer - newExternalNotificationConfig.alertMessageVibra = config.alertMessageVibra - newExternalNotificationConfig.active = config.active - newExternalNotificationConfig.output = Int32(config.output) - newExternalNotificationConfig.outputBuzzer = Int32(config.outputBuzzer) - newExternalNotificationConfig.outputVibra = Int32(config.outputVibra) - newExternalNotificationConfig.outputMilliseconds = Int32(config.outputMs) - newExternalNotificationConfig.nagTimeout = Int32(config.nagTimeout) - newExternalNotificationConfig.useI2SAsBuzzer = config.useI2SAsBuzzer - fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig - - } else { - fetchedNode[0].externalNotificationConfig?.enabled = config.enabled - fetchedNode[0].externalNotificationConfig?.usePWM = config.usePwm - fetchedNode[0].externalNotificationConfig?.alertBell = config.alertBell - fetchedNode[0].externalNotificationConfig?.alertBellBuzzer = config.alertBellBuzzer - fetchedNode[0].externalNotificationConfig?.alertBellVibra = config.alertBellVibra - fetchedNode[0].externalNotificationConfig?.alertMessage = config.alertMessage - fetchedNode[0].externalNotificationConfig?.alertMessageBuzzer = config.alertMessageBuzzer - fetchedNode[0].externalNotificationConfig?.alertMessageVibra = config.alertMessageVibra - fetchedNode[0].externalNotificationConfig?.active = config.active - fetchedNode[0].externalNotificationConfig?.output = Int32(config.output) - fetchedNode[0].externalNotificationConfig?.outputBuzzer = Int32(config.outputBuzzer) - fetchedNode[0].externalNotificationConfig?.outputVibra = Int32(config.outputVibra) - fetchedNode[0].externalNotificationConfig?.outputMilliseconds = Int32(config.outputMs) - fetchedNode[0].externalNotificationConfig?.nagTimeout = Int32(config.nagTimeout) - fetchedNode[0].externalNotificationConfig?.useI2SAsBuzzer = config.useI2SAsBuzzer - } - - do { - try context.save() - Logger.data.info("💾 Updated External Notification Module Config for node number: \(String(nodeNum))") - } catch { - context.rollback() - let nsError = error as NSError - Logger.data.error("Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)") - } + if let externalNotificationConfig = node.externalNotificationConfig { + externalNotificationConfig.update(with: config) } else { - Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save External Notification Module Config") + node.externalNotificationConfig = ExternalNotificationConfigEntity( + context: context, + config: config + ) + } + + do { + try context.save() + Logger.data.info("💾 Updated External Notification Module Config for node number: \(String(nodeNum))") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)") } } catch { let nsError = error as NSError @@ -1114,48 +1086,29 @@ func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, no guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else { return } - // Found a node, save MQTT Config - if !fetchedNode.isEmpty { - - if fetchedNode[0].mqttConfig == nil { - let newMQTTConfig = MQTTConfigEntity(context: context) - newMQTTConfig.enabled = config.enabled - newMQTTConfig.proxyToClientEnabled = config.proxyToClientEnabled - newMQTTConfig.address = config.address - newMQTTConfig.username = config.username - newMQTTConfig.password = config.password - newMQTTConfig.root = config.root - newMQTTConfig.encryptionEnabled = config.encryptionEnabled - newMQTTConfig.jsonEnabled = config.jsonEnabled - newMQTTConfig.tlsEnabled = config.tlsEnabled - newMQTTConfig.mapReportingEnabled = config.mapReportingEnabled - newMQTTConfig.mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision) - newMQTTConfig.mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs) - fetchedNode[0].mqttConfig = newMQTTConfig - } else { - fetchedNode[0].mqttConfig?.enabled = config.enabled - fetchedNode[0].mqttConfig?.proxyToClientEnabled = config.proxyToClientEnabled - fetchedNode[0].mqttConfig?.address = config.address - fetchedNode[0].mqttConfig?.username = config.username - fetchedNode[0].mqttConfig?.password = config.password - fetchedNode[0].mqttConfig?.root = config.root - fetchedNode[0].mqttConfig?.encryptionEnabled = config.encryptionEnabled - fetchedNode[0].mqttConfig?.jsonEnabled = config.jsonEnabled - fetchedNode[0].mqttConfig?.tlsEnabled = config.tlsEnabled - fetchedNode[0].mqttConfig?.mapReportingEnabled = config.mapReportingEnabled - fetchedNode[0].mqttConfig?.mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision) - fetchedNode[0].mqttConfig?.mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs) - } - do { - try context.save() - Logger.data.info("💾 Updated MQTT Config for node number: \(String(nodeNum))") - } catch { - context.rollback() - let nsError = error as NSError - Logger.data.error("Error Updating Core Data MQTTConfigEntity: \(nsError)") - } - } else { + + guard let node = fetchedNode.first else { Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save MQTT Module Config") + return + } + // Found a node, save MQTT Config + + if let mqttConfig = node.mqttConfig { + mqttConfig.update(with: config) + } else { + node.mqttConfig = MQTTConfigEntity( + context: context, + config: config + ) + } + + do { + try context.save() + Logger.data.info("💾 Updated MQTT Config for node number: \(String(nodeNum))") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("Error Updating Core Data MQTTConfigEntity: \(nsError)") } } catch { let nsError = error as NSError @@ -1177,32 +1130,28 @@ func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTest return } // Found a node, save Device Config - if !fetchedNode.isEmpty { - if fetchedNode[0].rangeTestConfig == nil { - let newRangeTestConfig = RangeTestConfigEntity(context: context) - newRangeTestConfig.sender = Int32(config.sender) - newRangeTestConfig.enabled = config.enabled - newRangeTestConfig.save = config.save - fetchedNode[0].rangeTestConfig = newRangeTestConfig + if let node = fetchedNode.first { + if let rangeTestConfig = node.rangeTestConfig { + rangeTestConfig.update(with: config) } else { - fetchedNode[0].rangeTestConfig?.sender = Int32(config.sender) - fetchedNode[0].rangeTestConfig?.enabled = config.enabled - fetchedNode[0].rangeTestConfig?.save = config.save + node.rangeTestConfig = RangeTestConfigEntity( + context: context, + config: config + ) } + do { try context.save() Logger.data.info("💾 Updated Range Test Config for node number: \(String(nodeNum))") } catch { context.rollback() - let nsError = error as NSError - Logger.data.error("Error Updating Core Data RangeTestConfigEntity: \(nsError)") + Logger.data.error("Error Updating Core Data RangeTestConfigEntity: \(error.localizedDescription)") } } else { Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Range Test Module Config") } } catch { - let nsError = error as NSError - Logger.data.error("Fetching node for core data RangeTestConfigEntity failed: \(nsError)") + Logger.data.error("Fetching node for core data RangeTestConfigEntity failed: \(error.localizedDescription)") } } @@ -1215,55 +1164,32 @@ func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) do { - guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else { return } - + guard let node = fetchedNode.first else { + return Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config") + } + // Found a node, save Device Config - if !fetchedNode.isEmpty { - - if fetchedNode[0].serialConfig == nil { - - let newSerialConfig = SerialConfigEntity(context: context) - newSerialConfig.enabled = config.enabled - newSerialConfig.echo = config.echo - newSerialConfig.rxd = Int32(config.rxd) - newSerialConfig.txd = Int32(config.txd) - newSerialConfig.baudRate = Int32(config.baud.rawValue) - newSerialConfig.timeout = Int32(config.timeout) - newSerialConfig.mode = Int32(config.mode.rawValue) - fetchedNode[0].serialConfig = newSerialConfig - - } else { - fetchedNode[0].serialConfig?.enabled = config.enabled - fetchedNode[0].serialConfig?.echo = config.echo - fetchedNode[0].serialConfig?.rxd = Int32(config.rxd) - fetchedNode[0].serialConfig?.txd = Int32(config.txd) - fetchedNode[0].serialConfig?.baudRate = Int32(config.baud.rawValue) - fetchedNode[0].serialConfig?.timeout = Int32(config.timeout) - fetchedNode[0].serialConfig?.mode = Int32(config.mode.rawValue) - } - - do { - try context.save() - Logger.data.info("💾 Updated Serial Module Config for node number: \(String(nodeNum))") - - } catch { - - context.rollback() - - let nsError = error as NSError - Logger.data.error("Error Updating Core Data SerialConfigEntity: \(nsError)") - } - + if let serialConfig = node.serialConfig { + node.serialConfig?.update(with: config) } else { - - Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config") + node.serialConfig = SerialConfigEntity( + context: context, + config: config + ) } + do { + try context.save() + Logger.data.info("💾 Updated Serial Module Config for node number: \(String(nodeNum))") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("Error Updating Core Data SerialConfigEntity: \(nsError)") + } } catch { - let nsError = error as NSError Logger.data.error("Fetching node for core data SerialConfigEntity failed: \(nsError)") } @@ -1282,36 +1208,26 @@ func upsertStoreForwardModuleConfigPacket(config: Meshtastic.ModuleConfig.StoreF guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else { return } - // Found a node, save Store & Forward Sensor Config - if !fetchedNode.isEmpty { - - if fetchedNode[0].storeForwardConfig == nil { - - let newConfig = StoreForwardConfigEntity(context: context) - newConfig.enabled = config.enabled - newConfig.heartbeat = config.heartbeat - newConfig.records = Int32(config.records) - newConfig.historyReturnMax = Int32(config.historyReturnMax) - newConfig.historyReturnWindow = Int32(config.historyReturnWindow) - fetchedNode[0].storeForwardConfig = newConfig - - } else { - fetchedNode[0].storeForwardConfig?.enabled = config.enabled - fetchedNode[0].storeForwardConfig?.heartbeat = config.heartbeat - fetchedNode[0].storeForwardConfig?.records = Int32(config.records) - fetchedNode[0].storeForwardConfig?.historyReturnMax = Int32(config.historyReturnMax) - fetchedNode[0].storeForwardConfig?.historyReturnWindow = Int32(config.historyReturnWindow) - } - do { - try context.save() - Logger.data.info("💾 Updated Store & Forward Module Config for node number: \(String(nodeNum))") - } catch { - context.rollback() - let nsError = error as NSError - Logger.data.error("Error Updating Core Data StoreForwardConfigEntity: \(nsError)") - } - } else { + guard let node = fetchedNode.first else { Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Store & Forward Module Config") + return + } + // Found a node, save Store & Forward Sensor Config + if let storeForwardConfig = node.storeForwardConfig { + storeForwardConfig.update(with: config) + } else { + node.storeForwardConfig = StoreForwardConfigEntity( + context: context, + config: config + ) + } + do { + try context.save() + Logger.data.info("💾 Updated Store & Forward Module Config for node number: \(String(nodeNum))") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("Error Updating Core Data StoreForwardConfigEntity: \(nsError)") } } catch { let nsError = error as NSError diff --git a/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift index 5c7291a5..78d66cf2 100644 --- a/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/MapKitMap/Custom/MapViewSwiftUI.swift @@ -183,7 +183,11 @@ struct MapViewSwiftUI: UIViewRepresentable { } var lineIndex = 0 for position in latest { - let nodePositions = positions.filter { $0.nodeCoordinate != nil && $0.nodePosition?.num ?? 0 == position.nodePosition?.num ?? -1 } + let nodePositions = positions.filter { + $0.nodeCoordinate != nil && + $0.nodePosition != nil && + $0.nodePosition?.num == position.nodePosition?.num + } let lineCoords = nodePositions.compactMap({(position) -> CLLocationCoordinate2D in return position.nodeCoordinate ?? LocationHelper.DefaultLocation }) diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index caa3f5d6..eff15a39 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -78,13 +78,10 @@ struct MeshMap: View { } newWaypointCoord = coordinate - editingWaypoint = WaypointEntity(context: context) - editingWaypoint!.name = "Waypoint Pin" - editingWaypoint!.expire = Date.now.addingTimeInterval(60 * 480) - editingWaypoint!.latitudeI = Int32((newWaypointCoord?.latitude ?? 0) * 1e7) - editingWaypoint!.longitudeI = Int32((newWaypointCoord?.longitude ?? 0) * 1e7) - editingWaypoint!.expire = Date.now.addingTimeInterval(60 * 480) - editingWaypoint!.id = 0 + editingWaypoint = WaypointEntity( + context: context, + coordinate: coordinate + ) Logger.services.debug("Long press occured at Lat: \(coordinate.latitude) Long: \(coordinate.longitude)") default: return } @@ -133,7 +130,7 @@ struct MeshMap: View { // //position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 1000, heading: 0, pitch: 60)) // } // } - .onChange(of: (selectedMapLayer)) { newMapLayer in + .onChange(of: selectedMapLayer) { newMapLayer in switch selectedMapLayer { case .standard: UserDefaults.mapLayer = newMapLayer diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index 689a009e..18a9890d 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -259,18 +259,18 @@ struct Channels: View { uplink = false downlink = false hasChanges = true - - let newChannel = ChannelEntity(context: context) - newChannel.id = channelIndex - newChannel.index = channelIndex - newChannel.uplinkEnabled = uplink - newChannel.downlinkEnabled = downlink - newChannel.name = channelName - newChannel.role = Int32(channelRole) - newChannel.psk = Data(base64Encoded: channelKey) ?? Data() - newChannel.positionPrecision = Int32(positionPrecision) - selectedChannel = newChannel - + + selectedChannel = ChannelEntity( + context: context, + id: channelIndex, + index: channelIndex, + uplinkEnabled: uplink, + downlinkEnabled: downlink, + name: channelName, + role: Int32(channelRole), + psk: Data(base64Encoded: channelKey) ?? Data(), + positionPrecision: Int32(positionPrecision) + ) } label: { Label("Add Channel", systemImage: "plus.square") } diff --git a/Meshtastic/Views/Settings/RouteRecorder.swift b/Meshtastic/Views/Settings/RouteRecorder.swift index c19dbd9f..38685a23 100644 --- a/Meshtastic/Views/Settings/RouteRecorder.swift +++ b/Meshtastic/Views/Settings/RouteRecorder.swift @@ -284,29 +284,22 @@ struct RouteRecorder: View { .onDisappear(perform: { UIApplication.shared.isIdleTimerDisabled = false }) - .onChange(of: locationsHandler.locationsArray.last) { newLoc in - if locationsHandler.isRecording { - if let loc = newLoc { - if recording != nil { - let locationEntity = LocationEntity(context: context) - locationEntity.routeLocation = recording - locationEntity.id = Int32(locationsHandler.count) - locationEntity.altitude = Int32(loc.altitude) - locationEntity.heading = Int32(loc.course) - locationEntity.speed = Int32(loc.speed) - locationEntity.latitudeI = Int32(loc.coordinate.latitude * 1e7) - locationEntity.longitudeI = Int32(loc.coordinate.longitude * 1e7) - 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)") - } - } - } + .onChange(of: locationsHandler.locationsArray.last) { location in + guard locationsHandler.isRecording, let location, let recording else { return } + let locationEntity = LocationEntity( + context: context, + route: recording, + id: Int32(locationsHandler.count), + location: location + ) + + do { + try context.save() + Logger.data.info("💾 Saved a new route location") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("Error Saving LocationEntity from the Route Recorder \(nsError)") } } } diff --git a/Widgets/Info.plist b/Widgets/Info.plist index 0f118fb7..b3dac3d4 100644 --- a/Widgets/Info.plist +++ b/Widgets/Info.plist @@ -2,6 +2,8 @@ + CFBundleVersion + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionPointIdentifier