mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Remove tracking mode setting, add button to mesh map
This commit is contained in:
parent
b367fde3db
commit
7e080cb2c6
8 changed files with 121 additions and 61 deletions
|
|
@ -117,6 +117,7 @@
|
|||
DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD6EEAE29BC024700383354 /* Firmware.swift */; };
|
||||
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; };
|
||||
DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; };
|
||||
DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443529F6287000EE2349 /* MapButtons.swift */; };
|
||||
DDDE59F529AF163D00490C6C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61C29AE7E8E003C5A37 /* WidgetKit.framework */; };
|
||||
DDDE59F629AF163D00490C6C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41A61E29AE7E8F003C5A37 /* SwiftUI.framework */; };
|
||||
DDDE59F929AF163D00490C6C /* WidgetsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE59F829AF163D00490C6C /* WidgetsBundle.swift */; };
|
||||
|
|
@ -297,6 +298,7 @@
|
|||
DDD6EEAE29BC024700383354 /* Firmware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firmware.swift; sourceTree = "<group>"; };
|
||||
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
|
||||
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DDDB443529F6287000EE2349 /* MapButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapButtons.swift; sourceTree = "<group>"; };
|
||||
DDDD527729B5B83F0045BC3C /* MeshtasticDataModelV9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV9.xcdatamodel; sourceTree = "<group>"; };
|
||||
DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DDDE59F829AF163D00490C6C /* WidgetsBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetsBundle.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -365,6 +367,7 @@
|
|||
C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */,
|
||||
DD964FC32974767D007C176F /* MapViewFitExtension.swift */,
|
||||
DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */,
|
||||
DDDB443529F6287000EE2349 /* MapButtons.swift */,
|
||||
);
|
||||
path = Custom;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -904,6 +907,7 @@
|
|||
DD5E523F298F5A9E00D21B61 /* AirQualityIndexCompact.swift in Sources */,
|
||||
DD964FBF296E76EF007C176F /* WaypointFormView.swift in Sources */,
|
||||
DD3501892852FC3B000FC853 /* Settings.swift in Sources */,
|
||||
DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */,
|
||||
DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */,
|
||||
DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */,
|
||||
DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -97,6 +97,13 @@ enum UserTrackingModes: Int, CaseIterable, Identifiable {
|
|||
return NSLocalizedString("map.usertrackingmode.followwithheading", comment: "Follow with Heading")
|
||||
}
|
||||
}
|
||||
var icon: String {
|
||||
switch self {
|
||||
case .none: return "location"
|
||||
case .follow: return "location.fill"
|
||||
case .followWithHeading: return "location.north.line.fill"
|
||||
}
|
||||
}
|
||||
func MKUserTrackingModeValue() -> MKUserTrackingMode {
|
||||
|
||||
switch self {
|
||||
|
|
|
|||
|
|
@ -193,7 +193,6 @@ extension UserDefaults {
|
|||
case meshMapCenteringMode
|
||||
case meshMapRecentering
|
||||
case meshMapCustomTileServer
|
||||
case meshMapUserTrackingMode
|
||||
case meshMapShowNodeHistory
|
||||
case meshMapShowRouteLines
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,12 +61,6 @@ class UserSettings: ObservableObject {
|
|||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
@Published var meshMapUserTrackingMode: Int {
|
||||
didSet {
|
||||
UserDefaults.standard.set(meshMapUserTrackingMode, forKey: "meshMapUserTrackingMode")
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
@Published var meshMapShowNodeHistory: Bool {
|
||||
didSet {
|
||||
UserDefaults.standard.set(meshMapShowNodeHistory, forKey: "meshMapShowNodeHistory")
|
||||
|
|
@ -91,7 +85,6 @@ class UserSettings: ObservableObject {
|
|||
self.meshMapCenteringMode = UserDefaults.standard.object(forKey: "meshMapCenteringMode") as? Int ?? 0
|
||||
self.meshMapRecentering = UserDefaults.standard.object(forKey: "meshMapRecentering") as? Bool ?? false
|
||||
self.meshMapCustomTileServer = UserDefaults.standard.string(forKey: "meshMapCustomTileServer") ?? ""
|
||||
self.meshMapUserTrackingMode = UserDefaults.standard.object(forKey: "meshMapUserTrackingMode") as? Int ?? 0
|
||||
self.meshMapShowNodeHistory = UserDefaults.standard.object(forKey: "meshMapShowNodeHistory") as? Bool ?? true
|
||||
self.meshMapShowRouteLines = UserDefaults.standard.object(forKey: "meshMapShowRouteLines") as? Bool ?? false
|
||||
}
|
||||
|
|
|
|||
66
Meshtastic/Views/Map/Custom/MapButtons.swift
Normal file
66
Meshtastic/Views/Map/Custom/MapButtons.swift
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// MapButtons.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright © Garth Vander Houwen 4/23/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MapButtons: View {
|
||||
let buttonWidth: CGFloat = 22
|
||||
let width: CGFloat = 45
|
||||
@Binding var tracking: UserTrackingModes
|
||||
@Binding var isPresentingInfoSheet: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack() {
|
||||
let impactLight = UIImpactFeedbackGenerator(style: .light)
|
||||
Button(action: {
|
||||
self.isPresentingInfoSheet.toggle()
|
||||
}) {
|
||||
Image(systemName: isPresentingInfoSheet ? "info.circle.fill" : "info.circle")
|
||||
.resizable()
|
||||
.frame(width: buttonWidth, height: buttonWidth, alignment: .center)
|
||||
.offset(y: -2)
|
||||
}
|
||||
Divider()
|
||||
Button(action: {
|
||||
switch self.tracking {
|
||||
case .none:
|
||||
self.tracking = .follow
|
||||
case .follow:
|
||||
self.tracking = .followWithHeading
|
||||
case .followWithHeading:
|
||||
self.tracking = .none
|
||||
}
|
||||
impactLight.impactOccurred()
|
||||
}) {
|
||||
Image(systemName: tracking.icon)
|
||||
.frame(width: buttonWidth, height: buttonWidth, alignment: .center)
|
||||
.offset(y: 3)
|
||||
}
|
||||
}
|
||||
.frame(width: width, height: width*2, alignment: .center)
|
||||
.background(Color(UIColor.systemBackground))
|
||||
.cornerRadius(8)
|
||||
.shadow(radius: 1)
|
||||
.offset(y: 25)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Previews
|
||||
struct MapControl_Previews: PreviewProvider {
|
||||
@State static var tracking: UserTrackingModes = .none
|
||||
@State static var isPresentingInfoSheet = false
|
||||
static var previews: some View {
|
||||
Group {
|
||||
MapButtons(tracking: $tracking, isPresentingInfoSheet: $isPresentingInfoSheet)
|
||||
.environment(\.colorScheme, .light)
|
||||
MapButtons(tracking: $tracking, isPresentingInfoSheet: $isPresentingInfoSheet)
|
||||
.environment(\.colorScheme, .dark)
|
||||
}
|
||||
|
||||
.previewLayout(.fixed(width: 60, height: 100))
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
@State private var loadedLastUpdatedLocalMapFile = 0
|
||||
var customMapOverlay: CustomMapOverlay?
|
||||
@State private var presentCustomMapOverlayHash: CustomMapOverlay?
|
||||
|
||||
// Custom Tile Server
|
||||
@AppStorage("meshMapCustomTileServer") private var tileServerUrl = ""
|
||||
var tileRenderer: MKTileOverlayRenderer?
|
||||
|
|
@ -70,10 +69,6 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
mapView.showsScale = true
|
||||
mapView.showsTraffic = true
|
||||
|
||||
let overlay = TileServerOverlay() // Offline-Map-Tiles
|
||||
overlay.canReplaceMapContent = true
|
||||
mapView.addOverlay(overlay, level: .aboveLabels)
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
// Show the default always visible compass and the mac only controls
|
||||
mapView.showsCompass = true
|
||||
|
|
@ -99,10 +94,29 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
|
||||
func updateUIView(_ mapView: MKMapView, context: Context) {
|
||||
|
||||
|
||||
mapView.mapType = mapViewType
|
||||
|
||||
if self.customMapOverlay != self.presentCustomMapOverlayHash || self.loadedLastUpdatedLocalMapFile != self.lastUpdatedLocalMapFile {
|
||||
if tileServerUrl.count > 0 {
|
||||
tileRenderer?.alpha = 0.0
|
||||
let overlays = mapView.overlays
|
||||
if mapView.mapType == .standard {
|
||||
let overlay = MKTileOverlay(urlTemplate: tileServerUrl)
|
||||
if overlays.contains(where: {$0 is MKPolyline}) {
|
||||
mapView.addOverlay(overlay, level: .aboveLabels)
|
||||
if let poly_overlay = overlays.filter({$0 is MKPolyline}).first {
|
||||
mapView.addOverlay(poly_overlay, level: .aboveLabels)
|
||||
}
|
||||
} else {
|
||||
mapView.addOverlay(overlay, level: .aboveLabels)
|
||||
|
||||
}
|
||||
} else {
|
||||
for overlay in overlays {
|
||||
if let ove = overlay as? MKTileOverlay {
|
||||
mapView.removeOverlay(ove)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if self.customMapOverlay != self.presentCustomMapOverlayHash || self.loadedLastUpdatedLocalMapFile != self.lastUpdatedLocalMapFile {
|
||||
mapView.removeOverlays(mapView.overlays)
|
||||
if self.customMapOverlay != nil {
|
||||
|
||||
|
|
@ -131,7 +145,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
.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)
|
||||
|
|
@ -152,7 +166,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
})
|
||||
let polyline = MKPolyline(coordinates: lineCoords, count: nodePositions.count)
|
||||
polyline.title = "\(String(position.nodePosition?.num ?? 0))"
|
||||
mapView.addOverlay(polyline)
|
||||
mapView.addOverlay(polyline, level: .aboveLabels)
|
||||
lineIndex += 1
|
||||
// There are 18 colors for lines, start over if we are at index 17
|
||||
if lineIndex > 17 {
|
||||
|
|
@ -176,30 +190,7 @@ struct MapViewSwiftUI: UIViewRepresentable {
|
|||
mapView.showsUserLocation = true
|
||||
}
|
||||
mapView.setUserTrackingMode(userTrackingMode, animated: true)
|
||||
|
||||
if tileServerUrl.count > 0 {
|
||||
tileRenderer?.alpha = 0.0
|
||||
let overlays = mapView.overlays
|
||||
if mapView.mapType == .standard {
|
||||
let overlay = MKTileOverlay(urlTemplate: tileServerUrl)
|
||||
if overlays.contains(where: {$0 is MKPolyline}) {
|
||||
mapView.addOverlay(overlay, level: .aboveLabels)
|
||||
if let poly_overlay = overlays.filter({$0 is MKPolyline}).first {
|
||||
mapView.addOverlay(poly_overlay, level: .aboveRoads)
|
||||
}
|
||||
} else {
|
||||
mapView.addOverlay(overlay, level: .aboveRoads)
|
||||
|
||||
}
|
||||
} else {
|
||||
for overlay in overlays {
|
||||
if let ove = overlay as? MKTileOverlay {
|
||||
mapView.removeOverlay(ove)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ struct NodeMap: View {
|
|||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
@AppStorage("meshMapType") private var meshMapType = "hybridFlyover"
|
||||
@AppStorage("meshMapUserTrackingMode") private var meshMapUserTrackingMode = 0
|
||||
@AppStorage("meshMapShowNodeHistory") private var meshMapShowNodeHistory = false
|
||||
@AppStorage("meshMapShowRouteLines") private var meshMapShowRouteLines = false
|
||||
|
||||
|
|
@ -32,7 +31,9 @@ struct NodeMap: View {
|
|||
private var waypoints: FetchedResults<WaypointEntity>
|
||||
|
||||
@State private var mapType: MKMapType = .standard
|
||||
@State private var userTrackingMode: MKUserTrackingMode = .none
|
||||
@State var selectedTracking: UserTrackingModes = .none
|
||||
@State var isPresentingInfoSheet: Bool = false
|
||||
|
||||
@State var waypointCoordinate: WaypointCoordinate?
|
||||
@State private var customMapOverlay: MapViewSwiftUI.CustomMapOverlay? = MapViewSwiftUI.CustomMapOverlay(
|
||||
mapName: "offlinemap",
|
||||
|
|
@ -56,11 +57,23 @@ struct NodeMap: View {
|
|||
positions: Array(positions),
|
||||
waypoints: Array(waypoints),
|
||||
mapViewType: mapType,
|
||||
userTrackingMode: userTrackingMode,
|
||||
userTrackingMode: selectedTracking.MKUserTrackingModeValue(),
|
||||
showNodeHistory: meshMapShowNodeHistory,
|
||||
showRouteLines: meshMapShowRouteLines,
|
||||
customMapOverlay: self.customMapOverlay
|
||||
)
|
||||
VStack(alignment: .trailing) {
|
||||
|
||||
HStack(alignment: .top) {
|
||||
Spacer()
|
||||
MapButtons(tracking: $selectedTracking, isPresentingInfoSheet: $isPresentingInfoSheet)
|
||||
.padding(.trailing, 8)
|
||||
.padding(.top, 16)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
}
|
||||
VStack {
|
||||
Spacer()
|
||||
Picker("Map Type", selection: $mapType) {
|
||||
|
|
@ -94,7 +107,6 @@ struct NodeMap: View {
|
|||
UIApplication.shared.isIdleTimerDisabled = true
|
||||
self.bleManager.context = context
|
||||
self.bleManager.userSettings = userSettings
|
||||
userTrackingMode = UserTrackingModes(rawValue: meshMapUserTrackingMode)?.MKUserTrackingModeValue() ?? MKUserTrackingMode.none
|
||||
switch meshMapType {
|
||||
case "standard":
|
||||
mapType = .standard
|
||||
|
|
|
|||
|
|
@ -82,15 +82,6 @@ struct AppSettings: View {
|
|||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
Picker("map.usertrackingmode", selection: $userSettings.meshMapUserTrackingMode) {
|
||||
ForEach(UserTrackingModes.allCases) { utm in
|
||||
Text(utm.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("When follow or follow with heading are selected maps will automatically center on the location of the GPS on the connected phone.")
|
||||
.font(.caption)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
Section(header: Text("map options")) {
|
||||
|
|
@ -102,14 +93,11 @@ struct AppSettings: View {
|
|||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
if userSettings.meshMapUserTrackingMode == 0 {
|
||||
Toggle(isOn: $userSettings.meshMapRecentering) {
|
||||
|
||||
Toggle(isOn: $userSettings.meshMapRecentering) {
|
||||
|
||||
Label("map.recentering", systemImage: "camera.metering.center.weighted")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Label("map.recentering", systemImage: "camera.metering.center.weighted")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Toggle(isOn: $userSettings.meshMapShowNodeHistory) {
|
||||
|
||||
Label("Show Node History", systemImage: "building.columns.fill")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue