mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #367 from meshtastic/2.1.16_working_changes
Show a week of position data on the mesh map
This commit is contained in:
commit
b9ef5cc97a
9 changed files with 466 additions and 33 deletions
|
|
@ -9,6 +9,7 @@
|
|||
/* Begin PBXBuildFile section */
|
||||
C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */; };
|
||||
C9697FA527933B8C00250207 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = C9697FA427933B8C00250207 /* SQLite */; };
|
||||
DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */ = {isa = PBXBuildFile; productRef = DD0D3D212A55CEB10066DB71 /* CocoaMQTT */; };
|
||||
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */; };
|
||||
DD1925B728CDA5A400720036 /* CannedMessagesConfigEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1925B628CDA5A400720036 /* CannedMessagesConfigEnums.swift */; };
|
||||
DD1925B928CDA93900720036 /* SerialConfigEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1925B828CDA93900720036 /* SerialConfigEnums.swift */; };
|
||||
|
|
@ -361,6 +362,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C9697FA527933B8C00250207 /* SQLite in Frameworks */,
|
||||
DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */,
|
||||
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -799,6 +801,7 @@
|
|||
packageProductDependencies = (
|
||||
DD5394FB276993AD00AD86B1 /* SwiftProtobuf */,
|
||||
C9697FA427933B8C00250207 /* SQLite */,
|
||||
DD0D3D212A55CEB10066DB71 /* CocoaMQTT */,
|
||||
);
|
||||
productName = MeshtasticClient;
|
||||
productReference = DDC2E15426CE248E0042C5E4 /* Meshtastic.app */;
|
||||
|
|
@ -898,6 +901,7 @@
|
|||
packageReferences = (
|
||||
DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */,
|
||||
C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */,
|
||||
DD0D3D202A55CEB10066DB71 /* XCRemoteSwiftPackageReference "CocoaMQTT" */,
|
||||
);
|
||||
productRefGroup = DDC2E15526CE248E0042C5E4 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
|
@ -1307,7 +1311,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.15;
|
||||
MARKETING_VERSION = 2.1.16;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1341,7 +1345,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.15;
|
||||
MARKETING_VERSION = 2.1.16;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1460,7 +1464,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.15;
|
||||
MARKETING_VERSION = 2.1.16;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
|
@ -1491,7 +1495,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.15;
|
||||
MARKETING_VERSION = 2.1.16;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
|
@ -1561,6 +1565,14 @@
|
|||
minimumVersion = 0.9.2;
|
||||
};
|
||||
};
|
||||
DD0D3D202A55CEB10066DB71 /* XCRemoteSwiftPackageReference "CocoaMQTT" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/emqx/CocoaMQTT";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.0.0;
|
||||
};
|
||||
};
|
||||
DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/apple/swift-protobuf.git";
|
||||
|
|
@ -1577,6 +1589,11 @@
|
|||
package = C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */;
|
||||
productName = SQLite;
|
||||
};
|
||||
DD0D3D212A55CEB10066DB71 /* CocoaMQTT */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DD0D3D202A55CEB10066DB71 /* XCRemoteSwiftPackageReference "CocoaMQTT" */;
|
||||
productName = CocoaMQTT;
|
||||
};
|
||||
DD5394FB276993AD00AD86B1 /* SwiftProtobuf */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,23 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "cocoamqtt",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/emqx/CocoaMQTT",
|
||||
"state" : {
|
||||
"revision" : "85387a2478551ad84f39be8a3c8587d34dd2bcf5",
|
||||
"version" : "2.1.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "mqttcocoaasyncsocket",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/leeway1208/MqttCocoaAsyncSocket",
|
||||
"state" : {
|
||||
"revision" : "ce3e18607fd01079495f86ff6195d8a3ca469f73",
|
||||
"version" : "1.0.8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sqlite.swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
|
@ -9,6 +27,15 @@
|
|||
"version" : "0.13.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "starscream",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/daltoniam/Starscream.git",
|
||||
"state" : {
|
||||
"revision" : "a063fda2b8145a231953c20e7a646be254365396",
|
||||
"version" : "3.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
|
|
|
|||
|
|
@ -399,33 +399,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
|
||||
// MyInfo from initial connection
|
||||
if decodedInfo.myInfo.isInitialized && decodedInfo.myInfo.myNodeNum > 0 {
|
||||
let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, peripheralId: self.connectedPeripheral.id, context: context!)
|
||||
|
||||
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")
|
||||
|
||||
if lastDotIndex == nil {
|
||||
invalidVersion = true
|
||||
connectedVersion = "0.0.0"
|
||||
} else {
|
||||
let version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))]
|
||||
nowKnown = true
|
||||
connectedVersion = String(version.dropLast())
|
||||
}
|
||||
|
||||
let supportedVersion = connectedVersion == "0.0.0" || self.minimumVersion.compare(connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(connectedVersion, options: .numeric) == .orderedSame
|
||||
if !supportedVersion {
|
||||
invalidVersion = true
|
||||
lastConnectionError = "🚨" + "update.firmware".localized
|
||||
return
|
||||
|
||||
} else {
|
||||
|
||||
let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, peripheralId: self.connectedPeripheral.id, context: context!)
|
||||
|
||||
if myInfo != nil {
|
||||
connectedPeripheral.num = myInfo!.myNodeNum
|
||||
connectedPeripheral.name = myInfo?.bleName ?? "unknown".localized
|
||||
connectedPeripheral.longName = myInfo?.bleName ?? "unknown".localized
|
||||
}
|
||||
if myInfo != nil {
|
||||
connectedPeripheral.num = myInfo!.myNodeNum
|
||||
connectedPeripheral.name = myInfo?.bleName ?? "unknown".localized
|
||||
connectedPeripheral.longName = myInfo?.bleName ?? "unknown".localized
|
||||
}
|
||||
tryClearExistingChannels()
|
||||
}
|
||||
|
|
@ -472,6 +451,26 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
nowKnown = true
|
||||
deviceMetadataPacket(metadata: decodedInfo.metadata, fromNum: connectedPeripheral.num, context: context!)
|
||||
connectedPeripheral.firmwareVersion = decodedInfo.metadata.firmwareVersion ?? "unknown".localized
|
||||
|
||||
let lastDotIndex = decodedInfo.metadata.firmwareVersion.lastIndex(of: ".")
|
||||
|
||||
if lastDotIndex == nil {
|
||||
invalidVersion = true
|
||||
connectedVersion = "0.0.0"
|
||||
} else {
|
||||
let version = decodedInfo.metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.metadata.firmwareVersion))]
|
||||
nowKnown = true
|
||||
connectedVersion = String(version.dropLast())
|
||||
}
|
||||
|
||||
let supportedVersion = connectedVersion == "0.0.0" || self.minimumVersion.compare(connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(connectedVersion, options: .numeric) == .orderedSame
|
||||
|
||||
if !supportedVersion {
|
||||
invalidVersion = true
|
||||
lastConnectionError = "🚨" + "update.firmware".localized
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
// Log any other unknownApp calls
|
||||
if !nowKnown { MeshLogger.log("🕸️ MESH PACKET received for Unknown App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") }
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ struct DeviceState {
|
|||
}
|
||||
|
||||
///
|
||||
/// New lite version of NodeDB to decrease
|
||||
/// New lite version of NodeDB to decrease memory footprint
|
||||
var nodeDbLite: [NodeInfoLite] {
|
||||
get {return _storage._nodeDbLite}
|
||||
set {_uniqueStorage()._nodeDbLite = newValue}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
/// B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer
|
||||
case nanoG1Explorer // = 17
|
||||
|
||||
///
|
||||
/// B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra
|
||||
case nanoG2Ultra // = 18
|
||||
|
||||
///
|
||||
/// B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station
|
||||
case stationG1 // = 25
|
||||
|
|
@ -176,6 +180,22 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
/// Raspberry Pi Pico (W) with Waveshare SX1262 LoRa Node Module
|
||||
case rpiPico // = 47
|
||||
|
||||
///
|
||||
/// Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT
|
||||
case heltecWirelessTracker // = 48
|
||||
|
||||
///
|
||||
/// Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display
|
||||
case heltecWirelessPaper // = 49
|
||||
|
||||
///
|
||||
/// LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display
|
||||
case tDeck // = 50
|
||||
|
||||
///
|
||||
/// LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display
|
||||
case tWatchS3 // = 51
|
||||
|
||||
///
|
||||
/// ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
/// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
|
|
@ -207,6 +227,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case 15: self = .tloraV211P8
|
||||
case 16: self = .tloraT3S3
|
||||
case 17: self = .nanoG1Explorer
|
||||
case 18: self = .nanoG2Ultra
|
||||
case 25: self = .stationG1
|
||||
case 26: self = .rak11310
|
||||
case 32: self = .loraRelayV1
|
||||
|
|
@ -225,6 +246,10 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case 45: self = .betafpv2400Tx
|
||||
case 46: self = .betafpv900NanoTx
|
||||
case 47: self = .rpiPico
|
||||
case 48: self = .heltecWirelessTracker
|
||||
case 49: self = .heltecWirelessPaper
|
||||
case 50: self = .tDeck
|
||||
case 51: self = .tWatchS3
|
||||
case 255: self = .privateHw
|
||||
default: self = .UNRECOGNIZED(rawValue)
|
||||
}
|
||||
|
|
@ -250,6 +275,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case .tloraV211P8: return 15
|
||||
case .tloraT3S3: return 16
|
||||
case .nanoG1Explorer: return 17
|
||||
case .nanoG2Ultra: return 18
|
||||
case .stationG1: return 25
|
||||
case .rak11310: return 26
|
||||
case .loraRelayV1: return 32
|
||||
|
|
@ -268,6 +294,10 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case .betafpv2400Tx: return 45
|
||||
case .betafpv900NanoTx: return 46
|
||||
case .rpiPico: return 47
|
||||
case .heltecWirelessTracker: return 48
|
||||
case .heltecWirelessPaper: return 49
|
||||
case .tDeck: return 50
|
||||
case .tWatchS3: return 51
|
||||
case .privateHw: return 255
|
||||
case .UNRECOGNIZED(let i): return i
|
||||
}
|
||||
|
|
@ -298,6 +328,7 @@ extension HardwareModel: CaseIterable {
|
|||
.tloraV211P8,
|
||||
.tloraT3S3,
|
||||
.nanoG1Explorer,
|
||||
.nanoG2Ultra,
|
||||
.stationG1,
|
||||
.rak11310,
|
||||
.loraRelayV1,
|
||||
|
|
@ -316,6 +347,10 @@ extension HardwareModel: CaseIterable {
|
|||
.betafpv2400Tx,
|
||||
.betafpv900NanoTx,
|
||||
.rpiPico,
|
||||
.heltecWirelessTracker,
|
||||
.heltecWirelessPaper,
|
||||
.tDeck,
|
||||
.tWatchS3,
|
||||
.privateHw,
|
||||
]
|
||||
}
|
||||
|
|
@ -1197,6 +1232,80 @@ struct Waypoint {
|
|||
init() {}
|
||||
}
|
||||
|
||||
///
|
||||
/// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server
|
||||
struct MqttClientProxyMessage {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
///
|
||||
/// The MQTT topic this message will be sent /received on
|
||||
var topic: String = String()
|
||||
|
||||
///
|
||||
/// The actual service envelope payload or text for mqtt pub / sub
|
||||
var payloadVariant: MqttClientProxyMessage.OneOf_PayloadVariant? = nil
|
||||
|
||||
///
|
||||
/// Bytes
|
||||
var data: Data {
|
||||
get {
|
||||
if case .data(let v)? = payloadVariant {return v}
|
||||
return Data()
|
||||
}
|
||||
set {payloadVariant = .data(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// Text
|
||||
var text: String {
|
||||
get {
|
||||
if case .text(let v)? = payloadVariant {return v}
|
||||
return String()
|
||||
}
|
||||
set {payloadVariant = .text(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// Whether the message should be retained (or not)
|
||||
var retained: Bool = false
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
/// The actual service envelope payload or text for mqtt pub / sub
|
||||
enum OneOf_PayloadVariant: Equatable {
|
||||
///
|
||||
/// Bytes
|
||||
case data(Data)
|
||||
///
|
||||
/// Text
|
||||
case text(String)
|
||||
|
||||
#if !swift(>=4.1)
|
||||
static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch (lhs, rhs) {
|
||||
case (.data, .data): return {
|
||||
guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.text, .text): return {
|
||||
guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
///
|
||||
/// A packet envelope sent/received over the mesh
|
||||
/// only payload_variant is sent in the payload portion of the LORA packet.
|
||||
|
|
@ -2006,6 +2115,16 @@ struct FromRadio {
|
|||
set {_uniqueStorage()._payloadVariant = .metadata(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT)
|
||||
var mqttClientProxyMessage: MqttClientProxyMessage {
|
||||
get {
|
||||
if case .mqttClientProxyMessage(let v)? = _storage._payloadVariant {return v}
|
||||
return MqttClientProxyMessage()
|
||||
}
|
||||
set {_uniqueStorage()._payloadVariant = .mqttClientProxyMessage(newValue)}
|
||||
}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
|
|
@ -2055,6 +2174,9 @@ struct FromRadio {
|
|||
///
|
||||
/// Device metadata message
|
||||
case metadata(DeviceMetadata)
|
||||
///
|
||||
/// MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT)
|
||||
case mqttClientProxyMessage(MqttClientProxyMessage)
|
||||
|
||||
#if !swift(>=4.1)
|
||||
static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool {
|
||||
|
|
@ -2110,6 +2232,10 @@ struct FromRadio {
|
|||
guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.mqttClientProxyMessage, .mqttClientProxyMessage): return {
|
||||
guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
|
@ -2180,6 +2306,16 @@ struct ToRadio {
|
|||
set {payloadVariant = .xmodemPacket(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device)
|
||||
var mqttClientProxyMessage: MqttClientProxyMessage {
|
||||
get {
|
||||
if case .mqttClientProxyMessage(let v)? = payloadVariant {return v}
|
||||
return MqttClientProxyMessage()
|
||||
}
|
||||
set {payloadVariant = .mqttClientProxyMessage(newValue)}
|
||||
}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
|
|
@ -2204,6 +2340,9 @@ struct ToRadio {
|
|||
/// (Sending this message is optional for clients)
|
||||
case disconnect(Bool)
|
||||
case xmodemPacket(XModem)
|
||||
///
|
||||
/// MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device)
|
||||
case mqttClientProxyMessage(MqttClientProxyMessage)
|
||||
|
||||
#if !swift(>=4.1)
|
||||
static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool {
|
||||
|
|
@ -2227,6 +2366,10 @@ struct ToRadio {
|
|||
guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.mqttClientProxyMessage, .mqttClientProxyMessage): return {
|
||||
guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
|
@ -2366,6 +2509,8 @@ extension Routing.OneOf_Variant: @unchecked Sendable {}
|
|||
extension Routing.Error: @unchecked Sendable {}
|
||||
extension DataMessage: @unchecked Sendable {}
|
||||
extension Waypoint: @unchecked Sendable {}
|
||||
extension MqttClientProxyMessage: @unchecked Sendable {}
|
||||
extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {}
|
||||
extension MeshPacket: @unchecked Sendable {}
|
||||
extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {}
|
||||
extension MeshPacket.Priority: @unchecked Sendable {}
|
||||
|
|
@ -2409,6 +2554,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
15: .same(proto: "TLORA_V2_1_1P8"),
|
||||
16: .same(proto: "TLORA_T3_S3"),
|
||||
17: .same(proto: "NANO_G1_EXPLORER"),
|
||||
18: .same(proto: "NANO_G2_ULTRA"),
|
||||
25: .same(proto: "STATION_G1"),
|
||||
26: .same(proto: "RAK11310"),
|
||||
32: .same(proto: "LORA_RELAY_V1"),
|
||||
|
|
@ -2427,6 +2573,10 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
45: .same(proto: "BETAFPV_2400_TX"),
|
||||
46: .same(proto: "BETAFPV_900_NANO_TX"),
|
||||
47: .same(proto: "RPI_PICO"),
|
||||
48: .same(proto: "HELTEC_WIRELESS_TRACKER"),
|
||||
49: .same(proto: "HELTEC_WIRELESS_PAPER"),
|
||||
50: .same(proto: "T_DECK"),
|
||||
51: .same(proto: "T_WATCH_S3"),
|
||||
255: .same(proto: "PRIVATE_HW"),
|
||||
]
|
||||
}
|
||||
|
|
@ -3048,6 +3198,78 @@ extension Waypoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
}
|
||||
}
|
||||
|
||||
extension MqttClientProxyMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".MqttClientProxyMessage"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "topic"),
|
||||
2: .same(proto: "data"),
|
||||
3: .same(proto: "text"),
|
||||
4: .same(proto: "retained"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.topic) }()
|
||||
case 2: try {
|
||||
var v: Data?
|
||||
try decoder.decodeSingularBytesField(value: &v)
|
||||
if let v = v {
|
||||
if self.payloadVariant != nil {try decoder.handleConflictingOneOf()}
|
||||
self.payloadVariant = .data(v)
|
||||
}
|
||||
}()
|
||||
case 3: try {
|
||||
var v: String?
|
||||
try decoder.decodeSingularStringField(value: &v)
|
||||
if let v = v {
|
||||
if self.payloadVariant != nil {try decoder.handleConflictingOneOf()}
|
||||
self.payloadVariant = .text(v)
|
||||
}
|
||||
}()
|
||||
case 4: try { try decoder.decodeSingularBoolField(value: &self.retained) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if !self.topic.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.topic, fieldNumber: 1)
|
||||
}
|
||||
switch self.payloadVariant {
|
||||
case .data?: try {
|
||||
guard case .data(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 2)
|
||||
}()
|
||||
case .text?: try {
|
||||
guard case .text(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 3)
|
||||
}()
|
||||
case nil: break
|
||||
}
|
||||
if self.retained != false {
|
||||
try visitor.visitSingularBoolField(value: self.retained, fieldNumber: 4)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: MqttClientProxyMessage, rhs: MqttClientProxyMessage) -> Bool {
|
||||
if lhs.topic != rhs.topic {return false}
|
||||
if lhs.payloadVariant != rhs.payloadVariant {return false}
|
||||
if lhs.retained != rhs.retained {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".MeshPacket"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
|
@ -3575,6 +3797,7 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
11: .same(proto: "queueStatus"),
|
||||
12: .same(proto: "xmodemPacket"),
|
||||
13: .same(proto: "metadata"),
|
||||
14: .same(proto: "mqttClientProxyMessage"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
|
@ -3753,6 +3976,19 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
_storage._payloadVariant = .metadata(v)
|
||||
}
|
||||
}()
|
||||
case 14: try {
|
||||
var v: MqttClientProxyMessage?
|
||||
var hadOneofValue = false
|
||||
if let current = _storage._payloadVariant {
|
||||
hadOneofValue = true
|
||||
if case .mqttClientProxyMessage(let m) = current {v = m}
|
||||
}
|
||||
try decoder.decodeSingularMessageField(value: &v)
|
||||
if let v = v {
|
||||
if hadOneofValue {try decoder.handleConflictingOneOf()}
|
||||
_storage._payloadVariant = .mqttClientProxyMessage(v)
|
||||
}
|
||||
}()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -3817,6 +4053,10 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
|
|||
guard case .metadata(let v)? = _storage._payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 13)
|
||||
}()
|
||||
case .mqttClientProxyMessage?: try {
|
||||
guard case .mqttClientProxyMessage(let v)? = _storage._payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 14)
|
||||
}()
|
||||
case nil: break
|
||||
}
|
||||
}
|
||||
|
|
@ -3846,6 +4086,7 @@ extension ToRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
3: .standard(proto: "want_config_id"),
|
||||
4: .same(proto: "disconnect"),
|
||||
5: .same(proto: "xmodemPacket"),
|
||||
6: .same(proto: "mqttClientProxyMessage"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -3896,6 +4137,19 @@ extension ToRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
self.payloadVariant = .xmodemPacket(v)
|
||||
}
|
||||
}()
|
||||
case 6: try {
|
||||
var v: MqttClientProxyMessage?
|
||||
var hadOneofValue = false
|
||||
if let current = self.payloadVariant {
|
||||
hadOneofValue = true
|
||||
if case .mqttClientProxyMessage(let m) = current {v = m}
|
||||
}
|
||||
try decoder.decodeSingularMessageField(value: &v)
|
||||
if let v = v {
|
||||
if hadOneofValue {try decoder.handleConflictingOneOf()}
|
||||
self.payloadVariant = .mqttClientProxyMessage(v)
|
||||
}
|
||||
}()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -3923,6 +4177,10 @@ extension ToRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
|
|||
guard case .xmodemPacket(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
|
||||
}()
|
||||
case .mqttClientProxyMessage?: try {
|
||||
guard case .mqttClientProxyMessage(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 6)
|
||||
}()
|
||||
case nil: break
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
|
|
|
|||
|
|
@ -184,6 +184,16 @@ struct ModuleConfig {
|
|||
set {payloadVariant = .neighborInfo(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
var ambientLighting: ModuleConfig.AmbientLightingConfig {
|
||||
get {
|
||||
if case .ambientLighting(let v)? = payloadVariant {return v}
|
||||
return ModuleConfig.AmbientLightingConfig()
|
||||
}
|
||||
set {payloadVariant = .ambientLighting(newValue)}
|
||||
}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
|
|
@ -219,6 +229,9 @@ struct ModuleConfig {
|
|||
///
|
||||
/// TODO: REPLACE
|
||||
case neighborInfo(ModuleConfig.NeighborInfoConfig)
|
||||
///
|
||||
/// TODO: REPLACE
|
||||
case ambientLighting(ModuleConfig.AmbientLightingConfig)
|
||||
|
||||
#if !swift(>=4.1)
|
||||
static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool {
|
||||
|
|
@ -266,6 +279,10 @@ struct ModuleConfig {
|
|||
guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.ambientLighting, .ambientLighting): return {
|
||||
guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
|
@ -321,6 +338,10 @@ struct ModuleConfig {
|
|||
/// This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs
|
||||
var root: String = String()
|
||||
|
||||
///
|
||||
/// If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection
|
||||
var proxyToClientEnabled: Bool = false
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
|
@ -931,6 +952,33 @@ struct ModuleConfig {
|
|||
init() {}
|
||||
}
|
||||
|
||||
///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels.
|
||||
///Initially created for the RAK14001 RGB LED module.
|
||||
struct AmbientLightingConfig {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
///Sets LED to on or off.
|
||||
var ledState: Bool = false
|
||||
|
||||
///Sets the overall current for the LED, firmware side range for the RAK14001 is 1-31, but users should be given a range of 0-100%
|
||||
var current: UInt32 = 0
|
||||
|
||||
/// Red level
|
||||
var red: UInt32 = 0
|
||||
|
||||
///Sets the green level of the LED, firmware side values are 0-255, but users should be given a range of 0-100%
|
||||
var green: UInt32 = 0
|
||||
|
||||
///Sets the blue level of the LED, firmware side values are 0-255, but users should be given a range of 0-100%
|
||||
var blue: UInt32 = 0
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
|
|
@ -1043,6 +1091,7 @@ extension ModuleConfig.RangeTestConfig: @unchecked Sendable {}
|
|||
extension ModuleConfig.TelemetryConfig: @unchecked Sendable {}
|
||||
extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {}
|
||||
extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {}
|
||||
extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {}
|
||||
extension RemoteHardwarePin: @unchecked Sendable {}
|
||||
#endif // swift(>=5.5) && canImport(_Concurrency)
|
||||
|
||||
|
|
@ -1071,6 +1120,7 @@ extension ModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
8: .same(proto: "audio"),
|
||||
9: .standard(proto: "remote_hardware"),
|
||||
10: .standard(proto: "neighbor_info"),
|
||||
11: .standard(proto: "ambient_lighting"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1209,6 +1259,19 @@ extension ModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
self.payloadVariant = .neighborInfo(v)
|
||||
}
|
||||
}()
|
||||
case 11: try {
|
||||
var v: ModuleConfig.AmbientLightingConfig?
|
||||
var hadOneofValue = false
|
||||
if let current = self.payloadVariant {
|
||||
hadOneofValue = true
|
||||
if case .ambientLighting(let m) = current {v = m}
|
||||
}
|
||||
try decoder.decodeSingularMessageField(value: &v)
|
||||
if let v = v {
|
||||
if hadOneofValue {try decoder.handleConflictingOneOf()}
|
||||
self.payloadVariant = .ambientLighting(v)
|
||||
}
|
||||
}()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -1260,6 +1323,10 @@ extension ModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
guard case .neighborInfo(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
|
||||
}()
|
||||
case .ambientLighting?: try {
|
||||
guard case .ambientLighting(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 11)
|
||||
}()
|
||||
case nil: break
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
|
|
@ -1283,6 +1350,7 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
6: .standard(proto: "json_enabled"),
|
||||
7: .standard(proto: "tls_enabled"),
|
||||
8: .same(proto: "root"),
|
||||
9: .standard(proto: "proxy_to_client_enabled"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1299,6 +1367,7 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
case 6: try { try decoder.decodeSingularBoolField(value: &self.jsonEnabled) }()
|
||||
case 7: try { try decoder.decodeSingularBoolField(value: &self.tlsEnabled) }()
|
||||
case 8: try { try decoder.decodeSingularStringField(value: &self.root) }()
|
||||
case 9: try { try decoder.decodeSingularBoolField(value: &self.proxyToClientEnabled) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -1329,6 +1398,9 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
if !self.root.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.root, fieldNumber: 8)
|
||||
}
|
||||
if self.proxyToClientEnabled != false {
|
||||
try visitor.visitSingularBoolField(value: self.proxyToClientEnabled, fieldNumber: 9)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
|
@ -1341,6 +1413,7 @@ extension ModuleConfig.MQTTConfig: SwiftProtobuf.Message, SwiftProtobuf._Message
|
|||
if lhs.jsonEnabled != rhs.jsonEnabled {return false}
|
||||
if lhs.tlsEnabled != rhs.tlsEnabled {return false}
|
||||
if lhs.root != rhs.root {return false}
|
||||
if lhs.proxyToClientEnabled != rhs.proxyToClientEnabled {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1999,6 +2072,62 @@ extension ModuleConfig.CannedMessageConfig.InputEventChar: SwiftProtobuf._ProtoN
|
|||
]
|
||||
}
|
||||
|
||||
extension ModuleConfig.AmbientLightingConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = ModuleConfig.protoMessageName + ".AmbientLightingConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "led_state"),
|
||||
2: .same(proto: "current"),
|
||||
3: .same(proto: "red"),
|
||||
4: .same(proto: "green"),
|
||||
5: .same(proto: "blue"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &self.ledState) }()
|
||||
case 2: try { try decoder.decodeSingularUInt32Field(value: &self.current) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self.red) }()
|
||||
case 4: try { try decoder.decodeSingularUInt32Field(value: &self.green) }()
|
||||
case 5: try { try decoder.decodeSingularUInt32Field(value: &self.blue) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.ledState != false {
|
||||
try visitor.visitSingularBoolField(value: self.ledState, fieldNumber: 1)
|
||||
}
|
||||
if self.current != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.current, fieldNumber: 2)
|
||||
}
|
||||
if self.red != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.red, fieldNumber: 3)
|
||||
}
|
||||
if self.green != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.green, fieldNumber: 4)
|
||||
}
|
||||
if self.blue != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.blue, fieldNumber: 5)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: ModuleConfig.AmbientLightingConfig, rhs: ModuleConfig.AmbientLightingConfig) -> Bool {
|
||||
if lhs.ledState != rhs.ledState {return false}
|
||||
if lhs.current != rhs.current {return false}
|
||||
if lhs.red != rhs.red {return false}
|
||||
if lhs.green != rhs.green {return false}
|
||||
if lhs.blue != rhs.blue {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension RemoteHardwarePin: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".RemoteHardwarePin"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ enum PortNum: SwiftProtobuf.Enum {
|
|||
/// Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
|
||||
case waypointApp // = 8
|
||||
|
||||
///
|
||||
/// Audio Payloads.
|
||||
/// Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
|
||||
case audioApp // = 9
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ struct EnvironmentMetrics {
|
|||
var barometricPressure: Float = 0
|
||||
|
||||
///
|
||||
/// Gas resistance in mOhm measured
|
||||
/// Gas resistance in MOhm measured
|
||||
var gasResistance: Float = 0
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ struct NodeMap: View {
|
|||
@State var selectedOverlayServer: MapOverlayServer = UserDefaults.mapOverlayServer
|
||||
@State var mapTilesAboveLabels: Bool = UserDefaults.mapTilesAboveLabels
|
||||
|
||||
let fromDate: NSDate = Calendar.current.date(byAdding: .month, value: -1, to: Date())! as NSDate
|
||||
|
||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "time", ascending: true)],
|
||||
predicate: NSPredicate(format: "time >= %@ && nodePosition != nil", Calendar.current.startOfDay(for: Date()) as NSDate), animation: .none)
|
||||
predicate: NSPredicate(format: "time >= %@ && nodePosition != nil", Calendar.current.date(byAdding: .day, value: -7, to: Date())! as NSDate), animation: .none)
|
||||
private var positions: FetchedResults<PositionEntity>
|
||||
|
||||
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "name", ascending: false)],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue