Skip to content

Commit

Permalink
Add tests, update changelog and formatting for final destination
Browse files Browse the repository at this point in the history
  • Loading branch information
kried committed Jan 18, 2023
1 parent 3283953 commit bc90da8
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 32 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## v2.11.0

### Map

* Added `NavigationMapView.addDestinationAnnotation(_:identifier:styleLoaded:)`, `NavigationMapView.removeDestinationAnnotation(_:)` to present and remove the final destination annotation on a NavigationMapView. ([#4253](https://github.com/mapbox/mapbox-navigation-ios/pull/4253))

### CarPlay

* Added `CarPlayManagerDelegate.carPlayManagerDidCancelPreview(_:)` to notify developers after CarPlay canceled routes preview, and `CarPlayManager.cancelRoutesPreview()` method to cancel routes preview on CarPlay. ([#4311](https://github.com/mapbox/mapbox-navigation-ios/pull/4311))
Expand Down
53 changes: 22 additions & 31 deletions Sources/MapboxNavigation/NavigationMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ open class NavigationMapView: UIView {
final destination `PointAnnotation` will be stored in this property and added to the `MapView`
later on.
*/
var finalDestinationAnnotations: [PointAnnotation] = []
private(set) var finalDestinationAnnotations: [PointAnnotation] = []

/**
Adds the route waypoints to the map given the current leg index. Previous waypoints for completed legs will be omitted.
Expand Down Expand Up @@ -1335,34 +1335,28 @@ open class NavigationMapView: UIView {

if let lastLeg = route.legs.last,
let destinationCoordinate = lastLeg.destination?.coordinate {
addDestinationAnnotation(destinationCoordinate) { [weak self] in
guard self != nil else { return }
}
addDestinationAnnotation(destinationCoordinate, identifier: AnnotationIdentifier.finalDestinationAnnotation)
}
}

/**
Adds a final destination annotation to the map.
Adds a final destination annotation to the map. The annotation will be added only after fully loading `MapView` style. In such case
final destination will be stored and added to the `MapView` later on. `delegate` will be notified about the change via
`NavigationMapViewDelegate.navigationMapView(_:didAdd:pointAnnotationManager:)` method.
- parameter coordinate: Coordinate which represents the annotation location.
- parameter identifier: String to uniquely identify the destination annotation. Defaults to `nil` and a default identifier will be provided.
- parameter styleLoaded: An escaping closure to be executed when the `MapView` style has finished loading.
*/
public func addDestinationAnnotation(_ coordinate: CLLocationCoordinate2D,
identifier: String? = nil,
styleLoaded: @escaping () -> Void) {
let identifier = identifier ?? String("finalDestinationAnnotation_\(finalDestinationAnnotations.count)")
identifier: String? = nil) {
let count = pointAnnotationManager?.annotations.count ?? finalDestinationAnnotations.count
let identifier = identifier ?? "\(AnnotationIdentifier.finalDestinationAnnotation)_\(count)"
var destinationAnnotation = PointAnnotation(id: identifier, coordinate: coordinate)
destinationAnnotation.image = .init(image: .defaultMarkerImage, name: ImageIdentifier.markerImage)

mapView.mapboxMap.onNext(event: .styleLoaded) { [weak self] _ in
guard self != nil else { return }
styleLoaded()
}


// If `PointAnnotationManager` is available - add `PointAnnotation`, if not - remember it
// and add it only after fully loading `MapView` style.
if let pointAnnotationManager = pointAnnotationManager {
if let pointAnnotationManager {
pointAnnotationManager.annotations.append(destinationAnnotation)
delegate?.navigationMapView(self,
didAdd: destinationAnnotation,
Expand All @@ -1373,18 +1367,20 @@ open class NavigationMapView: UIView {
}

/**
Removes a final destination annotation to the map.
- parameter identifier: String to uniquely identify the destination annotation to be removed. Defaults to `nil` and removes all destination annotations.
Removes a final destination annotation from the map.
- parameter identifier: String to uniquely identify the destination annotation to be removed. Defaults to `nil` and removes all destination annotations with non-custom identifiers.
*/
public func removeDestinationAnnotation(_ identifier: String? = nil) {
public func removeDestinationAnnotation(identifier: String? = nil) {
let filter: (PointAnnotation) -> Bool
if let identifier {
finalDestinationAnnotations.removeAll(where: { $0.id == identifier })
pointAnnotationManager?.annotations.removeAll(where: { $0.id == identifier })
filter = { $0.id == identifier }
} else {
finalDestinationAnnotations.removeAll(where: { $0.id.contains("finalDestinationAnnotation") })
pointAnnotationManager?.annotations.removeAll(where: { $0.id.contains("finalDestinationAnnotation") })
filter = { $0.id.contains(AnnotationIdentifier.finalDestinationAnnotation) }
}

finalDestinationAnnotations.removeAll(where: filter)
pointAnnotationManager?.annotations.removeAll(where: filter)
}

/**
Expand Down Expand Up @@ -1456,11 +1452,6 @@ open class NavigationMapView: UIView {
*/
public var pointAnnotationManager: PointAnnotationManager?

func annotationsToRemove() -> [Annotation] {
let identifier = NavigationMapView.AnnotationIdentifier.finalDestinationAnnotation
return pointAnnotationManager?.annotations.filter({ $0.id == identifier }) ?? []
}

// MARK: Map Rendering and Observing

var routes: [Route]?
Expand Down
94 changes: 93 additions & 1 deletion Tests/MapboxNavigationTests/NavigationMapViewTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import XCTest
import MapboxDirections
import TestHelper
import Turf
import MapboxMaps
@testable import MapboxMaps
@testable import MapboxNavigation
@testable import MapboxCoreNavigation

Expand All @@ -12,6 +12,7 @@ class NavigationMapViewTests: TestCase {
CLLocationCoordinate2D(latitude: 29.99908, longitude: -102.828197),
]))
var navigationMapView: NavigationMapView!
var pointAnnotationManager: PointAnnotationManager!

let options: NavigationRouteOptions = .init(coordinates: [
CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926),
Expand All @@ -21,10 +22,25 @@ class NavigationMapViewTests: TestCase {
let route = response.routes!.first!
return route
}()

private let coordinate1 = CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926)
private let coordinate2 = CLLocationCoordinate2D(latitude: 30.176322, longitude: -102.806108)
private let finalDestinationAnnotationTestPrefix = "MapboxNavigation-MapboxNavigation-resources_finalDestinationAnnotation"

private final class DisplayLinkCoordinatorSpy: DisplayLinkCoordinator {
func add(_ participant: DisplayLinkParticipant) {}
func remove(_ participant: DisplayLinkParticipant) {}
}

override func setUp() {
super.setUp()
navigationMapView = NavigationMapView(frame: CGRect(origin: .zero, size: .iPhone6Plus))
let mapboxMap = navigationMapView.mapView.mapboxMap!
pointAnnotationManager = PointAnnotationManager(id: "",
style: mapboxMap.style,
layerPosition: nil,
displayLinkCoordinator: DisplayLinkCoordinatorSpy(),
offsetPointCalculator: OffsetPointCalculator(mapboxMap: mapboxMap))
}

override func tearDown() {
Expand Down Expand Up @@ -584,6 +600,82 @@ class NavigationMapViewTests: TestCase {
XCTAssertFalse(style.layerExists(withId: NavigationMapView.LayerIdentifier.intersectionAnnotationsLayer))
}

func testAddFinalDestinationWithDefaultIdentifierIfStyleNotLoaded() {
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)

navigationMapView.addDestinationAnnotation(coordinate1)
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 1)
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[0].id, "\(finalDestinationAnnotationTestPrefix)_0")
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)

navigationMapView.addDestinationAnnotation(coordinate2)
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[1].id, "\(finalDestinationAnnotationTestPrefix)_1")
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)
}

func testAddFinalDestinationWithCustomIdentifierIfStyleNotLoaded() {
navigationMapView.addDestinationAnnotation(coordinate1, identifier: "custom")
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 1)
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[0].id, "custom")
}

func testRemovesFinalDestinationIfStyleNotLoaded() {
navigationMapView.addDestinationAnnotation(coordinate1)
navigationMapView.addDestinationAnnotation(coordinate2)

navigationMapView.removeDestinationAnnotation(identifier: "custom")
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)

navigationMapView.addDestinationAnnotation(coordinate2, identifier: "custom")
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 3)
navigationMapView.removeDestinationAnnotation(identifier: "custom")
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)

