mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Solid lines for routes
This commit is contained in:
parent
acc6eb017d
commit
e0073ebdc8
7 changed files with 335 additions and 332 deletions
|
|
@ -18,6 +18,7 @@ import CoreLocation
|
|||
var enableSmartPosition: Bool
|
||||
|
||||
@Published var locationsArray: [CLLocation]
|
||||
@Published var lastLocation: CLLocation
|
||||
@Published var isStationary = false
|
||||
@Published var count = 0
|
||||
@Published var isRecording = false
|
||||
|
|
@ -42,6 +43,7 @@ import CoreLocation
|
|||
private init() {
|
||||
self.manager = CLLocationManager() // Creating a location manager instance is safe to call here in `MainActor`.
|
||||
locationsArray = [CLLocation]()
|
||||
lastLocation = CLLocation()
|
||||
enableSmartPosition = true
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +66,11 @@ import CoreLocation
|
|||
locationAdded = addLocation(loc)
|
||||
//print("Added Location \(self.count): \(loc)")
|
||||
} else {
|
||||
locationsArray.append(loc)
|
||||
if !isRecording {
|
||||
lastLocation = loc
|
||||
} else {
|
||||
locationsArray.append(loc)
|
||||
}
|
||||
locationAdded = true
|
||||
}
|
||||
if locationAdded {
|
||||
|
|
@ -99,16 +105,14 @@ import CoreLocation
|
|||
return false
|
||||
}
|
||||
if isRecording {
|
||||
if let lastLocation = locationsArray.last {
|
||||
let distance = location.distance(from: lastLocation)
|
||||
let gain = location.altitude - lastLocation.altitude
|
||||
distanceTraveled += distance
|
||||
if gain > 0 {
|
||||
elevationGain += gain
|
||||
}
|
||||
let distance = location.distance(from: lastLocation)
|
||||
let gain = location.altitude - lastLocation.altitude
|
||||
distanceTraveled += distance
|
||||
if gain > 0 {
|
||||
elevationGain += gain
|
||||
}
|
||||
locationsArray.append(location)
|
||||
}
|
||||
locationsArray.append(location)
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -116,26 +120,23 @@ import CoreLocation
|
|||
|
||||
static var satsInView: Int {
|
||||
var sats = 0
|
||||
if let newLocation = shared.locationsArray.last {
|
||||
sats = 1
|
||||
if newLocation.verticalAccuracy > 0 {
|
||||
sats = 4
|
||||
if 0...5 ~= newLocation.horizontalAccuracy {
|
||||
sats = 12
|
||||
} else if 6...15 ~= newLocation.horizontalAccuracy {
|
||||
sats = 10
|
||||
} else if 16...30 ~= newLocation.horizontalAccuracy {
|
||||
sats = 9
|
||||
} else if 31...45 ~= newLocation.horizontalAccuracy {
|
||||
sats = 7
|
||||
} else if 46...60 ~= newLocation.horizontalAccuracy {
|
||||
sats = 5
|
||||
}
|
||||
} else if newLocation.verticalAccuracy < 0 && 60...300 ~= newLocation.horizontalAccuracy {
|
||||
sats = 3
|
||||
} else if newLocation.verticalAccuracy < 0 && newLocation.horizontalAccuracy > 300 {
|
||||
sats = 2
|
||||
if shared.lastLocation.verticalAccuracy > 0 {
|
||||
sats = 4
|
||||
if 0...5 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 12
|
||||
} else if 6...15 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 10
|
||||
} else if 16...30 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 9
|
||||
} else if 31...45 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 7
|
||||
} else if 46...60 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 5
|
||||
}
|
||||
} else if shared.lastLocation.verticalAccuracy < 0 && 60...300 ~= shared.lastLocation.horizontalAccuracy {
|
||||
sats = 3
|
||||
} else if shared.lastLocation.verticalAccuracy < 0 && shared.lastLocation.horizontalAccuracy > 300 {
|
||||
sats = 2
|
||||
}
|
||||
return sats
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,12 +150,12 @@ struct MeshMap: View {
|
|||
}
|
||||
}
|
||||
.annotationTitles(.automatic)
|
||||
let dashed = StrokeStyle(
|
||||
let solid = StrokeStyle(
|
||||
lineWidth: 3,
|
||||
lineCap: .round, lineJoin: .round, dash: [7, 10]
|
||||
lineCap: .round, lineJoin: .round
|
||||
)
|
||||
MapPolyline(coordinates: routeCoords)
|
||||
.stroke(Color(UIColor(hex: UInt32(route.color))), style: dashed)
|
||||
.stroke(Color(UIColor(hex: UInt32(route.color))), style: solid)
|
||||
|
||||
}
|
||||
/// Node Route Lines
|
||||
|
|
@ -275,7 +275,8 @@ struct MeshMap: View {
|
|||
print("Waypoint not found")
|
||||
return
|
||||
}
|
||||
position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 150, heading: 0, pitch: 60))
|
||||
showWaypoints = true
|
||||
position = .camera(MapCamera(centerCoordinate: waypoint.coordinate, distance: 300, heading: 0, pitch: 60))
|
||||
}
|
||||
}
|
||||
.onChange(of: (selectedMapLayer)) { newMapLayer in
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ struct MQTTConfig: View {
|
|||
@State var tlsEnabled = true
|
||||
@State var root = "msh"
|
||||
@State var mqttConnected: Bool = false
|
||||
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
|
@ -250,7 +252,7 @@ struct MQTTConfig: View {
|
|||
.navigationTitle("mqtt.config")
|
||||
.navigationBarItems(trailing:
|
||||
ZStack {
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", mqttProxyConnected: bleManager.mqttProxyConnected)
|
||||
})
|
||||
.onAppear {
|
||||
if self.bleManager.context == nil {
|
||||
|
|
|
|||
|
|
@ -112,8 +112,7 @@ struct Firmware: View {
|
|||
|
||||
if bleManager.sendEnterDfuMode(fromUser: connectedNode!.user!, toUser: node!.user!) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
bleManager.automaticallyReconnect = false
|
||||
bleManager.disconnectPeripheral()
|
||||
bleManager.disconnectPeripheral(reconnect: false)
|
||||
}
|
||||
} else {
|
||||
print("Enter DFU Failed")
|
||||
|
|
|
|||
|
|
@ -1,289 +1,289 @@
|
|||
////
|
||||
//// Routes.swift
|
||||
//// Meshtastic
|
||||
////
|
||||
//// Created by Garth Vander Houwen on 11/21/23.
|
||||
////
|
||||
//
|
||||
// Routes.swift
|
||||
// Meshtastic
|
||||
//import SwiftUI
|
||||
//import CoreData
|
||||
//import MapKit
|
||||
//import CoreLocation
|
||||
//import CoreMotion
|
||||
//
|
||||
// Created by Garth Vander Houwen on 11/21/23.
|
||||
//@available(iOS 17.0, macOS 14.0, *)
|
||||
//struct RouteRecorder: View {
|
||||
//
|
||||
// @ObservedObject var locationsHandler: LocationsHandler = LocationsHandler.shared
|
||||
// @Environment(\.managedObjectContext) var context
|
||||
// @State private var position: MapCameraPosition = .userLocation(followsHeading: true, fallback: .automatic)
|
||||
// //@State var mapStyle: MapStyle = MapStyle.hybrid(elevation: .realistic, pointsOfInterest: .all, showsTraffic: true)
|
||||
// @State var mapStyle: MapStyle = MapStyle.standard(elevation: .realistic)
|
||||
// @State var isShowingDetails = false
|
||||
// @Namespace var namespace
|
||||
// @Namespace var routerecorderscope
|
||||
// @State var recording: RouteEntity?
|
||||
// @State var color: Color = .blue
|
||||
//
|
||||
// var body: some View {
|
||||
// VStack {
|
||||
// ZStack {
|
||||
// Map(position: $position, scope: routerecorderscope) {
|
||||
// UserAnnotation()
|
||||
// /// Route Lines
|
||||
// let lineCoords = locationsHandler.locationsArray.compactMap({(position) -> CLLocationCoordinate2D in
|
||||
// return position.coordinate
|
||||
// })
|
||||
//
|
||||
// let gradient = LinearGradient(
|
||||
// colors: [color],
|
||||
// startPoint: .leading, endPoint: .trailing
|
||||
// )
|
||||
// let dashed = StrokeStyle(
|
||||
// lineWidth: 3,
|
||||
// lineCap: .round, lineJoin: .round, dash: [10, 10]
|
||||
// )
|
||||
// MapPolyline(coordinates: lineCoords)
|
||||
// .stroke(gradient, style: dashed)
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import MapKit
|
||||
import CoreLocation
|
||||
import CoreMotion
|
||||
|
||||
@available(iOS 17.0, macOS 14.0, *)
|
||||
struct RouteRecorder: View {
|
||||
|
||||
@ObservedObject var locationsHandler: LocationsHandler = LocationsHandler.shared
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@State private var position: MapCameraPosition = .userLocation(followsHeading: true, fallback: .automatic)
|
||||
//@State var mapStyle: MapStyle = MapStyle.hybrid(elevation: .realistic, pointsOfInterest: .all, showsTraffic: true)
|
||||
@State var mapStyle: MapStyle = MapStyle.standard(elevation: .realistic)
|
||||
@State var isShowingDetails = false
|
||||
@Namespace var namespace
|
||||
@Namespace var routerecorderscope
|
||||
@State var recording: RouteEntity?
|
||||
@State var color: Color = .blue
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
ZStack {
|
||||
Map(position: $position, scope: routerecorderscope) {
|
||||
UserAnnotation()
|
||||
/// Route Lines
|
||||
let lineCoords = locationsHandler.locationsArray.compactMap({(position) -> CLLocationCoordinate2D in
|
||||
return position.coordinate
|
||||
})
|
||||
|
||||
let gradient = LinearGradient(
|
||||
colors: [color],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
let dashed = StrokeStyle(
|
||||
lineWidth: 3,
|
||||
lineCap: .round, lineJoin: .round, dash: [10, 10]
|
||||
)
|
||||
MapPolyline(coordinates: lineCoords)
|
||||
.stroke(gradient, style: dashed)
|
||||
|
||||
}
|
||||
.mapStyle(mapStyle)
|
||||
}
|
||||
.mapScope(routerecorderscope)
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
ZStack {
|
||||
VStack {
|
||||
HStack(spacing: 10) {
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
isShowingDetails = true
|
||||
} label: {
|
||||
Image(systemName: locationsHandler.isRecording ? "record.circle.fill" : "record.circle")
|
||||
.font(.system(size: 72))
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.foregroundColor(.red)
|
||||
.buttonBorderShape(.circle)
|
||||
.matchedGeometryEffect(id: "Details Button", in: namespace)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.sheet(isPresented: $isShowingDetails) {
|
||||
NavigationStack {
|
||||
VStack {
|
||||
if locationsHandler.isRecording {
|
||||
HStack (alignment: .center) {
|
||||
Image(systemName: "record.circle.fill")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.font(.title)
|
||||
.foregroundColor(.red)
|
||||
Text("Recording route")
|
||||
.font(.title)
|
||||
Spacer()
|
||||
Text("\(locationsHandler.count)")
|
||||
.foregroundColor(.red)
|
||||
.font(.title2)
|
||||
}
|
||||
.padding()
|
||||
} else if locationsHandler.isRecordingPaused {
|
||||
HStack (alignment: .center) {
|
||||
|
||||
Image(systemName: "playpause")
|
||||
.symbolRenderingMode(.multicolor)
|
||||
.font(.title3)
|
||||
.foregroundColor(.red)
|
||||
Text("Route recording paused")
|
||||
.font(.title)
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
|
||||
if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
Divider()
|
||||
HStack {
|
||||
VStack {
|
||||
Text(locationsHandler.recordingStarted ?? Date(), style: .timer)
|
||||
.font(.title)
|
||||
.fixedSize()
|
||||
Text("Time")
|
||||
.font(.callout)
|
||||
.fixedSize()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
Divider()
|
||||
VStack {
|
||||
let distance = Measurement(value: locationsHandler.distanceTraveled, unit: UnitLength.meters)
|
||||
Text("\(distance.formatted())")
|
||||
.font(.title)
|
||||
.fixedSize()
|
||||
Text("Distance")
|
||||
.font(.callout)
|
||||
.fixedSize()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
Divider()
|
||||
VStack {
|
||||
let gain = Measurement(value: locationsHandler.elevationGain, unit: UnitLength.meters)
|
||||
Text(gain.formatted())
|
||||
.font(.title)
|
||||
Text("Elev. Gain")
|
||||
.font(.callout)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.frame(maxHeight: 90)
|
||||
}
|
||||
Divider()
|
||||
VStack(alignment: .leading) {
|
||||
List {
|
||||
GPSStatus(largeFont: .body, smallFont: .callout)
|
||||
}
|
||||
.listStyle(.plain)
|
||||
HStack {
|
||||
Spacer()
|
||||
if !locationsHandler.isRecording && !locationsHandler.isRecordingPaused {
|
||||
/// We are not recording or paused, show start recording button
|
||||
Button {
|
||||
locationsHandler.isRecording = true
|
||||
locationsHandler.count = 0
|
||||
locationsHandler.distanceTraveled = 0.0
|
||||
locationsHandler.elevationGain = 0.0
|
||||
locationsHandler.locationsArray.removeAll()
|
||||
locationsHandler.recordingStarted = Date()
|
||||
let newRoute = RouteEntity(context: context)
|
||||
newRoute.name = String("Route Recording")
|
||||
newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
|
||||
newRoute.color = Int64(UIColor.random.hex)
|
||||
newRoute.date = Date()
|
||||
newRoute.enabled = false
|
||||
color = Color(UIColor(hex: UInt32(newRoute.color)))
|
||||
self.recording = newRoute
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Saved a new route")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving RouteEntity from the Route Recorder \(nsError)")
|
||||
}
|
||||
} label: {
|
||||
Label("start", systemImage: "play")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
|
||||
} else if locationsHandler.isRecording {
|
||||
/// We are recording show pause button
|
||||
Button {
|
||||
locationsHandler.isRecording = false
|
||||
locationsHandler.isRecordingPaused = true
|
||||
} label: {
|
||||
Label("pause", systemImage: "pause")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
} else if locationsHandler.isRecordingPaused {
|
||||
/// We are paused show resume button
|
||||
Button {
|
||||
locationsHandler.isRecording = true
|
||||
locationsHandler.isRecordingPaused = false
|
||||
} label: {
|
||||
Label("resume", systemImage: "playpause")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
}
|
||||
|
||||
if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
/// We are recording or paused, show finish button
|
||||
Button {
|
||||
locationsHandler.isRecording = false
|
||||
locationsHandler.isRecordingPaused = false
|
||||
locationsHandler.distanceTraveled = 0.0
|
||||
locationsHandler.elevationGain = 0.0
|
||||
locationsHandler.locationsArray.removeAll()
|
||||
locationsHandler.recordingStarted = nil
|
||||
if let rec = recording {
|
||||
rec.enabled = true
|
||||
context.refresh(rec, mergeChanges:true)
|
||||
}
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Saved a route finish")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving RouteEntity from the Route Recorder \(nsError)")
|
||||
}
|
||||
} label: {
|
||||
Label("finish", systemImage: "flag.checkered")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
}
|
||||
#if targetEnvironment(macCatalyst)
|
||||
Button(role: .cancel) {
|
||||
isShowingDetails = false
|
||||
} label: {
|
||||
Label("close", systemImage: "xmark")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding(.bottom)
|
||||
#endif
|
||||
Spacer()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.fraction(0.30), .fraction(0.65)])
|
||||
.presentationDragIndicator(.hidden)
|
||||
.interactiveDismissDisabled(false)
|
||||
.onChange(of: locationsHandler.locationsArray.last) { newLoc in
|
||||
if locationsHandler.isRecording {
|
||||
if let loc = newLoc {
|
||||
if recording != nil {
|
||||
let locationEntity = LocationEntity(context: context)
|
||||
locationEntity.routeLocation = recording
|
||||
locationEntity.id = Int32(locationsHandler.count)
|
||||
locationEntity.altitude = Int32(loc.altitude)
|
||||
locationEntity.heading = Int32(loc.course)
|
||||
locationEntity.speed = Int32(loc.speed)
|
||||
locationEntity.latitudeI = Int32(loc.coordinate.latitude * 1e7)
|
||||
locationEntity.longitudeI = Int32(loc.coordinate.longitude * 1e7)
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Saved a new route location")
|
||||
//print("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
print("💥 Error Saving LocationEntity from the Route Recorder \(nsError)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ignoresSafeArea(.all, edges: [.top, .leading, .trailing])
|
||||
}
|
||||
}
|
||||
// }
|
||||
// .mapStyle(mapStyle)
|
||||
// }
|
||||
// .mapScope(routerecorderscope)
|
||||
// .safeAreaInset(edge: .bottom) {
|
||||
// ZStack {
|
||||
// VStack {
|
||||
// HStack(spacing: 10) {
|
||||
// Spacer()
|
||||
//
|
||||
// Button {
|
||||
// isShowingDetails = true
|
||||
// } label: {
|
||||
// Image(systemName: locationsHandler.isRecording ? "record.circle.fill" : "record.circle")
|
||||
// .font(.system(size: 72))
|
||||
// .symbolRenderingMode(.multicolor)
|
||||
// .foregroundColor(.red)
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .foregroundColor(.red)
|
||||
// .buttonBorderShape(.circle)
|
||||
// .matchedGeometryEffect(id: "Details Button", in: namespace)
|
||||
//
|
||||
// Spacer()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding()
|
||||
// }
|
||||
// .sheet(isPresented: $isShowingDetails) {
|
||||
// NavigationStack {
|
||||
// VStack {
|
||||
// if locationsHandler.isRecording {
|
||||
// HStack (alignment: .center) {
|
||||
// Image(systemName: "record.circle.fill")
|
||||
// .symbolRenderingMode(.multicolor)
|
||||
// .font(.title)
|
||||
// .foregroundColor(.red)
|
||||
// Text("Recording route")
|
||||
// .font(.title)
|
||||
// Spacer()
|
||||
// Text("\(locationsHandler.count)")
|
||||
// .foregroundColor(.red)
|
||||
// .font(.title2)
|
||||
// }
|
||||
// .padding()
|
||||
// } else if locationsHandler.isRecordingPaused {
|
||||
// HStack (alignment: .center) {
|
||||
//
|
||||
// Image(systemName: "playpause")
|
||||
// .symbolRenderingMode(.multicolor)
|
||||
// .font(.title3)
|
||||
// .foregroundColor(.red)
|
||||
// Text("Route recording paused")
|
||||
// .font(.title)
|
||||
// }
|
||||
// .padding(.top)
|
||||
// }
|
||||
//
|
||||
// if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
// Divider()
|
||||
// HStack {
|
||||
// VStack {
|
||||
// Text(locationsHandler.recordingStarted ?? Date(), style: .timer)
|
||||
// .font(.title)
|
||||
// .fixedSize()
|
||||
// Text("Time")
|
||||
// .font(.callout)
|
||||
// .fixedSize()
|
||||
// }
|
||||
// .padding(.horizontal)
|
||||
// Divider()
|
||||
// VStack {
|
||||
// let distance = Measurement(value: locationsHandler.distanceTraveled, unit: UnitLength.meters)
|
||||
// Text("\(distance.formatted())")
|
||||
// .font(.title)
|
||||
// .fixedSize()
|
||||
// Text("Distance")
|
||||
// .font(.callout)
|
||||
// .fixedSize()
|
||||
// }
|
||||
// .padding(.horizontal)
|
||||
// Divider()
|
||||
// VStack {
|
||||
// let gain = Measurement(value: locationsHandler.elevationGain, unit: UnitLength.meters)
|
||||
// Text(gain.formatted())
|
||||
// .font(.title)
|
||||
// Text("Elev. Gain")
|
||||
// .font(.callout)
|
||||
// }
|
||||
// .padding(.horizontal)
|
||||
// }
|
||||
// .frame(maxHeight: 90)
|
||||
// }
|
||||
// Divider()
|
||||
// VStack(alignment: .leading) {
|
||||
// List {
|
||||
// GPSStatus(largeFont: .body, smallFont: .callout)
|
||||
// }
|
||||
// .listStyle(.plain)
|
||||
// HStack {
|
||||
// Spacer()
|
||||
// if !locationsHandler.isRecording && !locationsHandler.isRecordingPaused {
|
||||
// /// We are not recording or paused, show start recording button
|
||||
// Button {
|
||||
// locationsHandler.isRecording = true
|
||||
// locationsHandler.count = 0
|
||||
// locationsHandler.distanceTraveled = 0.0
|
||||
// locationsHandler.elevationGain = 0.0
|
||||
// locationsHandler.locationsArray.removeAll()
|
||||
// locationsHandler.recordingStarted = Date()
|
||||
// let newRoute = RouteEntity(context: context)
|
||||
// newRoute.name = String("Route Recording")
|
||||
// newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
|
||||
// newRoute.color = Int64(UIColor.random.hex)
|
||||
// newRoute.date = Date()
|
||||
// newRoute.enabled = false
|
||||
// color = Color(UIColor(hex: UInt32(newRoute.color)))
|
||||
// self.recording = newRoute
|
||||
// do {
|
||||
// try context.save()
|
||||
// print("💾 Saved a new route")
|
||||
// } catch {
|
||||
// context.rollback()
|
||||
// let nsError = error as NSError
|
||||
// print("💥 Error Saving RouteEntity from the Route Recorder \(nsError)")
|
||||
// }
|
||||
// } label: {
|
||||
// Label("start", systemImage: "play")
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .buttonBorderShape(.capsule)
|
||||
// .controlSize(.large)
|
||||
// .padding(.bottom)
|
||||
//
|
||||
// } else if locationsHandler.isRecording {
|
||||
// /// We are recording show pause button
|
||||
// Button {
|
||||
// locationsHandler.isRecording = false
|
||||
// locationsHandler.isRecordingPaused = true
|
||||
// } label: {
|
||||
// Label("pause", systemImage: "pause")
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .buttonBorderShape(.capsule)
|
||||
// .controlSize(.large)
|
||||
// .padding(.bottom)
|
||||
// } else if locationsHandler.isRecordingPaused {
|
||||
// /// We are paused show resume button
|
||||
// Button {
|
||||
// locationsHandler.isRecording = true
|
||||
// locationsHandler.isRecordingPaused = false
|
||||
// } label: {
|
||||
// Label("resume", systemImage: "playpause")
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .buttonBorderShape(.capsule)
|
||||
// .controlSize(.large)
|
||||
// .padding(.bottom)
|
||||
// }
|
||||
//
|
||||
// if locationsHandler.isRecording || locationsHandler.isRecordingPaused {
|
||||
// /// We are recording or paused, show finish button
|
||||
// Button {
|
||||
// locationsHandler.isRecording = false
|
||||
// locationsHandler.isRecordingPaused = false
|
||||
// locationsHandler.distanceTraveled = 0.0
|
||||
// locationsHandler.elevationGain = 0.0
|
||||
// locationsHandler.locationsArray.removeAll()
|
||||
// locationsHandler.recordingStarted = nil
|
||||
// if let rec = recording {
|
||||
// rec.enabled = true
|
||||
// context.refresh(rec, mergeChanges:true)
|
||||
// }
|
||||
//
|
||||
// do {
|
||||
// try context.save()
|
||||
// print("💾 Saved a route finish")
|
||||
// } catch {
|
||||
// context.rollback()
|
||||
// let nsError = error as NSError
|
||||
// print("💥 Error Saving RouteEntity from the Route Recorder \(nsError)")
|
||||
// }
|
||||
// } label: {
|
||||
// Label("finish", systemImage: "flag.checkered")
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .buttonBorderShape(.capsule)
|
||||
// .controlSize(.large)
|
||||
// .padding(.bottom)
|
||||
// }
|
||||
//#if targetEnvironment(macCatalyst)
|
||||
// Button(role: .cancel) {
|
||||
// isShowingDetails = false
|
||||
// } label: {
|
||||
// Label("close", systemImage: "xmark")
|
||||
// }
|
||||
// .buttonStyle(.bordered)
|
||||
// .buttonBorderShape(.capsule)
|
||||
// .controlSize(.large)
|
||||
// .padding(.bottom)
|
||||
//#endif
|
||||
// Spacer()
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .presentationDetents([.fraction(0.30), .fraction(0.65)])
|
||||
// .presentationDragIndicator(.hidden)
|
||||
// .interactiveDismissDisabled(false)
|
||||
// .onChange(of: locationsHandler.locationsArray.last) { newLoc in
|
||||
// if locationsHandler.isRecording {
|
||||
// if let loc = newLoc {
|
||||
// if recording != nil {
|
||||
// let locationEntity = LocationEntity(context: context)
|
||||
// locationEntity.routeLocation = recording
|
||||
// locationEntity.id = Int32(locationsHandler.count)
|
||||
// locationEntity.altitude = Int32(loc.altitude)
|
||||
// locationEntity.heading = Int32(loc.course)
|
||||
// locationEntity.speed = Int32(loc.speed)
|
||||
// locationEntity.latitudeI = Int32(loc.coordinate.latitude * 1e7)
|
||||
// locationEntity.longitudeI = Int32(loc.coordinate.longitude * 1e7)
|
||||
// do {
|
||||
// try context.save()
|
||||
// print("💾 Saved a new route location")
|
||||
// //print("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
|
||||
// } catch {
|
||||
// context.rollback()
|
||||
// let nsError = error as NSError
|
||||
// print("💥 Error Saving LocationEntity from the Route Recorder \(nsError)")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .ignoresSafeArea(.all, edges: [.top, .leading, .trailing])
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -181,12 +181,12 @@ struct Routes: View {
|
|||
}
|
||||
}
|
||||
.annotationTitles(.automatic)
|
||||
let dashed = StrokeStyle(
|
||||
let solid = StrokeStyle(
|
||||
lineWidth: 3,
|
||||
lineCap: .round, lineJoin: .round, dash: [7, 10]
|
||||
lineCap: .round, lineJoin: .round
|
||||
)
|
||||
MapPolyline(coordinates: lineCoords)
|
||||
.stroke(Color(UIColor(hex: UInt32(selectedRoute?.color ?? 0))), style: dashed)
|
||||
.stroke(Color(UIColor(hex: UInt32(selectedRoute?.color ?? 0))), style: solid)
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.safeAreaInset(edge: .bottom, alignment: UIDevice.current.userInterfaceIdiom == .phone ? .leading : .trailing) {
|
||||
|
|
|
|||
|
|
@ -69,14 +69,14 @@ struct Settings: View {
|
|||
Text("routes")
|
||||
}
|
||||
.tag(SettingsSidebar.routes)
|
||||
NavigationLink {
|
||||
RouteRecorder()
|
||||
} label: {
|
||||
Image(systemName: "record.circle")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("route.recorder")
|
||||
}
|
||||
.tag(SettingsSidebar.routeRecorder)
|
||||
// NavigationLink {
|
||||
// RouteRecorder()
|
||||
// } label: {
|
||||
// Image(systemName: "record.circle")
|
||||
// .symbolRenderingMode(.hierarchical)
|
||||
// Text("route.recorder")
|
||||
// }
|
||||
// .tag(SettingsSidebar.routeRecorder)
|
||||
}
|
||||
|
||||
let node = nodes.first(where: { $0.num == preferredNodeNum })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue