diff --git a/Meshtastic/Enums/AppSettingsEnums.swift b/Meshtastic/Enums/AppSettingsEnums.swift index e176cee1..e882fd08 100644 --- a/Meshtastic/Enums/AppSettingsEnums.swift +++ b/Meshtastic/Enums/AppSettingsEnums.swift @@ -135,49 +135,72 @@ enum MapLayer: String, CaseIterable, Equatable { case satellite case offline var localized: String { self.rawValue.localized } - var zoomRange: [Int] { - switch self { - case .standard: - return [Int](0...24) - case .hybrid: - return [Int](0...24) - case .satellite: - return [Int](0...24) - case .offline: - return [Int](0...17) - } - } } -enum MapTileServerLinks: Int, CaseIterable, Identifiable { +enum MapTileServerLinks: String, CaseIterable, Identifiable { - case none = 0 - case openStreetMaps = 1 - case wikimedia = 2 - case nationalMap = 3 - var id: Int { self.rawValue } + case openStreetMaps + case usgsTopo + case usgsImageryTopo + case usgsImageryOnly + case watercolor + var id: String { self.rawValue } + var attribution: String { + switch self { + + case .openStreetMaps: + return "OpenStreetMap is a map of the world, created by people like you and free to use under an open license. © [OpenStreetMap](http://osm.org/copyright) contributors" + case .usgsTopo: + return "[USGS Topo](https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer) is a tile cache base map service that combines the most current data in The National Map (TNM), and other public-domain data, into a multi-scale topographic reference map." + case .usgsImageryTopo: + return "[USGS Imagery Topo](https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer) is a tile cache base map of orthoimagery in The National Map and US Topo vector data." + case .usgsImageryOnly: + return "[USGS Imagery Only](https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer) is a tile cache base map service of orthoimagery in The National Map." + case .watercolor: + return "Cooper Hewitt, Smithsonian Design Museum's [Watercolor Maptiles](https://watercolormaps.collection.cooperhewitt.org/) is a open-source mapping tool created by Stamen Design and built on OpenStreetMap data." + } + } var description: String { switch self { - case .none: - return "Please Select" - case .wikimedia: - return "Wikimedia" case .openStreetMaps: return "Open Street Maps" - case .nationalMap: - return "US National Map" + case .usgsTopo: + return "USGS Topographic" + case .usgsImageryTopo: + return "USGS Topo Imagery" + case .usgsImageryOnly: + return "USGS Imagery Only" + case .watercolor: + return "Watercolor Maptiles" } } var tileUrl: String { switch self { - case .none: - return "" - case .wikimedia: - return "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png" case .openStreetMaps: return "https://tile.openstreetmap.org/{z}/{x}/{y}.png" - case .nationalMap: + case .usgsTopo: + return "https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}" + case .usgsImageryTopo: + return "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}" + case .usgsImageryOnly: return "https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}" + case .watercolor: + return "https://watercolormaps.collection.cooperhewitt.org/tile/watercolor/{z}/{x}/{y}.jpg" + + } + } + var zoomRange: [Int] { + switch self { + case .openStreetMaps: + return [Int](0...17) + case .usgsTopo: + return [Int](0...17) + case .usgsImageryTopo: + return [Int](0...17) + case .usgsImageryOnly: + return [Int](0...17) + case .watercolor: + return [Int](0...17) } } } diff --git a/Meshtastic/Extensions/UserDefaults.swift b/Meshtastic/Extensions/UserDefaults.swift index 49a2bf4c..d8ee5e28 100644 --- a/Meshtastic/Extensions/UserDefaults.swift +++ b/Meshtastic/Extensions/UserDefaults.swift @@ -115,12 +115,13 @@ extension UserDefaults { } } - static var mapTileServer: String { + static var mapTileServer: MapTileServerLinks { get { - UserDefaults.standard.string(forKey: "mapTileServer") ?? "" + + MapTileServerLinks(rawValue: UserDefaults.standard.string(forKey: "mapTileServer") ?? MapTileServerLinks.openStreetMaps.rawValue) ?? MapTileServerLinks.openStreetMaps } set { - UserDefaults.standard.set(newValue, forKey: "mapTileServer") + UserDefaults.standard.set(newValue.rawValue, forKey: "mapTileServer") } } diff --git a/Meshtastic/Helpers/Map/OfflineTileManager.swift b/Meshtastic/Helpers/Map/OfflineTileManager.swift index 4dcbe5ca..7a5e7e4b 100644 --- a/Meshtastic/Helpers/Map/OfflineTileManager.swift +++ b/Meshtastic/Helpers/Map/OfflineTileManager.swift @@ -22,7 +22,7 @@ class OfflineTileManager: ObservableObject { } // MARK: - Private properties - private var overlay: MKTileOverlay { MKTileOverlay(urlTemplate: UserDefaults.mapTileServer.count > 1 ? UserDefaults.mapTileServer : "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png") } + private var overlay: MKTileOverlay { MKTileOverlay(urlTemplate: UserDefaults.mapTileServer.tileUrl.count > 1 ? UserDefaults.mapTileServer.tileUrl : MapTileServerLinks.openStreetMaps.tileUrl) } private var documentsDirectory: URL { fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! } diff --git a/Meshtastic/Views/Map/Custom/TilesView.swift b/Meshtastic/Views/Map/Custom/TilesView.swift index 77127d40..b5927945 100644 --- a/Meshtastic/Views/Map/Custom/TilesView.swift +++ b/Meshtastic/Views/Map/Custom/TilesView.swift @@ -23,8 +23,10 @@ struct TilesView: View { HStack { Image(systemName: "trash") + .font(.callout) .foregroundColor(.red) Text("\("map.tiles.delete".localized) (\(totalDownloadedTileSize))") + .font(.callout) .foregroundColor(.red) Spacer() } @@ -32,7 +34,6 @@ struct TilesView: View { .onAppear(perform: { totalDownloadedTileSize = tileManager.getAllDownloadedSize() }) - Divider() } } diff --git a/Meshtastic/Views/Nodes/NodeMap.swift b/Meshtastic/Views/Nodes/NodeMap.swift index 068201ff..160063c0 100644 --- a/Meshtastic/Views/Nodes/NodeMap.swift +++ b/Meshtastic/Views/Nodes/NodeMap.swift @@ -14,13 +14,15 @@ struct NodeMap: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + + @ObservedObject var tileManager = OfflineTileManager.shared @State var selectedMapLayer: MapLayer = UserDefaults.mapLayer @State var enableMapRecentering: Bool = UserDefaults.enableMapRecentering @State var enableMapRouteLines: Bool = UserDefaults.enableMapRouteLines @State var enableMapNodeHistoryPins: Bool = UserDefaults.enableMapNodeHistoryPins @State var enableOfflineMaps: Bool = UserDefaults.enableOfflineMaps - @State var mapTileServer: String = UserDefaults.mapTileServer + @State var selectedTileServer: MapTileServerLinks = UserDefaults.mapTileServer @State var enableOfflineMapsMBTiles: Bool = UserDefaults.enableOfflineMapsMBTiles @State var mapTilesAboveLabels: Bool = UserDefaults.mapTilesAboveLabels @@ -36,7 +38,7 @@ struct NodeMap: View { @State var waypointCoordinate: WaypointCoordinate? @State var selectedTracking: UserTrackingModes = .none - @State var selectedTileServer: MapTileServerLinks = .wikimedia + @State var isPresentingInfoSheet: Bool = false @State private var customMapOverlay: MapViewSwiftUI.CustomMapOverlay? = MapViewSwiftUI.CustomMapOverlay( @@ -155,22 +157,19 @@ struct NodeMap: View { if !enableOfflineMapsMBTiles { - HStack { - Label("Tile Server", systemImage: "square.grid.3x2") - TextField( - "Tile Server", - text: $mapTileServer, - axis: .vertical - ) - .keyboardType(.asciiCapable) - .disableAutocorrection(true) - .foregroundColor(.gray) - .font(.caption) - .onChange(of: (mapTileServer)) { newMapTileServer in - UserDefaults.mapTileServer = newMapTileServer + Picker(selection: $selectedTileServer, + label: Text("Tile Server")) { + ForEach(MapTileServerLinks.allCases, id: \.self) { tsl in + Text(tsl.description) } } - Text("A tile server will be used (defaults to wikimedia OSM) to load and cache map tiles as you browse the Offline map type.") + .pickerStyle(DefaultPickerStyle()) + .onChange(of: (selectedTileServer)) { newSelectedTileServer in + UserDefaults.mapTileServer = newSelectedTileServer + tileManager.removeAll() + selectedMapLayer = .standard + } + Text(LocalizedStringKey(selectedTileServer.attribution)) .font(.caption) .foregroundColor(.gray) Divider() @@ -182,9 +181,9 @@ struct NodeMap: View { self.mapTilesAboveLabels.toggle() UserDefaults.mapTilesAboveLabels = self.mapTilesAboveLabels } - Divider() - TilesView() + } + Divider() Toggle(isOn: $enableOfflineMapsMBTiles) { Text("Enable MB Tiles") } diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index dc544509..20c89de8 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -77,7 +77,9 @@ struct AppSettings: View { .font(.caption) .foregroundColor(.gray) } + } + TilesView() } HStack { Button { diff --git a/de.lproj/Localizable.strings b/de.lproj/Localizable.strings index cc289015..720cccf5 100644 --- a/de.lproj/Localizable.strings +++ b/de.lproj/Localizable.strings @@ -138,7 +138,7 @@ "lora.config"="LoRa Einstellungen"; "map"="Mesh Karte"; "map.centering"="Centering"; -"map.tiles.delete"="Delete Cached Tiles"; +"map.tiles.delete"="Delete Cached Map Tiles"; "map.recentering"="Automatic Re-centering"; "map.type"="kartentyp"; "map.usertrackingmode"="User tracking mode"; diff --git a/en.lproj/Localizable.strings b/en.lproj/Localizable.strings index 04841901..1ecdb327 100644 --- a/en.lproj/Localizable.strings +++ b/en.lproj/Localizable.strings @@ -139,7 +139,7 @@ "map"="Mesh Map"; "map.type"="Default Type"; "map.centering"="Centering Mode"; -"map.tiles.delete"="Delete Cached Tiles"; +"map.tiles.delete"="Delete Cached Map Tiles"; "map.recentering"="Automatic Re-centering"; "map.usertrackingmode"="User tracking mode"; "map.usertrackingmode.follow"="Follow"; diff --git a/zh-Hans.lproj/Localizable.strings b/zh-Hans.lproj/Localizable.strings index cf4e6b3b..949d7d8a 100644 --- a/zh-Hans.lproj/Localizable.strings +++ b/zh-Hans.lproj/Localizable.strings @@ -138,7 +138,7 @@ "lora.config"="LoRa 配置"; "map"="Mesh 地图"; "map.centering"="Centering"; -"map.tiles.delete"="Delete Cached Tiles"; +"map.tiles.delete"="Delete Cached Map Tiles"; "map.recentering"="Automatic Re-centering"; "map.type"="地图类型"; "map.usertrackingmode"="User tracking mode";