Clarify how the different mapLibre URLs are used.

This commit is contained in:
Stefan Ceriu
2025-11-10 15:13:19 +02:00
committed by Stefan Ceriu
parent 6465730638
commit dd95a4313a
5 changed files with 47 additions and 45 deletions
@@ -65,7 +65,7 @@ struct MapLibreMapView: UIViewRepresentable {
// Don't set the same value twice. Otherwise, if there is an error loading the map, a loop
// is caused as the `error` binding being set, which triggers this update, which sets a
// new URL, which causes another error, and so it goes on round and round in a circle.
let dynamicMapURL = mapURLBuilder.dynamicMapURL(for: .init(colorScheme))
let dynamicMapURL = mapURLBuilder.interactiveMapURL(for: .init(colorScheme))
if mapView.styleURL != dynamicMapURL {
mapView.styleURL = dynamicMapURL
}
@@ -86,7 +86,7 @@ struct MapLibreMapView: UIViewRepresentable {
}
private func makeMapView() -> MGLMapView {
let mapView = MGLMapView(frame: .zero, styleURL: mapURLBuilder.dynamicMapURL(for: colorScheme == .dark ? .dark : .light))
let mapView = MGLMapView(frame: .zero, styleURL: mapURLBuilder.interactiveMapURL(for: colorScheme == .dark ? .dark : .light))
mapView.logoViewPosition = .topLeft
mapView.attributionButtonPosition = .topLeft
mapView.attributionButtonMargins = .init(x: mapView.logoView.frame.maxX + 8, y: mapView.logoView.center.y / 2)
@@ -36,11 +36,11 @@ struct MapLibreStaticMapView<PinAnnotation: View>: View {
var body: some View {
GeometryReader { geometry in
if let url = mapURLBuilder.staticMapURL(for: colorScheme.mapStyle,
coordinates: coordinates,
zoomLevel: zoomLevel,
size: mapSize, // temporary using a fixed size since the refresh doesn't work properly on the UITableView based timeline
attribution: mapTilerAttributionPlacement) {
if let url = mapURLBuilder.staticMapTileImageURL(for: colorScheme.mapStyle,
coordinates: coordinates,
zoomLevel: zoomLevel,
size: mapSize, // temporary using a fixed size since the refresh doesn't work properly on the UITableView based timeline
attribution: mapTilerAttributionPlacement) {
AsyncImage(url: url) { phase in
switch phase {
case .empty:
@@ -114,13 +114,13 @@ struct MapLibreStaticMapView_Previews: PreviewProvider, TestablePreview {
}
private struct MapTilerURLBuilderMock: MapTilerURLBuilderProtocol {
func dynamicMapURL(for style: MapTilerStyle) -> URL? { nil }
func interactiveMapURL(for style: MapTilerStyle) -> URL? { nil }
func staticMapURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL? {
func staticMapTileImageURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL? {
switch style {
case .light:
return URL(string: "https://www.maptiler.com/img/cloud/home/map5.webp")
@@ -9,11 +9,11 @@
import CoreLocation
protocol MapTilerURLBuilderProtocol {
func dynamicMapURL(for style: MapTilerStyle) -> URL?
func interactiveMapURL(for style: MapTilerStyle) -> URL?
func staticMapURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL?
func staticMapTileImageURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL?
}
+11 -9
View File
@@ -9,18 +9,20 @@
import CoreLocation
extension MapTilerConfiguration: MapTilerURLBuilderProtocol {
func dynamicMapURL(for style: MapTilerStyle) -> URL? {
var url = makeNewURL(for: style)
/// For interactive MGLMap components
func interactiveMapURL(for style: MapTilerStyle) -> URL? {
var url = styleURL(for: style)
url?.appendPathComponent("style.json", conformingTo: .json)
return url
}
func staticMapURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL? {
var url = makeNewURL(for: style)
/// Used in the timeline where a full MGLMapView loading is unwanted
func staticMapTileImageURL(for style: MapTilerStyle,
coordinates: CLLocationCoordinate2D,
zoomLevel: Double,
size: CGSize,
attribution: MapTilerAttributionPlacement) -> URL? {
var url = styleURL(for: style)
url?.appendPathComponent(String(format: "static/%f,%f,%f/%dx%d@2x.png",
coordinates.longitude,
coordinates.latitude,
@@ -34,7 +36,7 @@ extension MapTilerConfiguration: MapTilerURLBuilderProtocol {
// MARK: Private
private func makeNewURL(for style: MapTilerStyle) -> URL? {
private func styleURL(for style: MapTilerStyle) -> URL? {
guard let apiKey else { return nil }
var url: URL = baseURL
+17 -17
View File
@@ -26,29 +26,29 @@ final class MapTilerURLBuilderTests: XCTestCase {
}
func testStaticMapBuilder() {
let url = builder.staticMapURL(for: .light,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .hidden)
let url = builder.staticMapTileImageURL(for: .light,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .hidden)
let expectedURL: URL = "http://www.foo.com/9bc819c8-e627-474a-a348-ec144fe3d810/static/2.000000,1.000000,5.000000/300x200@2x.png?key=some_key&attribution=false"
XCTAssertEqual(url, expectedURL)
}
func testStaticMapBuilderWithAttribution() {
let url = builder.staticMapURL(for: .dark,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .topLeft)
let url = builder.staticMapTileImageURL(for: .dark,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .topLeft)
let expectedURL: URL = "http://www.foo.com/dea61faf-292b-4774-9660-58fcef89a7f3/static/2.000000,1.000000,5.000000/300x200@2x.png?key=some_key&attribution=topleft"
XCTAssertEqual(url, expectedURL)
}
func testDynamicMapBuilder() {
let url = builder.dynamicMapURL(for: .dark)
let url = builder.interactiveMapURL(for: .dark)
let expectedURL: URL = "http://www.foo.com/dea61faf-292b-4774-9660-58fcef89a7f3/style.json?key=some_key"
XCTAssertEqual(url, expectedURL)
}
@@ -62,14 +62,14 @@ final class MapTilerURLBuilderTests: XCTestCase {
builder = configuration
let staticMapURL = builder.staticMapURL(for: .dark,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .topLeft)
let staticMapURL = builder.staticMapTileImageURL(for: .dark,
coordinates: .init(latitude: 1, longitude: 2),
zoomLevel: 5,
size: .init(width: 300, height: 200),
attribution: .topLeft)
XCTAssertNil(staticMapURL)
let dynamicMapURL = builder.dynamicMapURL(for: .light)
let dynamicMapURL = builder.interactiveMapURL(for: .light)
XCTAssertNil(dynamicMapURL)
}
}