diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5b6a42c..f20faea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: rymndhng/release-on-push-action@master + - uses: rymndhng/release-on-push-action@v0.28.0 with: - bump_version_scheme: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'patch' || inputs.bump_version_scheme }} \ No newline at end of file + bump_version_scheme: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'patch' || inputs.bump_version_scheme }} diff --git a/Package.resolved b/Package.resolved index 8b80b5a..8f732c4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/maplibre/maplibre-gl-native-distribution.git", "state" : { - "revision" : "6d0071977ed1f2380c739715f82ac650f99b0824", - "version" : "6.4.0" + "revision" : "a40e82162772e53180a2e0b1052e454db43a297d", + "version" : "6.5.1" } }, { @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/stadiamaps/maplibre-swift-macros.git", "state" : { - "revision" : "d52adbcbfaf96bd0723a156bd838826916ff7a69", - "version" : "0.0.3" + "revision" : "236215c13bff962009e0f0257d6d8349be33442f", + "version" : "0.0.4" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Kolos65/Mockable.git", "state" : { - "revision" : "3b79620f2b916941035b5544bbca321fa7b33ed4", - "version" : "0.0.3" + "revision" : "81ccaead99a3c038c09345caa2888ae74b644ee9", + "version" : "0.0.9" } }, { @@ -32,14 +32,14 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "625ccca8570773dd84a34ee51a81aa2bc5a4f97a", - "version" : "1.16.0" + "revision" : "c097f955b4e724690f0fc8ffb7a6d4b881c9c4e3", + "version" : "1.17.2" } }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax", + "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", "version" : "509.1.1" diff --git a/Package.swift b/Package.swift index 06a554e..7fc10eb 100644 --- a/Package.swift +++ b/Package.swift @@ -24,8 +24,8 @@ let package = Package( .package(url: "https://github.com/maplibre/maplibre-gl-native-distribution.git", from: "6.4.0"), .package(url: "https://github.com/stadiamaps/maplibre-swift-macros.git", from: "0.0.3"), // Testing - .package(url: "https://github.com/Kolos65/Mockable.git", exact: "0.0.3"), - .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.15.3"), + .package(url: "https://github.com/Kolos65/Mockable.git", exact: "0.0.9"), + .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.17.2"), ], targets: [ .target( diff --git a/Sources/MapLibreSwiftDSL/Style Layers/Fill.swift b/Sources/MapLibreSwiftDSL/Style Layers/Fill.swift new file mode 100644 index 0000000..f900d17 --- /dev/null +++ b/Sources/MapLibreSwiftDSL/Style Layers/Fill.swift @@ -0,0 +1,40 @@ +// import Foundation +// import MapLibre +// import InternalUtils +// import MapLibreSwiftMacros +// +//// TODO: background opacity property (and resolved image properties in general) +//// TODO: Generalization: color properties and numeric properties +// @MLNStyleProperty("backgroundColor", supportsInterpolation: true) +// @MLNStyleProperty("backgroundOpacity", supportsInterpolation: true) +// public struct FillLayer: SourceBoundStyleLayerDefinition { +// public let identifier: String +// public var insertionPosition: LayerInsertionPosition = .belowOthers +// public var isVisible: Bool = true +// public var maximumZoomLevel: Float? = nil +// public var minimumZoomLevel: Float? = nil +// +// public var source: StyleLayerSource +// +// public init(identifier: String, source: Source) { +// self.identifier = identifier +// self.source = .source(source) +// } +// +// public init(identifier: String, source: MLNSource) { +// self.identifier = identifier +// self.source = .mglSource(source) +// } +// +// public func makeStyleLayer(style: MLNStyle) -> StyleLayer { +// let styleSource = addSource(to: style) +// +// let result = MLNFillStyleLayer(identifier: identifier, source: source) +// +// // TODO: Macro-ize this +// result.backgroundColor = backgroundColor +// result.backgroundOpacity = backgroundOpacity +// +// return result +// } +// } diff --git a/Sources/MapLibreSwiftUI/StaticLocationManager.swift b/Sources/MapLibreSwiftUI/StaticLocationManager.swift index 1bbe6b6..b94ba51 100644 --- a/Sources/MapLibreSwiftUI/StaticLocationManager.swift +++ b/Sources/MapLibreSwiftUI/StaticLocationManager.swift @@ -10,7 +10,8 @@ import MapLibre /// /// You can provide a new location by setting the ``lastLocation`` property. /// -/// This class does not ever perform any authorization checks. That is the responsibility of the caller. +/// While this class is required to implement authorization status per the underlying protocol, +/// it does not ever actually check whether you have access to Core Location services. public final class StaticLocationManager: NSObject, @unchecked Sendable { public var delegate: (any MLNLocationManagerDelegate)? diff --git a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift index 47efe30..59fb355 100644 --- a/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift +++ b/Tests/MapLibreSwiftUITests/MapViewCoordinator/MapViewCoordinatorCameraTests.swift @@ -23,6 +23,13 @@ final class MapViewCoordinatorCameraTests: XCTestCase { @MainActor func testUnchangedCamera() { let camera: MapViewCamera = .default() + given(maplibreMapView) + .setCenter(.any, + zoomLevel: .any, + direction: .any, + animated: .any) + .willReturn() + coordinator.updateCamera(mapView: maplibreMapView, camera: camera, animated: false) // Run a second update. We're testing that the snapshotCamera correctly exits the function // when nothing changed. @@ -32,173 +39,192 @@ final class MapViewCoordinatorCameraTests: XCTestCase { // This verifies the comment above. verify(maplibreMapView) .userTrackingMode(newValue: .value(.none)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setCenter(.value(MapViewCamera.Defaults.coordinate), zoomLevel: .value(10), direction: .value(0), animated: .value(false)) - .called(count: 1) + .called(1) // Due to the .frame == .zero workaround, min/max pitch setting is called twice, once to set the // pitch, and then once to set the actual range. verify(maplibreMapView) .minimumPitch(newValue: .value(0)) - .setterCalled(count: 2) + .setCalled(2) verify(maplibreMapView) .maximumPitch(newValue: .value(0)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .maximumPitch(newValue: .value(60)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setZoomLevel(.any, animated: .any) - .called(count: 0) + .called(0) } @MainActor func testCenterCameraUpdate() { let coordinate = CLLocationCoordinate2D(latitude: 12.3, longitude: 23.4) let newCamera: MapViewCamera = .center(coordinate, zoom: 13) + given(maplibreMapView) + .setCenter(.any, + zoomLevel: .any, + direction: .any, + animated: .any) + .willReturn() + coordinator.updateCamera(mapView: maplibreMapView, camera: newCamera, animated: false) verify(maplibreMapView) .userTrackingMode(newValue: .value(.none)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setCenter(.value(coordinate), zoomLevel: .value(13), direction: .value(0), animated: .value(false)) - .called(count: 1) + .called(1) // Due to the .frame == .zero workaround, min/max pitch setting is called twice, once to set the // pitch, and then once to set the actual range. verify(maplibreMapView) .minimumPitch(newValue: .value(0)) - .setterCalled(count: 2) + .setCalled(2) verify(maplibreMapView) .maximumPitch(newValue: .value(0)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .maximumPitch(newValue: .value(60)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setZoomLevel(.any, animated: .any) - .called(count: 0) + .called(0) } @MainActor func testUserTrackingCameraUpdate() { let newCamera: MapViewCamera = .trackUserLocation() + given(maplibreMapView) + .setZoomLevel(.any, animated: .any) + .willReturn() + coordinator.updateCamera(mapView: maplibreMapView, camera: newCamera, animated: false) verify(maplibreMapView) .userTrackingMode(newValue: .value(.follow)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setCenter(.any, zoomLevel: .any, direction: .any, animated: .any) - .called(count: 0) + .called(0) // Due to the .frame == .zero workaround, min/max pitch setting is called twice, once to set the // pitch, and then once to set the actual range. verify(maplibreMapView) .minimumPitch(newValue: .value(0)) - .setterCalled(count: 2) + .setCalled(2) verify(maplibreMapView) .maximumPitch(newValue: .value(0)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .maximumPitch(newValue: .value(60)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setZoomLevel(.value(10), animated: .value(false)) - .called(count: 1) + .called(1) } @MainActor func testUserTrackingWithCourseCameraUpdate() { let newCamera: MapViewCamera = .trackUserLocationWithCourse() + given(maplibreMapView) + .setZoomLevel(.any, animated: .any) + .willReturn() + coordinator.updateCamera(mapView: maplibreMapView, camera: newCamera, animated: false) verify(maplibreMapView) .userTrackingMode(newValue: .value(.followWithCourse)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setCenter(.any, zoomLevel: .any, direction: .any, animated: .any) - .called(count: 0) + .called(0) // Due to the .frame == .zero workaround, min/max pitch setting is called twice, once to set the // pitch, and then once to set the actual range. verify(maplibreMapView) .minimumPitch(newValue: .value(0)) - .setterCalled(count: 2) + .setCalled(2) verify(maplibreMapView) .maximumPitch(newValue: .value(0)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .maximumPitch(newValue: .value(60)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setZoomLevel(.value(10), animated: .value(false)) - .called(count: 1) + .called(1) } @MainActor func testUserTrackingWithHeadingUpdate() { let newCamera: MapViewCamera = .trackUserLocationWithHeading() + given(maplibreMapView) + .setZoomLevel(.any, animated: .any) + .willReturn() + coordinator.updateCamera(mapView: maplibreMapView, camera: newCamera, animated: false) verify(maplibreMapView) .userTrackingMode(newValue: .value(.followWithHeading)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setCenter(.any, zoomLevel: .any, direction: .any, animated: .any) - .called(count: 0) + .called(0) // Due to the .frame == .zero workaround, min/max pitch setting is called twice, once to set the // pitch, and then once to set the actual range. verify(maplibreMapView) .minimumPitch(newValue: .value(0)) - .setterCalled(count: 2) + .setCalled(2) verify(maplibreMapView) .maximumPitch(newValue: .value(0)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .maximumPitch(newValue: .value(60)) - .setterCalled(count: 1) + .setCalled(1) verify(maplibreMapView) .setZoomLevel(.value(10), animated: .value(false)) - .called(count: 1) + .called(1) } // TODO: Test Rect & Showcase once we build it! diff --git a/Tests/MapLibreSwiftUITests/Support/XCTestAssertView.swift b/Tests/MapLibreSwiftUITests/Support/XCTestAssertView.swift index 7ea9ff5..1f48166 100644 --- a/Tests/MapLibreSwiftUITests/Support/XCTestAssertView.swift +++ b/Tests/MapLibreSwiftUITests/Support/XCTestAssertView.swift @@ -3,7 +3,6 @@ import SnapshotTesting import SwiftUI import XCTest -// TODO: This is a WIP that needs some additional eyes extension XCTestCase { func assertView( named name: String? = nil, @@ -18,7 +17,7 @@ extension XCTestCase { let view = content() .frame(width: frame.width, height: frame.height) - assertSnapshot(matching: view, + assertSnapshot(of: view, as: .image(precision: 0.9, perceptualPrecision: 0.95), named: name, record: record,