navigationMapView.removeDestinationAnnotation()
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 0)
}

func testAddFinalDestinationWithDefaultIdentifierIfStyleLoaded() {
navigationMapView.pointAnnotationManager = pointAnnotationManager

navigationMapView.addDestinationAnnotation(coordinate1)
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
XCTAssertEqual(pointAnnotationManager.annotations.count, 1)
XCTAssertEqual(pointAnnotationManager.annotations[0].id, "\(finalDestinationAnnotationTestPrefix)_0")

navigationMapView.addDestinationAnnotation(coordinate2)
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)
XCTAssertEqual(pointAnnotationManager.annotations[1].id, "\(finalDestinationAnnotationTestPrefix)_1")
}

func testAddFinalDestinationWithCustomIdentifierIfStyleLoaded() {
navigationMapView.pointAnnotationManager = pointAnnotationManager

navigationMapView.addDestinationAnnotation(coordinate1, identifier: "custom")
XCTAssertEqual(pointAnnotationManager.annotations.count, 1)
XCTAssertEqual(pointAnnotationManager.annotations[0].id, "custom")
}

func testRemovesFinalDestinationIfStyleLoaded() {
navigationMapView.pointAnnotationManager = pointAnnotationManager
navigationMapView.addDestinationAnnotation(coordinate1)
navigationMapView.addDestinationAnnotation(coordinate2)

navigationMapView.removeDestinationAnnotation(identifier: "custom")
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)

navigationMapView.addDestinationAnnotation(coordinate2, identifier: "custom")
XCTAssertEqual(pointAnnotationManager.annotations.count, 3)
navigationMapView.removeDestinationAnnotation(identifier: "custom")
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)

navigationMapView.removeDestinationAnnotation()
XCTAssertEqual(pointAnnotationManager.annotations.count, 0)
}

private func configureIntersections() {
let style = navigationMapView.mapView.mapboxMap.style
var source = GeoJSONSource()
Expand Down

0 comments on commit bc90da8

Please sign in to comment.