Skip to content

Commit

Permalink
Changing MapViewPort to MapViewProxy (#65)
Browse files Browse the repository at this point in the history
* changing MapViewPort to MapViewProxy

* ran swiftformat

* annotation test as mainactor
  • Loading branch information
hactar authored Jan 9, 2025
1 parent e9ad082 commit 4f40a6d
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 69 deletions.
4 changes: 2 additions & 2 deletions Sources/MapLibreSwiftUI/MapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct MapView<T: MapViewHostViewController>: UIViewControllerRepresentab
var gestures = [MapGesture]()

var onStyleLoaded: ((MLNStyle) -> Void)?
var onViewPortChanged: ((MapViewPort) -> Void)?
var onViewProxyChanged: ((MapViewProxy) -> Void)?

var mapViewContentInset: UIEdgeInsets?

Expand Down Expand Up @@ -50,7 +50,7 @@ public struct MapView<T: MapViewHostViewController>: UIViewControllerRepresentab
MapViewCoordinator<T>(
parent: self,
onGesture: { processGesture($0, $1) },
onViewPortChanged: { onViewPortChanged?($0) }
onViewProxyChanged: { onViewProxyChanged?($0) }
)
}

Expand Down
24 changes: 10 additions & 14 deletions Sources/MapLibreSwiftUI/MapViewCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class MapViewCoordinator<T: MapViewHostViewController>: NSObject, MLNMapV

var onStyleLoaded: ((MLNStyle) -> Void)?
var onGesture: (MLNMapView, UIGestureRecognizer) -> Void
var onViewPortChanged: (MapViewPort) -> Void
var onViewProxyChanged: (MapViewProxy) -> Void

init(parent: MapView<T>,
onGesture: @escaping (MLNMapView, UIGestureRecognizer) -> Void,
onViewPortChanged: @escaping (MapViewPort) -> Void)
onViewProxyChanged: @escaping (MapViewProxy) -> Void)
{
self.parent = parent
self.onGesture = onGesture
self.onViewPortChanged = onViewPortChanged
self.onViewProxyChanged = onViewProxyChanged
}

// MARK: Core UIView Functionality
Expand Down Expand Up @@ -366,7 +366,7 @@ public class MapViewCoordinator<T: MapViewHostViewController>: NSObject, MLNMapV
public func mapView(_ mapView: MLNMapView, regionDidChangeWith reason: MLNCameraChangeReason, animated _: Bool) {
// TODO: We could put this in regionIsChangingWith if we calculate significant change/debounce.
MainActor.assumeIsolated {
updateViewPort(mapView: mapView, reason: reason)
updateViewProxy(mapView: mapView, reason: reason)

Check warning on line 369 in Sources/MapLibreSwiftUI/MapViewCoordinator.swift

View workflow job for this annotation

GitHub Actions / platform=iOS Simulator,name=iPhone 16,OS=18.1

sending 'self' risks causing data races; this is an error in the Swift 6 language mode

guard !suppressCameraUpdatePropagation else {
return
Expand All @@ -376,17 +376,13 @@ public class MapViewCoordinator<T: MapViewHostViewController>: NSObject, MLNMapV
}
}

// MARK: MapViewPort
// MARK: MapViewProxy

@MainActor private func updateViewPort(mapView: MLNMapView, reason: MLNCameraChangeReason) {
// Calculate the Raw "ViewPort"
let calculatedViewPort = MapViewPort(
center: mapView.centerCoordinate,
zoom: mapView.zoomLevel,
direction: mapView.direction,
lastReasonForChange: CameraChangeReason(reason)
)
@MainActor private func updateViewProxy(mapView: MLNMapView, reason: MLNCameraChangeReason) {
// Calculate the Raw "ViewProxy"
let calculatedViewProxy = MapViewProxy(mapView: mapView,
lastReasonForChange: CameraChangeReason(reason))

onViewPortChanged(calculatedViewPort)
onViewProxyChanged(calculatedViewProxy)
}
}
4 changes: 2 additions & 2 deletions Sources/MapLibreSwiftUI/MapViewModifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ public extension MapView {
return result
}

func onMapViewPortUpdate(_ onViewPortChanged: @escaping (MapViewPort) -> Void) -> Self {
func onMapViewProxyUpdate(_ onViewProxyChanged: @escaping (MapViewProxy) -> Void) -> Self {
var result = self
result.onViewPortChanged = onViewPortChanged
result.onViewProxyChanged = onViewProxyChanged
return result
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import MapLibre

@MainActor
public enum CameraChangeReason: Hashable {
case programmatic
case resetNorth
Expand Down
50 changes: 0 additions & 50 deletions Sources/MapLibreSwiftUI/Models/MapViewPort.swift

This file was deleted.

73 changes: 73 additions & 0 deletions Sources/MapLibreSwiftUI/Models/MapViewProxy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import CoreLocation
import Foundation
import MapLibre

/// A read only representation of the MapView's current View.
///
/// Provides access to properties and functions of the underlying MLNMapView,
/// but properties only expose their getter, and functions are only available if they
/// do no change the state of the MLNMapView. Writing directly to properties of MLNMapView
/// could clash with swiftui-dsl's state management, which is why modifiying functions
/// and properties are not exposed.
///
/// You can use `MapView.onMapViewProxyUpdate(_ onViewProxyChanged: @escaping (MapViewProxy) -> Void)` to
/// recieve access to the MapViewProxy.
///
/// For more information about the properties and functions, see
/// https://maplibre.org/maplibre-native/ios/latest/documentation/maplibre/mlnmapview
@MainActor
public struct MapViewProxy: Hashable, Equatable {
/// The current center coordinate of the MapView
public var centerCoordinate: CLLocationCoordinate2D {
mapView.centerCoordinate
}

/// The current zoom value of the MapView
public var zoomLevel: Double {
mapView.zoomLevel
}

/// The current compass direction of the MapView
public var direction: CLLocationDirection {
mapView.direction
}

public var visibleCoordinateBounds: MLNCoordinateBounds {
mapView.visibleCoordinateBounds
}

public var mapViewSize: CGSize {
mapView.frame.size
}

public var contentInset: UIEdgeInsets {
mapView.contentInset
}

/// The reason the view port was changed.
public let lastReasonForChange: CameraChangeReason?

private let mapView: MLNMapView

public func convert(_ coordinate: CLLocationCoordinate2D, toPointTo: UIView?) -> CGPoint {
mapView.convert(coordinate, toPointTo: toPointTo)
}

public init(mapView: MLNMapView,
lastReasonForChange: CameraChangeReason?)
{
self.mapView = mapView
self.lastReasonForChange = lastReasonForChange
}
}

public extension MapViewProxy {
/// Generate a basic MapViewCamera that represents the MapView
///
/// - Returns: The calculated MapViewCamera
func asMapViewCamera() -> MapViewCamera {
.center(centerCoordinate,
zoom: zoomLevel,
direction: direction)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class MapViewCoordinatorCameraTests: XCTestCase {
mapView = MapView(styleURL: URL(string: "https://maplibre.org")!)
coordinator = MapView.Coordinator(parent: mapView) { _, _ in
// No action
} onViewPortChanged: { _ in
} onViewProxyChanged: { _ in
// No action
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import MapLibre
import XCTest
@testable import MapLibreSwiftUI

@MainActor
final class CameraChangeReasonTests: XCTestCase {
func testProgrammatic() {
let mlnReason: MLNCameraChangeReason = [.programmatic]
Expand Down

0 comments on commit 4f40a6d

Please sign in to comment.