diff --git a/Meshtastic/Model/UserSettings.swift b/Meshtastic/Model/UserSettings.swift index 45a161c0..675d238c 100644 --- a/Meshtastic/Model/UserSettings.swift +++ b/Meshtastic/Model/UserSettings.swift @@ -51,6 +51,12 @@ class UserSettings: ObservableObject { UserDefaults.standard.synchronize() } } + @Published var meshMapRecentering: Bool { + didSet { + UserDefaults.standard.set(meshMapCenteringMode, forKey: "meshMapRecentering") + UserDefaults.standard.synchronize() + } + } @Published var meshMapCustomTileServer: String { didSet { UserDefaults.standard.set(meshMapCustomTileServer, forKey: "meshMapCustomTileServer") @@ -67,6 +73,7 @@ class UserSettings: ObservableObject { self.keyboardType = UserDefaults.standard.object(forKey: "keyboardType") as? Int ?? 0 self.meshMapType = UserDefaults.standard.string(forKey: "meshMapType") ?? "standard" self.meshMapCenteringMode = UserDefaults.standard.object(forKey: "meshMapCenteringMode") as? Int ?? 0 + self.meshMapRecentering = UserDefaults.standard.object(forKey: "meshMapRecentering") as? Bool ?? true self.meshMapCustomTileServer = UserDefaults.standard.string(forKey: "meshMapCustomTileServer") ?? "" } } diff --git a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift index 14c55fc6..ec549754 100644 --- a/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift +++ b/Meshtastic/Views/Map/Custom/MapViewSwiftUI.swift @@ -22,6 +22,7 @@ struct MapViewSwiftUI: UIViewRepresentable { let centeringMode: CenteringMode let centerOnPositionsOnly: Bool + @AppStorage("meshMapRecenter") private var recenter = true // Offline Maps //make this view dependent on the UserDefault that is updated when importing a new map file @@ -38,19 +39,19 @@ struct MapViewSwiftUI: UIViewRepresentable { mapView.addAnnotations(waypoints) // Logic to manage the map centering options switch centeringMode { - case .allAnnotations: - mapView.addAnnotations(positions) - mapView.fitAllAnnotations() - case .allPositions: - mapView.fit(annotations: positions, andShow: true) - case .clientGps: - - let span = MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003) - let center = CLLocationCoordinate2D(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude) - let region = MKCoordinateRegion(center: center, span: span) - mapView.setRegion(region, animated: true) - mapView.setUserTrackingMode(.followWithHeading, animated: true) - mapView.addAnnotations(positions) + case .allAnnotations: + mapView.addAnnotations(positions) + mapView.fitAllAnnotations() + case .allPositions: + mapView.fit(annotations: positions, andShow: true) + case .clientGps: + + let span = MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003) + let center = CLLocationCoordinate2D(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude) + let region = MKCoordinateRegion(center: center, span: span) + mapView.setRegion(region, animated: true) + mapView.setUserTrackingMode(.followWithHeading, animated: true) + mapView.addAnnotations(positions) } // Other MKMapView Settings @@ -61,14 +62,27 @@ struct MapViewSwiftUI: UIViewRepresentable { mapView.isScrollEnabled = true mapView.isZoomEnabled = true mapView.showsBuildings = true - mapView.showsCompass = true mapView.showsScale = true mapView.showsTraffic = true - #if targetEnvironment(macCatalyst) +#if targetEnvironment(macCatalyst) + // Show the default always visible compass and the mac only controls + mapView.showsCompass = true mapView.showsZoomControls = true mapView.showsPitchControl = true - #endif +#else + +#if os(iOS) + // Hide the default compass that only appears when you are not going north and instead always show the compass in the bottom right corner of the map + mapView.showsCompass = false + let compassButton = MKCompassButton(mapView: mapView) // Make a new compass + compassButton.compassVisibility = .visible // Make it visible + mapView.addSubview(compassButton) // Add it to the view + compassButton.translatesAutoresizingMaskIntoConstraints = false + compassButton.trailingAnchor.constraint(equalTo: mapView.trailingAnchor, constant: -5).isActive = true + compassButton.bottomAnchor.constraint(equalTo: mapView.bottomAnchor, constant: -25).isActive = true +#endif +#endif mapView.delegate = context.coordinator return mapView } @@ -79,7 +93,7 @@ struct MapViewSwiftUI: UIViewRepresentable { if self.customMapOverlay != self.presentCustomMapOverlayHash || self.loadedLastUpdatedLocalMapFile != self.lastUpdatedLocalMapFile { mapView.removeOverlays(mapView.overlays) if self.customMapOverlay != nil { - + let fileManager = FileManager.default let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! let tilePath = documentsDirectory.appendingPathComponent("offline_map.mbtiles", isDirectory: false).path @@ -105,14 +119,22 @@ struct MapViewSwiftUI: UIViewRepresentable { switch centeringMode { case .allAnnotations: mapView.addAnnotations(positions) - mapView.fitAllAnnotations() + if recenter { + mapView.fitAllAnnotations() + } case .allPositions: - mapView.fit(annotations: positions, andShow: true) + if recenter { + mapView.fit(annotations: positions, andShow: true) + } else { + mapView.addAnnotations(positions) + } case .clientGps: mapView.addAnnotations(positions) - let span = MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003) - let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude), span: span) + if recenter { + let span = MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003) + let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude), span: span) mapView.setRegion(region, animated: true) + } } } } @@ -289,9 +311,9 @@ struct MapViewSwiftUI: UIViewRepresentable { } public func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { - + if let index = self.overlays.firstIndex(where: { overlay_ in overlay_.shape.hash == overlay.hash }) { - + let unwrappedOverlay = self.overlays[index] if let circleOverlay = unwrappedOverlay.shape as? MKCircle { let renderer = MKCircleRenderer(circle: circleOverlay) diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index 4113945f..133a7b81 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -77,6 +77,12 @@ struct AppSettings: View { } } .pickerStyle(DefaultPickerStyle()) + + Toggle(isOn: $userSettings.meshMapRecentering) { + + Label("map.recentering", systemImage: "rectangle.center.inset.filled") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) } } HStack { diff --git a/de.lproj/Localizable.strings b/de.lproj/Localizable.strings index 8db9471a..f6785b90 100644 --- a/de.lproj/Localizable.strings +++ b/de.lproj/Localizable.strings @@ -138,6 +138,7 @@ "lora.config"="LoRa Einstellungen"; "map"="Mesh Karte"; "map.centering"="Centering"; +"map.recentering"="Automatic Re-centering"; "map.type"="kartentyp"; "mesh.log"="Mesh Log"; "mesh.log.bluetooth.config %@"="Bluetooth Konfiguration empfangen: %@"; diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 542377e5..36951b44 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -138,7 +138,8 @@ "lora.config"="LoRa Config"; "map"="Mesh Map"; "map.type"="Default Type"; -"map.centering"="Centering"; +"map.centering"="Centering Mode"; +"map.recentering"="Automatic Re-centering"; "mesh.log"="Mesh Log"; "mesh.log.bluetooth.config %@"="Bluetooth config received: %@"; "mesh.log.cannedmessage.config %@"="Canned Message module config received: %@"; diff --git a/zh-Hans.lproj/Localizable.strings b/zh-Hans.lproj/Localizable.strings index 3a337e5a..9a54174b 100644 --- a/zh-Hans.lproj/Localizable.strings +++ b/zh-Hans.lproj/Localizable.strings @@ -138,6 +138,7 @@ "lora.config"="LoRa 配置"; "map"="Mesh 地图"; "map.centering"="Centering"; +"map.recentering"="Automatic Re-centering"; "map.type"="地图类型"; "mesh.log"="Mesh 日志"; "mesh.log.bluetooth.config %@"="Bluetooth config received: %@";