mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Additional cleanup for nodes tab. Show connected node on every view for a phon, only the detail tab on ipad and mac
This commit is contained in:
parent
7ca655535a
commit
28386ee681
14 changed files with 933 additions and 547 deletions
|
|
@ -25,7 +25,7 @@
|
|||
DD2553592855B52700E55709 /* PositionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2553582855B52700E55709 /* PositionConfig.swift */; };
|
||||
DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */; };
|
||||
DD2DC2C029BCD8AB003B383C /* HardwareModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2DC2BF29BCD8AB003B383C /* HardwareModels.swift */; };
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E65252767A01F00E45FC5 /* NodeDetail.swift */; };
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetailOld.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E65252767A01F00E45FC5 /* NodeDetailOld.swift */; };
|
||||
DD3501892852FC3B000FC853 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3501882852FC3B000FC853 /* Settings.swift */; };
|
||||
DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */; };
|
||||
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */; };
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582928585C32009B0E59 /* RangeTestConfig.swift */; };
|
||||
DD41A61529AB0035003C5A37 /* NodeWeatherForecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41A61429AB0035003C5A37 /* NodeWeatherForecast.swift */; };
|
||||
DD457188293C7E63000C49FB /* BLESignalStrengthIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */; };
|
||||
DD47E3CE26F103C600029299 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeList.swift */; };
|
||||
DD47E3CE26F103C600029299 /* NodeListOld.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeListOld.swift */; };
|
||||
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D526F17ED900029299 /* CircleText.swift */; };
|
||||
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; };
|
||||
DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */; };
|
||||
|
|
@ -134,9 +134,9 @@
|
|||
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 /* NodeListSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB263E2AABEE20003AFCB7 /* NodeListSplit.swift */; };
|
||||
DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB263E2AABEE20003AFCB7 /* NodeList.swift */; };
|
||||
DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26412AABF655003AFCB7 /* NodeListItem.swift */; };
|
||||
DDDB26442AAC0206003AFCB7 /* NodeDetailItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26432AAC0206003AFCB7 /* NodeDetailItem.swift */; };
|
||||
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */; };
|
||||
DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */; };
|
||||
DDDB26482AACD6D1003AFCB7 /* NodeMapControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26472AACD6D1003AFCB7 /* NodeMapControl.swift */; };
|
||||
DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443529F6287000EE2349 /* MapButtons.swift */; };
|
||||
|
|
@ -227,7 +227,7 @@
|
|||
DD2553582855B52700E55709 /* PositionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionConfig.swift; sourceTree = "<group>"; };
|
||||
DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = "<group>"; };
|
||||
DD2DC2BF29BCD8AB003B383C /* HardwareModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardwareModels.swift; sourceTree = "<group>"; };
|
||||
DD2E65252767A01F00E45FC5 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = "<group>"; };
|
||||
DD2E65252767A01F00E45FC5 /* NodeDetailOld.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetailOld.swift; sourceTree = "<group>"; };
|
||||
DD3501882852FC3B000FC853 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
||||
DD3CC6B428E33FD100FA9159 /* ShareChannels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannels.swift; sourceTree = "<group>"; };
|
||||
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModel.xcdatamodel; sourceTree = "<group>"; };
|
||||
|
|
@ -242,7 +242,7 @@
|
|||
DD41A61E29AE7E8F003C5A37 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||
DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLESignalStrengthIndicator.swift; sourceTree = "<group>"; };
|
||||
DD457BC4295D5E35004BCE4D /* MeshtasticDataModelV5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV5.xcdatamodel; sourceTree = "<group>"; };
|
||||
DD47E3CD26F103C600029299 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = "<group>"; };
|
||||
DD47E3CD26F103C600029299 /* NodeListOld.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListOld.swift; sourceTree = "<group>"; };
|
||||
DD47E3D526F17ED900029299 /* CircleText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleText.swift; sourceTree = "<group>"; };
|
||||
DD4A911D2708C65400501B7E /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
|
||||
DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentMetricsLog.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -354,11 +354,12 @@
|
|||
DDD6EEAE29BC024700383354 /* Firmware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firmware.swift; sourceTree = "<group>"; };
|
||||
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
|
||||
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DDDB263E2AABEE20003AFCB7 /* NodeListSplit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListSplit.swift; sourceTree = "<group>"; };
|
||||
DDDB263E2AABEE20003AFCB7 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = "<group>"; };
|
||||
DDDB26412AABF655003AFCB7 /* NodeListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeListItem.swift; sourceTree = "<group>"; };
|
||||
DDDB26432AAC0206003AFCB7 /* NodeDetailItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetailItem.swift; sourceTree = "<group>"; };
|
||||
DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = "<group>"; };
|
||||
DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoItem.swift; sourceTree = "<group>"; };
|
||||
DDDB26472AACD6D1003AFCB7 /* NodeMapControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMapControl.swift; sourceTree = "<group>"; };
|
||||
DDDB26492AAD743E003AFCB7 /* MeshtasticDataModelV18.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV18.xcdatamodel; sourceTree = "<group>"; };
|
||||
DDDB443529F6287000EE2349 /* MapButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapButtons.swift; sourceTree = "<group>"; };
|
||||
DDDB443C29F6592F00EE2349 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
|
||||
DDDB443F29F79AB000EE2349 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -467,14 +468,14 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
DDDB26402AABEF7B003AFCB7 /* Helpers */,
|
||||
DD2E65252767A01F00E45FC5 /* NodeDetail.swift */,
|
||||
DD47E3CD26F103C600029299 /* NodeList.swift */,
|
||||
DD90860D26F69BAE00DC5189 /* NodeMap.swift */,
|
||||
DDDB263E2AABEE20003AFCB7 /* NodeList.swift */,
|
||||
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */,
|
||||
DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */,
|
||||
DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */,
|
||||
DD90860D26F69BAE00DC5189 /* NodeMap.swift */,
|
||||
DD73FD1028750779000852D6 /* PositionLog.swift */,
|
||||
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */,
|
||||
DDDB263E2AABEE20003AFCB7 /* NodeListSplit.swift */,
|
||||
DD2E65252767A01F00E45FC5 /* NodeDetailOld.swift */,
|
||||
DD47E3CD26F103C600029299 /* NodeListOld.swift */,
|
||||
);
|
||||
path = Nodes;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -810,7 +811,7 @@
|
|||
DDDB26402AABEF7B003AFCB7 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DDDB26432AAC0206003AFCB7 /* NodeDetailItem.swift */,
|
||||
DDDB26432AAC0206003AFCB7 /* NodeDetail.swift */,
|
||||
DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */,
|
||||
DDDB26412AABF655003AFCB7 /* NodeListItem.swift */,
|
||||
DDDB26472AACD6D1003AFCB7 /* NodeMapControl.swift */,
|
||||
|
|
@ -1101,7 +1102,7 @@
|
|||
DD5E5213298EE33B00D21B61 /* deviceonly.pb.swift in Sources */,
|
||||
DD5E5208298EE33B00D21B61 /* rtttl.pb.swift in Sources */,
|
||||
DD6193792863875F00E59241 /* SerialConfig.swift in Sources */,
|
||||
DDDB263F2AABEE20003AFCB7 /* NodeListSplit.swift in Sources */,
|
||||
DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */,
|
||||
DDA0B6B2294CDC55001356EC /* Channels.swift in Sources */,
|
||||
DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */,
|
||||
DDDB26482AACD6D1003AFCB7 /* NodeMapControl.swift in Sources */,
|
||||
|
|
@ -1135,7 +1136,7 @@
|
|||
DD5E520D298EE33B00D21B61 /* storeforward.pb.swift in Sources */,
|
||||
DD964FC2297272AE007C176F /* WaypointEntityExtension.swift in Sources */,
|
||||
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */,
|
||||
DD47E3CE26F103C600029299 /* NodeList.swift in Sources */,
|
||||
DD47E3CE26F103C600029299 /* NodeListOld.swift in Sources */,
|
||||
DD5E520A298EE33B00D21B61 /* channel.pb.swift in Sources */,
|
||||
DDDEE5E129DA3E1100A8E078 /* NodeInfoView.swift in Sources */,
|
||||
DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */,
|
||||
|
|
@ -1159,7 +1160,7 @@
|
|||
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */,
|
||||
DD8ED9C52898D51F00B3B0AB /* NetworkConfig.swift in Sources */,
|
||||
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
|
||||
DD2E65262767A01F00E45FC5 /* NodeDetailOld.swift in Sources */,
|
||||
DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */,
|
||||
DD1925B928CDA93900720036 /* SerialConfigEnums.swift in Sources */,
|
||||
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */,
|
||||
|
|
@ -1191,7 +1192,7 @@
|
|||
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */,
|
||||
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */,
|
||||
DDC4C9FF2A8D982900CE201C /* DetectionSensorConfig.swift in Sources */,
|
||||
DDDB26442AAC0206003AFCB7 /* NodeDetailItem.swift in Sources */,
|
||||
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
|
||||
DD5E5210298EE33B00D21B61 /* telemetry.pb.swift in Sources */,
|
||||
DD77093F2AA1B146007A8BF0 /* UIColor.swift in Sources */,
|
||||
DD5E5205298EE33B00D21B61 /* mesh.pb.swift in Sources */,
|
||||
|
|
@ -1713,6 +1714,7 @@
|
|||
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
DDDB26492AAD743E003AFCB7 /* MeshtasticDataModelV18.xcdatamodel */,
|
||||
DDF6B2462A9AEB9E00BA6931 /* MeshtasticDataModelV17.xcdatamodel */,
|
||||
DDC4CA012A8DAA3800CE201C /* MeshtasticDataModelV16.xcdatamodel */,
|
||||
DD14E72C2A80738F006E39BC /* MeshtasticDataModelV15.xcdatamodel */,
|
||||
|
|
@ -1731,7 +1733,7 @@
|
|||
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */,
|
||||
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */,
|
||||
);
|
||||
currentVersion = DDF6B2462A9AEB9E00BA6931 /* MeshtasticDataModelV17.xcdatamodel */;
|
||||
currentVersion = DDDB26492AAD743E003AFCB7 /* MeshtasticDataModelV18.xcdatamodel */;
|
||||
name = Meshtastic.xcdatamodeld;
|
||||
path = Meshtastic/Meshtastic.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ extension NodeInfoEntity {
|
|||
let environmentMetrics = telemetries?.filter{ ($0 as AnyObject).metricsType == 1 }
|
||||
return environmentMetrics?.count ?? 0 > 0
|
||||
}
|
||||
var hasDetectionSensorMetrics: Bool {
|
||||
return user?.sensorMessageList.count ?? 0 > 0
|
||||
}
|
||||
|
||||
var isOnline: Bool {
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
extension UserEntity {
|
||||
|
||||
|
||||
var messageList: [MessageEntity] {
|
||||
self.value(forKey: "allMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
|
|
@ -17,6 +18,10 @@ extension UserEntity {
|
|||
self.value(forKey: "adminMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
}
|
||||
|
||||
var sensorMessageList: [MessageEntity] {
|
||||
self.value(forKey: "detectionSensorMessages") as? [MessageEntity] ?? [MessageEntity]()
|
||||
}
|
||||
|
||||
var unreadMessages: Int {
|
||||
let unreadMessages = messageList.filter{ ($0 as AnyObject).read == false }
|
||||
return unreadMessages.count
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>MeshtasticDataModelV17.xcdatamodel</string>
|
||||
<string>MeshtasticDataModelV18.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@
|
|||
<fetchedProperty name="allMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false"/>
|
||||
</fetchedProperty>
|
||||
<fetchedProperty name="detectionSensorMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="UserEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND isEmoji == false AND portNum = 10"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="WaypointEntity" representedClassName="WaypointEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="created" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,366 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22221.1" systemVersion="23A5337a" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
|
||||
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="bluetoothConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="bluetoothConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="CannedMessageConfigEntity" representedClassName="CannedMessageConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventCcw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventCw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventPress" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerPinA" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerPinB" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerPinPress" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<attribute name="messages" optional="YES" attributeType="String" minValueString="0" maxValueString="198"/>
|
||||
<attribute name="rotary1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="updown1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="cannedMessagesConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="cannedMessageConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="ChannelEntity" representedClassName="ChannelEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="downlinkEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="index" attributeType="Integer 32" minValueString="0" maxValueString="13" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="psk" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="uplinkEnabled" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="myInfoChannel" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="channels" inverseEntity="MyInfoEntity"/>
|
||||
<fetchedProperty name="allPrivateMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="channel == $FETCH_SOURCE.index && toUser == nil AND isEmoji == false"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="index"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="DetectionSensorConfigEntity" representedClassName="DetectionSensorConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="detectionTriggeredHigh" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="minimumBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="monitorPin" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="stateBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="usePullup" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="detectionSensorConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="detectionSensorConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="buttonGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="buzzerGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="doubleTapAsButtonPress" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="isManaged" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="nodeInfoBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rebroadcastMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="serialEnabled" optional="YES" attributeType="Boolean" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="deviceConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="deviceConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DeviceMetadataEntity" representedClassName="DeviceMetadataEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="canShutdown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceStateVersion" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
|
||||
<attribute name="hasBluetooth" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hasEthernet" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hwModel" optional="YES" attributeType="String"/>
|
||||
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="metadataNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="metadata" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="compassNorthTop" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="displayMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="flipScreen" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="headingBold" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="oledType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="screenCarouselInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="screenOnSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="wakeOnTapOrMotion" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<relationship name="displayConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="displayConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="ExternalNotificationConfigEntity" representedClassName="ExternalNotificationConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="active" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBellBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBellVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessageBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessageVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="nagTimeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputBuzzer" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputVibra" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="usePWM" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="LocationEntity" representedClassName="LocationEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<attribute name="latitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="routeLocation" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RouteEntity" inverseName="locations" inverseEntity="RouteEntity"/>
|
||||
</entity>
|
||||
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bandwidth" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="channelNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="codingRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="frequencyOffset" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="overrideDutyCycle" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="overrideFrequency" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="regionCode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="spreadFactor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="sx126xRxBoostedGain" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="txEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="txPower" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="usePreset" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<relationship name="loRaConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="loRaConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="MessageEntity" representedClassName="MessageEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="ackError" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ackSNR" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="ackTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="admin" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="adminDescription" optional="YES" attributeType="String"/>
|
||||
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="messagePayload" optional="YES" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="messagePayloadMarkdown" optional="YES" attributeType="String"/>
|
||||
<attribute name="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="portNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="read" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="realACK" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="receivedTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="fromUser" optional="YES" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
|
||||
<relationship name="toUser" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="receivedMessages" inverseEntity="UserEntity"/>
|
||||
<fetchedProperty name="tapbacks" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="replyID == $FETCH_SOURCE.messageId AND isEmoji == true"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="messageId"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="MQTTConfigEntity" representedClassName="MQTTConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="address" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="encryptionEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="jsonEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="password" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<attribute name="proxyToClientEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="root" optional="YES" attributeType="String" defaultValueString="msh"/>
|
||||
<attribute name="tlsEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="username" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<relationship name="mqttConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="mqttConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="adminIndex" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="peripheralId" optional="YES" attributeType="String"/>
|
||||
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="channels" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="ChannelEntity" inverseName="myInfoChannel" inverseEntity="ChannelEntity"/>
|
||||
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
|
||||
<fetchedProperty name="allMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="toUser == nil"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="myNodeNum"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="NetworkConfigEntity" representedClassName="NetworkConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="dns" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ethEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="gateway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ip" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ntpServer" optional="YES" attributeType="String"/>
|
||||
<attribute name="subnet" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiMode" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiPsk" optional="YES" attributeType="String" minValueString="0" maxValueString="60"/>
|
||||
<attribute name="wifiSsid" optional="YES" attributeType="String" minValueString="0" maxValueString="30"/>
|
||||
<relationship name="networkConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="networkConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="detection" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="environment" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="lastHeard" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="peripheralId" optional="YES" attributeType="String"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="bluetoothConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BluetoothConfigEntity" inverseName="bluetoothConfigNode" inverseEntity="BluetoothConfigEntity"/>
|
||||
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
|
||||
<relationship name="detectionSensorConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DetectionSensorConfigEntity" inverseName="detectionSensorConfigNode" inverseEntity="DetectionSensorConfigEntity"/>
|
||||
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
|
||||
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DisplayConfigEntity" inverseName="displayConfigNode" inverseEntity="DisplayConfigEntity"/>
|
||||
<relationship name="externalNotificationConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ExternalNotificationConfigEntity" inverseName="externalNotificationConfigNode" inverseEntity="ExternalNotificationConfigEntity"/>
|
||||
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
|
||||
<relationship name="metadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceMetadataEntity" inverseName="metadataNode" inverseEntity="DeviceMetadataEntity"/>
|
||||
<relationship name="mqttConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MQTTConfigEntity" inverseName="mqttConfigNode" inverseEntity="MQTTConfigEntity"/>
|
||||
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
|
||||
<relationship name="networkConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NetworkConfigEntity" inverseName="networkConfigNode" inverseEntity="NetworkConfigEntity"/>
|
||||
<relationship name="positionConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PositionConfigEntity" inverseName="positionConfigNode" inverseEntity="PositionConfigEntity"/>
|
||||
<relationship name="positions" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PositionEntity" inverseName="nodePosition" inverseEntity="PositionEntity"/>
|
||||
<relationship name="rangeTestConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RangeTestConfigEntity" inverseName="rangeTestConfigNode" inverseEntity="RangeTestConfigEntity"/>
|
||||
<relationship name="rtttlConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RTTTLConfigEntity" inverseName="rtttlConfigNode" inverseEntity="RTTTLConfigEntity"/>
|
||||
<relationship name="serialConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SerialConfigEntity" inverseName="serialConfigNode" inverseEntity="SerialConfigEntity"/>
|
||||
<relationship name="storeForwardConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreForwardConfigEntity" inverseName="storeForwardConfigNode" inverseEntity="StoreForwardConfigEntity"/>
|
||||
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
|
||||
<relationship name="telemetryConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TelemetryConfigEntity" inverseName="telemetryConfigNode" inverseEntity="TelemetryConfigEntity"/>
|
||||
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="num"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="PositionConfigEntity" representedClassName="PositionConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="broadcastSmartMinimumDistance" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="broadcastSmartMinimumIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceGpsEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="fixedPosition" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsAttemptTime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="positionBroadcastSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rxGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="smartPositionEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="txGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="positionConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positionConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="PositionEntity" representedClassName="PositionEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="latest" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="satsInView" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="seqNo" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="nodePosition" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positions" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="RangeTestConfigEntity" representedClassName="RangeTestConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="save" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="sender" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="color" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="notes" optional="YES" attributeType="String"/>
|
||||
<relationship name="locations" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LocationEntity" inverseName="routeLocation" inverseEntity="LocationEntity"/>
|
||||
</entity>
|
||||
<entity name="RTTTLConfigEntity" representedClassName="RTTTLConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="ringtone" optional="YES" attributeType="String" maxValueString="228" defaultValueString=""/>
|
||||
<relationship name="rtttlConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rtttlConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="SerialConfigEntity" representedClassName="SerialConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="baudRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="echo" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rxd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="timeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="txd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="serialConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="serialConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="StoreForwardConfigEntity" representedClassName="StoreForwardConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="heartbeat" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="historyReturnMax" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="historyReturnWindow" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="records" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="storeForwardConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="storeForwardConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="TelemetryConfigEntity" representedClassName="TelemetryConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="deviceUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentDisplayFahrenheit" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentMeasurementEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="telemetryConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetryConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="TelemetryEntity" representedClassName="TelemetryEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="airUtilTx" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="barometricPressure" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="batteryLevel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="channelUtilization" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="current" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="gasResistance" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="metricsType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="relativeHumidity" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="temperature" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="voltage" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="nodeTelemetry" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetries" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="UserEntity" representedClassName="UserEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="hwModel" attributeType="String"/>
|
||||
<attribute name="isLicensed" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="lastMessage" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="longName" attributeType="String"/>
|
||||
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="shortName" attributeType="String"/>
|
||||
<attribute name="userId" attributeType="String"/>
|
||||
<attribute name="vip" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<relationship name="receivedMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="toUser" inverseEntity="MessageEntity"/>
|
||||
<relationship name="sentMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="fromUser" inverseEntity="MessageEntity"/>
|
||||
<relationship name="userNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="user" inverseEntity="NodeInfoEntity"/>
|
||||
<fetchedProperty name="adminMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND isEmoji == false AND admin = true"/>
|
||||
</fetchedProperty>
|
||||
<fetchedProperty name="allMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false"/>
|
||||
</fetchedProperty>
|
||||
<fetchedProperty name="detectionSensorMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND portNum = 10"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="WaypointEntity" representedClassName="WaypointEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="created" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="expire" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="icon" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="lastUpdated" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="locked" attributeType="Integer 64" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="longDescription" optional="YES" attributeType="String" maxValueString="100"/>
|
||||
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" attributeType="String" minValueString="1" maxValueString="30"/>
|
||||
</entity>
|
||||
</model>
|
||||
|
|
@ -10,35 +10,39 @@ struct ConnectedDevice: View {
|
|||
var deviceConnected: Bool
|
||||
var name: String
|
||||
var mqttProxyConnected: Bool = false
|
||||
var phoneOnly: Bool = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
HStack {
|
||||
if bluetoothOn {
|
||||
if deviceConnected && mqttProxyConnected {
|
||||
if mqttProxyConnected {
|
||||
Image(systemName: "iphone.gen3.radiowaves.left.and.right.circle.fill")
|
||||
|
||||
if (phoneOnly && UIDevice.current.userInterfaceIdiom == .phone) || !phoneOnly {
|
||||
if bluetoothOn {
|
||||
if deviceConnected && mqttProxyConnected {
|
||||
if mqttProxyConnected {
|
||||
Image(systemName: "iphone.gen3.radiowaves.left.and.right.circle.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.green)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
}
|
||||
if deviceConnected {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.circle.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.green)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
}
|
||||
if deviceConnected {
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.circle.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.green)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text(name).font(name.isEmoji() ? .title : .callout).foregroundColor(.gray)
|
||||
} else {
|
||||
Text(name).font(name.isEmoji() ? .title : .callout).foregroundColor(.gray)
|
||||
} else {
|
||||
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.imageScale(.medium)
|
||||
.foregroundColor(.red)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
} else {
|
||||
Text("bluetooth.off").font(.subheadline).foregroundColor(.red)
|
||||
}
|
||||
Image(systemName: "antenna.radiowaves.left.and.right.slash")
|
||||
.imageScale(.medium)
|
||||
.foregroundColor(.red)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
}
|
||||
} else {
|
||||
Text("bluetooth.off").font(.subheadline).foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,261 +1,261 @@
|
|||
////
|
||||
//// NodeInfoView.swift
|
||||
//// Meshtastic
|
||||
////
|
||||
//// Created by Garth Vander Houwen on 4/2/23.
|
||||
////
|
||||
//
|
||||
// NodeInfoView.swift
|
||||
// Meshtastic
|
||||
////
|
||||
//// DistanceText.swift
|
||||
//// Meshtastic
|
||||
////
|
||||
//// Copyright(c) Garth Vander Houwen 8/19/22.
|
||||
////
|
||||
//
|
||||
// Created by Garth Vander Houwen on 4/2/23.
|
||||
//import SwiftUI
|
||||
//import CoreLocation
|
||||
//import MapKit
|
||||
//
|
||||
|
||||
//struct NodeInfoView: View {
|
||||
//
|
||||
// DistanceText.swift
|
||||
// Meshtastic
|
||||
// var node: NodeInfoEntity
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 8/19/22.
|
||||
// var body: some View {
|
||||
// let hwModelString = node.user?.hwModel ?? "UNSET"
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreLocation
|
||||
import MapKit
|
||||
|
||||
struct NodeInfoView: View {
|
||||
|
||||
var node: NodeInfoEntity
|
||||
|
||||
var body: some View {
|
||||
let hwModelString = node.user?.hwModel ?? "UNSET"
|
||||
|
||||
Divider()
|
||||
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
HStack {
|
||||
VStack(alignment: .center) {
|
||||
CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 150)
|
||||
}
|
||||
Divider()
|
||||
VStack {
|
||||
if node.user != nil {
|
||||
Image(hwModelString)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 100, height: 100)
|
||||
.cornerRadius(5)
|
||||
|
||||
Text(String(hwModelString))
|
||||
.foregroundColor(.gray)
|
||||
.font(.title).fixedSize()
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
if node.snr != 0 {
|
||||
VStack(alignment: .center) {
|
||||
let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: ModemPresets.longModerate)
|
||||
LoRaSignalStrengthIndicator(signalStrength: signalStrength)
|
||||
Text("Signal \(signalStrength.description)").font(.title)
|
||||
Text("SNR \(String(format: "%.2f", node.snr))dB")
|
||||
.foregroundColor(getSnrColor(snr: node.snr, preset: ModemPresets.longModerate))
|
||||
.font(.title3)
|
||||
Text("RSSI \(node.rssi)dB")
|
||||
.foregroundColor(getRssiColor(rssi: node.rssi))
|
||||
.font(.title3)
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
|
||||
if node.hasDeviceMetrics {
|
||||
let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
VStack(alignment: .center) {
|
||||
BatteryGauge(batteryLevel: Double(mostRecent?.batteryLevel ?? 0))
|
||||
if mostRecent?.voltage ?? 0 > 0.0 {
|
||||
|
||||
Text(String(format: "%.2f", mostRecent?.voltage ?? 0.0) + " V")
|
||||
.font(.title)
|
||||
.foregroundColor(.gray)
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
|
||||
Divider()
|
||||
HStack(alignment: .center) {
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "person")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("user").font(.title)+Text(":").font(.title)
|
||||
}
|
||||
Text("!\(String(format: "%02x", node.num))")
|
||||
.font(.title).foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "number")
|
||||
.font(.title2)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("Node Number:").font(.title)
|
||||
}
|
||||
Text(String(node.num)).font(.title).foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "clock.badge.checkmark.fill")
|
||||
.font(.title)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("heard.last").font(.title)+Text(":").font(.title)
|
||||
|
||||
}
|
||||
DateTimeText(dateTime: node.lastHeard)
|
||||
.font(.title3)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
|
||||
} else {
|
||||
|
||||
HStack {
|
||||
|
||||
VStack(alignment: .center) {
|
||||
CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65)
|
||||
}
|
||||
if node.user != nil {
|
||||
Divider()
|
||||
VStack {
|
||||
Image(node.user!.hwModel ?? "unset".localized)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 75, height: 75)
|
||||
.cornerRadius(5)
|
||||
Text(String(node.user!.hwModel ?? "unset".localized))
|
||||
.font(.caption2).fixedSize()
|
||||
}
|
||||
}
|
||||
if node.snr != 0 {
|
||||
Divider()
|
||||
VStack(alignment: .center) {
|
||||
let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: ModemPresets.longModerate)
|
||||
LoRaSignalStrengthIndicator(signalStrength: signalStrength)
|
||||
Text("Signal \(signalStrength.description)").font(.footnote)
|
||||
Text("SNR \(String(format: "%.2f", node.snr))dB")
|
||||
.foregroundColor(getSnrColor(snr: node.snr, preset: ModemPresets.longModerate))
|
||||
.font(.caption2)
|
||||
Text("RSSI \(node.rssi)dB")
|
||||
.foregroundColor(getRssiColor(rssi: node.rssi))
|
||||
.font(.caption2)
|
||||
}
|
||||
}
|
||||
let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
if deviceMetrics?.count ?? 0 >= 1 {
|
||||
Divider()
|
||||
let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
VStack(alignment: .center) {
|
||||
BatteryGauge(batteryLevel: Double(mostRecent?.batteryLevel ?? 0))
|
||||
if mostRecent?.voltage ?? 0 > 0 {
|
||||
|
||||
Text(String(format: "%.2f", mostRecent?.voltage ?? 0) + " V")
|
||||
.font(.callout)
|
||||
.foregroundColor(.gray)
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
HStack(alignment: .center) {
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "person")
|
||||
.font(.title2)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("User Id:").font(.title2)
|
||||
}
|
||||
Text(node.user?.userId ?? "?").font(.title3).foregroundColor(.gray)
|
||||
}
|
||||
Divider()
|
||||
VStack {
|
||||
HStack {
|
||||
Image(systemName: "number")
|
||||
.font(.title2)
|
||||
.foregroundColor(.accentColor)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("Node Number:").font(.title2)
|
||||
}
|
||||
Text(String(node.num)).font(.title3).foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
|
||||
VStack {
|
||||
|
||||
if node.hasPositions{
|
||||
|
||||
NavigationLink {
|
||||
PositionLog(node: node)
|
||||
} label: {
|
||||
|
||||
Image(systemName: "building.columns")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Position Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Divider()
|
||||
}
|
||||
|
||||
if node.hasDeviceMetrics {
|
||||
|
||||
NavigationLink {
|
||||
DeviceMetricsLog(node: node)
|
||||
} label: {
|
||||
|
||||
Image(systemName: "flipphone")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Device Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
if node.hasEnvironmentMetrics {
|
||||
NavigationLink {
|
||||
EnvironmentMetricsLog(node: node)
|
||||
} label: {
|
||||
|
||||
Image(systemName: "chart.xyaxis.line")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Environment Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
Divider()
|
||||
}
|
||||
NavigationLink {
|
||||
DetectionSensorLog(node: node)
|
||||
} label: {
|
||||
|
||||
Image(systemName: "sensor")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Detection Sensor Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Divider()
|
||||
// if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
// HStack {
|
||||
// VStack(alignment: .center) {
|
||||
// CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 150)
|
||||
// }
|
||||
// Divider()
|
||||
// VStack {
|
||||
// if node.user != nil {
|
||||
// Image(hwModelString)
|
||||
// .resizable()
|
||||
// .aspectRatio(contentMode: .fit)
|
||||
// .frame(width: 100, height: 100)
|
||||
// .cornerRadius(5)
|
||||
//
|
||||
// Text(String(hwModelString))
|
||||
// .foregroundColor(.gray)
|
||||
// .font(.title).fixedSize()
|
||||
// }
|
||||
// }
|
||||
// Divider()
|
||||
// if node.snr != 0 {
|
||||
// VStack(alignment: .center) {
|
||||
// let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: ModemPresets.longModerate)
|
||||
// LoRaSignalStrengthIndicator(signalStrength: signalStrength)
|
||||
// Text("Signal \(signalStrength.description)").font(.title)
|
||||
// Text("SNR \(String(format: "%.2f", node.snr))dB")
|
||||
// .foregroundColor(getSnrColor(snr: node.snr, preset: ModemPresets.longModerate))
|
||||
// .font(.title3)
|
||||
// Text("RSSI \(node.rssi)dB")
|
||||
// .foregroundColor(getRssiColor(rssi: node.rssi))
|
||||
// .font(.title3)
|
||||
// }
|
||||
// Divider()
|
||||
// }
|
||||
//
|
||||
// if node.hasDeviceMetrics {
|
||||
// let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
// let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
// VStack(alignment: .center) {
|
||||
// BatteryGauge(batteryLevel: Double(mostRecent?.batteryLevel ?? 0))
|
||||
// if mostRecent?.voltage ?? 0 > 0.0 {
|
||||
//
|
||||
// Text(String(format: "%.2f", mostRecent?.voltage ?? 0.0) + " V")
|
||||
// .font(.title)
|
||||
// .foregroundColor(.gray)
|
||||
// .fixedSize()
|
||||
// }
|
||||
// }
|
||||
// .padding()
|
||||
// }
|
||||
// }
|
||||
// .padding()
|
||||
//
|
||||
// Divider()
|
||||
// HStack(alignment: .center) {
|
||||
//
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Image(systemName: "person")
|
||||
// .font(.title)
|
||||
// .foregroundColor(.accentColor)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("user").font(.title)+Text(":").font(.title)
|
||||
// }
|
||||
// Text("!\(String(format: "%02x", node.num))")
|
||||
// .font(.title).foregroundColor(.gray)
|
||||
// }
|
||||
// Divider()
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Image(systemName: "number")
|
||||
// .font(.title2)
|
||||
// .foregroundColor(.accentColor)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("Node Number:").font(.title)
|
||||
// }
|
||||
// Text(String(node.num)).font(.title).foregroundColor(.gray)
|
||||
// }
|
||||
// Divider()
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Image(systemName: "clock.badge.checkmark.fill")
|
||||
// .font(.title)
|
||||
// .foregroundColor(.accentColor)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("heard.last").font(.title)+Text(":").font(.title)
|
||||
//
|
||||
// }
|
||||
// DateTimeText(dateTime: node.lastHeard)
|
||||
// .font(.title3)
|
||||
// .foregroundColor(.gray)
|
||||
// }
|
||||
// }
|
||||
// Divider()
|
||||
//
|
||||
// } else {
|
||||
//
|
||||
// HStack {
|
||||
//
|
||||
// VStack(alignment: .center) {
|
||||
// CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65)
|
||||
// }
|
||||
// if node.user != nil {
|
||||
// Divider()
|
||||
// VStack {
|
||||
// Image(node.user!.hwModel ?? "unset".localized)
|
||||
// .resizable()
|
||||
// .aspectRatio(contentMode: .fit)
|
||||
// .frame(width: 75, height: 75)
|
||||
// .cornerRadius(5)
|
||||
// Text(String(node.user!.hwModel ?? "unset".localized))
|
||||
// .font(.caption2).fixedSize()
|
||||
// }
|
||||
// }
|
||||
// if node.snr != 0 {
|
||||
// Divider()
|
||||
// VStack(alignment: .center) {
|
||||
// let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: ModemPresets.longModerate)
|
||||
// LoRaSignalStrengthIndicator(signalStrength: signalStrength)
|
||||
// Text("Signal \(signalStrength.description)").font(.footnote)
|
||||
// Text("SNR \(String(format: "%.2f", node.snr))dB")
|
||||
// .foregroundColor(getSnrColor(snr: node.snr, preset: ModemPresets.longModerate))
|
||||
// .font(.caption2)
|
||||
// Text("RSSI \(node.rssi)dB")
|
||||
// .foregroundColor(getRssiColor(rssi: node.rssi))
|
||||
// .font(.caption2)
|
||||
// }
|
||||
// }
|
||||
// let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
// if deviceMetrics?.count ?? 0 >= 1 {
|
||||
// Divider()
|
||||
// let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
// VStack(alignment: .center) {
|
||||
// BatteryGauge(batteryLevel: Double(mostRecent?.batteryLevel ?? 0))
|
||||
// if mostRecent?.voltage ?? 0 > 0 {
|
||||
//
|
||||
// Text(String(format: "%.2f", mostRecent?.voltage ?? 0) + " V")
|
||||
// .font(.callout)
|
||||
// .foregroundColor(.gray)
|
||||
// .fixedSize()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Divider()
|
||||
// HStack(alignment: .center) {
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Image(systemName: "person")
|
||||
// .font(.title2)
|
||||
// .foregroundColor(.accentColor)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("User Id:").font(.title2)
|
||||
// }
|
||||
// Text(node.user?.userId ?? "?").font(.title3).foregroundColor(.gray)
|
||||
// }
|
||||
// Divider()
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Image(systemName: "number")
|
||||
// .font(.title2)
|
||||
// .foregroundColor(.accentColor)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("Node Number:").font(.title2)
|
||||
// }
|
||||
// Text(String(node.num)).font(.title3).foregroundColor(.gray)
|
||||
// }
|
||||
// }
|
||||
// Divider()
|
||||
// }
|
||||
//
|
||||
// VStack {
|
||||
//
|
||||
// if node.hasPositions{
|
||||
//
|
||||
// NavigationLink {
|
||||
// PositionLog(node: node)
|
||||
// } label: {
|
||||
//
|
||||
// Image(systemName: "building.columns")
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .font(.title)
|
||||
//
|
||||
// Text("Position Log")
|
||||
// .font(.title3)
|
||||
// }
|
||||
// .fixedSize(horizontal: false, vertical: true)
|
||||
// Divider()
|
||||
// }
|
||||
//
|
||||
// if node.hasDeviceMetrics {
|
||||
//
|
||||
// NavigationLink {
|
||||
// DeviceMetricsLog(node: node)
|
||||
// } label: {
|
||||
//
|
||||
// Image(systemName: "flipphone")
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .font(.title)
|
||||
//
|
||||
// Text("Device Metrics Log")
|
||||
// .font(.title3)
|
||||
// }
|
||||
// Divider()
|
||||
// }
|
||||
// if node.hasEnvironmentMetrics {
|
||||
// NavigationLink {
|
||||
// EnvironmentMetricsLog(node: node)
|
||||
// } label: {
|
||||
//
|
||||
// Image(systemName: "chart.xyaxis.line")
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .font(.title)
|
||||
//
|
||||
// Text("Environment Metrics Log")
|
||||
// .font(.title3)
|
||||
// }
|
||||
// Divider()
|
||||
// }
|
||||
// NavigationLink {
|
||||
// DetectionSensorLog(node: node)
|
||||
// } label: {
|
||||
//
|
||||
// Image(systemName: "sensor")
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .font(.title)
|
||||
//
|
||||
// Text("Detection Sensor Log")
|
||||
// .font(.title3)
|
||||
// }
|
||||
// .fixedSize(horizontal: false, vertical: true)
|
||||
// Divider()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import WeatherKit
|
|||
import MapKit
|
||||
import CoreLocation
|
||||
|
||||
struct NodeDetailItem: View {
|
||||
struct NodeDetail: View {
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
|
@ -39,18 +39,6 @@ struct NodeDetailItem: View {
|
|||
}
|
||||
.disabled(!node.hasDeviceMetrics)
|
||||
Divider()
|
||||
NavigationLink {
|
||||
EnvironmentMetricsLog(node: node)
|
||||
} label: {
|
||||
Image(systemName: "chart.xyaxis.line")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Environment Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.disabled(!node.hasEnvironmentMetrics)
|
||||
Divider()
|
||||
NavigationLink {
|
||||
NodeMapControl(node: node)
|
||||
} label: {
|
||||
|
|
@ -75,6 +63,18 @@ struct NodeDetailItem: View {
|
|||
}
|
||||
.disabled(!node.hasPositions)
|
||||
Divider()
|
||||
NavigationLink {
|
||||
EnvironmentMetricsLog(node: node)
|
||||
} label: {
|
||||
Image(systemName: "chart.xyaxis.line")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.title)
|
||||
|
||||
Text("Environment Metrics Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.disabled(!node.hasEnvironmentMetrics)
|
||||
Divider()
|
||||
NavigationLink {
|
||||
DetectionSensorLog(node: node)
|
||||
} label: {
|
||||
|
|
@ -85,6 +85,7 @@ struct NodeDetailItem: View {
|
|||
Text("Detection Sensor Log")
|
||||
.font(.title3)
|
||||
}
|
||||
.disabled(!node.hasDetectionSensorMetrics)
|
||||
Divider()
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ struct NodeDetailItem: View {
|
|||
ConnectedDevice(
|
||||
bluetoothOn: bleManager.isSwitchedOn,
|
||||
deviceConnected: bleManager.connectedPeripheral != nil,
|
||||
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
|
||||
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", phoneOnly: true)
|
||||
})
|
||||
}
|
||||
.padding(.bottom, 2)
|
||||
|
|
@ -1,136 +1,109 @@
|
|||
////
|
||||
//// NodeList.swift
|
||||
//// Meshtastic
|
||||
////
|
||||
//// Copyright(c) Garth Vander Houwen 8/7/21.
|
||||
////
|
||||
//
|
||||
//// Abstract:
|
||||
//// A view showing a list of devices that have been seen on the mesh network from the perspective of the connected device.
|
||||
// NodeListSplit.swift
|
||||
// Meshtastic
|
||||
//
|
||||
//import SwiftUI
|
||||
//import CoreLocation
|
||||
// Created by Garth Vander Houwen on 9/8/23.
|
||||
//
|
||||
//struct NodeList: View {
|
||||
//
|
||||
// @State private var searchText = ""
|
||||
// var nodesQuery: Binding<String> {
|
||||
// Binding {
|
||||
// searchText
|
||||
// } set: { newValue in
|
||||
// searchText = newValue
|
||||
// nodes.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "user.longName CONTAINS[c] %@ OR user.shortName CONTAINS[c] %@", newValue, newValue)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Environment(\.managedObjectContext) var context
|
||||
// @EnvironmentObject var bleManager: BLEManager
|
||||
//
|
||||
// @FetchRequest(
|
||||
// sortDescriptors: [NSSortDescriptor(key: "lastHeard", ascending: false)],
|
||||
// animation: .default)
|
||||
//
|
||||
// private var nodes: FetchedResults<NodeInfoEntity>
|
||||
//
|
||||
// @State private var selection: NodeInfoEntity? // Nothing selected by default.
|
||||
//
|
||||
// var body: some View {
|
||||
//
|
||||
// NavigationSplitView {
|
||||
// let connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
// let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
// List(nodes, id: \.self, selection: $selection) { node in
|
||||
// if nodes.count == 0 {
|
||||
// Text("no.nodes").font(.title)
|
||||
// } else {
|
||||
// NavigationLink(value: node) {
|
||||
// let connected: Bool = (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 == node.num)
|
||||
// LazyVStack(alignment: .leading) {
|
||||
// HStack {
|
||||
// VStack(alignment: .leading) {
|
||||
// CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65)
|
||||
// .padding(.trailing, 5)
|
||||
// let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
// if deviceMetrics?.count ?? 0 >= 1 {
|
||||
// let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
// BatteryLevelCompact(batteryLevel: mostRecent?.batteryLevel, font: .caption2, iconFont: .callout, color: .accentColor)
|
||||
// }
|
||||
// }
|
||||
// VStack(alignment: .leading) {
|
||||
// Text(node.user?.longName ?? "unknown".localized)
|
||||
// .fontWeight(.medium)
|
||||
// .font(.callout)
|
||||
// if connected {
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: "antenna.radiowaves.left.and.right.circle.fill")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .foregroundColor(.green)
|
||||
// Text("connected").font(.caption)
|
||||
// }
|
||||
// }
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: node.isOnline ? "checkmark.circle.fill" : "moon.circle.fill")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .foregroundColor(node.isOnline ? .green : .orange)
|
||||
// LastHeardText(lastHeard: node.lastHeard)
|
||||
// .font(.caption)
|
||||
// }
|
||||
// if node.positions?.count ?? 0 > 0 && (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 != node.num) {
|
||||
// HStack(alignment: .bottom) {
|
||||
// let lastPostion = node.positions!.reversed()[0] as! PositionEntity
|
||||
// let myCoord = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude)
|
||||
// if lastPostion.nodeCoordinate != nil && myCoord.coordinate.longitude != LocationHelper.DefaultLocation.longitude && myCoord.coordinate.latitude != LocationHelper.DefaultLocation.latitude {
|
||||
// let nodeCoord = CLLocation(latitude: lastPostion.nodeCoordinate!.latitude, longitude: lastPostion.nodeCoordinate!.longitude)
|
||||
// let metersAway = nodeCoord.distance(from: myCoord)
|
||||
// Image(systemName: "lines.measurement.horizontal")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// DistanceText(meters: metersAway).font(.caption)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if node.channel > 0 {
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: "fibrechannel")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("Channel: \(node.channel)")
|
||||
// .font(.footnote)
|
||||
// }
|
||||
// }
|
||||
// if !connected {
|
||||
// HStack(alignment: .bottom) { let preset = ModemPresets(rawValue: Int(connectedNode?.loRaConfig?.modemPreset ?? 0))
|
||||
// LoRaSignalStrengthMeter(snr: node.snr, rssi: node.rssi, preset: preset ?? ModemPresets.longFast, compact: true)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .frame(maxWidth: .infinity, alignment: .leading)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding([.top, .bottom])
|
||||
import SwiftUI
|
||||
import CoreLocation
|
||||
|
||||
enum SelectedDetail {
|
||||
case positionLog
|
||||
case nodeMap
|
||||
case deviceMetricsLog
|
||||
case environmentMetricsLog
|
||||
case detectionSensorLog
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct NodeListSplit: View {
|
||||
|
||||
@State private var columnVisibility = NavigationSplitViewVisibility.all
|
||||
@State private var selectedNode: NodeInfoEntity?
|
||||
@State private var selectedDetail: SelectedDetail?
|
||||
|
||||
@SceneStorage("selectedDetailView") var selectedDetailView: String?
|
||||
|
||||
@State private var searchText = ""
|
||||
var nodesQuery: Binding<String> {
|
||||
Binding {
|
||||
searchText
|
||||
} set: { newValue in
|
||||
searchText = newValue
|
||||
nodes.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "user.longName CONTAINS[c] %@ OR user.shortName CONTAINS[c] %@", newValue, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(key: "lastHeard", ascending: false)],
|
||||
animation: .default)
|
||||
|
||||
private var nodes: FetchedResults<NodeInfoEntity>
|
||||
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView(columnVisibility: $columnVisibility) {
|
||||
|
||||
let connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
List(nodes, id: \.self, selection: $selectedNode) { node in
|
||||
|
||||
NodeListItem(node: node, connected: bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 == node.num, connectedNode: (bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? -1 : -1), modemPreset: Int(connectedNode?.loRaConfig?.modemPreset ?? 0))
|
||||
}
|
||||
.searchable(text: nodesQuery, prompt: "Find a node")
|
||||
.navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count)))
|
||||
.listStyle(.plain)
|
||||
.navigationSplitViewColumnWidth(min: 100, ideal: 250, max: 500)
|
||||
.navigationBarItems(leading:
|
||||
MeshtasticLogo(),
|
||||
trailing:
|
||||
ZStack {
|
||||
ConnectedDevice(
|
||||
bluetoothOn: bleManager.isSwitchedOn,
|
||||
deviceConnected: bleManager.connectedPeripheral != nil,
|
||||
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", phoneOnly: true)
|
||||
})
|
||||
} content: {
|
||||
|
||||
if let node = selectedNode {
|
||||
NodeDetail(node: node)
|
||||
|
||||
} else {
|
||||
Text("select.node")
|
||||
}
|
||||
|
||||
} detail: {
|
||||
Text("Select something to view")
|
||||
}
|
||||
.navigationSplitViewStyle(.balanced)
|
||||
.onChange(of: selectedNode) { _ in
|
||||
selectedDetail = nil
|
||||
}
|
||||
.onAppear {
|
||||
if self.bleManager.context == nil {
|
||||
self.bleManager.context = context
|
||||
}
|
||||
}
|
||||
|
||||
// } detail: {
|
||||
// VStack {
|
||||
// Button("Detail Only") {
|
||||
// columnVisibility = .detailOnly
|
||||
// }
|
||||
// }
|
||||
// .listStyle(.plain)
|
||||
// .navigationSplitViewColumnWidth(300)
|
||||
// .navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count)))
|
||||
// .navigationBarItems(leading:
|
||||
// MeshtasticLogo()
|
||||
// )
|
||||
// .onAppear {
|
||||
// if self.bleManager.context == nil {
|
||||
// self.bleManager.context = context
|
||||
//
|
||||
// Button("Content and Detail") {
|
||||
// columnVisibility = .doubleColumn
|
||||
// }
|
||||
//
|
||||
// Button("Show All") {
|
||||
// columnVisibility = .all
|
||||
// }
|
||||
// }
|
||||
// } detail: {
|
||||
// if let node = selection {
|
||||
// NodeDetail(node: node)
|
||||
// } else {
|
||||
// Text("select.node")
|
||||
// }
|
||||
// }
|
||||
// .searchable(text: nodesQuery, prompt: "Find a node")
|
||||
// }
|
||||
//}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
136
Meshtastic/Views/Nodes/NodeListOld.swift
Normal file
136
Meshtastic/Views/Nodes/NodeListOld.swift
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
////
|
||||
//// NodeList.swift
|
||||
//// Meshtastic
|
||||
////
|
||||
//// Copyright(c) Garth Vander Houwen 8/7/21.
|
||||
////
|
||||
//
|
||||
//// Abstract:
|
||||
//// A view showing a list of devices that have been seen on the mesh network from the perspective of the connected device.
|
||||
//
|
||||
//import SwiftUI
|
||||
//import CoreLocation
|
||||
//
|
||||
//struct NodeList: View {
|
||||
//
|
||||
// @State private var searchText = ""
|
||||
// var nodesQuery: Binding<String> {
|
||||
// Binding {
|
||||
// searchText
|
||||
// } set: { newValue in
|
||||
// searchText = newValue
|
||||
// nodes.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "user.longName CONTAINS[c] %@ OR user.shortName CONTAINS[c] %@", newValue, newValue)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Environment(\.managedObjectContext) var context
|
||||
// @EnvironmentObject var bleManager: BLEManager
|
||||
//
|
||||
// @FetchRequest(
|
||||
// sortDescriptors: [NSSortDescriptor(key: "lastHeard", ascending: false)],
|
||||
// animation: .default)
|
||||
//
|
||||
// private var nodes: FetchedResults<NodeInfoEntity>
|
||||
//
|
||||
// @State private var selection: NodeInfoEntity? // Nothing selected by default.
|
||||
//
|
||||
// var body: some View {
|
||||
//
|
||||
// NavigationSplitView {
|
||||
// let connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
// let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
// List(nodes, id: \.self, selection: $selection) { node in
|
||||
// if nodes.count == 0 {
|
||||
// Text("no.nodes").font(.title)
|
||||
// } else {
|
||||
// NavigationLink(value: node) {
|
||||
// let connected: Bool = (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 == node.num)
|
||||
// LazyVStack(alignment: .leading) {
|
||||
// HStack {
|
||||
// VStack(alignment: .leading) {
|
||||
// CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 65)
|
||||
// .padding(.trailing, 5)
|
||||
// let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0"))
|
||||
// if deviceMetrics?.count ?? 0 >= 1 {
|
||||
// let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity
|
||||
// BatteryLevelCompact(batteryLevel: mostRecent?.batteryLevel, font: .caption2, iconFont: .callout, color: .accentColor)
|
||||
// }
|
||||
// }
|
||||
// VStack(alignment: .leading) {
|
||||
// Text(node.user?.longName ?? "unknown".localized)
|
||||
// .fontWeight(.medium)
|
||||
// .font(.callout)
|
||||
// if connected {
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: "antenna.radiowaves.left.and.right.circle.fill")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .foregroundColor(.green)
|
||||
// Text("connected").font(.caption)
|
||||
// }
|
||||
// }
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: node.isOnline ? "checkmark.circle.fill" : "moon.circle.fill")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// .foregroundColor(node.isOnline ? .green : .orange)
|
||||
// LastHeardText(lastHeard: node.lastHeard)
|
||||
// .font(.caption)
|
||||
// }
|
||||
// if node.positions?.count ?? 0 > 0 && (bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 != node.num) {
|
||||
// HStack(alignment: .bottom) {
|
||||
// let lastPostion = node.positions!.reversed()[0] as! PositionEntity
|
||||
// let myCoord = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude)
|
||||
// if lastPostion.nodeCoordinate != nil && myCoord.coordinate.longitude != LocationHelper.DefaultLocation.longitude && myCoord.coordinate.latitude != LocationHelper.DefaultLocation.latitude {
|
||||
// let nodeCoord = CLLocation(latitude: lastPostion.nodeCoordinate!.latitude, longitude: lastPostion.nodeCoordinate!.longitude)
|
||||
// let metersAway = nodeCoord.distance(from: myCoord)
|
||||
// Image(systemName: "lines.measurement.horizontal")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// DistanceText(meters: metersAway).font(.caption)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if node.channel > 0 {
|
||||
// HStack(alignment: .bottom) {
|
||||
// Image(systemName: "fibrechannel")
|
||||
// .font(.footnote)
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("Channel: \(node.channel)")
|
||||
// .font(.footnote)
|
||||
// }
|
||||
// }
|
||||
// if !connected {
|
||||
// HStack(alignment: .bottom) { let preset = ModemPresets(rawValue: Int(connectedNode?.loRaConfig?.modemPreset ?? 0))
|
||||
// LoRaSignalStrengthMeter(snr: node.snr, rssi: node.rssi, preset: preset ?? ModemPresets.longFast, compact: true)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .frame(maxWidth: .infinity, alignment: .leading)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding([.top, .bottom])
|
||||
// }
|
||||
// }
|
||||
// .listStyle(.plain)
|
||||
// .navigationSplitViewColumnWidth(300)
|
||||
// .navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count)))
|
||||
// .navigationBarItems(leading:
|
||||
// MeshtasticLogo()
|
||||
// )
|
||||
// .onAppear {
|
||||
// if self.bleManager.context == nil {
|
||||
// self.bleManager.context = context
|
||||
// }
|
||||
// }
|
||||
// } detail: {
|
||||
// if let node = selection {
|
||||
// NodeDetail(node: node)
|
||||
// } else {
|
||||
// Text("select.node")
|
||||
// }
|
||||
// }
|
||||
// .searchable(text: nodesQuery, prompt: "Find a node")
|
||||
// }
|
||||
//}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
//
|
||||
// NodeListSplit.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Garth Vander Houwen on 9/8/23.
|
||||
//
|
||||
import SwiftUI
|
||||
import CoreLocation
|
||||
|
||||
enum SelectedDetail {
|
||||
case positionLog
|
||||
case nodeMap
|
||||
case deviceMetricsLog
|
||||
case environmentMetricsLog
|
||||
case detectionSensorLog
|
||||
}
|
||||
|
||||
struct NodeListSplit: View {
|
||||
|
||||
@State private var columnVisibility = NavigationSplitViewVisibility.all
|
||||
@State private var selectedNode: NodeInfoEntity?
|
||||
@State private var selectedDetail: SelectedDetail?
|
||||
|
||||
@SceneStorage("selectedDetailView") var selectedDetailView: String?
|
||||
|
||||
@State private var searchText = ""
|
||||
var nodesQuery: Binding<String> {
|
||||
Binding {
|
||||
searchText
|
||||
} set: { newValue in
|
||||
searchText = newValue
|
||||
nodes.nsPredicate = newValue.isEmpty ? nil : NSPredicate(format: "user.longName CONTAINS[c] %@ OR user.shortName CONTAINS[c] %@", newValue, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(key: "lastHeard", ascending: false)],
|
||||
animation: .default)
|
||||
|
||||
private var nodes: FetchedResults<NodeInfoEntity>
|
||||
|
||||
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView(columnVisibility: $columnVisibility) {
|
||||
|
||||
let connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0)
|
||||
let connectedNode = nodes.first(where: { $0.num == connectedNodeNum })
|
||||
List(nodes, id: \.self, selection: $selectedNode) { node in
|
||||
|
||||
NodeListItem(node: node, connected: bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral?.num ?? -1 == node.num, connectedNode: (bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? -1 : -1), modemPreset: Int(connectedNode?.loRaConfig?.modemPreset ?? 0))
|
||||
}
|
||||
.searchable(text: nodesQuery, prompt: "Find a node")
|
||||
.navigationTitle(String.localizedStringWithFormat("nodes %@".localized, String(nodes.count)))
|
||||
.listStyle(.plain)
|
||||
.navigationSplitViewColumnWidth(min: 100, ideal: 250, max: 500)
|
||||
.navigationBarItems(leading:
|
||||
MeshtasticLogo()
|
||||
)
|
||||
} content: {
|
||||
|
||||
if let node = selectedNode {
|
||||
NodeDetailItem(node: node)
|
||||
|
||||
} else {
|
||||
Text("select.node")
|
||||
}
|
||||
|
||||
} detail: {
|
||||
Text("Select something to view")
|
||||
}
|
||||
.navigationSplitViewStyle(.balanced)
|
||||
.onChange(of: selectedNode) { _ in
|
||||
selectedDetail = nil
|
||||
}
|
||||
.onAppear {
|
||||
if self.bleManager.context == nil {
|
||||
self.bleManager.context = context
|
||||
}
|
||||
}
|
||||
|
||||
// } detail: {
|
||||
// VStack {
|
||||
// Button("Detail Only") {
|
||||
// columnVisibility = .detailOnly
|
||||
// }
|
||||
//
|
||||
// Button("Content and Detail") {
|
||||
// columnVisibility = .doubleColumn
|
||||
// }
|
||||
//
|
||||
// Button("Show All") {
|
||||
// columnVisibility = .all
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
@ -24,12 +24,6 @@ struct PositionLog: View {
|
|||
var body: some View {
|
||||
NavigationStack {
|
||||
|
||||
|
||||
if node.hasPositions {
|
||||
|
||||
} else {
|
||||
Text("Node has no positions.")
|
||||
}
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
|
||||
if UIDevice.current.userInterfaceIdiom == .pad && !useGrid || UIDevice.current.userInterfaceIdiom == .mac {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue