Checkpoint 2 CoreData upgrade

This commit is contained in:
Garth Vander Houwen 2021-12-16 14:13:54 -08:00
parent fd5b9eb1c3
commit 6a3e661345
15 changed files with 416 additions and 597 deletions

View file

@ -9,11 +9,9 @@
/* Begin PBXBuildFile section */
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */; };
DD23A51326FEF5D500D9B90C /* MessageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A51226FEF5D500D9B90C /* MessageData.swift */; };
DD2E652427679E4000E45FC5 /* NodeInfoEntityRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E652327679E4000E45FC5 /* NodeInfoEntityRow.swift */; };
DD2E65262767A01F00E45FC5 /* NodeInfoEntityDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E65252767A01F00E45FC5 /* NodeInfoEntityDetail.swift */; };
DD47E3CC26F0E51D00029299 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CB26F0E51D00029299 /* NodeDetail.swift */; };
DD2E652427679E4000E45FC5 /* NodeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E652327679E4000E45FC5 /* NodeRow.swift */; };
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2E65252767A01F00E45FC5 /* NodeDetail.swift */; };
DD47E3CE26F103C600029299 /* NodeList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CD26F103C600029299 /* NodeList.swift */; };
DD47E3D026F1073F00029299 /* NodeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3CF26F1073F00029299 /* NodeRow.swift */; };
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D526F17ED900029299 /* CircleText.swift */; };
DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D826F3093800029299 /* MessageBubble.swift */; };
DD47E3DB26F3901B00029299 /* Channels.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3DA26F3901A00029299 /* Channels.swift */; };
@ -22,11 +20,11 @@
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; };
DD4A91202708C66600501B7E /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911F2708C66600501B7E /* Configuration.swift */; };
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; };
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */; };
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */; };
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FE272476C700F4AB02 /* LogDocument.swift */; };
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD836AE626F6B38600ABCC23 /* Connect.swift */; };
DD836AED26F858F900ABCC23 /* MeshData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD836AEC26F858F900ABCC23 /* MeshData.swift */; };
DD836AEF26F85D8D00ABCC23 /* NodeInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD836AEE26F85D8D00ABCC23 /* NodeInfoModel.swift */; };
DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860B26F684AF00DC5189 /* BatteryIcon.swift */; };
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; };
@ -75,11 +73,9 @@
/* Begin PBXFileReference section */
DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = "<group>"; };
DD23A51226FEF5D500D9B90C /* MessageData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageData.swift; sourceTree = "<group>"; };
DD2E652327679E4000E45FC5 /* NodeInfoEntityRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityRow.swift; sourceTree = "<group>"; };
DD2E65252767A01F00E45FC5 /* NodeInfoEntityDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityDetail.swift; sourceTree = "<group>"; };
DD47E3CB26F0E51D00029299 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = "<group>"; };
DD2E652327679E4000E45FC5 /* NodeRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeRow.swift; sourceTree = "<group>"; };
DD2E65252767A01F00E45FC5 /* NodeDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeDetail.swift; sourceTree = "<group>"; };
DD47E3CD26F103C600029299 /* NodeList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeList.swift; sourceTree = "<group>"; };
DD47E3CF26F1073F00029299 /* NodeRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeRow.swift; sourceTree = "<group>"; };
DD47E3D526F17ED900029299 /* CircleText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleText.swift; sourceTree = "<group>"; };
DD47E3D826F3093800029299 /* MessageBubble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBubble.swift; sourceTree = "<group>"; };
DD47E3DA26F3901A00029299 /* Channels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Channels.swift; sourceTree = "<group>"; };
@ -87,11 +83,11 @@
DD47E3DE26F39D9F00029299 /* MyInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoModel.swift; sourceTree = "<group>"; };
DD4A911D2708C65400501B7E /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
DD4A911F2708C66600501B7E /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = "<group>"; };
DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = "<group>"; };
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = "<group>"; };
DD8169FE272476C700F4AB02 /* LogDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDocument.swift; sourceTree = "<group>"; };
DD836AE626F6B38600ABCC23 /* Connect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connect.swift; sourceTree = "<group>"; };
DD836AEC26F858F900ABCC23 /* MeshData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshData.swift; sourceTree = "<group>"; };
DD836AEE26F85D8D00ABCC23 /* NodeInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoModel.swift; sourceTree = "<group>"; };
DD90860A26F645B700DC5189 /* MeshtasticClient.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MeshtasticClient.entitlements; sourceTree = "<group>"; };
DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = "<group>"; };
@ -156,12 +152,10 @@
DD47E3CA26F0E50300029299 /* Nodes */ = {
isa = PBXGroup;
children = (
DD47E3CB26F0E51D00029299 /* NodeDetail.swift */,
DD47E3CD26F103C600029299 /* NodeList.swift */,
DD47E3CF26F1073F00029299 /* NodeRow.swift */,
DD90860D26F69BAE00DC5189 /* NodeMap.swift */,
DD2E652327679E4000E45FC5 /* NodeInfoEntityRow.swift */,
DD2E65252767A01F00E45FC5 /* NodeInfoEntityDetail.swift */,
DD2E652327679E4000E45FC5 /* NodeRow.swift */,
DD2E65252767A01F00E45FC5 /* NodeDetail.swift */,
);
path = Nodes;
sourceTree = "<group>";
@ -292,7 +286,6 @@
children = (
DD47E3DE26F39D9F00029299 /* MyInfoModel.swift */,
DDF924C526FA2375009FE055 /* MessageModel.swift */,
DD836AEC26F858F900ABCC23 /* MeshData.swift */,
DD836AEE26F85D8D00ABCC23 /* NodeInfoModel.swift */,
DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */,
DD23A51226FEF5D500D9B90C /* MessageData.swift */,
@ -344,6 +337,7 @@
isa = PBXGroup;
children = (
DDC4D567275499A500A4208E /* Persistence.swift */,
DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */,
);
path = Persistence;
sourceTree = "<group>";
@ -506,20 +500,19 @@
files = (
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */,
DDAF8C6E26ED19040058C060 /* Extensions.swift in Sources */,
DD47E3CC26F0E51D00029299 /* NodeDetail.swift in Sources */,
DD836AEF26F85D8D00ABCC23 /* NodeInfoModel.swift in Sources */,
DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */,
DDAF8C5F26ED09B50058C060 /* radioconfig.pb.swift in Sources */,
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */,
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */,
DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */,
DDC4D568275499A500A4208E /* Persistence.swift in Sources */,
DD2E652427679E4000E45FC5 /* NodeInfoEntityRow.swift in Sources */,
DD2E652427679E4000E45FC5 /* NodeRow.swift in Sources */,
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */,
DD47E3DB26F3901B00029299 /* Channels.swift in Sources */,
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */,
DDAF8C6926ED0D070058C060 /* deviceonly.pb.swift in Sources */,
DD23A51326FEF5D500D9B90C /* MessageData.swift in Sources */,
DD836AED26F858F900ABCC23 /* MeshData.swift in Sources */,
DDAF8C6B26ED0DD80058C060 /* environmental_measurement.pb.swift in Sources */,
DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */,
DD4A91202708C66600501B7E /* Configuration.swift in Sources */,
@ -531,14 +524,13 @@
DD47E3DF26F39D9F00029299 /* MyInfoModel.swift in Sources */,
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */,
DD47E3CE26F103C600029299 /* NodeList.swift in Sources */,
DD47E3D026F1073F00029299 /* NodeRow.swift in Sources */,
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */,
DDF924C626FA2375009FE055 /* MessageModel.swift in Sources */,
DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */,
DDAF8C6326ED0A230058C060 /* admin.pb.swift in Sources */,
DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */,
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */,
DD2E65262767A01F00E45FC5 /* NodeInfoEntityDetail.swift in Sources */,
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */,
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */,
DDAF8C6726ED0C8C0058C060 /* remote_hardware.pb.swift in Sources */,

View file

@ -72,8 +72,8 @@
filePath = "MeshtasticClient/Helpers/BLEManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "839"
endingLineNumber = "839"
startingLineNumber = "824"
endingLineNumber = "824"
landmarkName = "sendMessage(message:)"
landmarkType = "7">
</BreakpointContent>
@ -88,8 +88,8 @@
filePath = "MeshtasticClient/Helpers/BLEManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "862"
endingLineNumber = "862"
startingLineNumber = "847"
endingLineNumber = "847"
landmarkName = "sendMessage(message:)"
landmarkType = "7">
</BreakpointContent>
@ -113,33 +113,17 @@
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "03628B8D-EBF0-453E-884C-1161447647CD"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "MeshtasticClient/Views/Messages/Messages.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "54"
endingLineNumber = "54"
landmarkName = "body"
landmarkType = "24">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "2F7DD194-C7B0-472F-8346-9128AE44D6AD"
uuid = "64E92D44-3827-42C3-AFC0-3EE687F00068"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "MeshtasticClient/Views/Messages/Messages.swift"
filePath = "MeshtasticClient/Helpers/BLEManager.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "56"
endingLineNumber = "56"
landmarkName = "body"
landmarkType = "24">
startingLineNumber = "447"
endingLineNumber = "447"
landmarkName = "peripheral(_:didUpdateValueFor:error:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>

View file

@ -109,7 +109,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
self.timeoutTimerCount += 1
if timeoutTimerCount == 6 {
if timeoutTimerCount == 10 {
if connectedPeripheral != nil {
@ -167,16 +167,16 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
peripheralName = name
}
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, name: peripheralName, firmwareVersion: "Unknown", rssi: RSSI.intValue, subscribed: false, peripheral: peripheral, myInfo: nil)
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, name: peripheralName, shortName: "", longName: "", firmwareVersion: "Unknown", rssi: RSSI.intValue, subscribed: false, peripheral: peripheral)
let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id })
if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected {
//newPeripheral.myInfo = peripherals.first(where: { $0.id == newPeripheral.id })?.myInfo
peripherals[peripheralIndex!] = newPeripheral
peripherals.remove(at: peripheralIndex!)
peripherals.append(newPeripheral)
print("Updating peripheral: \(peripheralName)")
} else {
if newPeripheral.peripheral.state != CBPeripheralState.connected {
@ -190,7 +190,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Called when a peripheral is connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
// guard let connectedPeripheral = connectedPeripheral else { return }
self.isConnected = true
// Invalidate and reset connection timer count, remove any connection errors
@ -202,15 +201,16 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first
connectedPeripheral.peripheral.delegate = self
let fetchNodeRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeRequest.predicate = NSPredicate(format: "bleName MATCHES %@", String(peripheral.name ?? "???"))
let fetchConnectedPeripheralRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchConnectedPeripheralRequest.predicate = NSPredicate(format: "bleName MATCHES %@", String(peripheral.name ?? "???"))
do {
let fetchedNode = try context?.fetch(fetchNodeRequest) as! [NodeInfoEntity]
let fetchedNode = try context?.fetch(fetchConnectedPeripheralRequest) as! [NodeInfoEntity]
if fetchedNode.count == 1 {
connectedPeripheral.name = fetchedNode[0].user!.longName!
connectedPeripheral.shortName = fetchedNode[0].user!.shortName!
connectedPeripheral.longName = fetchedNode[0].user!.longName!
connectedPeripheral.firmwareVersion = (fetchedNode[0].myInfo?.firmwareVersion ?? "Unknown")
}
@ -395,7 +395,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("Save a CoreData MyInfoEntity")
let fetchMyInfoRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %i", Int64(decodedInfo.myInfo.myNodeNum))
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.myInfo.myNodeNum))
do {
let fetchedMyInfo = try context?.fetch(fetchMyInfoRequest) as! [MyInfoEntity]
@ -493,7 +493,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Look for a MyInfo
let fetchMyInfoRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %i", Int64(decodedInfo.nodeInfo.num))
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(decodedInfo.nodeInfo.num))
do {
@ -661,15 +661,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
} else if decodedInfo.packet.decoded.portnum == PortNum.nodeinfoApp {
//let fetchNodeInfoAppRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
//fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %i", Int64(decodedInfo.packet.from))
let fetchNodeRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.packet.from))
let fetchNodeInfoAppRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.packet.from))
do {
let fetchedNode = try context?.fetch(fetchNodeRequest) as! [NodeInfoEntity]
let fetchedNode = try context?.fetch(fetchNodeInfoAppRequest) as! [NodeInfoEntity]
if fetchedNode.count == 1 {
fetchedNode[0].id = Int64(decodedInfo.nodeInfo.num)
@ -686,7 +683,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
try context!.save()
if meshLoggingEnabled {
MeshLogger.log("MESH PACKET Updated NodeInfo SNR and Time from Node Info App Packet For: \(fetchedNode[0].num)")
MeshLogger.log("MESH PACKET Updated NodeInfo SNR and Time from Node Info App Packet For: \(Int64(decodedInfo.nodeInfo.num))")
}
print("Updated NodeInfo SNR and Time from Packet For: \(fetchedNode[0].num)")
@ -696,17 +693,15 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let nsError = error as NSError
print("Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)")
}
} catch {
print("Error Fetching NodeInfoEntity for NODEINFO_APP")
}
print(decodedInfo.packet.decoded.payload)
} else if decodedInfo.packet.decoded.portnum == PortNum.positionApp {
let fetchNodePositionRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
@ -746,16 +741,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("Error Fetching NodeInfoEntity for NODEINFO_APP")
}
print(decodedInfo.packet.decoded.payload)
// if meshLoggingEnabled {
// MeshLogger.log("MESH PACKET Updated NodeInfo SNR and Time from Position App Packet For: \(updatedNode.num)")
// }
// print("Updated NodeInfo SNR and Time from Packet For: \(updatedNode.num)")
//
// print("Postion Payload")
// print(try decodedInfo.packet.jsonString())
} else if decodedInfo.packet.decoded.portnum == PortNum.adminApp {

View file

@ -1,7 +1,7 @@
import Foundation
class MeshLogger {
static var logFile: URL? {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
let fileName = "mesh.log"

View file

@ -1,60 +0,0 @@
import Foundation
class MeshData: ObservableObject {
private static var documentsFolder: URL {
do {
return try FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
} catch {
fatalError("Can't find documents directory.")
}
}
private static var fileURL: URL {
return documentsFolder.appendingPathComponent("nodeinfo.data")
}
@Published var nodes: [NodeInfoModel] = []
func load() {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let data = try? Data(contentsOf: Self.fileURL) else {
#if DEBUG
DispatchQueue.main.async {
self?.nodes = NodeInfoModel.data
}
#endif
return
}
guard let nodeList = try? JSONDecoder().decode([NodeInfoModel].self, from: data) else {
do {
// If the file is borked delete it so we stop crashing
try FileManager.default.removeItem(at: Self.fileURL)
} catch {
fatalError("Can't delete saved node data.")
}
fatalError("Can't decode saved node data.")
}
DispatchQueue.main.async {
self?.nodes = nodeList
}
}
}
func save() {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let scrums = self?.nodes else { fatalError("Self out of scope") }
guard let data = try? JSONEncoder().encode(scrums) else { fatalError("Error encoding data") }
do {
let outfile = Self.fileURL
try data.write(to: outfile)
} catch {
fatalError("Can't write to file")
}
}
}
}

View file

@ -4,20 +4,24 @@ import CoreBluetooth
struct Peripheral: Identifiable {
var id: String
var name: String
var shortName: String
var longName: String
var firmwareVersion: String
var rssi: Int
var subscribed: Bool
var peripheral: CBPeripheral
var myInfo: MyInfoModel?
//var myInfo: MyInfoModel?
init(id: String, name: String, firmwareVersion: String, rssi: Int, subscribed: Bool, peripheral: CBPeripheral, myInfo: MyInfoModel?) {
init(id: String, name: String, shortName: String, longName: String, firmwareVersion: String, rssi: Int, subscribed: Bool, peripheral: CBPeripheral) {//, myInfo: MyInfoModel?) {
self.id = id
self.name = name
self.shortName = shortName
self.longName = longName
self.firmwareVersion = firmwareVersion
self.rssi = rssi
self.subscribed = subscribed
self.peripheral = peripheral
self.myInfo = myInfo
//self.myInfo = myInfo
}
}

View file

@ -0,0 +1,45 @@
import CoreData
import CoreLocation
import MapKit
import SwiftUI
extension PositionEntity {
var latitude: Double? {
let d = Double(latitudeI)
if d == 0 {
return nil
}
return d / 1e7
}
var longitude: Double? {
let d = Double(longitudeI)
if d == 0 {
return nil
}
return d / 1e7
}
var coordinate: CLLocationCoordinate2D? {
if latitude != nil && longitude != nil {
let coord = CLLocationCoordinate2D(latitude: latitude!, longitude: longitude!)
return coord
} else {
return nil
}
}
var annotaton: MKPointAnnotation {
let pointAnn = MKPointAnnotation()
if coordinate != nil {
pointAnn.coordinate = coordinate!
}
return pointAnn
}
}

View file

@ -52,17 +52,17 @@ struct Connect: View {
if bleManager.connectedPeripheral != nil {
Text(bleManager.connectedPeripheral.name).font(.title2)
Text(bleManager.connectedPeripheral.longName).font(.title2)
} else {
Text(String(bleManager.connectedPeripheral.peripheral.name ?? "Unknown")).font(.title2)
}
Text("BLE Name: ").font(.caption)+Text(bleManager.connectedPeripheral.name)
.font(.caption).foregroundColor(Color.gray)
if bleManager.connectedPeripheral != nil {
//Text("Model: ").font(.caption)+Text(bleManager.connectedNode?.user!.hwModel ?? "(null)").font(.caption).foregroundColor(Color.gray)
}
Text("BLE Name: ").font(.caption)+Text(bleManager.connectedPeripheral.name).font(.caption).foregroundColor(Color.gray)
if bleManager.connectedPeripheral != nil {
//Text("FW Version: ").font(.caption)+Text(bleManager.connectedPeripheral.myInfo?.firmwareVersion ?? "(null)").font(.caption).foregroundColor(Color.gray)
Text("FW Version: ").font(.caption)+Text(bleManager.connectedPeripheral.firmwareVersion)
.font(.caption).foregroundColor(Color.gray)
}
if bleManager.connectedPeripheral.subscribed {
Text("Properly Subscribed").font(.caption)
@ -200,8 +200,12 @@ struct Connect: View {
.navigationBarItems(trailing:
ZStack {
//ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName :
"???")
}
)
}

View file

@ -57,6 +57,7 @@ struct Messages: View {
print("I want to delete message: \(message.messageId)")
self.showDeleteMessageAlert = true
self.deleteMessageId = message.messageId
print(deleteMessageId)
})
@ -89,13 +90,19 @@ struct Messages: View {
print("OK button tapped")
if deleteMessageId > 0 {
//let message = messages.first.where: { $0.messageId == deleteMessageId })
//context.delete(object: message)
//bleManager.messageData.messages.remove(at: messageIndex!)
//bleManager.messageData.save()
//print("Deleted message: \(message.messageId)")
//showDeleteMessageAlert = false
deleteMessageId = 0
let message = messages.first(where: { $0.messageId == deleteMessageId })
context.delete(message!)
do {
try context.save()
deleteMessageId = 0
messageCount = messages.count
} catch {
print("Failed to delete message \(deleteMessageId)")
}
}
},
secondaryButton: .cancel()
@ -194,12 +201,16 @@ struct Messages: View {
}
}
.navigationTitle("Channel - Primary")
//.navigationBarTitleDisplayMode(.inline)
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
ZStack {
//ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName :
"???")
})
.onAppear(perform: {

View file

@ -1,176 +1,187 @@
///*
//Abstract:
//A view showing the details for a node.
//*/
/*
Abstract:
A view showing the details for a node.
*/
import SwiftUI
import MapKit
import CoreLocation
struct NodeDetail: View {
// CoreData
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
var node: NodeInfoEntity
struct MapLocation: Identifiable {
let id = UUID()
let name: String
let coordinate: CLLocationCoordinate2D
}
var body: some View {
GeometryReader { bounds in
VStack {
if node.positions != nil && node.positions!.count > 0 {
// let nodeCoordinatePosition = CLLocationCoordinate2D(latitude: node.position.latitude!, longitude: node.position.longitude!)
//
//import SwiftUI
//import MapKit
//import CoreLocation
// let regionBinding = Binding<MKCoordinateRegion>(
// get: {
// MKCoordinateRegion(center: nodeCoordinatePosition, span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
// },
// set: { _ in }
// )
// let annotations = [MapLocation(name: node.user.shortName, coordinate: node.position.coordinate!)]
//
//struct NodeDetail: View {
//
// @EnvironmentObject var bleManager: BLEManager
//
// var node: NodeInfoModel
//
// struct MapLocation: Identifiable {
// let id = UUID()
// let name: String
// let coordinate: CLLocationCoordinate2D
// }
//
// var body: some View {
//
// GeometryReader { bounds in
//
// VStack {
//
// if node.position.coordinate != nil {
//
// let nodeCoordinatePosition = CLLocationCoordinate2D(latitude: node.position.latitude!, longitude: node.position.longitude!)
//
// let regionBinding = Binding<MKCoordinateRegion>(
// get: {
// MKCoordinateRegion(center: nodeCoordinatePosition, span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
// },
// set: { _ in }
// )
// let annotations = [MapLocation(name: node.user.shortName, coordinate: node.position.coordinate!)]
//
// Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none, annotationItems: annotations) { location in
// MapAnnotation(
// coordinate: location.coordinate,
// content: {
// Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none, annotationItems: annotations) { location in
// MapAnnotation(
// coordinate: location.coordinate,
// content: {
// CircleText(text: node.user.shortName, color: .accentColor)
// }
// )
// }.frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 2)
// } else {
// Image(node.user.hwModel)
// .resizable()
// .aspectRatio(contentMode: .fit)
// .frame(width: bounds.size.width, height: bounds.size.height / 2)
// }
// ScrollView {
//
// HStack {
//
// VStack(alignment: .center) {
// Text("AKA").font(.title2).fixedSize()
// CircleText(text: node.user.shortName, color: .accentColor)
// .offset(y: 10)
// }
// .padding([.leading, .trailing, .bottom])
// Divider()
// if node.snr != nil && node.snr! > 0 {
// VStack(alignment: .center) {
//
// Image(systemName: "waveform.path")
// .font(.title)
// .foregroundColor(.accentColor)
// .symbolRenderingMode(.hierarchical)
// Text("SNR").font(.title2).fixedSize()
// Text(String(node.snr ?? 0))
// .font(.title2)
// .foregroundColor(.gray)
// }
// Divider()
// }
// VStack(alignment: .center) {
// }
// )
// }.frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 2)
} else {
Image(node.user?.hwModel ?? "UNSET")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: bounds.size.width, height: bounds.size.height / 2)
}
ScrollView {
HStack {
VStack(alignment: .center) {
Text("AKA").font(.title2).fixedSize()
CircleText(text: node.user?.shortName ?? "???", color: .accentColor)
.offset(y: 10)
}
.padding([.leading, .trailing, .bottom])
Divider()
if node.snr > 0 {
VStack(alignment: .center) {
Image(systemName: "waveform.path")
.font(.title)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
Text("SNR").font(.title2).fixedSize()
Text(String(node.snr))
.font(.title2)
.foregroundColor(.gray)
}
Divider()
}
// VStack(alignment: .center) {
// BatteryIcon(batteryLevel: node.position.batteryLevel, font: .title, color: .accentColor)
// if node.position.batteryLevel != nil && node.position.batteryLevel! > 0 {
// Text("Battery").font(.title2).fixedSize()
// Text(String(node.position.batteryLevel!) + "%")
// .font(.title2)
// .foregroundColor(.gray)
// .symbolRenderingMode(.hierarchical)
// } else {
// Text("Powered").font(.title2)
// }
// }
//
// }.padding(4)
// Divider()
// HStack {
//
// Image(node.user.hwModel)
// .resizable()
// .frame(width: 60, height: 60)
// .cornerRadius(5)
//
// Text("Model: " + String(node.user.hwModel))
// .font(.title3)
// }
// .padding()
// Divider()
//
// if node.lastHeard > 0 {
//
// HStack {
//
// Image(systemName: "clock").font(.title2).foregroundColor(.accentColor)
// let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
// Text("Last Heard: \(lastHeard, style: .relative) ago").font(.title3)
// }.padding()
// Divider()
// }
//
// if node.position.coordinate != nil {
// HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 14) {
// if node.position.batteryLevel != nil && node.position.batteryLevel! > 0 {
// Text("Battery").font(.title2).fixedSize()
// Text(String(node.position.batteryLevel!) + "%")
// .font(.title2)
// .foregroundColor(.gray)
// .symbolRenderingMode(.hierarchical)
// } else {
// Text("Powered").font(.title2)
// }
// }
}.padding(4)
Divider()
HStack {
Image(node.user!.hwModel ?? "UNSET")
.resizable()
.frame(width: 60, height: 60)
.cornerRadius(5)
Text("Model: " + String(node.user!.hwModel ?? "UNSET"))
.font(.title3)
}
.padding()
Divider()
if node.lastHeard > 0 {
HStack {
Image(systemName: "clock").font(.title2).foregroundColor(.accentColor)
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.title3)
}.padding()
Divider()
}
// if node.position.coordinate != nil {
// HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 14) {
// Image(systemName: "mappin").font(.title).foregroundColor(.accentColor)
// VStack(alignment: .leading) {
// Text("Latitude").font(.headline)
// Text(String(node.position.latitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Longitude").font(.headline)
// Text(String(node.position.longitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Altitude").font(.headline)
// Text(String(node.position.altitude ?? 0) + " m").font(.caption).foregroundColor(.gray)
// }
// }.padding()
// Divider()
// }
// HStack(alignment: .center) {
// VStack {
// HStack {
// Image(systemName: "person").font(.title3).foregroundColor(.accentColor)
// Text("Unique Id:").font(.title3)
// }
// Text(node.user.id).font(.headline).foregroundColor(.gray)
// }
// Divider()
// VStack {
// HStack {
// Image(systemName: "number").font(.title3).foregroundColor(.accentColor)
// Text("Node Number:").font(.title3)
// }
// Text(String(node.num)).font(.headline).foregroundColor(.gray)
// }
// }.padding()
// }
// }.navigationTitle(node.user.longName)
// .navigationBarTitleDisplayMode(.inline)
// .navigationBarItems(trailing:
//
// ZStack {
// // ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
// })
// }.ignoresSafeArea(.all, edges: [.leading, .trailing])
// }
//}
//
//struct NodeDetail_Previews: PreviewProvider {
// static let bleManager = BLEManager()
//
// static var previews: some View {
// Group {
// NodeDetail(node: bleManager.meshData.nodes[0])
// NodeDetail(node: bleManager.meshData.nodes[1])
// }
// }
//}
// VStack(alignment: .leading) {
// Text("Latitude").font(.headline)
// Text(String(node.position.latitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Longitude").font(.headline)
// Text(String(node.position.longitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Altitude").font(.headline)
// Text(String(node.position.altitude ?? 0) + " m").font(.caption).foregroundColor(.gray)
// }
// }.padding()
// Divider()
// }
HStack(alignment: .center) {
VStack {
HStack {
Image(systemName: "person").font(.title3).foregroundColor(.accentColor)
Text("Unique Id:").font(.title3)
}
Text(node.user?.userId ?? "??????").font(.headline).foregroundColor(.gray)
}
Divider()
VStack {
HStack {
Image(systemName: "number").font(.title3).foregroundColor(.accentColor)
Text("Node Number:").font(.title3)
}
Text(String(node.num)).font(.headline).foregroundColor(.gray)
}
}.padding()
}
}.navigationTitle(node.user!.longName ?? "Unknown")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName :
"???")
})
.onAppear(perform: {
self.bleManager.context = context
})
}.ignoresSafeArea(.all, edges: [.leading, .trailing])
}
}
struct NodeInfoEntityDetail_Previews: PreviewProvider {
static let bleManager = BLEManager()
static var previews: some View {
Group {
//NodeInfoEntityDetail(node: node)
}
}
}

View file

@ -1,175 +0,0 @@
/*
Abstract:
A view showing the details for a node.
*/
import SwiftUI
import MapKit
import CoreLocation
struct NodeInfoEntityDetail: View {
@EnvironmentObject var bleManager: BLEManager
var node: NodeInfoEntity
struct MapLocation: Identifiable {
let id = UUID()
let name: String
let coordinate: CLLocationCoordinate2D
}
var body: some View {
GeometryReader { bounds in
VStack {
if node.positions!.count > 0 {
// let nodeCoordinatePosition = CLLocationCoordinate2D(latitude: node.position.latitude!, longitude: node.position.longitude!)
//
// let regionBinding = Binding<MKCoordinateRegion>(
// get: {
// MKCoordinateRegion(center: nodeCoordinatePosition, span: MKCoordinateSpan(latitudeDelta: 0.005, longitudeDelta: 0.005))
// },
// set: { _ in }
// )
// let annotations = [MapLocation(name: node.user.shortName, coordinate: node.position.coordinate!)]
//
// Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none, annotationItems: annotations) { location in
// MapAnnotation(
// coordinate: location.coordinate,
// content: {
// CircleText(text: node.user.shortName, color: .accentColor)
// }
// )
// }.frame(idealWidth: bounds.size.width, minHeight: bounds.size.height / 2)
} else {
Image(node.user?.hwModel ?? "UNSET")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: bounds.size.width, height: bounds.size.height / 2)
}
ScrollView {
HStack {
VStack(alignment: .center) {
Text("AKA").font(.title2).fixedSize()
CircleText(text: node.user?.shortName ?? "???", color: .accentColor)
.offset(y: 10)
}
.padding([.leading, .trailing, .bottom])
Divider()
if node.snr > 0 {
VStack(alignment: .center) {
Image(systemName: "waveform.path")
.font(.title)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
Text("SNR").font(.title2).fixedSize()
Text(String(node.snr))
.font(.title2)
.foregroundColor(.gray)
}
Divider()
}
// VStack(alignment: .center) {
// BatteryIcon(batteryLevel: node.position.batteryLevel, font: .title, color: .accentColor)
// if node.position.batteryLevel != nil && node.position.batteryLevel! > 0 {
// Text("Battery").font(.title2).fixedSize()
// Text(String(node.position.batteryLevel!) + "%")
// .font(.title2)
// .foregroundColor(.gray)
// .symbolRenderingMode(.hierarchical)
// } else {
// Text("Powered").font(.title2)
// }
// }
}.padding(4)
Divider()
HStack {
Image(node.user!.hwModel ?? "UNSET")
.resizable()
.frame(width: 60, height: 60)
.cornerRadius(5)
Text("Model: " + String(node.user!.hwModel ?? "UNSET"))
.font(.title3)
}
.padding()
Divider()
if node.lastHeard > 0 {
HStack {
Image(systemName: "clock").font(.title2).foregroundColor(.accentColor)
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.title3)
}.padding()
Divider()
}
// if node.position.coordinate != nil {
// HStack(alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/, spacing: 14) {
// Image(systemName: "mappin").font(.title).foregroundColor(.accentColor)
// VStack(alignment: .leading) {
// Text("Latitude").font(.headline)
// Text(String(node.position.latitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Longitude").font(.headline)
// Text(String(node.position.longitude ?? 0)).font(.caption).foregroundColor(.gray)
// }
// Divider()
// VStack(alignment: .leading) {
// Text("Altitude").font(.headline)
// Text(String(node.position.altitude ?? 0) + " m").font(.caption).foregroundColor(.gray)
// }
// }.padding()
// Divider()
// }
HStack(alignment: .center) {
VStack {
HStack {
Image(systemName: "person").font(.title3).foregroundColor(.accentColor)
Text("Unique Id:").font(.title3)
}
Text(node.user?.userId ?? "??????").font(.headline).foregroundColor(.gray)
}
Divider()
VStack {
HStack {
Image(systemName: "number").font(.title3).foregroundColor(.accentColor)
Text("Node Number:").font(.title3)
}
Text(String(node.num)).font(.headline).foregroundColor(.gray)
}
}.padding()
}
}.navigationTitle(node.user!.longName ?? "Unknown")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(trailing:
ZStack {
// ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
})
}.ignoresSafeArea(.all, edges: [.leading, .trailing])
}
}
struct NodeInfoEntityDetail_Previews: PreviewProvider {
static let bleManager = BLEManager()
static var previews: some View {
Group {
//NodeInfoEntityDetail(node: node)
}
}
}

