Skip to content

Commit

Permalink
Restore EORVC presentation which was removed in #54.
Browse files Browse the repository at this point in the history
Where possible, the particulars of presentation were copied from
b790f96 (aka before #54).
  • Loading branch information
michaelkirk committed Jun 27, 2024
1 parent dc97796 commit 6e075a1
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 27 deletions.
9 changes: 5 additions & 4 deletions MapboxNavigation/EndOfRouteViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ class EndOfRouteViewController: UIViewController {
lazy var endOfRouteArrivedText: String = NSLocalizedString("END_OF_ROUTE_ARRIVED", bundle: .mapboxNavigation, value: "You have arrived", comment: "Title used for arrival")
lazy var endNavigationText: String = NSLocalizedString("END_NAVIGATION", bundle: .mapboxNavigation, value: "End Navigation", comment: "End Navigation Button Text")

let dismissHandler: () -> Void
init(dismissHandler: @escaping () -> Void) {
self.dismissHandler = dismissHandler
var dismissHandler: (() -> Void)?

init() {
super.init(nibName: nil, bundle: nil)
}

Expand Down Expand Up @@ -107,7 +107,8 @@ class EndOfRouteViewController: UIViewController {
// MARK: - Actions

@objc func endNavigationPressed(_ sender: Any) {
self.dismissHandler()
assert(self.dismissHandler != nil)
self.dismissHandler?()
}

// MARK: - Private Functions
Expand Down
24 changes: 22 additions & 2 deletions MapboxNavigation/NavigationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ open class NavigationView: UIView {
self.informationStackView.bottomAnchor.constraint(equalTo: self.topAnchor),
self.instructionsBannerContentView.topAnchor.constraint(equalTo: self.instructionsBannerView.topAnchor)
]


lazy var endOfRouteShowConstraint: NSLayoutConstraint? = self.endOfRouteView?.bottomAnchor.constraint(equalTo: self.bottomAnchor)

lazy var endOfRouteHideConstraint: NSLayoutConstraint? = self.endOfRouteView?.topAnchor.constraint(equalTo: self.bottomAnchor)

lazy var endOfRouteHeightConstraint: NSLayoutConstraint? = self.endOfRouteView?.heightAnchor.constraint(equalToConstant: Constants.endOfRouteHeight)

private enum Images {
static let overview = UIImage(named: "overview", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate)
static let volumeUp = UIImage(named: "volume_up", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate)
Expand Down Expand Up @@ -123,7 +129,21 @@ open class NavigationView: UIView {
view.cancelButton.addTarget(self, action: Actions.cancelButton, for: .touchUpInside)
return view
}()


var endOfRouteView: UIView? {
didSet {
if let active: [NSLayoutConstraint] = constraints(affecting: oldValue) {
NSLayoutConstraint.deactivate(active)
}

oldValue?.removeFromSuperview()
if let endOfRouteView {
endOfRouteView.translatesAutoresizingMaskIntoConstraints = false
addSubview(endOfRouteView)
}
}
}

weak var delegate: NavigationViewDelegate? {
didSet {
self.updateDelegates()
Expand Down
15 changes: 12 additions & 3 deletions MapboxNavigation/NavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,12 @@ open class NavigationViewController: UIViewController {
An instance of `MLNAnnotation` representing the origin of your route.
*/
public var origin: MLNAnnotation?


/**
Shows End of route Feedback UI when the route controller arrives at the final destination. Defaults to `true.`
*/
public var showsEndOfRouteFeedback: Bool = true

/**
The receiver’s delegate.
*/
Expand Down Expand Up @@ -640,8 +645,12 @@ extension NavigationViewController: RouteControllerDelegate {

if !self.isConnectedToCarPlay, // CarPlayManager shows rating on CarPlay if it's connected
routeController.routeProgress.isFinalLeg, advancesToNextLeg {
self.mapViewController.transitionToEndNavigation(with: 1)
self.delegate?.navigationViewControllerDidFinishRouting?(self)
self.mapViewController.completeRoute(showArrivalUI: self.showsEndOfRouteFeedback, onDismiss: { [weak self] in
guard let self else {
return
}
self.delegate?.navigationViewControllerDidFinishRouting?(self)
})
}
return advancesToNextLeg
}
Expand Down
9 changes: 9 additions & 0 deletions MapboxNavigation/NavigationViewLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,13 @@ extension NavigationView {
])
NSLayoutConstraint.activate(self.bannerShowConstraints)
}

func constrainEndOfRoute() {
endOfRouteHideConstraint?.isActive = true

endOfRouteView?.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
endOfRouteView?.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true

endOfRouteHeightConstraint?.isActive = true
}
}
83 changes: 65 additions & 18 deletions MapboxNavigation/RouteMapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class RouteMapViewController: UIViewController {
var lastTimeUserRerouted: Date?
var stepsViewController: StepsViewController?
var destination: Waypoint?
var showsEndOfRoute: Bool = true
var arrowCurrentStep: RouteStep?

var contentInsets: UIEdgeInsets {
Expand Down Expand Up @@ -124,18 +123,7 @@ class RouteMapViewController: UIViewController {
right: 20)
}

lazy var endOfRouteViewController: EndOfRouteViewController = .init(dismissHandler: { [weak self] in
guard let self else {
return
}
guard let routeController else {
assertionFailure("routeController was unexpectedly nil")
return
}
routeController.endNavigation()
self.delegate?.mapViewControllerDidFinish(self, byCanceling: false)
})

let endOfRouteViewController = EndOfRouteViewController()
weak var delegate: RouteMapViewControllerDelegate?

// MARK: - Lifecycle
Expand Down Expand Up @@ -454,8 +442,60 @@ class RouteMapViewController: UIViewController {
}

// MARK: End Of Route

func transitionToEndNavigation(with duration: TimeInterval, completion: ((Bool) -> Void)? = nil) {

func completeRoute(showArrivalUI: Bool, presentationDuration: TimeInterval = 1.0, presentationCompletion: ((Bool) -> Void)? = nil, onDismiss: @escaping () -> Void) {
if showArrivalUI {
self.showEndOfRoute(duration: presentationDuration, onDismiss: onDismiss, presentationCompletion: presentationCompletion)
} else {
self.transitionToEndNavigation(duration: presentationDuration, completion: { completed in
onDismiss()
presentationCompletion?(completed)
})
}
}

func embedEndOfRoute() {
let endOfRoute = self.endOfRouteViewController
addChild(endOfRoute)
self.navigationView.endOfRouteView = endOfRoute.view
self.navigationView.constrainEndOfRoute()
endOfRoute.didMove(toParent: self)
}

func unembedEndOfRoute() {
let endOfRoute = self.endOfRouteViewController
endOfRoute.willMove(toParent: nil)
endOfRoute.removeFromParent()
}

func showEndOfRoute(duration: TimeInterval = 1.0, onDismiss: @escaping () -> Void, presentationCompletion: ((Bool) -> Void)? = nil) {
self.embedEndOfRoute()
self.endOfRouteViewController.dismissHandler = onDismiss
self.endOfRouteViewController.destination = self.destination
self.navigationView.endOfRouteView?.isHidden = false

self.view.layoutIfNeeded() // flush layout queue
self.navigationView.endOfRouteHideConstraint?.isActive = false
self.navigationView.endOfRouteShowConstraint?.isActive = true

self.transitionToEndNavigation(duration: duration, completion: presentationCompletion)

guard let height = navigationView.endOfRouteHeightConstraint?.constant else { return }
let insets = UIEdgeInsets(top: navigationView.instructionsBannerView.bounds.height, left: 20, bottom: height + 20, right: 20)

// zoom in a bit to focus on the arrived destination
if let coordinates = routeController?.routeProgress.route.coordinates, let userLocation = routeController?.locationManager.location?.coordinate {
let slicedLine = Polyline(coordinates).sliced(from: userLocation).coordinates
let line = MLNPolyline(coordinates: slicedLine, count: UInt(slicedLine.count))

let camera = self.navigationView.mapView.cameraThatFitsShape(line, direction: self.navigationView.mapView.camera.heading, edgePadding: insets)
camera.pitch = 0
camera.altitude = self.navigationView.mapView.camera.altitude
self.navigationView.mapView.setCamera(camera, animated: true)
}
}

func transitionToEndNavigation(duration: TimeInterval = 1.0, completion: ((Bool) -> Void)? = nil) {
self.view.layoutIfNeeded() // flush layout queue
NSLayoutConstraint.deactivate(self.navigationView.bannerShowConstraints)
NSLayoutConstraint.activate(self.navigationView.bannerHideConstraints)
Expand All @@ -478,6 +518,8 @@ class RouteMapViewController: UIViewController {

func hideEndOfRoute(duration: TimeInterval = 0.3, completion: ((Bool) -> Void)? = nil) {
self.view.layoutIfNeeded() // flush layout queue
self.navigationView.endOfRouteHideConstraint?.isActive = true
self.navigationView.endOfRouteShowConstraint?.isActive = false
self.view.clipsToBounds = true

self.mapView.enableFrameByFrameCourseViewTracking(for: duration)
Expand All @@ -488,14 +530,19 @@ class RouteMapViewController: UIViewController {
self.navigationView.floatingStackView.alpha = 1.0
}

let complete: (Bool) -> Void = {
self.navigationView.endOfRouteView?.isHidden = true
self.unembedEndOfRoute()
completion?($0)
}

let noAnimation = {
animate()
completion?(true)
complete(true)
}

guard duration > 0.0 else { return noAnimation() }

UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: animate, completion: completion)
UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: animate, completion: complete)
}
}

Expand Down

0 comments on commit 6e075a1

Please sign in to comment.