From b00f8c2daa82fdccf95a21668278d2eb74496e94 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 16 Jan 2023 17:40:28 -0800 Subject: [PATCH] Janky waypoint edit --- Meshtastic.xcodeproj/project.pbxproj | 4 +++ Meshtastic/Helpers/BLEManager.swift | 15 +++++------ Meshtastic/Persistence/QueryCoreData.swift | 24 +++++++++++++++++ .../Views/Map/Custom/MapViewSwiftUI.swift | 21 ++++++++++++--- Meshtastic/Views/Map/WaypointFormView.swift | 27 +++++++++++++++++-- Meshtastic/Views/Nodes/NodeDetail.swift | 21 ++++++--------- Meshtastic/Views/Nodes/NodeMap.swift | 15 +++++------ Meshtastic/Views/Settings/AppSettings.swift | 3 +++ 8 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 Meshtastic/Persistence/QueryCoreData.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 7e342fb5..a18269eb 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ DD964FBF296E76EF007C176F /* WaypointFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FBE296E76EF007C176F /* WaypointFormView.swift */; }; DD964FC2297272AE007C176F /* WaypointEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */; }; DD964FC42974767D007C176F /* MapViewFitExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC32974767D007C176F /* MapViewFitExtension.swift */; }; + DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD964FC52975DBFD007C176F /* QueryCoreData.swift */; }; DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */; }; DD97E96828EFE9A00056DDA4 /* About.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97E96728EFE9A00056DDA4 /* About.swift */; }; DD994B69295F88B60013760A /* IntervalEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD994B68295F88B60013760A /* IntervalEnums.swift */; }; @@ -197,6 +198,7 @@ DD964FC029724F6D007C176F /* MeshtasticDataModelV6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV6.xcdatamodel; sourceTree = ""; }; DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointEntityExtension.swift; sourceTree = ""; }; DD964FC32974767D007C176F /* MapViewFitExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewFitExtension.swift; sourceTree = ""; }; + DD964FC52975DBFD007C176F /* QueryCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryCoreData.swift; sourceTree = ""; }; DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticLogo.swift; sourceTree = ""; }; DD97E96728EFE9A00056DDA4 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = ""; }; DD994B68295F88B60013760A /* IntervalEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntervalEnums.swift; sourceTree = ""; }; @@ -570,6 +572,7 @@ DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */, DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */, DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */, + DD964FC52975DBFD007C176F /* QueryCoreData.swift */, DD3CC6C128EB9D4900FA9159 /* UpdateCoreData.swift */, DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */, ); @@ -804,6 +807,7 @@ DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */, DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */, DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */, + DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */, DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */, DD8ED9C52898D51F00B3B0AB /* NetworkConfig.swift in Sources */, DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */, diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index c4d0e3d9..65fe7a12 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -732,7 +732,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { var success = false let fromNodeNum = UInt32(connectedPeripheral.num) var waypointPacket = waypoint - waypointPacket.id = UInt32.random(in: UInt32(UInt8.max)..= 1 ? waypointPacket.name : "Dropped Pin" - wayPointEntity.longDescription = waypointPacket.description_p - wayPointEntity.icon = Int64(waypointPacket.icon) - wayPointEntity.latitudeI = waypointPacket.latitudeI - wayPointEntity.longitudeI = waypointPacket.longitudeI + + let wayPointEntity = getWaypoint(id: Int64(waypoint.id), context: context!) + wayPointEntity.name = waypoint.name.count >= 1 ? waypointPacket.name : "Dropped Pin" + wayPointEntity.longDescription = waypoint.description_p + wayPointEntity.icon = Int64(waypoint.icon) + wayPointEntity.latitudeI = waypoint.latitudeI + wayPointEntity.longitudeI = waypoint.longitudeI do { try context!.save() print("💾 Updated Waypoint from Waypoint App Packet From: \(fromNodeNum)") diff --git a/Meshtastic/Persistence/QueryCoreData.swift b/Meshtastic/Persistence/QueryCoreData.swift new file mode 100644 index 00000000..3ddfe46d --- /dev/null +++ b/Meshtastic/Persistence/QueryCoreData.swift @@ -0,0 +1,24 @@ +// +// QueryCoreData.swift +// Meshtastic +// +// Created(c) Garth Vander Houwen 1/16/23. +// + +import CoreData + +public func getWaypoint(id: Int64, context: NSManagedObjectContext) -> WaypointEntity { + + let fetchWaypointRequest: NSFetchRequest = NSFetchRequest.init(entityName: "WaypointEntity") + fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(id)) + + do { + let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as! [WaypointEntity] + if fetchedWaypoint.count == 1 { + return fetchedWaypoint[0] + } + } catch { + return WaypointEntity() + } + return WaypointEntity() +} diff --git a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift index 9438e038..5b9d54ab 100644 --- a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift @@ -3,14 +3,13 @@ // Meshtastic // // Copyright(c) Josh Pirihi & Garth Vander Houwen 1/16/22. -// import SwiftUI import MapKit struct MapViewSwiftUI: UIViewRepresentable { - var onMarkerTap: (_ waypointCoordinate: CLLocationCoordinate2D? ) -> Void + var onMarkerTap: (_ waypointCoordinate: CLLocationCoordinate2D?, _ tag: Int? ) -> Void let mapView = MKMapView() let positions: [PositionEntity] let waypoints: [WaypointEntity] @@ -111,9 +110,11 @@ struct MapViewSwiftUI: UIViewRepresentable { case _ as MKClusterAnnotation: let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "nodeGroup") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "nodeGroup") annotationView.markerTintColor = .brown//.systemRed + annotationView.tag = -1 return annotationView case _ as PositionEntity: let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "node") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "Node") + annotationView.tag = -1 annotationView.canShowCallout = true annotationView.glyphText = "📟" annotationView.clusteringIdentifier = "nodeGroup" @@ -122,6 +123,7 @@ struct MapViewSwiftUI: UIViewRepresentable { return annotationView case let waypointAnnotation as WaypointEntity: let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "waypoint") as? MKMarkerAnnotationView ?? MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: "Waypoint") + annotationView.tag = Int(waypointAnnotation.id) annotationView.canShowCallout = true if waypointAnnotation.icon == 0 { annotationView.glyphText = "📍" @@ -136,12 +138,24 @@ struct MapViewSwiftUI: UIViewRepresentable { } } + func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) + { + // Only Allow Edit for annotations with a tag + if view.tag > 0 { + // Screen Position - CGPoint + let location = longPressRecognizer.location(in: self.parent.mapView) + // Map Coordinate - CLLocationCoordinate2D + let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView) + parent.onMarkerTap(coordinate, view.tag) + } + } + @objc func longPressHandler(_ gesture: UILongPressGestureRecognizer) { // Screen Position - CGPoint let location = longPressRecognizer.location(in: self.parent.mapView) // Map Coordinate - CLLocationCoordinate2D let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView) - parent.onMarkerTap(coordinate) + parent.onMarkerTap(coordinate, 0) // Add annotation: let annotation = MKPointAnnotation() annotation.title = "Dropped Pin" @@ -291,7 +305,6 @@ struct MapViewSwiftUI: UIViewRepresentable { let urlstring = self.mapName+"\(path.z)/\(path.x)/\(path.y).png" return URL(string: urlstring)! } - } } diff --git a/Meshtastic/Views/Map/WaypointFormView.swift b/Meshtastic/Views/Map/WaypointFormView.swift index d0aecc58..cea01009 100644 --- a/Meshtastic/Views/Map/WaypointFormView.swift +++ b/Meshtastic/Views/Map/WaypointFormView.swift @@ -13,9 +13,10 @@ struct WaypointFormView: View { @EnvironmentObject var bleManager: BLEManager @Environment(\.dismiss) private var dismiss @State var coordinate: CLLocationCoordinate2D + @State var id: Int = 0 @FocusState private var iconIsFocused: Bool - @State private var id: Int32? + @State private var name: String = "" @State private var description: String = "" @State private var icon: String = "📍" @@ -26,7 +27,7 @@ struct WaypointFormView: View { var body: some View { Form { let distance = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude).distance(from: CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)) - Section(header: Text("Waypoint")) { + Section(header: Text((id > 0) ? "Editing Waypoint" : "Create Waypoint")) { HStack { Text("Location: \(String(format: "%.5f", coordinate.latitude ) + "," + String(format: "%.5f", coordinate.longitude ))") .textSelection(.enabled) @@ -121,7 +122,14 @@ struct WaypointFormView: View { } HStack { Button { + var newWaypoint = Waypoint() + + if id == 0 { + newWaypoint.id = UInt32.random(in: UInt32(UInt8.max).. 0 { + let waypoint = getWaypoint(id: Int64(id), context: bleManager.context!) + id = Int(waypoint.id) + name = waypoint.name ?? "Dropped Pin" + description = waypoint.longDescription ?? "" + icon = String(UnicodeScalar(Int(waypoint.icon)) ?? "📍") + if waypoint.expire != nil { + expires = true + expire = waypoint.expire ?? Date() + } else { + expires = false + } + } + } } } diff --git a/Meshtastic/Views/Nodes/NodeDetail.swift b/Meshtastic/Views/Nodes/NodeDetail.swift index 8dcc538d..e8a83316 100644 --- a/Meshtastic/Views/Nodes/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/NodeDetail.swift @@ -14,6 +14,7 @@ struct NodeDetail: View { @State var satsInView = 0 @State private var mapType: MKMapType = .standard @State var waypointCoordinate: CLLocationCoordinate2D? + @State var editingWaypoint: Int = 0 @State private var showingDetailsPopover = false @State private var showingShutdownConfirm: Bool = false @State private var showingRebootConfirm: Bool = false @@ -47,11 +48,10 @@ struct NodeDetail: View { ZStack { let annotations = node.positions?.array as! [PositionEntity] ZStack { - MapViewSwiftUI(onMarkerTap: { coord in + MapViewSwiftUI(onMarkerTap: { coord, id in waypointCoordinate = coord - if waypointCoordinate == nil { - presentingWaypointForm = false - } else { + editingWaypoint = id ?? 0 + if waypointCoordinate != nil { presentingWaypointForm = true } }, positions: annotations, waypoints: Array(waypoints), mapViewType: mapType, @@ -66,12 +66,9 @@ struct NodeDetail: View { .font(.caption) .offset(y: 20) Picker("Map Type", selection: $mapType) { - Text("Standard").tag(MKMapType.standard) - Text("Muted").tag(MKMapType.mutedStandard) - Text("Hybrid").tag(MKMapType.hybrid) - Text("Hybrid Flyover").tag(MKMapType.hybridFlyover) - Text("Satellite").tag(MKMapType.satellite) - Text("Sat Flyover").tag(MKMapType.satelliteFlyover) + ForEach(MeshMapType.allCases) { map in + Text(map.description).tag(map.MKMapTypeValue()) + } } .pickerStyle(.menu) } @@ -388,11 +385,9 @@ struct NodeDetail: View { } .edgesIgnoringSafeArea([.leading, .trailing]) .sheet(isPresented: $presentingWaypointForm ) {//, onDismiss: didDismissSheet) { - if waypointCoordinate != nil { - WaypointFormView(coordinate: waypointCoordinate!) + WaypointFormView(coordinate: waypointCoordinate ?? LocationHelper.DefaultLocation, id: editingWaypoint) .presentationDetents([.medium, .large]) .presentationDragIndicator(.automatic) - } } .navigationBarTitle(String(node.user?.longName ?? NSLocalizedString("unknown", comment: "")), displayMode: .inline) .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Nodes/NodeMap.swift b/Meshtastic/Views/Nodes/NodeMap.swift index 8ca536f8..1642c62f 100644 --- a/Meshtastic/Views/Nodes/NodeMap.swift +++ b/Meshtastic/Views/Nodes/NodeMap.swift @@ -41,6 +41,7 @@ struct NodeMap: View { @State private var mapType: MKMapType = .standard @State var waypointCoordinate: CLLocationCoordinate2D? + @State var editingWaypoint: Int = 0 @State private var presentingWaypointForm = false @State private var customMapOverlay: MapViewSwiftUI.CustomMapOverlay? = MapViewSwiftUI.CustomMapOverlay( mapName: "offlinemap", @@ -54,7 +55,8 @@ struct NodeMap: View { NavigationStack { ZStack { - MapViewSwiftUI(onMarkerTap: { coord in + MapViewSwiftUI(onMarkerTap: { coord, id in + editingWaypoint = id ?? 0 waypointCoordinate = coord if waypointCoordinate == nil { presentingWaypointForm = false @@ -69,12 +71,9 @@ struct NodeMap: View { VStack { Spacer() Picker("Map Type", selection: $mapType) { - Text("Standard").tag(MKMapType.standard) - Text("Standard Muted").tag(MKMapType.mutedStandard) - Text("Hybrid").tag(MKMapType.hybrid) - Text("Hybrid Flyover").tag(MKMapType.hybridFlyover) - Text("Satellite").tag(MKMapType.satellite) - Text("Satellite Flyover").tag(MKMapType.satelliteFlyover) + ForEach(MeshMapType.allCases) { map in + Text(map.description).tag(map.MKMapTypeValue()) + } } .pickerStyle(.menu) } @@ -83,7 +82,7 @@ struct NodeMap: View { .frame(maxHeight: .infinity) .sheet(isPresented: $presentingWaypointForm ) {//, onDismiss: didDismissSheet) { if waypointCoordinate != nil { - WaypointFormView(coordinate: waypointCoordinate!) + WaypointFormView(coordinate: waypointCoordinate!, id: editingWaypoint) .presentationDetents([.medium, .large]) .presentationDragIndicator(.automatic) } diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index a9d9ada1..9e2a2af7 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -102,6 +102,9 @@ struct AppSettings: View { .onAppear { self.bleManager.context = context } + .onChange(of: userSettings.provideLocation) { newProvideLocation in + self.bleManager.sendWantConfig() + } } }