From 5da79ef567ecb2d57caceb56ad270de71219b8d5 Mon Sep 17 00:00:00 2001 From: PW Date: Mon, 8 Jul 2024 13:13:16 +0200 Subject: [PATCH] generic init implementation to keep cleaner callsite --- Sources/MapLibreSwiftUI/Examples/Camera.swift | 2 +- .../MapLibreSwiftUI/Examples/Gestures.swift | 4 +- Sources/MapLibreSwiftUI/Examples/Layers.swift | 14 +++---- Sources/MapLibreSwiftUI/Examples/Other.swift | 2 +- .../MapLibreSwiftUI/Examples/Polyline.swift | 2 +- .../Examples/User Location.swift | 4 +- Sources/MapLibreSwiftUI/MapView.swift | 39 +++++++++++-------- .../Examples/LayerPreviewTests.swift | 15 ++++--- .../Examples/MapControlsTests.swift | 22 +++++++---- .../MapView/MapViewGestureTests.swift | 4 +- .../MapViewCoordinatorCameraTests.swift | 1 + 11 files changed, 66 insertions(+), 43 deletions(-) diff --git a/Sources/MapLibreSwiftUI/Examples/Camera.swift b/Sources/MapLibreSwiftUI/Examples/Camera.swift index 3853e03..a7f0f11 100644 --- a/Sources/MapLibreSwiftUI/Examples/Camera.swift +++ b/Sources/MapLibreSwiftUI/Examples/Camera.swift @@ -9,7 +9,7 @@ struct CameraDirectManipulationPreview: View { var targetCameraAfterDelay: MapViewCamera? = nil var body: some View { - MapView(styleURL: styleURL, camera: $camera) + MapView(styleURL: styleURL, camera: $camera) .onStyleLoaded { _ in onStyleLoaded?() } diff --git a/Sources/MapLibreSwiftUI/Examples/Gestures.swift b/Sources/MapLibreSwiftUI/Examples/Gestures.swift index f7e8575..a2f0d38 100644 --- a/Sources/MapLibreSwiftUI/Examples/Gestures.swift +++ b/Sources/MapLibreSwiftUI/Examples/Gestures.swift @@ -5,7 +5,7 @@ import SwiftUI #Preview("Tappable Circles") { let tappableID = "simple-circles" - return MapView(styleURL: demoTilesURL) { + return MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon CircleStyleLayer(identifier: tappableID, source: pointSource) .radius(16) @@ -24,7 +24,7 @@ import SwiftUI } #Preview("Tappable Countries") { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .onTapMapGesture(on: ["countries-fill"], onTapChanged: { _, features in print("Tapped on \(features.first?.description ?? "")") }) diff --git a/Sources/MapLibreSwiftUI/Examples/Layers.swift b/Sources/MapLibreSwiftUI/Examples/Layers.swift index 7096bc9..bbd40fd 100644 --- a/Sources/MapLibreSwiftUI/Examples/Layers.swift +++ b/Sources/MapLibreSwiftUI/Examples/Layers.swift @@ -34,7 +34,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c } #Preview("Rose Tint") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Silly example: a background layer on top of everything to create a tint effect BackgroundLayer(identifier: "rose-colored-glasses") .backgroundColor(.systemPink.withAlphaComponent(0.3)) @@ -44,7 +44,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c } #Preview("Simple Symbol") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "simple-symbols", source: pointSource) .iconImage(UIImage(systemName: "mappin")!) @@ -53,7 +53,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c } #Preview("Rotated Symbols (Const)") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "rotated-symbols", source: pointSource) .iconImage(UIImage(systemName: "location.north.circle.fill")!) @@ -63,7 +63,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c } #Preview("Rotated Symbols (Dynamic)") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "rotated-symbols", source: pointSource) .iconImage(UIImage(systemName: "location.north.circle.fill")!) @@ -73,7 +73,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c } #Preview("Circles with Symbols") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon CircleStyleLayer(identifier: "simple-circles", source: pointSource) .radius(16) @@ -94,7 +94,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c zoom: 5, direction: 0 ) - return MapView(styleURL: demoTilesURL, camera: $camera) { + return MapView(styleURL: demoTilesURL, camera: $camera) { // Clusters pins when they would touch // Cluster == YES shows only those pins that are clustered, using .text @@ -135,7 +135,7 @@ let clustered = ShapeSource(identifier: "points", options: [.clustered: true, .c // TODO: Fixme // #Preview("Multiple Symbol Icons") { -// MapView(styleURL: demoTilesURL) { +// MapView(styleURL: demoTilesURL) { // // Simple symbol layer demonstration with an icon // SymbolStyleLayer(identifier: "simple-symbols", source: pointSource) // .iconImage(attribute: "icon", diff --git a/Sources/MapLibreSwiftUI/Examples/Other.swift b/Sources/MapLibreSwiftUI/Examples/Other.swift index 05aac9e..5c76bd9 100644 --- a/Sources/MapLibreSwiftUI/Examples/Other.swift +++ b/Sources/MapLibreSwiftUI/Examples/Other.swift @@ -4,7 +4,7 @@ import MapLibreSwiftDSL import SwiftUI #Preview("Unsafe MapView Modifier") { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // A collection of points with various // attributes let pointSource = ShapeSource(identifier: "points") { diff --git a/Sources/MapLibreSwiftUI/Examples/Polyline.swift b/Sources/MapLibreSwiftUI/Examples/Polyline.swift index d202c86..20e22ce 100644 --- a/Sources/MapLibreSwiftUI/Examples/Polyline.swift +++ b/Sources/MapLibreSwiftUI/Examples/Polyline.swift @@ -7,7 +7,7 @@ struct PolylinePreview: View { let styleURL: URL var body: some View { - MapView(styleURL: styleURL, + MapView(styleURL: styleURL, camera: .constant(.center(samplePedestrianWaypoints.first!, zoom: 14))) { // Note: This line does not add the source to the style as if it diff --git a/Sources/MapLibreSwiftUI/Examples/User Location.swift b/Sources/MapLibreSwiftUI/Examples/User Location.swift index 3c1e580..b30b575 100644 --- a/Sources/MapLibreSwiftUI/Examples/User Location.swift +++ b/Sources/MapLibreSwiftUI/Examples/User Location.swift @@ -14,7 +14,7 @@ private let locationManager = StaticLocationManager(initialLocation: CLLocation( )) #Preview("Track user location") { - MapView( + MapView( styleURL: demoTilesURL, camera: .constant(.trackUserLocation(zoom: 4, pitch: 45)), locationManager: locationManager @@ -24,7 +24,7 @@ private let locationManager = StaticLocationManager(initialLocation: CLLocation( } #Preview("Track user location with Course") { - MapView( + MapView( styleURL: demoTilesURL, camera: .constant(.trackUserLocationWithCourse(zoom: 4, pitch: 45)), locationManager: locationManager diff --git a/Sources/MapLibreSwiftUI/MapView.swift b/Sources/MapLibreSwiftUI/MapView.swift index 7e9394a..265c1f0 100644 --- a/Sources/MapLibreSwiftUI/MapView.swift +++ b/Sources/MapLibreSwiftUI/MapView.swift @@ -3,13 +3,33 @@ import MapLibre import MapLibreSwiftDSL import SwiftUI + +public extension MapView where T == MapViewController { + + @MainActor + init( + styleURL: URL, + camera: Binding = .constant(.default()), + locationManager: MLNLocationManager? = nil, + @MapViewContentBuilder _ makeMapContent: () -> [StyleLayerDefinition] = { [] } + ) { + makeViewController = { + return MapViewController() + + } + styleSource = .url(styleURL) + _camera = camera + userLayers = makeMapContent() + self.locationManager = locationManager + } +} public struct MapView: UIViewControllerRepresentable { public typealias UIViewControllerType = T var cameraDisabled: Bool = true @Binding var camera: MapViewCamera - let makeViewController: (() -> T)? + let makeViewController: (() -> T) let styleSource: MapStyleSource let userLayers: [StyleLayerDefinition] @@ -50,19 +70,6 @@ public struct MapView: UIViewControllerRepresentable { self.locationManager = locationManager } - public init( - styleURL: URL, - camera: Binding = .constant(.default()), - locationManager: MLNLocationManager? = nil, - @MapViewContentBuilder _ makeMapContent: () -> [StyleLayerDefinition] = { [] } - ) { - makeViewController = nil - styleSource = .url(styleURL) - _camera = camera - userLayers = makeMapContent() - self.locationManager = locationManager - } - public func makeCoordinator() -> MapViewCoordinator { MapViewCoordinator( parent: self, @@ -73,7 +80,7 @@ public struct MapView: UIViewControllerRepresentable { public func makeUIViewController(context: Context) -> T { // Create the map view - let controller = makeViewController?() ?? T() + let controller = makeViewController() controller.mapView.delegate = context.coordinator context.coordinator.mapView = controller.mapView @@ -145,7 +152,7 @@ public struct MapView: UIViewControllerRepresentable { } #Preview { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .ignoresSafeArea(.all) .previewDisplayName("Vanilla Map") diff --git a/Tests/MapLibreSwiftUITests/Examples/LayerPreviewTests.swift b/Tests/MapLibreSwiftUITests/Examples/LayerPreviewTests.swift index 167dc10..b1e98cb 100644 --- a/Tests/MapLibreSwiftUITests/Examples/LayerPreviewTests.swift +++ b/Tests/MapLibreSwiftUITests/Examples/LayerPreviewTests.swift @@ -23,9 +23,10 @@ final class LayerPreviewTests: XCTestCase { } } + @MainActor func testRoseTint() { assertView { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Silly example: a background layer on top of everything to create a tint effect BackgroundLayer(identifier: "rose-colored-glasses") .backgroundColor(.systemPink.withAlphaComponent(0.3)) @@ -34,9 +35,10 @@ final class LayerPreviewTests: XCTestCase { } } + @MainActor func testSimpleSymbol() { assertView { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "simple-symbols", source: pointSource) .iconImage(UIImage(systemName: "mappin")!) @@ -44,9 +46,10 @@ final class LayerPreviewTests: XCTestCase { } } + @MainActor func testRotatedSymbolConst() { assertView { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "rotated-symbols", source: pointSource) .iconImage(UIImage(systemName: "location.north.circle.fill")!) @@ -55,9 +58,10 @@ final class LayerPreviewTests: XCTestCase { } } + @MainActor func testRotatedSymboleDynamic() { assertView { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon SymbolStyleLayer(identifier: "rotated-symbols", source: pointSource) .iconImage(UIImage(systemName: "location.north.circle.fill")!) @@ -66,9 +70,10 @@ final class LayerPreviewTests: XCTestCase { } } + @MainActor func testCirclesWithSymbols() { assertView { - MapView(styleURL: demoTilesURL) { + MapView(styleURL: demoTilesURL) { // Simple symbol layer demonstration with an icon CircleStyleLayer(identifier: "simple-circles", source: pointSource) .radius(16) diff --git a/Tests/MapLibreSwiftUITests/Examples/MapControlsTests.swift b/Tests/MapLibreSwiftUITests/Examples/MapControlsTests.swift index 4d40b7c..dc3c8ea 100644 --- a/Tests/MapLibreSwiftUITests/Examples/MapControlsTests.swift +++ b/Tests/MapLibreSwiftUITests/Examples/MapControlsTests.swift @@ -4,27 +4,31 @@ import XCTest @testable import MapLibreSwiftUI final class MapControlsTests: XCTestCase { + + @MainActor func testEmptyControls() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { // No controls } } } + @MainActor func testLogoOnly() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { LogoView() } } } + @MainActor func testLogoChangePosition() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { LogoView() .position(.topLeft) @@ -32,18 +36,20 @@ final class MapControlsTests: XCTestCase { } } + @MainActor func testCompassOnly() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { CompassView() } } } + @MainActor func testCompassChangePosition() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { CompassView() .position(.topLeft) @@ -51,18 +57,20 @@ final class MapControlsTests: XCTestCase { } } + @MainActor func testAttributionOnly() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { AttributionButton() } } } + @MainActor func testAttributionChangePosition() { assertView { - MapView(styleURL: demoTilesURL) + MapView(styleURL: demoTilesURL) .mapControls { AttributionButton() .position(.topLeft) diff --git a/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift b/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift index 031f972..9b17c8b 100644 --- a/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift +++ b/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift @@ -5,7 +5,9 @@ import XCTest final class MapViewGestureTests: XCTestCase { let maplibreMapView = MLNMapView() - let mapView = MapView(styleURL: URL(string: "https://maplibre.org")!) + + @MainActor + let mapView = MapView(styleURL: URL(string: "https://maplibre.org")!) // MARK: Gesture View Modifiers diff --git a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift index 890f262..3cbff2b 100644 --- a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift +++ b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift @@ -8,6 +8,7 @@ final class MapViewCoordinatorCameraTests: XCTestCase { var mapView: MapView! var coordinator: MapView.Coordinator! + @MainActor override func setUp() async throws { maplibreMapView = MockMLNMapViewCameraUpdating() given(maplibreMapView).frame.willReturn(.zero)