mirror of
https://github.com/seemoo-lab/openhaystack.git
synced 2026-02-14 17:49:54 +00:00
Add history view (shows all location reports for a single accessory)
This commit is contained in:
@@ -69,6 +69,7 @@ class AccessoryController: ObservableObject {
|
||||
|
||||
accessory.lastLocation = report?.location
|
||||
accessory.locationTimestamp = report?.timestamp
|
||||
accessory.locations = device.decryptedReports
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class Accessory: ObservableObject, Codable, Identifiable, Equatable, Hashable {
|
||||
@Published var name: String
|
||||
let id: Int
|
||||
let privateKey: Data
|
||||
@Published var locations: [FindMyLocationReport]?
|
||||
@Published var color: Color
|
||||
@Published var icon: String
|
||||
@Published var lastLocation: CLLocation?
|
||||
|
||||
@@ -103,3 +103,11 @@ class AccessoryAnnotation: NSObject, MKAnnotation {
|
||||
self.accessory = accessory
|
||||
}
|
||||
}
|
||||
|
||||
class AccessoryHistoryAnnotation: NSObject, MKAnnotation {
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
|
||||
init(coordinate: CLLocationCoordinate2D) {
|
||||
self.coordinate = coordinate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import SwiftUI
|
||||
struct AccessoryMapView: NSViewControllerRepresentable {
|
||||
@ObservedObject var accessoryController: AccessoryController
|
||||
@Binding var mapType: MKMapType
|
||||
var focusedAccessory: Accessory?
|
||||
@Binding var focusedAccessory: Accessory?
|
||||
@Binding var showHistory: Bool
|
||||
|
||||
func makeNSViewController(context: Context) -> MapViewController {
|
||||
return MapViewController(nibName: NSNib.Name("MapViewController"), bundle: nil)
|
||||
@@ -23,8 +24,14 @@ struct AccessoryMapView: NSViewControllerRepresentable {
|
||||
func updateNSViewController(_ nsViewController: MapViewController, context: Context) {
|
||||
let accessories = self.accessoryController.accessories
|
||||
|
||||
nsViewController.zoom(on: focusedAccessory)
|
||||
nsViewController.addLastLocations(from: accessories)
|
||||
nsViewController.focusedAccessory = focusedAccessory
|
||||
if showHistory {
|
||||
nsViewController.addAllLocations(from: focusedAccessory!)
|
||||
nsViewController.zoomInOnAll()
|
||||
} else {
|
||||
nsViewController.addLastLocations(from: accessories)
|
||||
nsViewController.zoomInOnSelection()
|
||||
}
|
||||
nsViewController.changeMapType(mapType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ struct OpenHaystackMainView: View {
|
||||
@State var mapType: MKMapType = .standard
|
||||
@State var isLoading = false
|
||||
@State var focusedAccessory: Accessory?
|
||||
@State var historyMapView = false
|
||||
@State var accessoryToDeploy: Accessory?
|
||||
@State var showMailPlugInPopover = false
|
||||
|
||||
@@ -48,7 +49,7 @@ struct OpenHaystackMainView: View {
|
||||
.frame(minWidth: 250, idealWidth: 280, maxWidth: .infinity, minHeight: 300, idealHeight: 400, maxHeight: .infinity, alignment: .center)
|
||||
|
||||
ZStack {
|
||||
AccessoryMapView(accessoryController: self.accessoryController, mapType: self.$mapType, focusedAccessory: self.focusedAccessory)
|
||||
AccessoryMapView(accessoryController: self.accessoryController, mapType: self.$mapType, focusedAccessory: self.$focusedAccessory, showHistory: self.$historyMapView)
|
||||
.overlay(self.mapOverlay)
|
||||
if self.popUpAlertType != nil {
|
||||
VStack {
|
||||
@@ -108,6 +109,10 @@ struct OpenHaystackMainView: View {
|
||||
/// All toolbar items shown
|
||||
var toolbarView: some View {
|
||||
Group {
|
||||
Toggle(isOn: $historyMapView) {
|
||||
Label("Show location history", systemImage: "clock")
|
||||
}
|
||||
.disabled(self.focusedAccessory == nil)
|
||||
|
||||
Picker("", selection: self.$mapType) {
|
||||
Text("Satellite").tag(MKMapType.hybrid)
|
||||
|
||||
@@ -19,11 +19,7 @@ final class MapViewController: NSViewController, MKMapViewDelegate {
|
||||
super.viewDidLoad()
|
||||
self.mapView.delegate = self
|
||||
self.mapView.register(AccessoryAnnotationView.self, forAnnotationViewWithReuseIdentifier: "Accessory")
|
||||
}
|
||||
|
||||
func zoom(on accessory: Accessory?) {
|
||||
self.focusedAccessory = accessory
|
||||
self.zoomInOnSelection()
|
||||
self.mapView.register(MKPinAnnotationView.self, forAnnotationViewWithReuseIdentifier: "AccessoryHistory")
|
||||
}
|
||||
|
||||
func addLastLocations(from accessories: [Accessory]) {
|
||||
@@ -34,15 +30,11 @@ final class MapViewController: NSViewController, MKMapViewDelegate {
|
||||
let annotation = AccessoryAnnotation(accessory: accessory)
|
||||
self.mapView.addAnnotation(annotation)
|
||||
}
|
||||
self.zoomInOnSelection()
|
||||
}
|
||||
|
||||
func zoomInOnSelection() {
|
||||
var annotations = [MKAnnotation]()
|
||||
|
||||
if focusedAccessory == nil {
|
||||
// Show all locations
|
||||
annotations = self.mapView.annotations
|
||||
zoomInOnAll()
|
||||
} else {
|
||||
// Show focused accessory
|
||||
let focusedAnnotation: MKAnnotation? = self.mapView.annotations.first(where: { annotation in
|
||||
@@ -50,9 +42,16 @@ final class MapViewController: NSViewController, MKMapViewDelegate {
|
||||
return accessoryAnnotation.accessory == self.focusedAccessory
|
||||
})
|
||||
if let annotation = focusedAnnotation {
|
||||
annotations = [annotation]
|
||||
zoomInOn(annotations: [annotation])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func zoomInOnAll() {
|
||||
zoomInOn(annotations: self.mapView.annotations)
|
||||
}
|
||||
|
||||
func zoomInOn(annotations: [MKAnnotation]) {
|
||||
DispatchQueue.main.async {
|
||||
self.mapView.showAnnotations(annotations, animated: true)
|
||||
}
|
||||
@@ -62,12 +61,25 @@ final class MapViewController: NSViewController, MKMapViewDelegate {
|
||||
self.mapView.mapType = mapType
|
||||
}
|
||||
|
||||
func addAllLocations(from accessory: Accessory) {
|
||||
self.mapView.removeAnnotations(self.mapView.annotations)
|
||||
for location in accessory.locations ?? [] {
|
||||
let coordinate = CLLocationCoordinate2DMake(location.latitude, location.longitude)
|
||||
let annotation = AccessoryHistoryAnnotation(coordinate: coordinate)
|
||||
self.mapView.addAnnotation(annotation)
|
||||
}
|
||||
}
|
||||
|
||||
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
|
||||
switch annotation {
|
||||
case is AccessoryAnnotation:
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "Accessory", for: annotation)
|
||||
annotationView.annotation = annotation
|
||||
return annotationView
|
||||
case is AccessoryHistoryAnnotation:
|
||||
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "AccessoryHistory", for: annotation)
|
||||
annotationView.annotation = annotation
|
||||
return annotationView
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user