Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate some hardcoded mapbox styles, and replace those that remain with maplibre styles. (+docs!) #45

Merged
merged 8 commits into from
May 29, 2024
Merged
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
- Updated MapLibre Native dependency to ios-v6.0.0 (https://github.com/maplibre/maplibre-native/releases/tag/ios-v6.0.0). Implementers need to change the prefix MGL to MLN for all MapLibre Native classes that are referenced.
- Only snap location to route if the location is within the `RouteControllerUserLocationSnappingDistance`
- Add support for Swift Package Manager while dropping Carthage and Cocoapods.
- Removed implicit default dependencies on MapBox tileservers by requiring explicit styles URLs in more places.
- Merged in <https://github.com/maplibre/maplibre-navigation-ios/pull/45>.
- BREAKING: Removed `MLNStyle` extensions referencing non-functioning MapBox styles, e.g. `MLNStyle.navigationGuidanceDayStyleURL`.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically breaking from an API standpoint, though it seems like it would not have been working for anyone before.

Alternatively, we could keep the old methods around, deprecate them, and have them all return DayStyle(demoStyle: ()) or something?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking is fine for me 👍

- Added `Day/NightStyle(styleURL:)` which takes an explicit URL to a hosting tileserver style.
- Added `Day/NightStyle(demoStyle: ())` as an explicit alternative when the user doesn't have a tileserver handy. This uses MapLibre's demo style and is intended for testing and demonstration use only.
- Deprecated `DayStyle()`/`NightStyle()` initializers because they were backed by an implicit tile service. If these default styles *are* still used, they'll now use the MapLibre demo style.
- `NavigationViewController` now expects explicit style URLs with `NavigationViewController(route:dayStyleURL:nightStyleURL:...)` or NavigationViewController(route:dayStyle:nightStyle:...)` and the existing initializer, which allowed "default" styles, is deprecated and uses the MapLibre demo styles.

## v2.0.0 (May 23, 2023)
- Upgrade minimum iOS version from 11.0 to 12.0.
Expand Down
4 changes: 2 additions & 2 deletions MapboxNavigation/CarPlayMapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ class CarPlayMapViewController: UIViewController, MLNMapViewDelegate {
super.viewDidLoad()

self.styleManager = StyleManager(self)
self.styleManager.styles = [DayStyle(), NightStyle()]
self.styleManager.styles = [DayStyle(demoStyle: ()), NightStyle(demoStyle: ())]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The demo styles are now being used in some places that were previously defaulting to mapbox styles. This is probably wrong, but (I think) no worse than things being completely broken before.

Probably these should somehow be surfaced or inferred as well. I somewhat arbitrarily decided this was out of scope for this PR, but I could follow up in this PR or another depending on how people are feeling about it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't mind your approach here 👍


self.resetCamera(animated: false, altitude: CarPlayMapViewController.defaultAltitude)
self.mapView.setUserTrackingMode(.followWithCourse, animated: true, completionHandler: nil)
}
Expand Down
4 changes: 2 additions & 2 deletions MapboxNavigation/CarPlayNavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
view.addSubview(mapView)

self.styleManager = StyleManager(self)
self.styleManager.styles = [DayStyle(), NightStyle()]
self.styleManager.styles = [DayStyle(demoStyle: ()), NightStyle(demoStyle: ())]

self.resumeNotifications()
self.routeController.resume()
mapView.recenterMap()
Expand Down Expand Up @@ -264,7 +264,7 @@

var maneuvers: [CPManeuver] = [primaryManeuver]

// Add tertiary text if available. TODO: handle lanes.

Check warning on line 267 in MapboxNavigation/CarPlayNavigationViewController.swift

View workflow job for this annotation

GitHub Actions / Code Style

TODOs should be resolved (handle lanes.) (todo)
if let tertiaryInstruction = visualInstruction.tertiaryInstruction, !tertiaryInstruction.containsLaneIndications {
let tertiaryManeuver = CPManeuver()
tertiaryManeuver.symbolSet = tertiaryInstruction.maneuverImageSet(side: visualInstruction.drivingSide)
Expand All @@ -291,7 +291,7 @@

func endOfRouteFeedbackTemplate() -> CPGridTemplate {
let buttonHandler: (_: CPGridButton) -> Void = { [weak self] _ in
// TODO: no such method exists, and the replacement candidate ignores the feedback sent, so ... ?

Check warning on line 294 in MapboxNavigation/CarPlayNavigationViewController.swift

View workflow job for this annotation

GitHub Actions / Code Style

TODOs should be resolved (no such method exists, and the...) (todo)
// self?.routeController.setEndOfRoute(rating: Int(button.titleVariants.first!.components(separatedBy: CharacterSet.decimalDigits.inverted).joined())!, comment: nil)
self?.carInterfaceController.popTemplate(animated: true)
self?.exitNavigation()
Expand Down
11 changes: 4 additions & 7 deletions MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ private extension UIFont {
*/
@objc(MBDayStyle)
open class DayStyle: Style {
public required init() {
super.init()
mapStyleURL = MLNStyle.navigationGuidanceDayStyleURL
@objc public required init(mapStyleURL: URL) {
super.init(mapStyleURL: mapStyleURL)
styleType = .day
statusBarStyle = .default
}
Expand Down Expand Up @@ -166,10 +165,8 @@ open class DayStyle: Style {
*/
@objc(MBNightStyle)
open class NightStyle: DayStyle {
public required init() {
super.init()
mapStyleURL = MLNStyle.navigationGuidanceNightStyleURL
previewMapStyleURL = MLNStyle.navigationPreviewNightStyleURL
public required init(mapStyleURL: URL) {
super.init(mapStyleURL: mapStyleURL)
styleType = .night
statusBarStyle = .lightContent
}
Expand Down
74 changes: 0 additions & 74 deletions MapboxNavigation/MLNStyle.swift

This file was deleted.

2 changes: 1 addition & 1 deletion MapboxNavigation/NavigationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ open class NavigationView: UIView {

override open func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
DayStyle().apply()
DayStyle(demoStyle: ()).apply()
[self.mapView, self.instructionsBannerView, self.lanesView, self.bottomBannerView, self.nextBannerView].forEach { $0.prepareForInterfaceBuilder() }
self.wayNameView.text = "Street Label"
}
Expand Down
99 changes: 88 additions & 11 deletions MapboxNavigation/NavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -345,20 +345,97 @@ open class NavigationViewController: UIViewController {
super.init(coder: aDecoder)
}

/**
Initializes a `NavigationViewController` that provides turn by turn navigation for the given route. A optional `direction` object is needed for potential rerouting.

See [Mapbox Directions](https://mapbox.github.io/mapbox-navigation-ios/directions/) for further information.
*/
/// Initializes a `NavigationViewController` that provides turn by turn navigation for the given route.
///
/// ```
/// let dayStyle = DayStyle(mapStyleURL: styleURL)
/// let vc = NavigationViewController(route: route, styles: [dayStyle])
/// self.presentViewController(vc, animated: true)
/// ```
/// - Parameters:
/// - route: The route to follow.
/// - directions: Used when recomputing a new route, for example if the user takes a wrong turn and needs re-routing. If unspecified, a default will be used.
/// - styles: The `[dayStyle]` or `[dayStyle, nightStyle]` styles used to render the map. If nil, the default styles will be used.
/// - routeController: Used to monitor the route and notify of changes to the route. If nil, a default will be used.
/// - locationManager: Tracks the users location along the route. If nil, a default will be used.
/// - voiceController: Produces voice instructions for route navigation. If nil, a default will be used.
///
/// See [Mapbox Directions](https://mapbox.github.io/mapbox-navigation-ios/directions/) for further information.
@available(*, deprecated, message: "Use `init(for:dayStyle:...) or init(for:dayStyleURL:...)` instead.")
@objc(initWithRoute:directions:styles:routeController:locationManager:voiceController:)
public convenience init(for route: Route,
directions: Directions = Directions.shared,
styles: [Style]? = [DayStyle(), NightStyle()],
routeController: RouteController? = nil,
locationManager: NavigationLocationManager? = nil,
voiceController: RouteVoiceController? = nil) {
let styles = styles ?? []
assert(styles.count <= 2, "Having more than two styles is undefined.")
let dayStyle = styles.first ?? DayStyle(demoStyle: ())
let nightStyle = styles.count > 1 ? styles[1] : NightStyle(mapStyleURL: dayStyle.mapStyleURL)

self.init(for: route, dayStyle: dayStyle, nightStyle: nightStyle, directions: directions, routeController: routeController, locationManager: locationManager, voiceController: voiceController)
}

/// Initializes a `NavigationViewController` that provides turn by turn navigation for the given route.
///
/// - Parameters:
/// - route: The route to follow.
/// - dayStyleURL: URL for the style rules used to render the map during daylight hours.
/// - nightStyleURL: URL for the style rules used to render the map during nighttime hours. If nil, `dayStyleURL` will be used at night as well.
/// - directions: Used when recomputing a new route, for example if the user takes a wrong turn and needs re-routing. If unspecified, a default will be used.
/// - routeController: Used to monitor the route and notify of changes to the route. If nil, a default will be used.
/// - locationManager: Tracks the users location along the route. If nil, a default will be used.
/// - voiceController: Produces voice instructions for route navigation. If nil, a default will be used.
///
/// See [Mapbox Directions](https://mapbox.github.io/mapbox-navigation-ios/directions/) for further information.
@objc(initWithRoute:dayStyleURL:nightStyleURL:directions:routeController:locationManager:voiceController:)
public convenience init(for route: Route,
dayStyleURL: URL,
nightStyleURL: URL? = nil,
directions: Directions = Directions.shared,
routeController: RouteController? = nil,
locationManager: NavigationLocationManager? = nil,
voiceController: RouteVoiceController? = nil) {
let dayStyle = DayStyle(mapStyleURL: dayStyleURL)
let nightStyle = NightStyle(mapStyleURL: nightStyleURL ?? dayStyleURL)
self.init(for: route, dayStyle: dayStyle, nightStyle: nightStyle, directions: directions, routeController: routeController, locationManager: locationManager, voiceController: voiceController)
}

/// Initializes a `NavigationViewController` that provides turn by turn navigation for the given route.
///
/// - Parameters:
/// - route: The route to follow.
/// - dayStyle: Style used to render the map during daylight hours.
/// - nightStyle: Style used to render the map during nighttime hours. If nil, `dayStyle` will be used at night as well.
/// - directions: Used when recomputing a new route, for example if the user takes a wrong turn and needs re-routing. If unspecified, a default will be used.
/// - routeController: Used to monitor the route and notify of changes to the route. If nil, a default will be used.
/// - locationManager: Tracks the users location along the route. If nil, a default will be used.
/// - voiceController: Produces voice instructions for route navigation. If nil, a default will be used.
///
/// See [Mapbox Directions](https://mapbox.github.io/mapbox-navigation-ios/directions/) for further information.
@objc(initWithRoute:dayStyle:nightStyle:directions:routeController:locationManager:voiceController:)
public required init(for route: Route,
dayStyle: Style,
nightStyle: Style? = nil,
directions: Directions = Directions.shared,
styles: [Style]? = [DayStyle(), NightStyle()],
routeController: RouteController? = nil,
locationManager: NavigationLocationManager? = nil,
voiceController: RouteVoiceController? = nil) {
let nightStyle = {
if let nightStyle {
return nightStyle
}

let dayCopy: Style = dayStyle.copy() as! Style
dayCopy.styleType = .night
return dayCopy
}()

assert(dayStyle.styleType == .day)
assert(nightStyle.styleType == .night)

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

self.locationManager = locationManager ?? NavigationLocationManager()
let routeController = routeController ?? RouteController(along: route, directions: directions, locationManager: self.locationManager)
self.routeController = routeController
Expand Down Expand Up @@ -387,8 +464,8 @@ open class NavigationViewController: UIViewController {
mapViewController.reportButton.isHidden = !self.showsReportFeedback

self.styleManager = StyleManager(self)
self.styleManager.styles = styles ?? [DayStyle(), NightStyle()]
self.styleManager.styles = [dayStyle, nightStyle]

if !(route.routeOptions is NavigationRouteOptions) {
print("`Route` was created using `RouteOptions` and not `NavigationRouteOptions`. Although not required, this may lead to a suboptimal navigation experience. Without `NavigationRouteOptions`, it is not guaranteed you will get congestion along the route line, better ETAs and ETA label color dependent on congestion.")
}
Expand Down Expand Up @@ -515,8 +592,8 @@ open class NavigationViewController: UIViewController {
let locationManager = routeController.locationManager.copy() as! NavigationLocationManager
let directions = routeController.directions
let route = routeController.routeProgress.route
let navigationViewController = NavigationViewController(for: route, directions: directions, routeController: routeController, locationManager: locationManager)
let navigationViewController = NavigationViewController(for: route, dayStyle: DayStyle(demoStyle: ()), directions: directions, routeController: routeController, locationManager: locationManager)

window.rootViewController?.topMostViewController()?.present(navigationViewController, animated: true, completion: {
navigationViewController.isUsedInConjunctionWithCarPlayWindow = true
})
Expand Down
36 changes: 30 additions & 6 deletions MapboxNavigation/Style.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,52 @@ open class Style: NSObject {
/**
URL of the style to display on the map during turn-by-turn navigation.
*/
@objc open var mapStyleURL: URL = MLNStyle.navigationGuidanceDayStyleURL
@objc open var mapStyleURL: URL = MLNStyle.defaultStyle().url

#if canImport(CarPlay)
/**
URL of the style to display on the map when previewing a route, for example on CarPlay.
*/
@objc open var previewMapStyleURL = MLNStyle.navigationPreviewDayStyleURL
@objc open var previewMapStyleURL = MLNStyle.defaultStyle().url
#else
/**
URL of the style to display on the map when previewing a route.

This property is currently unused by default, but you can use it to present your own route preview map.
*/
@objc open var previewMapStyleURL = MLNStyle.navigationPreviewDayStyleURL
@objc open var previewMapStyleURL = MLNStyle.defaultStyle().url
#endif

/**
Applies the style for all changed properties.
*/
@objc open func apply() {}

@objc override public required init() {}

@available(*, deprecated, message: "Use `init(mapStyleURL:)` to specify your map style. If you want to try the demo maplibre tiles, use init(demoStyle: ()).")
@objc override public convenience init() {
self.init(demoStyle: ())
}

@objc public required init(mapStyleURL: URL) {
self.mapStyleURL = mapStyleURL
}

@objc public convenience init(demoStyle: ()) {
self.init(mapStyleURL: MLNStyle.defaultStyle().url)
}
}

extension Style: NSCopying {
public func copy(with zone: NSZone? = nil) -> Any {
let copy = Self(mapStyleURL: self.mapStyleURL)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Living in Swift land for a while, I forgot about NSCopying!

copy.tintColor = self.tintColor
copy.statusBarStyle = self.statusBarStyle
copy.fontFamily = self.fontFamily
copy.styleType = self.styleType
copy.mapStyleURL = self.mapStyleURL
copy.previewMapStyleURL = self.previewMapStyleURL
return copy
}
}

/**
Expand Down
Loading
Loading