mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Janky waypoint edit
This commit is contained in:
parent
ac6cca636f
commit
b00f8c2daa
8 changed files with 95 additions and 35 deletions
|
|
@ -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 = "<group>"; };
|
||||
DD964FC1297272AE007C176F /* WaypointEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaypointEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DD964FC32974767D007C176F /* MapViewFitExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewFitExtension.swift; sourceTree = "<group>"; };
|
||||
DD964FC52975DBFD007C176F /* QueryCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryCoreData.swift; sourceTree = "<group>"; };
|
||||
DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticLogo.swift; sourceTree = "<group>"; };
|
||||
DD97E96728EFE9A00056DDA4 /* About.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = About.swift; sourceTree = "<group>"; };
|
||||
DD994B68295F88B60013760A /* IntervalEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntervalEnums.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -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 */,
|
||||
|
|
|
|||
|
|
@ -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)..<UInt32.max)
|
||||
var meshPacket = MeshPacket()
|
||||
meshPacket.to = emptyNodeNum
|
||||
meshPacket.from = fromNodeNum
|
||||
|
|
@ -752,13 +751,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
|
||||
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
|
||||
success = true
|
||||
let wayPointEntity = WaypointEntity(context: context!)
|
||||
wayPointEntity.id = Int64(waypointPacket.id)
|
||||
wayPointEntity.name = waypointPacket.name.count >= 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)")
|
||||
|
|
|
|||
24
Meshtastic/Persistence/QueryCoreData.swift
Normal file
24
Meshtastic/Persistence/QueryCoreData.swift
Normal file
|
|
@ -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<NSFetchRequestResult> = 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()
|
||||
}
|
||||
|
|
@ -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)!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)..<UInt32.max)
|
||||
} else {
|
||||
newWaypoint.id = UInt32(id)
|
||||
}
|
||||
newWaypoint.name = name.count < 1 ? "Dropped Pin" : name
|
||||
newWaypoint.description_p = description
|
||||
newWaypoint.latitudeI = Int32(coordinate.latitude * 1e7)
|
||||
|
|
@ -161,5 +169,20 @@ struct WaypointFormView: View {
|
|||
.controlSize(.large)
|
||||
.padding()
|
||||
}
|
||||
.onAppear {
|
||||
if id > 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ struct AppSettings: View {
|
|||
.onAppear {
|
||||
self.bleManager.context = context
|
||||
}
|
||||
.onChange(of: userSettings.provideLocation) { newProvideLocation in
|
||||
self.bleManager.sendWantConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue