Skip to content

Commit

Permalink
Send location uncertainty within a geo uri (#1309)
Browse files Browse the repository at this point in the history
* Add uncertainty

* Add UTs

* Delete verticalAccuracy
  • Loading branch information
alfogrillo authored Jul 12, 2023
1 parent c573892 commit adb253f
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 11 deletions.
29 changes: 22 additions & 7 deletions ElementX/Sources/Other/MapLibre/MapLibreMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ struct MapLibreMapView: UIViewRepresentable {
@Binding var mapCenterCoordinate: CLLocationCoordinate2D?

@Binding var isLocationAuthorized: Bool?

// The radius of uncertainty for the location, measured in meters.
@Binding var geolocationUncertainty: CLLocationAccuracy?

/// Called when the user pan on the map
var userDidPan: (() -> Void)?
Expand Down Expand Up @@ -155,6 +158,7 @@ extension MapLibreMapView {
}

previousUserLocation = userLocation
updateGeolocationUncertainty(location: userLocation)
}

func mapView(_ mapView: MGLMapView, didChangeLocationManagerAuthorization manager: MGLLocationManager) {
Expand All @@ -176,13 +180,7 @@ extension MapLibreMapView {
mapLibreView.mapCenterCoordinate = mapView.centerCoordinate
}
}

// MARK: Callout

func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
false
}


func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool {
// we send the userDidPan event only for the reasons that actually will change the map center, and not zoom only / rotations only events.
switch reason {
Expand All @@ -203,6 +201,23 @@ extension MapLibreMapView {
}
return true
}

// MARK: Callout

func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
false
}

// MARK: Private

private func updateGeolocationUncertainty(location: MGLUserLocation) {
guard let clLocation = location.location, clLocation.horizontalAccuracy >= 0 else {
mapLibreView.geolocationUncertainty = nil
return
}

mapLibreView.geolocationUncertainty = clLocation.horizontalAccuracy
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ struct StaticLocationScreenViewState: BindableState {

struct StaticLocationScreenBindings {
var mapCenterLocation: CLLocationCoordinate2D?
var geolocationUncertainty: CLLocationAccuracy?

var showsUserLocationMode: ShowUserLocationMode

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class StaticLocationScreenViewModel: StaticLocationScreenViewModelType, StaticLo
actionsSubject.send(.close)
case .selectLocation:
guard let coordinate = state.bindings.mapCenterLocation else { return }
actionsSubject.send(.sendLocation(.init(coordinate: coordinate), isUserLocation: state.isSharingUserLocation))
let uncertainty = state.isSharingUserLocation ? context.geolocationUncertainty : nil
actionsSubject.send(.sendLocation(.init(coordinate: coordinate, uncertainty: uncertainty), isUserLocation: state.isSharingUserLocation))
case .userDidPan:
state.bindings.showsUserLocationMode = .show
case .centerToUser:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ struct StaticLocationScreen: View {
showsUserLocationMode: $context.showsUserLocationMode,
error: $context.mapError,
mapCenterCoordinate: $context.mapCenterLocation,
isLocationAuthorized: $context.isLocationAuthorized) {
isLocationAuthorized: $context.isLocationAuthorized,
geolocationUncertainty: $context.geolocationUncertainty) {
context.send(viewAction: .userDidPan)
}
.ignoresSafeArea(.all, edges: mapSafeAreaEdges)

if context.viewState.isLocationPickerMode {
LocationMarkerView()
}
Expand Down
4 changes: 2 additions & 2 deletions ElementX/Sources/Services/Timeline/GeoURI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ private extension RegexGeoURI {
}

extension GeoURI {
init(coordinate: CLLocationCoordinate2D) {
self.init(latitude: coordinate.latitude, longitude: coordinate.longitude)
init(coordinate: CLLocationCoordinate2D, uncertainty: CLLocationAccuracy?) {
self.init(latitude: coordinate.latitude, longitude: coordinate.longitude, uncertainty: uncertainty)
}
}

Expand Down
27 changes: 27 additions & 0 deletions UnitTests/Sources/StaticLocationScreenViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,31 @@ class StaticLocationScreenViewModelTests: XCTestCase {
let authorizationError = AlertInfo(locationSharingViewError: .missingAuthorization)
XCTAssertEqual(authorizationError.message, L10n.errorMissingLocationAuth(InfoPlistReader.main.bundleDisplayName))
}

func testSendUserLocation() async throws {
context.mapCenterLocation = .init(latitude: 0, longitude: 0)
context.geolocationUncertainty = 10
let deferred = deferFulfillment(viewModel.actions.first())
context.send(viewAction: .selectLocation)
guard case .sendLocation(let geoUri, let isUserLocation) = try await deferred.fulfill() else {
XCTFail("Sent action should be 'sendLocation'")
return
}
XCTAssertEqual(geoUri.uncertainty, 10)
XCTAssertTrue(isUserLocation)
}

func testSendPickedLocation() async throws {
context.mapCenterLocation = .init(latitude: 0, longitude: 0)
context.isLocationAuthorized = nil
context.geolocationUncertainty = 10
let deferred = deferFulfillment(viewModel.actions.first())
context.send(viewAction: .selectLocation)
guard case .sendLocation(let geoUri, let isUserLocation) = try await deferred.fulfill() else {
XCTFail("Sent action should be 'sendLocation'")
return
}
XCTAssertEqual(geoUri.uncertainty, nil)
XCTAssertFalse(isUserLocation)
}
}

0 comments on commit adb253f

Please sign in to comment.