View file

@ -42,17 +42,28 @@ struct NodeList: View {
} else {
ForEach( nodes ) { node in
let index = nodes.firstIndex(where: { $0.id == node.id })
NavigationLink(destination: NodeInfoEntityDetail(node: node), tag: String(index!), selection: $selection) {
NavigationLink(destination: NodeDetail(node: node), tag: String(index!), selection: $selection) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.myInfo != nil {
if bleManager.connectedPeripheral != nil {
let connected: Bool = (bleManager.connectedPeripheral.myInfo!.myNodeNum == node.id)
NodeInfoEntityRow(node: node, connected: connected)
let connected: Bool = (bleManager.connectedPeripheral.name == node.bleName)
NodeRow(node: node, connected: connected)
} else {
NodeInfoEntityRow(node: node, connected: false)
NodeRow(node: node, connected: false)
}
}
.swipeActions {
Button {
context.delete(node)
} label: {
Label("Delete from app", systemImage: "trash")
}
.tint(.red)
}
}
}
}

View file

@ -21,13 +21,6 @@ struct NodeMap: View {
animation: .default)
private var locationNodes: FetchedResults<NodeInfoEntity>
//var locationNodes: [NodeInfoModel]// {
//bleManager.meshData.nodes.filter { node in
// (node.position.coordinate != nil)
// }
//}
struct MapLocation: Identifiable {
let id = UUID()
@ -38,6 +31,7 @@ struct NodeMap: View {
var body: some View {
let location = LocationHelper.currentLocation
let currentCoordinatePosition = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
let regionBinding = Binding<MKCoordinateRegion>(
get: {
@ -49,20 +43,32 @@ struct NodeMap: View {
NavigationView {
ZStack {
// Map(coordinateRegion: regionBinding,
// interactionModes: [.all],
// showsUserLocation: true,
// userTrackingMode: .constant(.follow), annotationItems: locationNodes) { location in
//
// MapAnnotation(
// coordinate: location.position.coordinate!,
// content: {
// CircleText(text: location.user.shortName, color: .accentColor)
// }
// )
// }
// .frame(maxHeight: .infinity)
// .ignoresSafeArea(.all, edges: [.leading, .trailing])
Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none)
.frame(maxHeight: .infinity)
//, annotationItems: locationNodes[0].positions?) { location in
// MapAnnotation(
// coordinate: location.coordinate,
// content: {
// CircleText(text: location.latitude, color: .accentColor)
// }
// )
// }.frame(maxHeight: .infinity)
//Map(coordinateRegion: regionBinding,
// interactionModes: [.all],
// showsUserLocation: true,
// userTrackingMode: .constant(.follow), annotationItems: locationNodes) { node in
//MapAnnotation(
//coordinate: node.positions[0].coordinate,
//content: {
// CircleText(text: node.user!.shortName, color: .accentColor)
//}
// )
//}
//.frame(maxHeight: .infinity)
//.ignoresSafeArea(.all, edges: [.leading, .trailing])
}
.navigationTitle("Mesh Map")
.navigationBarTitleDisplayMode(.inline)

View file

@ -1,64 +1,64 @@
//import SwiftUI
//
//struct NodeRow: View {
// var node: NodeInfoModel
// var connected: Bool
//
// var body: some View {
// VStack(alignment: .leading) {
//
// HStack {
//
// CircleText(text: node.user.shortName, color: Color.accentColor).offset(y: 1).padding(.trailing, 5)
// .offset(x: -15)
//
// if UIDevice.current.userInterfaceIdiom == .pad {
// Text(node.user.longName).font(.headline)
// .offset(x: -15)
// } else {
// Text(node.user.longName).font(.title)
// .offset(x: -15)
// }
// }
// .padding(.bottom, 10)
//
// HStack(alignment: .bottom) {
//
// Image(systemName: "clock.badge.checkmark.fill").font(.headline).foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
//
// if UIDevice.current.userInterfaceIdiom == .pad {
//
// if connected {
// Text("Currently Connected").font(.caption).foregroundColor(Color.accentColor)
// } else if node.lastHeard > 0 {
// let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
// Text("Last Heard: \(lastHeard, style: .relative) ago").font(.caption).foregroundColor(.gray)
// } else {
// Text("Last Heard: Unknown").font(.caption).foregroundColor(.gray)
// }
//
// } else {
// if connected {
// Text("Currently Connected").font(.subheadline).foregroundColor(Color.accentColor)
// } else if node.lastHeard > 0 {
// let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
// Text("Last Heard: \(lastHeard, style: .relative) ago").font(.subheadline).foregroundColor(.gray)
// } else {
// Text("Last Heard: Unknown").font(.subheadline).foregroundColor(.gray)
// }
// }
// }
// }.padding([.leading, .top, .bottom])
// }
//}
//
//struct NodeRow_Previews: PreviewProvider {
// static var nodes = BLEManager().meshData.nodes
//
// static var previews: some View {
// Group {
// NodeRow(node: nodes[0], connected: true)
// }
// .previewLayout(.fixed(width: 300, height: 70))
// }
//}
import SwiftUI
struct NodeRow: View {
var node: NodeInfoEntity
var connected: Bool
var body: some View {
VStack(alignment: .leading) {
HStack {
CircleText(text: node.user?.shortName ?? "???", color: Color.accentColor).offset(y: 1).padding(.trailing, 5)
.offset(x: -15)
if UIDevice.current.userInterfaceIdiom == .pad {
Text(node.user?.longName ?? "Unknown").font(.headline)
.offset(x: -15)
} else {
Text(node.user?.longName ?? "Unknown").font(.title)
.offset(x: -15)
}
}
.padding(.bottom, 10)
HStack(alignment: .bottom) {
Image(systemName: "clock.badge.checkmark.fill").font(.headline).foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
if UIDevice.current.userInterfaceIdiom == .pad {
if connected {
Text("Currently Connected").font(.caption).foregroundColor(Color.accentColor)
} else if node.lastHeard > 0 {
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.caption).foregroundColor(.gray)
} else {
Text("Last Heard: Unknown").font(.caption).foregroundColor(.gray)
}
} else {
if connected {
Text("Currently Connected").font(.subheadline).foregroundColor(Color.accentColor)
} else if node.lastHeard > 0 {
let lastHeard = Date(timeIntervalSince1970: TimeInterval(node.lastHeard))
Text("Last Heard: \(lastHeard, style: .relative) ago").font(.subheadline).foregroundColor(.gray)
} else {
Text("Last Heard: Unknown").font(.subheadline).foregroundColor(.gray)
}
}
}
}.padding([.leading, .top, .bottom])
}
}
struct NodeRow_Previews: PreviewProvider {
//static var nodes = BLEManager().meshData.nodes
static var previews: some View {
Group {
//NodeInfoEntityRow(node: nodes[0], connected: true)
}
.previewLayout(.fixed(width: 300, height: 70))
}
}

View file

@ -144,7 +144,9 @@ struct AppSettings: View {
.navigationBarItems(trailing:
ZStack {
// ConnectedDevice(bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, name: (self.bleManager.connectedNode != nil) ? self.bleManager.connectedNode.user.shortName : ((self.bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.name : "Unknown") )
//ConnectedDevice(bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, name: (self.bleManager.connectedNode != nil) ? self.bleManager.connectedNode.user.shortName : ((self.bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.name : "Unknown") )
})
}
.navigationViewStyle(StackNavigationViewStyle())
@ -152,8 +154,7 @@ struct AppSettings: View {
}
struct AppSettings_Previews: PreviewProvider {
static let meshData = MeshData()
static var previews: some View {
Group {
AppSettings()