diff --git a/Sources/MapLibreSwiftUI/MapViewCoordinator.swift b/Sources/MapLibreSwiftUI/MapViewCoordinator.swift index 1a13700..5259f0a 100644 --- a/Sources/MapLibreSwiftUI/MapViewCoordinator.swift +++ b/Sources/MapLibreSwiftUI/MapViewCoordinator.swift @@ -48,21 +48,29 @@ public class MapViewCoordinator: NSObject { } switch camera.state { - case let .centered(onCoordinate: coordinate, zoom: zoom): + case let .centered(onCoordinate: coordinate, zoom: zoom, pitch: pitch, direction: direction): mapView.userTrackingMode = .none mapView.setCenter(coordinate, zoomLevel: zoom, - direction: camera.direction, + direction: direction, animated: animated) - case let .trackingUserLocation(zoom: zoom): + mapView.minimumPitch = pitch.rangeValue.lowerBound + mapView.maximumPitch = pitch.rangeValue.upperBound + case let .trackingUserLocation(zoom: zoom, pitch: pitch): mapView.userTrackingMode = .follow mapView.setZoomLevel(zoom, animated: animated) - case let .trackingUserLocationWithHeading(zoom: zoom): + mapView.minimumPitch = pitch.rangeValue.lowerBound + mapView.maximumPitch = pitch.rangeValue.upperBound + case let .trackingUserLocationWithHeading(zoom: zoom, pitch: pitch): mapView.userTrackingMode = .followWithHeading mapView.setZoomLevel(zoom, animated: animated) - case let .trackingUserLocationWithCourse(zoom: zoom): + mapView.minimumPitch = pitch.rangeValue.lowerBound + mapView.maximumPitch = pitch.rangeValue.upperBound + case let .trackingUserLocationWithCourse(zoom: zoom, pitch: pitch): mapView.userTrackingMode = .followWithCourse mapView.setZoomLevel(zoom, animated: animated) + mapView.minimumPitch = pitch.rangeValue.lowerBound + mapView.maximumPitch = pitch.rangeValue.upperBound case let .rect(boundingBox, padding): mapView.setVisibleCoordinateBounds(boundingBox, edgePadding: padding, @@ -73,10 +81,6 @@ public class MapViewCoordinator: NSObject { break } - // Set the correct pitch range. - mapView.minimumPitch = camera.pitch.rangeValue.lowerBound - mapView.maximumPitch = camera.pitch.rangeValue.upperBound - snapshotCamera = camera } diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift index e2f7546..ecb36f2 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/CameraState.swift @@ -4,25 +4,30 @@ import MapLibre /// The CameraState is used to understand the current context of the MapView's camera. public enum CameraState: Hashable { /// Centered on a coordinate - case centered(onCoordinate: CLLocationCoordinate2D, zoom: Double) + case centered( + onCoordinate: CLLocationCoordinate2D, + zoom: Double, + pitch: CameraPitch, + direction: CLLocationDirection + ) /// Follow the user's location using the MapView's internal camera. /// /// This feature uses the MLNMapView's userTrackingMode to .follow which automatically /// follows the user from within the MLNMapView. - case trackingUserLocation(zoom: Double) + case trackingUserLocation(zoom: Double, pitch: CameraPitch) /// Follow the user's location using the MapView's internal camera with the user's heading. /// /// This feature uses the MLNMapView's userTrackingMode to .followWithHeading which automatically /// follows the user from within the MLNMapView. - case trackingUserLocationWithHeading(zoom: Double) + case trackingUserLocationWithHeading(zoom: Double, pitch: CameraPitch) /// Follow the user's location using the MapView's internal camera with the users' course /// /// This feature uses the MLNMapView's userTrackingMode to .followWithCourse which automatically /// follows the user from within the MLNMapView. - case trackingUserLocationWithCourse(zoom: Double) + case trackingUserLocationWithCourse(zoom: Double, pitch: CameraPitch) /// Centered on a bounding box/rectangle. case rect( @@ -37,8 +42,8 @@ public enum CameraState: Hashable { extension CameraState: CustomDebugStringConvertible { public var debugDescription: String { switch self { - case let .centered(onCoordinate: coordinate, zoom: zoom): - "CameraState.centered(onCoordinate: \(coordinate), zoom: \(zoom))" + case let .centered(onCoordinate: coordinate, zoom: zoom, pitch: pitch, direction: direction): + "CameraState.centered(onCoordinate: \(coordinate), zoom: \(zoom), pitch: \(pitch), direction: \(direction))" case let .trackingUserLocation(zoom: zoom): "CameraState.trackingUserLocation(zoom: \(zoom))" case let .trackingUserLocationWithHeading(zoom: zoom): diff --git a/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift b/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift index 7caca65..cb1345e 100644 --- a/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift +++ b/Sources/MapLibreSwiftUI/Models/MapCamera/MapViewCamera.swift @@ -14,8 +14,6 @@ public struct MapViewCamera: Hashable { } public var state: CameraState - public var pitch: CameraPitch - public var direction: CLLocationDirection /// The reason the camera was changed. /// @@ -29,10 +27,15 @@ public struct MapViewCamera: Hashable { /// /// - Returns: The constructed MapViewCamera. public static func `default`() -> MapViewCamera { - MapViewCamera(state: .centered(onCoordinate: Defaults.coordinate, zoom: Defaults.zoom), - pitch: Defaults.pitch, - direction: Defaults.direction, - lastReasonForChange: .programmatic) + MapViewCamera( + state: .centered( + onCoordinate: Defaults.coordinate, + zoom: Defaults.zoom, + pitch: Defaults.pitch, + direction: Defaults.direction + ), + lastReasonForChange: .programmatic + ) } /// Center the map on a specific location. @@ -49,9 +52,7 @@ public struct MapViewCamera: Hashable { direction: CLLocationDirection = Defaults.direction, reason: CameraChangeReason? = nil) -> MapViewCamera { - MapViewCamera(state: .centered(onCoordinate: coordinate, zoom: zoom), - pitch: pitch, - direction: direction, + MapViewCamera(state: .centered(onCoordinate: coordinate, zoom: zoom, pitch: pitch, direction: direction), lastReasonForChange: reason) } @@ -68,9 +69,7 @@ public struct MapViewCamera: Hashable { pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { // Coordinate is ignored when tracking user location. However, pitch and zoom are valid. - MapViewCamera(state: .trackingUserLocation(zoom: zoom), - pitch: pitch, - direction: Defaults.direction, + MapViewCamera(state: .trackingUserLocation(zoom: zoom, pitch: pitch), lastReasonForChange: .programmatic) } @@ -87,9 +86,7 @@ public struct MapViewCamera: Hashable { pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { // Coordinate is ignored when tracking user location. However, pitch and zoom are valid. - MapViewCamera(state: .trackingUserLocationWithHeading(zoom: zoom), - pitch: pitch, - direction: Defaults.direction, + MapViewCamera(state: .trackingUserLocationWithHeading(zoom: zoom, pitch: pitch), lastReasonForChange: .programmatic) } @@ -106,9 +103,7 @@ public struct MapViewCamera: Hashable { pitch: CameraPitch = Defaults.pitch) -> MapViewCamera { // Coordinate is ignored when tracking user location. However, pitch and zoom are valid. - MapViewCamera(state: .trackingUserLocationWithCourse(zoom: zoom), - pitch: pitch, - direction: Defaults.direction, + MapViewCamera(state: .trackingUserLocationWithCourse(zoom: zoom, pitch: pitch), lastReasonForChange: .programmatic) } @@ -122,10 +117,7 @@ public struct MapViewCamera: Hashable { _ box: MLNCoordinateBounds, edgePadding: UIEdgeInsets = .init(top: 20, left: 20, bottom: 20, right: 20) ) -> MapViewCamera { - // TODO: pitch & direction are ignored. We should extract these into the state parameter. MapViewCamera(state: .rect(boundingBox: box, edgePadding: edgePadding), - pitch: Defaults.pitch, - direction: Defaults.direction, lastReasonForChange: .programmatic) } } diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift index 8d2ff09..0bbbae1 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/CameraStateTests.swift @@ -7,26 +7,26 @@ final class CameraStateTests: XCTestCase { let coordinate = CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4) func testCenterCameraState() { - let state: CameraState = .centered(onCoordinate: coordinate, zoom: 4) - XCTAssertEqual(state, .centered(onCoordinate: coordinate, zoom: 4)) + let state: CameraState = .centered(onCoordinate: coordinate, zoom: 4, pitch: .free, direction: 42) + XCTAssertEqual(state, .centered(onCoordinate: coordinate, zoom: 4, pitch: .free, direction: 42)) assertSnapshot(of: state, as: .description) } func testTrackingUserLocation() { - let state: CameraState = .trackingUserLocation(zoom: 4) - XCTAssertEqual(state, .trackingUserLocation(zoom: 4)) + let state: CameraState = .trackingUserLocation(zoom: 4, pitch: .free) + XCTAssertEqual(state, .trackingUserLocation(zoom: 4, pitch: .free)) assertSnapshot(of: state, as: .description) } func testTrackingUserLocationWithHeading() { - let state: CameraState = .trackingUserLocationWithHeading(zoom: 4) - XCTAssertEqual(state, .trackingUserLocationWithHeading(zoom: 4)) + let state: CameraState = .trackingUserLocationWithHeading(zoom: 4, pitch: .free) + XCTAssertEqual(state, .trackingUserLocationWithHeading(zoom: 4, pitch: .free)) assertSnapshot(of: state, as: .description) } func testTrackingUserLocationWithCourse() { - let state: CameraState = .trackingUserLocationWithCourse(zoom: 4) - XCTAssertEqual(state, .trackingUserLocationWithCourse(zoom: 4)) + let state: CameraState = .trackingUserLocationWithCourse(zoom: 4, pitch: .free) + XCTAssertEqual(state, .trackingUserLocationWithCourse(zoom: 4, pitch: .free)) assertSnapshot(of: state, as: .description) } diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testCenterCameraState.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testCenterCameraState.1.txt index 2308330..6d2f3a0 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testCenterCameraState.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testCenterCameraState.1.txt @@ -1 +1 @@ -CameraState.centered(onCoordinate: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4), zoom: 4.0) \ No newline at end of file +CameraState.centered(onCoordinate: CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4), zoom: 4.0, pitch: free, direction: 42.0) \ No newline at end of file diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocation.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocation.1.txt index f12ebc7..8c216f7 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocation.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocation.1.txt @@ -1 +1 @@ -CameraState.trackingUserLocation(zoom: 4.0) \ No newline at end of file +CameraState.trackingUserLocation(zoom: (4.0, MapLibreSwiftUI.CameraPitch.free)) \ No newline at end of file diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithCourse.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithCourse.1.txt index 43551e8..639e899 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithCourse.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithCourse.1.txt @@ -1 +1 @@ -CameraState.trackingUserLocationWithCourse(zoom: 4.0) \ No newline at end of file +CameraState.trackingUserLocationWithCourse(zoom: (4.0, MapLibreSwiftUI.CameraPitch.free)) \ No newline at end of file diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithHeading.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithHeading.1.txt index 5f4fe12..13adebe 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithHeading.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/CameraStateTests/testTrackingUserLocationWithHeading.1.txt @@ -1 +1 @@ -CameraState.trackingUserLocationWithHeading(zoom: 4.0) \ No newline at end of file +CameraState.trackingUserLocationWithHeading(zoom: (4.0, MapLibreSwiftUI.CameraPitch.free)) \ No newline at end of file diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testBoundingBox.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testBoundingBox.1.txt index cca3c0e..092ae5f 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testBoundingBox.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testBoundingBox.1.txt @@ -1,8 +1,6 @@ ▿ MapViewCamera - - direction: 0.0 ▿ lastReasonForChange: Optional - some: CameraChangeReason.programmatic - - pitch: CameraPitch.free ▿ state: CameraState ▿ rect: (2 elements) ▿ boundingBox: MLNCoordinateBounds diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testCenterCamera.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testCenterCamera.1.txt index 359bbb5..d3c277d 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testCenterCamera.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testCenterCamera.1.txt @@ -1,13 +1,13 @@ ▿ MapViewCamera - - direction: 23.0 - lastReasonForChange: Optional.none - ▿ pitch: CameraPitch - ▿ freeWithinRange: (2 elements) - - minimum: 12.0 - - maximum: 34.0 ▿ state: CameraState - ▿ centered: (2 elements) + ▿ centered: (4 elements) ▿ onCoordinate: CLLocationCoordinate2D - latitude: 12.3 - longitude: 23.4 - zoom: 5.0 + ▿ pitch: CameraPitch + ▿ freeWithinRange: (2 elements) + - minimum: 12.0 + - maximum: 34.0 + - direction: 23.0 diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithCourse.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithCourse.1.txt index b556f5d..4c5c2d5 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithCourse.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithCourse.1.txt @@ -1,11 +1,10 @@ ▿ MapViewCamera - - direction: 0.0 ▿ lastReasonForChange: Optional - some: CameraChangeReason.programmatic - ▿ pitch: CameraPitch - ▿ freeWithinRange: (2 elements) - - minimum: 12.0 - - maximum: 34.0 ▿ state: CameraState - ▿ trackingUserLocationWithCourse: (1 element) + ▿ trackingUserLocationWithCourse: (2 elements) - zoom: 18.0 + ▿ pitch: CameraPitch + ▿ freeWithinRange: (2 elements) + - minimum: 12.0 + - maximum: 34.0 diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithHeading.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithHeading.1.txt index c4aa6b8..47942b2 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithHeading.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackUserLocationWithHeading.1.txt @@ -1,8 +1,7 @@ ▿ MapViewCamera - - direction: 0.0 ▿ lastReasonForChange: Optional - some: CameraChangeReason.programmatic - - pitch: CameraPitch.free ▿ state: CameraState - ▿ trackingUserLocationWithHeading: (1 element) + ▿ trackingUserLocationWithHeading: (2 elements) - zoom: 10.0 + - pitch: CameraPitch.free diff --git a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackingUserLocation.1.txt b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackingUserLocation.1.txt index 406bffe..922b6bb 100644 --- a/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackingUserLocation.1.txt +++ b/Tests/MapLibreSwiftUITests/Models/MapCamera/__Snapshots__/MapViewCameraTests/testTrackingUserLocation.1.txt @@ -1,11 +1,10 @@ ▿ MapViewCamera - - direction: 0.0 ▿ lastReasonForChange: Optional - some: CameraChangeReason.programmatic - ▿ pitch: CameraPitch - ▿ freeWithinRange: (2 elements) - - minimum: 12.0 - - maximum: 34.0 ▿ state: CameraState - ▿ trackingUserLocation: (1 element) + ▿ trackingUserLocation: (2 elements) - zoom: 10.0 + ▿ pitch: CameraPitch + ▿ freeWithinRange: (2 elements) + - minimum: 12.0 + - maximum: 34.0