From c1eb952db44c6df72cbe0008ea9c1d79441cde90 Mon Sep 17 00:00:00 2001 From: Jacob Fielding Date: Wed, 7 Feb 2024 19:02:26 -0800 Subject: [PATCH] Updated version to latest --- ...a.swift => MLNMapViewCameraUpdating.swift} | 4 ++-- .../Extensions/MapView/MapViewGestures.swift | 2 +- ...nizer.swift => UIGestureRecognizing.swift} | 4 ++-- .../MapLibreSwiftUI/MapViewCoordinator.swift | 6 ++--- .../MapLibreSwiftUI/MapViewModifiers.swift | 2 +- .../Models/Gesture/MapGesture.swift | 2 +- .../Models/MapCamera/CameraChangeReason.swift | 6 ++--- .../Models/MapCamera/CameraPitch.swift | 4 ++-- .../Models/MapCamera/CameraState.swift | 6 ++--- .../Models/MapCamera/MapViewCamera.swift | 12 +++++----- .../MapView/MapViewGestureTests.swift | 22 ++++++++++--------- .../MapViewCoordinatorCameraTests.swift | 11 +++++----- .../MapCamera/CameraChangeReasonTests.swift | 2 +- .../Models/MapCamera/CameraPitchTests.swift | 2 +- .../Models/MapCamera/CameraStateTests.swift | 6 ++--- .../Models/MapCamera/MapViewCameraTests.swift | 6 ++--- 16 files changed, 49 insertions(+), 48 deletions(-) rename Sources/MapLibreSwiftUI/Extensions/MapLibre/{MLNMapViewCamera.swift => MLNMapViewCameraUpdating.swift} (83%) rename Sources/MapLibreSwiftUI/Extensions/UIKit/{UIGestureRecognizer.swift => UIGestureRecognizing.swift} (67%) diff --git a/Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCamera.swift b/Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCameraUpdating.swift similarity index 83% rename from Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCamera.swift rename to Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCameraUpdating.swift index b19012e..d3f2e17 100644 --- a/Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCamera.swift +++ b/Sources/MapLibreSwiftUI/Extensions/MapLibre/MLNMapViewCameraUpdating.swift @@ -4,7 +4,7 @@ import MapLibre import Mockable @Mockable -protocol MLNMapViewCamera: AnyObject { +protocol MLNMapViewCameraUpdating: AnyObject { var userTrackingMode: MLNUserTrackingMode { get set } var minimumPitch: CGFloat { get set } var maximumPitch: CGFloat { get set } @@ -15,6 +15,6 @@ protocol MLNMapViewCamera: AnyObject { func setZoomLevel(_ zoomLevel: Double, animated: Bool) } -extension MLNMapView: MLNMapViewCamera { +extension MLNMapView: MLNMapViewCameraUpdating { // No definition } diff --git a/Sources/MapLibreSwiftUI/Extensions/MapView/MapViewGestures.swift b/Sources/MapLibreSwiftUI/Extensions/MapView/MapViewGestures.swift index e9302df..0e2e914 100644 --- a/Sources/MapLibreSwiftUI/Extensions/MapView/MapViewGestures.swift +++ b/Sources/MapLibreSwiftUI/Extensions/MapView/MapViewGestures.swift @@ -58,7 +58,7 @@ extension MapView { /// - gesture: The gesture definition for this event. /// - sender: The UIKit gesture emitting from the map view. /// - Returns: The calculated context from the sending UIKit gesture - func processContextFromGesture(_ mapView: MLNMapView, gesture: MapGesture, sender: UIGestureRecognizerProtocol) -> MapGestureContext { + func processContextFromGesture(_ mapView: MLNMapView, gesture: MapGesture, sender: UIGestureRecognizing) -> MapGestureContext { // Build the context of the gesture's event. var point: CGPoint switch gesture.method { diff --git a/Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizer.swift b/Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizing.swift similarity index 67% rename from Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizer.swift rename to Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizing.swift index 267a901..eb3b480 100644 --- a/Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizer.swift +++ b/Sources/MapLibreSwiftUI/Extensions/UIKit/UIGestureRecognizing.swift @@ -2,12 +2,12 @@ import UIKit import Mockable @Mockable -protocol UIGestureRecognizerProtocol: AnyObject { +protocol UIGestureRecognizing: AnyObject { var state: UIGestureRecognizer.State { get } func location(in view: UIView?) -> CGPoint func location(ofTouch touchIndex: Int, in view: UIView?) -> CGPoint } -extension UIGestureRecognizer: UIGestureRecognizerProtocol { +extension UIGestureRecognizer: UIGestureRecognizing { // No definition } diff --git a/Sources/MapLibreSwiftUI/MapViewCoordinator.swift b/Sources/MapLibreSwiftUI/MapViewCoordinator.swift index 2e2c1ea..39bfd5f 100644 --- a/Sources/MapLibreSwiftUI/MapViewCoordinator.swift +++ b/Sources/MapLibreSwiftUI/MapViewCoordinator.swift @@ -33,14 +33,14 @@ public class MapViewCoordinator: NSObject { // MARK: - Coordinator API - Camera + Manipulation - func updateCamera(mapView: MLNMapViewCamera, camera: MapViewCamera, animated: Bool) { + func updateCamera(mapView: MLNMapViewCameraUpdating, camera: MapViewCamera, animated: Bool) { guard camera != snapshotCamera else { // No action - camera has not changed. return } switch camera.state { - case .centered(let coordinate): + case .coordinate(let coordinate): mapView.userTrackingMode = .none mapView.setCenter(coordinate, zoomLevel: camera.zoom, @@ -170,8 +170,8 @@ public class MapViewCoordinator: NSObject { extension MapViewCoordinator: MLNMapViewDelegate { public func mapView(_ mapView: MLNMapView, didFinishLoading mglStyle: MLNStyle) { - onStyleLoaded?(mglStyle) addLayers(to: mglStyle) + onStyleLoaded?(mglStyle) } /// The MapView's region has changed with a specific reason. diff --git a/Sources/MapLibreSwiftUI/MapViewModifiers.swift b/Sources/MapLibreSwiftUI/MapViewModifiers.swift index 174cb44..71319f9 100644 --- a/Sources/MapLibreSwiftUI/MapViewModifiers.swift +++ b/Sources/MapLibreSwiftUI/MapViewModifiers.swift @@ -7,7 +7,7 @@ import MapLibre extension MapView { - /// Perform an action when the map view has loaded its style. + /// Perform an action when the map view has loaded its style and all locally added style definitions. /// /// - Parameter perform: The action to perform with the loaded style. /// - Returns: The modified map view. diff --git a/Sources/MapLibreSwiftUI/Models/Gesture/MapGesture.swift b/Sources/MapLibreSwiftUI/Models/Gesture/MapGesture.swift index 7a444f9..f299030 100644 --- a/Sources/MapLibreSwiftUI/Models/Gesture/MapGesture.swift +++ b/Sources/MapLibreSwiftUI/Models/Gesture/MapGesture.swift @@ -24,7 +24,7 @@ public class MapGesture: NSObject { let onChange: (MapGestureContext) -> Void /// The underlying gesture recognizer - var gestureRecognizer: UIGestureRecognizer? + weak var gestureRecognizer: UIGestureRecognizer? /// Create a new gesture recognizer definition for the MapView /// diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraChangeReason.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraChangeReason.swift index a2b5039..adc82d0 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraChangeReason.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraChangeReason.swift @@ -15,11 +15,11 @@ public enum CameraChangeReason: Hashable { /// Initialize a Swift CameraChangeReason from the MLN NSOption. /// - /// This method will only show the largest reason. If you need a full history of the full bit range, - /// use MLNCameraChangeReason directly + /// This method will only show the largest bitwise reason contained in MLNCameraChangeReason. + /// If you need a full history of the full bit range, use MLNCameraChangeReason directly /// /// - Parameter mlnCameraChangeReason: The camera change reason options list from the MapLibre MapViewDelegate - public init?(_ mlnCameraChangeReason: MLNCameraChangeReason) { + init?(_ mlnCameraChangeReason: MLNCameraChangeReason) { switch mlnCameraChangeReason.largestBitwiseReason { case .programmatic: diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraPitch.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraPitch.swift index a6c7492..56dbc83 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraPitch.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraPitch.swift @@ -8,7 +8,7 @@ public enum CameraPitch: Hashable { case free /// The user is free to control pitch within the minimum and maximum range. - case withinRange(minimum: Double, maximum: Double) + case freeWithinRange(minimum: Double, maximum: Double) /// The pitch is fixed to a certain value. case fixed(Double) @@ -21,7 +21,7 @@ public enum CameraPitch: Hashable { case .free: return 0...60 // TODO: set this to a maplibre constant (this is available on Android, but maybe not iOS)? - case .withinRange(minimum: let minimum, maximum: let maximum): + case .freeWithinRange(minimum: let minimum, maximum: let maximum): return minimum...maximum case .fixed(let value): return value...value diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift index 02e05c9..2ce6225 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift @@ -5,7 +5,7 @@ import MapLibre public enum CameraState: Hashable { /// Centered on a coordinate - case centered(onCenter: CLLocationCoordinate2D) + case coordinate(onCenter: CLLocationCoordinate2D) /// Follow the user's location using the MapView's internal camera. /// @@ -36,8 +36,8 @@ extension CameraState: CustomDebugStringConvertible { public var debugDescription: String { switch self { - case .centered(onCenter: let onCenter): - return "CameraState.center(onCenter: \(onCenter)" + case .coordinate(onCenter: let onCenter): + return "CameraState.coordinate(onCenter: \(onCenter)" case .trackingUserLocation: return "CameraState.trackingUserLocation" case .trackingUserLocationWithHeading: diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift index 7196df6..84be6fc 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift @@ -31,7 +31,7 @@ public struct MapViewCamera: Hashable { /// /// - Returns: The constructed MapViewCamera. public static func `default`() -> MapViewCamera { - return MapViewCamera(state: .centered(onCenter: Defaults.coordinate), + return MapViewCamera(state: .coordinate(onCenter: Defaults.coordinate), zoom: Defaults.zoom, pitch: Defaults.pitch, direction: Defaults.direction, @@ -43,7 +43,7 @@ public struct MapViewCamera: Hashable { /// - Parameters: /// - coordinate: The coordinate to center the map on. /// - zoom: The zoom level. - /// - pitch: The camera pitch. Default is 90 (straight down). + /// - pitch: Set the camera pitch method. /// - direction: The course. Default is 0 (North). /// - Returns: The constructed MapViewCamera. public static func center(_ coordinate: CLLocationCoordinate2D, @@ -52,7 +52,7 @@ public struct MapViewCamera: Hashable { direction: CLLocationDirection = Defaults.direction, reason: CameraChangeReason? = nil) -> MapViewCamera { - return MapViewCamera(state: .centered(onCenter: coordinate), + return MapViewCamera(state: .coordinate(onCenter: coordinate), zoom: zoom, pitch: pitch, direction: direction, @@ -65,7 +65,7 @@ public struct MapViewCamera: Hashable { /// /// - Parameters: /// - zoom: Set the desired zoom. This is a one time event and the user can manipulate their zoom after unlike pitch. - /// - pitch: Provide a fixed pitch value. The user will not be able to adjust pitch using gestures when this is set. Use nil/default to allow user control. + /// - pitch: Set the camera pitch method. /// - Returns: The MapViewCamera representing the scenario public static func trackUserLocation(zoom: Double = Defaults.zoom, pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { @@ -84,7 +84,7 @@ public struct MapViewCamera: Hashable { /// /// - Parameters: /// - zoom: Set the desired zoom. This is a one time event and the user can manipulate their zoom after unlike pitch. - /// - pitch: Provide a fixed pitch value. The user will not be able to adjust pitch using gestures when this is set. Use nil/default to allow user control. + /// - pitch: Set the camera pitch method. /// - Returns: The MapViewCamera representing the scenario public static func trackUserLocationWithHeading(zoom: Double = Defaults.zoom, pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { @@ -103,7 +103,7 @@ public struct MapViewCamera: Hashable { /// /// - Parameters: /// - zoom: Set the desired zoom. This is a one time event and the user can manipulate their zoom after unlike pitch. - /// - pitch: Provide a fixed pitch value. The user will not be able to adjust pitch using gestures when this is set. Use nil/default to allow user control. + /// - pitch: Set the camera pitch method. /// - Returns: The MapViewCamera representing the scenario public static func trackUserLocationWithCourse(zoom: Double = Defaults.zoom, pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { diff --git a/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift b/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift index 417ac34..e4b8e3a 100644 --- a/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift +++ b/Tests/MapLibreSwiftUITests/MapView/MapViewGestureTests.swift @@ -11,13 +11,17 @@ final class MapViewGestureTests: XCTestCase { // MARK: Gesture View Modifiers func testMapViewOnTapGestureModifier() { - let newMapView = mapView.onTapMapGesture { _ in } + let newMapView = mapView.onTapMapGesture { _ in + // Do nothing + } XCTAssertEqual(newMapView.gestures.first?.method, .tap()) } func testMapViewOnLongPressGestureModifier() { - let newMapView = mapView.onLongPressMapGesture { _ in } + let newMapView = mapView.onLongPressMapGesture { _ in + // Do nothing + } XCTAssertEqual(newMapView.gestures.first?.method, .longPress()) } @@ -26,10 +30,10 @@ final class MapViewGestureTests: XCTestCase { func testTapGesture() { let gesture = MapGesture(method: .tap(numberOfTaps: 2)) { _ in - // No capture + // Do nothing } - let mockTapGesture = MockUIGestureRecognizerProtocol() + let mockTapGesture = MockUIGestureRecognizing() given(mockTapGesture) .state.willReturn(.ended) @@ -44,18 +48,17 @@ final class MapViewGestureTests: XCTestCase { XCTAssertEqual(result.gestureMethod, .tap(numberOfTaps: 2)) XCTAssertEqual(result.point, CGPoint(x: 10, y: 10)) - - // TODO: Delete this? The MLNMapView is technically converting something. Probably not reliably, but it could still be useful to track. + // This is what the un-rendered map view returns. We're simply testing it returns something. XCTAssertEqual(result.coordinate.latitude, 15, accuracy: 1) XCTAssertEqual(result.coordinate.longitude, -15, accuracy: 1) } func testLongPressGesture() { let gesture = MapGesture(method: .longPress(minimumDuration: 1)) { _ in - // No capture + // Do nothing } - let mockTapGesture = MockUIGestureRecognizerProtocol() + let mockTapGesture = MockUIGestureRecognizing() given(mockTapGesture) .state.willReturn(.ended) @@ -70,8 +73,7 @@ final class MapViewGestureTests: XCTestCase { XCTAssertEqual(result.gestureMethod, .longPress(minimumDuration: 1)) XCTAssertEqual(result.point, CGPoint(x: 10, y: 10)) - - // TODO: Delete this? The MLNMapView is technically converting something. Probably not reliably, but it could still be useful to track. + // This is what the un-rendered map view returns. We're simply testing it returns something. XCTAssertEqual(result.coordinate.latitude, 15, accuracy: 1) XCTAssertEqual(result.coordinate.longitude, -15, accuracy: 1) } diff --git a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift index 0a7c45c..39a2f64 100644 --- a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift +++ b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift @@ -5,12 +5,12 @@ import CoreLocation final class MapViewCoordinatorCameraTests: XCTestCase { - var maplibreMapView: MockMLNMapViewCamera! + var maplibreMapView: MockMLNMapViewCameraUpdating! var mapView: MapView! var coordinator: MapView.Coordinator! override func setUp() async throws { - maplibreMapView = MockMLNMapViewCamera() + maplibreMapView = MockMLNMapViewCameraUpdating() mapView = MapView(styleURL: URL(string: "https://maplibre.org")!) coordinator = MapView.Coordinator(parent: mapView) { _, _ in // No action @@ -21,11 +21,12 @@ final class MapViewCoordinatorCameraTests: XCTestCase { let camera: MapViewCamera = .default() coordinator.updateCamera(mapView: maplibreMapView, camera: camera, animated: false) - // Run a second update. + // Run a second update. We're testing that the snapshotCamera correctly exits the function + // when nothing changed. coordinator.updateCamera(mapView: maplibreMapView, camera: camera, animated: false) - // Note all of the actions only allow 1 count of set even though we've run the action - // twice. + // All of the actions only allow 1 count of set even though we've run the action twice. + // This verifies the comment above. verify(maplibreMapView) .userTrackingMode(newValue: .value(.none)) .setterCalled(count: 1) diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraChangeReasonTests.swift b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraChangeReasonTests.swift index cd265c1..3cfaa8e 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraChangeReasonTests.swift +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraChangeReasonTests.swift @@ -40,7 +40,7 @@ final class CameraChangeReasonTests: XCTestCase { } func testGestureZoomIn() { - let mlnReason: MLNCameraChangeReason = [.programmatic, .gestureZoomIn] + let mlnReason: MLNCameraChangeReason = [.gestureZoomIn, .programmatic, ] XCTAssertEqual(CameraChangeReason(mlnReason), .gestureZoomIn) } diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraPitchTests.swift b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraPitchTests.swift index 71d1b2b..36c5401 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraPitchTests.swift +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraPitchTests.swift @@ -10,7 +10,7 @@ final class CameraPitchTests: XCTestCase { } func testRangePitch() { - let pitch = CameraPitch.withinRange(minimum: 9, maximum: 29) + let pitch = CameraPitch.freeWithinRange(minimum: 9, maximum: 29) XCTAssertEqual(pitch.rangeValue.lowerBound, 9) XCTAssertEqual(pitch.rangeValue.upperBound, 29) } diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift index 4fb56d1..b8eef86 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift @@ -6,9 +6,9 @@ final class CameraStateTests: XCTestCase { func testCenterCameraState() { let expectedCoordinate = CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4) - let state: CameraState = .centered(onCenter: expectedCoordinate) - XCTAssertEqual(state, .centered(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4))) - XCTAssertEqual(String(describing: state), "CameraState.center(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4)") + let state: CameraState = .coordinate(onCenter: expectedCoordinate) + XCTAssertEqual(state, .coordinate(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4))) + XCTAssertEqual(String(describing: state), "CameraState.coordinate(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4)") } func testTrackingUserLocation() { diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/MapViewCameraTests.swift b/Tests/MapLibreSwiftUITests/Models/MapCamera/MapViewCameraTests.swift index 480324a..69bff3a 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/MapViewCameraTests.swift +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/MapViewCameraTests.swift @@ -4,12 +4,10 @@ import CoreLocation final class MapViewCameraTests: XCTestCase { - - func testCenterCamera() { let expectedCoordinate = CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4) - let state: CameraState = .centered(onCenter: expectedCoordinate) - XCTAssertEqual(state, .centered(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4))) + let state: CameraState = .coordinate(onCenter: expectedCoordinate) + XCTAssertEqual(state, .coordinate(onCenter: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4))) } func testTrackingUserLocation() {