Skip to content

Commit bc90da8

Browse files
committed
Add tests, update changelog and formatting for final destination
1 parent 3283953 commit bc90da8

File tree

3 files changed

+119
-32
lines changed

3 files changed

+119
-32
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## v2.11.0
44

5+
### Map
6+
7+
* 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))
8+
59
### CarPlay
610

711
* 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))

Sources/MapboxNavigation/NavigationMapView.swift

+22-31
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ open class NavigationMapView: UIView {
12731273
final destination `PointAnnotation` will be stored in this property and added to the `MapView`
12741274
later on.
12751275
*/
1276-
var finalDestinationAnnotations: [PointAnnotation] = []
1276+
private(set) var finalDestinationAnnotations: [PointAnnotation] = []
12771277

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

13361336
if let lastLeg = route.legs.last,
13371337
let destinationCoordinate = lastLeg.destination?.coordinate {
1338-
addDestinationAnnotation(destinationCoordinate) { [weak self] in
1339-
guard self != nil else { return }
1340-
}
1338+
addDestinationAnnotation(destinationCoordinate, identifier: AnnotationIdentifier.finalDestinationAnnotation)
13411339
}
13421340
}
1343-
1341+
13441342
/**
1345-
Adds a final destination annotation to the map.
1346-
1343+
Adds a final destination annotation to the map. The annotation will be added only after fully loading `MapView` style. In such case
1344+
final destination will be stored and added to the `MapView` later on. `delegate` will be notified about the change via
1345+
`NavigationMapViewDelegate.navigationMapView(_:didAdd:pointAnnotationManager:)` method.
1346+
13471347
- parameter coordinate: Coordinate which represents the annotation location.
13481348
- parameter identifier: String to uniquely identify the destination annotation. Defaults to `nil` and a default identifier will be provided.
1349-
- parameter styleLoaded: An escaping closure to be executed when the `MapView` style has finished loading.
13501349
*/
13511350
public func addDestinationAnnotation(_ coordinate: CLLocationCoordinate2D,
1352-
identifier: String? = nil,
1353-
styleLoaded: @escaping () -> Void) {
1354-
let identifier = identifier ?? String("finalDestinationAnnotation_\(finalDestinationAnnotations.count)")
1351+
identifier: String? = nil) {
1352+
let count = pointAnnotationManager?.annotations.count ?? finalDestinationAnnotations.count
1353+
let identifier = identifier ?? "\(AnnotationIdentifier.finalDestinationAnnotation)_\(count)"
13551354
var destinationAnnotation = PointAnnotation(id: identifier, coordinate: coordinate)
13561355
destinationAnnotation.image = .init(image: .defaultMarkerImage, name: ImageIdentifier.markerImage)
1357-
1358-
mapView.mapboxMap.onNext(event: .styleLoaded) { [weak self] _ in
1359-
guard self != nil else { return }
1360-
styleLoaded()
1361-
}
1362-
1356+
13631357
// If `PointAnnotationManager` is available - add `PointAnnotation`, if not - remember it
13641358
// and add it only after fully loading `MapView` style.
1365-
if let pointAnnotationManager = pointAnnotationManager {
1359+
if let pointAnnotationManager {
13661360
pointAnnotationManager.annotations.append(destinationAnnotation)
13671361
delegate?.navigationMapView(self,
13681362
didAdd: destinationAnnotation,
@@ -1373,18 +1367,20 @@ open class NavigationMapView: UIView {
13731367
}
13741368

13751369
/**
1376-
Removes a final destination annotation to the map.
1377-
1378-
- parameter identifier: String to uniquely identify the destination annotation to be removed. Defaults to `nil` and removes all destination annotations.
1370+
Removes a final destination annotation from the map.
1371+
1372+
- parameter identifier: String to uniquely identify the destination annotation to be removed. Defaults to `nil` and removes all destination annotations with non-custom identifiers.
13791373
*/
1380-
public func removeDestinationAnnotation(_ identifier: String? = nil) {
1374+
public func removeDestinationAnnotation(identifier: String? = nil) {
1375+
let filter: (PointAnnotation) -> Bool
13811376
if let identifier {
1382-
finalDestinationAnnotations.removeAll(where: { $0.id == identifier })
1383-
pointAnnotationManager?.annotations.removeAll(where: { $0.id == identifier })
1377+
filter = { $0.id == identifier }
13841378
} else {
1385-
finalDestinationAnnotations.removeAll(where: { $0.id.contains("finalDestinationAnnotation") })
1386-
pointAnnotationManager?.annotations.removeAll(where: { $0.id.contains("finalDestinationAnnotation") })
1379+
filter = { $0.id.contains(AnnotationIdentifier.finalDestinationAnnotation) }
13871380
}
1381+
1382+
finalDestinationAnnotations.removeAll(where: filter)
1383+
pointAnnotationManager?.annotations.removeAll(where: filter)
13881384
}
13891385

13901386
/**
@@ -1456,11 +1452,6 @@ open class NavigationMapView: UIView {
14561452
*/
14571453
public var pointAnnotationManager: PointAnnotationManager?
14581454

1459-
func annotationsToRemove() -> [Annotation] {
1460-
let identifier = NavigationMapView.AnnotationIdentifier.finalDestinationAnnotation
1461-
return pointAnnotationManager?.annotations.filter({ $0.id == identifier }) ?? []
1462-
}
1463-
14641455
// MARK: Map Rendering and Observing
14651456

14661457
var routes: [Route]?

Tests/MapboxNavigationTests/NavigationMapViewTests.swift

+93-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import XCTest
22
import MapboxDirections
33
import TestHelper
44
import Turf
5-
import MapboxMaps
5+
@testable import MapboxMaps
66
@testable import MapboxNavigation
77
@testable import MapboxCoreNavigation
88

@@ -12,6 +12,7 @@ class NavigationMapViewTests: TestCase {
1212
CLLocationCoordinate2D(latitude: 29.99908, longitude: -102.828197),
1313
]))
1414
var navigationMapView: NavigationMapView!
15+
var pointAnnotationManager: PointAnnotationManager!
1516

1617
let options: NavigationRouteOptions = .init(coordinates: [
1718
CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926),
@@ -21,10 +22,25 @@ class NavigationMapViewTests: TestCase {
2122
let route = response.routes!.first!
2223
return route
2324
}()
25+
26+
private let coordinate1 = CLLocationCoordinate2D(latitude: 40.311012, longitude: -112.47926)
27+
private let coordinate2 = CLLocationCoordinate2D(latitude: 30.176322, longitude: -102.806108)
28+
private let finalDestinationAnnotationTestPrefix = "MapboxNavigation-MapboxNavigation-resources_finalDestinationAnnotation"
29+
30+
private final class DisplayLinkCoordinatorSpy: DisplayLinkCoordinator {
31+
func add(_ participant: DisplayLinkParticipant) {}
32+
func remove(_ participant: DisplayLinkParticipant) {}
33+
}
2434

2535
override func setUp() {
2636
super.setUp()
2737
navigationMapView = NavigationMapView(frame: CGRect(origin: .zero, size: .iPhone6Plus))
38+
let mapboxMap = navigationMapView.mapView.mapboxMap!
39+
pointAnnotationManager = PointAnnotationManager(id: "",
40+
style: mapboxMap.style,
41+
layerPosition: nil,
42+
displayLinkCoordinator: DisplayLinkCoordinatorSpy(),
43+
offsetPointCalculator: OffsetPointCalculator(mapboxMap: mapboxMap))
2844
}
2945

3046
override func tearDown() {
@@ -584,6 +600,82 @@ class NavigationMapViewTests: TestCase {
584600
XCTAssertFalse(style.layerExists(withId: NavigationMapView.LayerIdentifier.intersectionAnnotationsLayer))
585601
}
586602

603+
func testAddFinalDestinationWithDefaultIdentifierIfStyleNotLoaded() {
604+
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
605+
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)
606+
607+
navigationMapView.addDestinationAnnotation(coordinate1)
608+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 1)
609+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[0].id, "\(finalDestinationAnnotationTestPrefix)_0")
610+
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)
611+
612+
navigationMapView.addDestinationAnnotation(coordinate2)
613+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)
614+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[1].id, "\(finalDestinationAnnotationTestPrefix)_1")
615+
XCTAssertTrue(pointAnnotationManager.annotations.isEmpty)
616+
}
617+
618+
func testAddFinalDestinationWithCustomIdentifierIfStyleNotLoaded() {
619+
navigationMapView.addDestinationAnnotation(coordinate1, identifier: "custom")
620+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 1)
621+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations[0].id, "custom")
622+
}
623+
624+
func testRemovesFinalDestinationIfStyleNotLoaded() {
625+
navigationMapView.addDestinationAnnotation(coordinate1)
626+
navigationMapView.addDestinationAnnotation(coordinate2)
627+
628+
navigationMapView.removeDestinationAnnotation(identifier: "custom")
629+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)
630+
631+
navigationMapView.addDestinationAnnotation(coordinate2, identifier: "custom")
632+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 3)
633+
navigationMapView.removeDestinationAnnotation(identifier: "custom")
634+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 2)
635+
636+
navigationMapView.removeDestinationAnnotation()
637+
XCTAssertEqual(navigationMapView.finalDestinationAnnotations.count, 0)
638+
}
639+
640+
func testAddFinalDestinationWithDefaultIdentifierIfStyleLoaded() {
641+
navigationMapView.pointAnnotationManager = pointAnnotationManager
642+
643+
navigationMapView.addDestinationAnnotation(coordinate1)
644+
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
645+
XCTAssertEqual(pointAnnotationManager.annotations.count, 1)
646+
XCTAssertEqual(pointAnnotationManager.annotations[0].id, "\(finalDestinationAnnotationTestPrefix)_0")
647+
648+
navigationMapView.addDestinationAnnotation(coordinate2)
649+
XCTAssertTrue(navigationMapView.finalDestinationAnnotations.isEmpty)
650+
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)
651+
XCTAssertEqual(pointAnnotationManager.annotations[1].id, "\(finalDestinationAnnotationTestPrefix)_1")
652+
}
653+
654+
func testAddFinalDestinationWithCustomIdentifierIfStyleLoaded() {
655+
navigationMapView.pointAnnotationManager = pointAnnotationManager
656+
657+
navigationMapView.addDestinationAnnotation(coordinate1, identifier: "custom")
658+
XCTAssertEqual(pointAnnotationManager.annotations.count, 1)
659+
XCTAssertEqual(pointAnnotationManager.annotations[0].id, "custom")
660+
}
661+
662+
func testRemovesFinalDestinationIfStyleLoaded() {
663+
navigationMapView.pointAnnotationManager = pointAnnotationManager
664+
navigationMapView.addDestinationAnnotation(coordinate1)
665+
navigationMapView.addDestinationAnnotation(coordinate2)
666+
667+
navigationMapView.removeDestinationAnnotation(identifier: "custom")
668+
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)
669+
670+
navigationMapView.addDestinationAnnotation(coordinate2, identifier: "custom")
671+
XCTAssertEqual(pointAnnotationManager.annotations.count, 3)
672+
navigationMapView.removeDestinationAnnotation(identifier: "custom")
673+
XCTAssertEqual(pointAnnotationManager.annotations.count, 2)
674+
675+
navigationMapView.removeDestinationAnnotation()
676+
XCTAssertEqual(pointAnnotationManager.annotations.count, 0)
677+
}
678+
587679
private func configureIntersections() {
588680
let style = navigationMapView.mapView.mapboxMap.style
589681
var source = GeoJSONSource()

0 commit comments

Comments
 (0)