Add map type selector to the settings tab

This commit is contained in:
Joshua Pirihi 2021-12-25 14:48:01 +13:00
parent 2576742820
commit 9bb5ee9335
5 changed files with 89 additions and 21 deletions

View file

@ -8,18 +8,19 @@
import UIKit
import MapKit
//a simple circle annotation, with a string in it
class PositionAnnotation: NSObject, MKAnnotation {
// This property must be key-value observable, which the `@objc dynamic` attributes provide.
@objc dynamic var coordinate = CLLocationCoordinate2D(latitude: 0, longitude: 0)
// Required if you set the annotation view's `canShowCallout` property to `true`
var title: String? = "Title"
//this string fills the callout label when you tap an annotation
var title: String?
//the text to appear inside the little circle
var shortName: String?
// This property defined by `MKAnnotation` is not required.
//var subtitle: String? = NSLocalizedString("SAN_FRANCISCO_SUBTITLE", comment: "SF annotation")
}
class PositionAnnotationView: MKAnnotationView {

View file

@ -11,49 +11,73 @@ import MapKit
import SwiftUI
import CoreData
//wrap a MKMapView into something we can use in SwiftUI
struct MapView: UIViewRepresentable {
//@Binding var route: MKPolyline?
var nodes: FetchedResults<NodeInfoEntity>
let mapViewDelegate = MapViewDelegate()
//observe changes to the key in UserDefaults
@AppStorage("meshMapType") var type: String = "hybrid"
func makeUIView(context: Context) -> MKMapView {
let map = MKMapView(frame: .zero)
map.userTrackingMode = .follow
map.mapType = .satellite
let region = MKCoordinateRegion( center: map.centerCoordinate, latitudinalMeters: CLLocationDistance(exactly: 500)!, longitudinalMeters: CLLocationDistance(exactly: 500)!)
map.setRegion(map.regionThatFits(region), animated: false)
//self.updateMapType(map)
map.register(PositionAnnotationView.self, forAnnotationViewWithReuseIdentifier: NSStringFromClass(PositionAnnotationView.self))
return map
}
func updateUIView(_ view: MKMapView, context: Context) {
view.delegate = mapViewDelegate // (1) This should be set in makeUIView, but it is getting reset to `nil`
view.translatesAutoresizingMaskIntoConstraints = false // (2) In the absence of this, we get constraints error on rotation; and again, it seems one should do this in makeUIView, but has to be here
//addRoute(to: view)
showNodePositions(to: view)
self.updateMapType(view)
self.showNodePositions(to: view)
}
func updateMapType(_ map: MKMapView) {
switch self.type {
case "satellite":
map.mapType = .satellite
break
case "standard":
map.mapType = .standard
break
case "hybrid":
map.mapType = .hybrid
break
default:
map.mapType = .hybrid
}
}
}
private extension MapView {
//func addRoute(to view: MKMapView) {
// if !view.overlays.isEmpty {
// view.removeOverlays(view.overlays)
// }
//guard let route = route else { return }
//let mapRect = route.boundingMapRect
//view.setVisibleMapRect(mapRect, edgePadding: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), animated: true)
//view.addOverlay(route)
//}
func showNodePositions(to view: MKMapView) {
//clear any existing annotations
if !view.annotations.isEmpty {
view.removeAnnotations(view.annotations)
}
for node in self.nodes {
//try and get the last position
if (node.positions?.count ?? 0) > 0 {
if (node.positions?.count ?? 0) > 0 && (node.positions!.lastObject as! PositionEntity).coordinate != nil {
let annotation = PositionAnnotation()
annotation.coordinate = (node.positions!.lastObject as! PositionEntity).coordinate ?? CLLocationCoordinate2D(latitude: 0, longitude: 0)
annotation.coordinate = (node.positions!.lastObject as! PositionEntity).coordinate!
annotation.title = node.user?.longName ?? "Unknown"
annotation.shortName = node.user?.shortName?.uppercased() ?? "???"

View file

@ -16,11 +16,15 @@ struct NodeMap: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
//@AppStorage("meshMapType") var meshMapType: String = "hybrid"
@State private var showLabels: Bool = false
@State private var annotationItems: [MapLocation] = []
@FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \NodeInfoEntity.lastHeard, ascending: false)], animation: .default)
private var locationNodes: FetchedResults<NodeInfoEntity>
var annotations: [MapLocation] = [MapLocation]()
@ -72,8 +76,7 @@ struct NodeMap: View {
}*/
MapView(nodes: self.locationNodes)
MapView(nodes: self.locationNodes)//.environmentObject(userSettings)
//}
.frame(maxHeight: .infinity)
.ignoresSafeArea(.all, edges: [.leading, .trailing])

View file

@ -2,6 +2,7 @@ import Foundation
import Combine
import SwiftUI
import SwiftProtobuf
import MapKit
enum KeyboardType: Int, CaseIterable, Identifiable {
@ -30,6 +31,28 @@ enum KeyboardType: Int, CaseIterable, Identifiable {
}
}
enum MeshMapType: String, CaseIterable, Identifiable {
case satellite = "satellite"
case hybrid = "hybrid"
case standard = "standard"
var id: String { self.rawValue }
var description: String {
get {
switch self {
case .satellite:
return "Satellite"
case .standard:
return "Standard"
case .hybrid:
return "Hybrid"
}
}
}
}
class UserSettings: ObservableObject {
// @Published var meshtasticUsername: String {
// didSet {
@ -61,6 +84,14 @@ class UserSettings: ObservableObject {
UserDefaults.standard.set(meshActivityLog, forKey: "meshActivityLog")
}
}
@Published var meshMapType: String {
didSet {
UserDefaults.standard.set(meshMapType, forKey: "meshMapType")
}
}
init() {
@ -70,6 +101,7 @@ class UserSettings: ObservableObject {
//self.provideLocation = UserDefaults.standard.object(forKey: "provideLocation") as? Bool ?? false
self.keyboardType = UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0
self.meshActivityLog = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false
self.meshMapType = UserDefaults.standard.string(forKey: "meshMapType") ?? "hybrid"
}
}
@ -140,6 +172,14 @@ struct AppSettings: View {
.listRowSeparator(.visible)
}
}
Section(header: Text("MAP OPTIONS")) {
Picker("Map Type", selection: $userSettings.meshMapType) {
ForEach(MeshMapType.allCases) { map in
Text(map.description)
}
}
.pickerStyle(DefaultPickerStyle())
}
}
}
.navigationTitle("App Settings")