From 76d5da1d21f7d3c0140d7f685bbf3266295e5f96 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 15 Sep 2023 17:19:02 -0700 Subject: [PATCH] Put look around behind a button --- .../Views/Nodes/DetectionSensorLog.swift | 2 +- Meshtastic/Views/Nodes/DeviceMetricsLog.swift | 233 +++++++++--------- .../Views/Nodes/EnvironmentMetricsLog.swift | 2 +- .../Views/Nodes/Helpers/NodeMapSwiftUI.swift | 45 +++- Meshtastic/Views/Nodes/PositionLog.swift | 2 +- 5 files changed, 152 insertions(+), 132 deletions(-) diff --git a/Meshtastic/Views/Nodes/DetectionSensorLog.swift b/Meshtastic/Views/Nodes/DetectionSensorLog.swift index 6d2551cd..b6d13c99 100644 --- a/Meshtastic/Views/Nodes/DetectionSensorLog.swift +++ b/Meshtastic/Views/Nodes/DetectionSensorLog.swift @@ -23,7 +23,7 @@ struct DetectionSensorLog: View { .filter { $0.timestamp >= oneDayAgo! } .sorted { $0.timestamp < $1.timestamp } - NavigationStack { + VStack { if chartData.count > 0 { GroupBox(label: Label("\(detections.count) Total Detection Events", systemImage: "sensor")) { Chart { diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 232e1b8f..adf91aa8 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -28,143 +28,140 @@ struct DeviceMetricsLog: View { let chartData = deviceMetrics .filter { $0.time != nil && $0.time! >= oneWeekAgo! } .sorted { $0.time! < $1.time! } + + if chartData.count > 0 { + GroupBox(label: Label("\(deviceMetrics.count) Readings Total", systemImage: "chart.xyaxis.line")) { - NavigationStack { + Chart { - if chartData.count > 0 { - GroupBox(label: Label("\(deviceMetrics.count) Readings Total", systemImage: "chart.xyaxis.line")) { + ForEach(chartData, id: \.self) { point in - Chart { + Plot { + LineMark( + x: .value("x", point.time!), + y: .value("y", point.batteryLevel) + ) + } + .accessibilityLabel("Line Series") + .accessibilityValue("X: \(point.time!), Y: \(point.batteryLevel)") + .foregroundStyle(batteryChartColor) + .interpolationMethod(.catmullRom(alpha: 1.0)) - ForEach(chartData, id: \.self) { point in + Plot { + PointMark( + x: .value("x", point.time!), + y: .value("y", point.channelUtilization) + ) + } + .accessibilityLabel("Line Series") + .accessibilityValue("X: \(point.time!), Y: \(point.channelUtilization)") + .foregroundStyle(channelUtilizationChartColor) - Plot { - LineMark( - x: .value("x", point.time!), - y: .value("y", point.batteryLevel) - ) - } - .accessibilityLabel("Line Series") - .accessibilityValue("X: \(point.time!), Y: \(point.batteryLevel)") - .foregroundStyle(batteryChartColor) - .interpolationMethod(.catmullRom(alpha: 1.0)) - - Plot { - PointMark( - x: .value("x", point.time!), - y: .value("y", point.channelUtilization) - ) - } - .accessibilityLabel("Line Series") - .accessibilityValue("X: \(point.time!), Y: \(point.channelUtilization)") - .foregroundStyle(channelUtilizationChartColor) - - RuleMark(y: .value("Limit", 10)) - .lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 10])) - .foregroundStyle(airtimeChartColor) - - Plot { - PointMark( - x: .value("x", point.time!), - y: .value("y", point.airUtilTx) - ) - } - .accessibilityLabel("Line Series") - .accessibilityValue("X: \(point.time!), Y: \(point.airUtilTx)") + RuleMark(y: .value("Limit", 10)) + .lineStyle(StrokeStyle(lineWidth: 1, dash: [5, 10])) .foregroundStyle(airtimeChartColor) + + Plot { + PointMark( + x: .value("x", point.time!), + y: .value("y", point.airUtilTx) + ) } + .accessibilityLabel("Line Series") + .accessibilityValue("X: \(point.time!), Y: \(point.airUtilTx)") + .foregroundStyle(airtimeChartColor) } - .chartXAxis(content: { - AxisMarks(position: .top) - }) - .chartXAxis(.automatic) - .chartYScale(domain: 0...100) - .chartForegroundStyleScale([ - "Battery Level": .blue, - "Channel Utilization": .green, - "Airtime": .orange - ]) - .chartLegend(position: .automatic, alignment: .bottom) } - .frame(minHeight: 250) + .chartXAxis(content: { + AxisMarks(position: .top) + }) + .chartXAxis(.automatic) + .chartYScale(domain: 0...100) + .chartForegroundStyleScale([ + "Battery Level": .blue, + "Channel Utilization": .green, + "Airtime": .orange + ]) + .chartLegend(position: .automatic, alignment: .bottom) } - 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 { - // Add a table for mac and ipad - // Table(Array(deviceMetrics),id: \.self) { - Table(deviceMetrics) { - TableColumn("battery.level") { dm in - if dm.batteryLevel > 100 { - Text("Powered") - } else { - Text("\(String(dm.batteryLevel))%") - } + .frame(minHeight: 250) + } + 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 { + // Add a table for mac and ipad + // Table(Array(deviceMetrics),id: \.self) { + Table(deviceMetrics) { + TableColumn("battery.level") { dm in + if dm.batteryLevel > 100 { + Text("Powered") + } else { + Text("\(String(dm.batteryLevel))%") } - TableColumn("voltage") { dm in - Text("\(String(format: "%.2f", dm.voltage))") - } - TableColumn("channel.utilization") { dm in - Text("\(String(format: "%.2f", dm.channelUtilization))%") - } - TableColumn("airtime") { dm in - Text("\(String(format: "%.2f", dm.airUtilTx))%") - } - TableColumn("timestamp") { dm in - Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) - } - .width(min: 180) } - } else { - ScrollView { - let columns = [ - GridItem(.flexible(minimum: 30, maximum: 45), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 50), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 70), spacing: 0.1), - GridItem(.flexible(minimum: 30, maximum: 65), spacing: 0.1), - GridItem(.flexible(minimum: 130, maximum: 200), spacing: 0.1) - ] - LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { + TableColumn("voltage") { dm in + Text("\(String(format: "%.2f", dm.voltage))") + } + TableColumn("channel.utilization") { dm in + Text("\(String(format: "%.2f", dm.channelUtilization))%") + } + TableColumn("airtime") { dm in + Text("\(String(format: "%.2f", dm.airUtilTx))%") + } + TableColumn("timestamp") { dm in + Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) + } + .width(min: 180) + } + } else { + ScrollView { + let columns = [ + GridItem(.flexible(minimum: 30, maximum: 45), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 50), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 70), spacing: 0.1), + GridItem(.flexible(minimum: 30, maximum: 65), spacing: 0.1), + GridItem(.flexible(minimum: 130, maximum: 200), spacing: 0.1) + ] + LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { + GridRow { + Text("Batt") + .font(.caption) + .fontWeight(.bold) + Text("Volt") + .font(.caption) + .fontWeight(.bold) + Text("ChUtil") + .font(.caption) + .fontWeight(.bold) + Text("AirTm") + .font(.caption) + .fontWeight(.bold) + Text("timestamp") + .font(.caption) + .fontWeight(.bold) + } + ForEach(deviceMetrics) { dm in GridRow { - Text("Batt") - .font(.caption) - .fontWeight(.bold) - Text("Volt") - .font(.caption) - .fontWeight(.bold) - Text("ChUtil") - .font(.caption) - .fontWeight(.bold) - Text("AirTm") - .font(.caption) - .fontWeight(.bold) - Text("timestamp") - .font(.caption) - .fontWeight(.bold) - } - ForEach(deviceMetrics) { dm in - GridRow { - if dm.batteryLevel > 100 { - Text("PWD") - .font(.caption) - } else { - Text("\(String(dm.batteryLevel))%") - .font(.caption) - } - Text(String(dm.voltage)) + if dm.batteryLevel > 100 { + Text("PWD") .font(.caption) - Text("\(String(format: "%.2f", dm.channelUtilization))%") - .font(.caption) - Text("\(String(format: "%.2f", dm.airUtilTx))%") - .font(.caption) - Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) + } else { + Text("\(String(dm.batteryLevel))%") .font(.caption) } + Text(String(dm.voltage)) + .font(.caption) + Text("\(String(format: "%.2f", dm.channelUtilization))%") + .font(.caption) + Text("\(String(format: "%.2f", dm.airUtilTx))%") + .font(.caption) + Text(dm.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) + .font(.caption) } } - .padding(.leading, 15) - .padding(.trailing, 5) } + .padding(.leading, 15) + .padding(.trailing, 5) } } HStack { diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index f402be8a..370b050a 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -28,7 +28,7 @@ struct EnvironmentMetricsLog: View { let locale = NSLocale.current as NSLocale let localeUnit = locale.object(forKey: NSLocale.Key(rawValue: "kCFLocaleTemperatureUnitKey")) let format: UnitTemperature = localeUnit as? String ?? "Celsius" == "Fahrenheit" ? .fahrenheit : .celsius - NavigationStack { + VStack { if chartData.count > 0 { GroupBox(label: Label("\(environmentMetrics.count) Readings Total", systemImage: "chart.xyaxis.line")) { Chart { diff --git a/Meshtastic/Views/Nodes/Helpers/NodeMapSwiftUI.swift b/Meshtastic/Views/Nodes/Helpers/NodeMapSwiftUI.swift index 748c67bb..d7dbb3b0 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeMapSwiftUI.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeMapSwiftUI.swift @@ -10,6 +10,10 @@ import CoreLocation import MapKit import WeatherKit +extension CLLocationCoordinate2D { + static let bigBen = CLLocationCoordinate2D(latitude: 51.500685, longitude: -0.124570) + static let towerBridge = CLLocationCoordinate2D(latitude: 51.505507, longitude: -0.075402) +} @available(iOS 17.0, macOS 14.0, *) struct NodeMapSwiftUI: View { @@ -22,6 +26,7 @@ struct NodeMapSwiftUI: View { @AppStorage("meshMapShowRouteLines") private var showRouteLines = false @State private var position = MapCameraPosition.automatic @State private var scene: MKLookAroundScene? + @State private var isLookingAround = false @State private var showUserLocation: Bool = false @State var selected: PositionEntity? /// Unused map items @@ -131,28 +136,22 @@ struct NodeMapSwiftUI: View { } MapPitchToggle(scope: mapScope) .mapControlVisibility(.visible) - #if targetEnvironment(macCatalyst) - MapZoomStepper(scope: mapScope) - .mapControlVisibility(.visible) - MapPitchSlider(scope: mapScope) - .mapControlVisibility(.visible) - #endif MapCompass(scope: mapScope) .mapControlVisibility(.visible) } .controlSize(.regular) .overlay(alignment: .bottom) { - if scene != nil{ - LookAroundPreview(scene: $scene, allowsNavigation: false, badgePosition: .bottomTrailing) + if scene != nil && isLookingAround { + LookAroundPreview(initialScene: scene) .frame(height: 175) .clipShape(RoundedRectangle(cornerRadius: 12)) - .safeAreaPadding(.bottom, UIDevice.current.userInterfaceIdiom == .phone ? 30 : 75) + //.safeAreaPadding(.bottom, UIDevice.current.userInterfaceIdiom == .phone ? 20 : 75) .padding(.horizontal, 20) } } .onChange(of: node) { let mostRecent = node.positions?.lastObject as? PositionEntity - position = .camera(MapCamera(centerCoordinate: mostRecent!.coordinate, distance: 1500, heading: 0, pitch: 60)) + position = .camera(MapCamera(centerCoordinate: mostRecent!.coordinate, distance: 1500, heading: 0, pitch: 0)) if let mostRecent { Task { scene = try? await fetchScene(for: mostRecent.coordinate) @@ -167,10 +166,34 @@ struct NodeMapSwiftUI: View { } } } + .safeAreaInset(edge: .bottom, alignment: UIDevice.current.userInterfaceIdiom == .phone ? .leading : .trailing) { + HStack { + /// Look Around Button + if self.scene != nil { + Button(action: { + withAnimation { + isLookingAround = !isLookingAround + } + }) { + Image(systemName: isLookingAround ? "binoculars.fill" : "binoculars") + .padding(.vertical, 5) + } + .tint(Color(UIColor.secondarySystemBackground)) + .foregroundColor(.accentColor) + .buttonStyle(.borderedProminent) + } + #if targetEnvironment(macCatalyst) + MapZoomStepper(scope: mapScope) + .mapControlVisibility(.visible) + MapPitchSlider(scope: mapScope) + .mapControlVisibility(.visible) + #endif + } + .padding(5) + } .onDisappear { UIApplication.shared.isIdleTimerDisabled = false } - } .navigationBarTitle(String((node.user?.shortName ?? "unknown".localized) + (" \(node.positions?.count ?? 0) points")), displayMode: .inline) .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index e0b5a78f..0c8c034a 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -22,7 +22,7 @@ struct PositionLog: View { @State private var sortOrder = [KeyPathComparator(\PositionEntity.time)] var body: some View { - NavigationStack { + VStack { if node.hasPositions { let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current) let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")