diff --git a/Meshtastic/Helpers/LocationHelper.swift b/Meshtastic/Helpers/LocationHelper.swift index f218b516..1c8c22a1 100644 --- a/Meshtastic/Helpers/LocationHelper.swift +++ b/Meshtastic/Helpers/LocationHelper.swift @@ -16,8 +16,6 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate { locationManager.pausesLocationUpdatesAutomatically = true locationManager.allowsBackgroundLocationUpdates = true locationManager.activityType = .otherNavigation - //locationManager.requestWhenInUseAuthorization() - //locationManager.startUpdatingLocation() } // Apple Park @@ -89,10 +87,7 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate { } return sats } -//} -//extension LocationHelper: CLLocationManagerDelegate { - func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { switch manager.authorizationStatus { case .authorizedWhenInUse: @@ -114,11 +109,11 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate { } } - func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { - print("Location manager error: \(error.localizedDescription)") - } - func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + print("Location manager error: \(error.localizedDescription)") + } } diff --git a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift index ecf300a4..778302ed 100644 --- a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift @@ -120,10 +120,9 @@ struct MapViewSwiftUI: UIViewRepresentable { let latest = positions .filter { $0.latest == true } .sorted { $0.nodePosition?.num ?? 0 > $1.nodePosition?.num ?? -1 } + let annotationCount = waypoints.count + (showNodeHistory ? positions.count : latest.count) - - -// if annotationCount != mapView.annotations.count { + if annotationCount != mapView.annotations.count { print("Annotation Count: \(annotationCount) Map Annotations: \(mapView.annotations.count)") mapView.removeAnnotations(mapView.annotations) mapView.addAnnotations(waypoints) @@ -168,7 +167,7 @@ struct MapViewSwiftUI: UIViewRepresentable { mapView.showsUserLocation = true } mapView.setUserTrackingMode(userTrackingMode, animated: true) - // } + } } } diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 5eec57f4..68f6a4e9 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -114,6 +114,7 @@ struct DeviceMetricsLog: View { TableColumn("timestamp") { dm in Text(dm.time?.formattedDate(format: dateFormatString) ?? NSLocalizedString("unknown.age", comment: "")) } + .width(min: 180) } } else { ScrollView { diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index f3a5af1d..a5f1410d 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -103,6 +103,7 @@ struct EnvironmentMetricsLog: View { TableColumn("timestamp") { em in Text(em.time?.formattedDate(format: dateFormatString) ?? NSLocalizedString("unknown.age", comment: "")) } + .width(min: 180) } } else { ScrollView { diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index c275e0ad..fcf4fb2f 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -7,34 +7,42 @@ import SwiftUI struct PositionLog: View { - + @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager - + @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass? + @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass? + var useGrid: Bool { + let result = (verticalSizeClass == .regular || verticalSizeClass == .compact) && horizontalSizeClass == .compact + return result + } + @State var isExporting = false @State var exportString = "" - + var node: NodeInfoEntity - + @State private var isPresentingClearLogConfirm = false - + @State private var sortOrder = [KeyPathComparator(\PositionEntity.latitude)] + var body: some View { - + NavigationStack { let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current) let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "") - if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { + if UIDevice.current.userInterfaceIdiom == .pad && !useGrid || UIDevice.current.userInterfaceIdiom == .mac { // Add a table for mac and ipad - Table(node.positions?.reversed() as? [PositionEntity] ?? []) { - TableColumn("SeqNo") { position in - Text(String(position.seqNo)) - } + var positions = node.positions?.reversed() as? [PositionEntity] ?? [] + + Table(positions) { TableColumn("Latitude") { position in Text(String(format: "%.5f", position.latitude ?? 0)) } + .width(min: 120) TableColumn("Longitude") { position in Text(String(format: "%.5f", position.longitude ?? 0)) } + .width(min: 120) TableColumn("Altitude") { position in let altitude = Measurement(value: Double(position.altitude), unit: UnitLength.meters) Text(String(altitude.formatted())) @@ -55,10 +63,11 @@ struct PositionLog: View { TableColumn("Time Stamp") { position in Text(position.time?.formattedDate(format: dateFormatString) ?? NSLocalizedString("unknown.age", comment: "")) } + .width(min: 180) } - + } else { - + ScrollView { // Use a grid on iOS as a table only shows a single column let columns = [ @@ -69,9 +78,8 @@ struct PositionLog: View { GridItem(spacing: 0) ] LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { - + GridRow { - Text("Latitude") .font(.caption2) .fontWeight(.bold) @@ -107,9 +115,9 @@ struct PositionLog: View { } .padding(.leading) } - + HStack { - + Button(role: .destructive) { isPresentingClearLogConfirm = true } label: { @@ -127,41 +135,41 @@ struct PositionLog: View { Button("Delete all positions?", role: .destructive) { if clearPositions(destNum: node.num, context: context) { print("Successfully Cleared Position Log") - + } else { print("Clear Position Log Failed") } } } - + Button { - + exportString = positionToCsvFile(positions: node.positions!.array as? [PositionEntity] ?? []) isExporting = true - - } label: { - - Label("save", systemImage: "square.and.arrow.down") - } - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.large) - .padding() + + } label: { + + Label("save", systemImage: "square.and.arrow.down") } - .fileExporter( + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + } + .fileExporter( isPresented: $isExporting, document: CsvDocument(emptyCsv: exportString), contentType: .commaSeparatedText, defaultFilename: String("\(node.user?.longName ?? "Node") Position Log"), onCompletion: { result in - + if case .success = result { - + print("Position log download succeeded.") self.isExporting = false - + } else { - + print("Position log download failed: \(result).") } } @@ -169,13 +177,13 @@ struct PositionLog: View { } .navigationTitle("Position Log \(node.positions?.count ?? 0) Points") .navigationBarItems(trailing: - - ZStack { - + + ZStack { + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") }) .onAppear { - + self.bleManager.context = context } } diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index 38bbc23d..c568da57 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -39,6 +39,30 @@ struct AppSettings: View { } Section(header: Text("phone.gps")) { + let accuracy = Measurement(value: locationHelper.locationManager.location?.horizontalAccuracy ?? 300, unit: UnitLength.meters) + let altitiude = Measurement(value: locationHelper.locationManager.location?.altitude ?? 0, unit: UnitLength.meters) + let speed = Measurement(value: locationHelper.locationManager.location?.speed ?? 0, unit: UnitSpeed.kilometersPerHour) + HStack { + Label("Accuracy \(accuracy.formatted())", systemImage: "scope") + .font(.callout) + Label("Sats \(LocationHelper.satsInView)", systemImage: "sparkles") + .font(.callout) + } + Label("Coordinates \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.latitude ?? 0)), \(String(format: "%.5f", locationHelper.locationManager.location?.coordinate.longitude ?? 0))", systemImage: "mappin") + .font(.callout) + .textSelection(.enabled) + if locationHelper.locationManager.location?.verticalAccuracy ?? 0 > 0 { + Label("Altitude \(altitiude.formatted())", systemImage: "mountain.2") + .font(.callout) + } + if locationHelper.locationManager.location?.courseAccuracy ?? 0 > 0 { + Label("Heading \(String(format: "%.2f", locationHelper.locationManager.location?.course ?? 0))°", systemImage: "location.circle") + .font(.callout) + } + if locationHelper.locationManager.location?.speedAccuracy ?? 0 > 0 { + Label("Speed \(speed.formatted())", systemImage: "speedometer") + .font(.callout) + } Toggle(isOn: $userSettings.provideLocation) {