Conversation
|
@frederoni can we merge the UI example with the Example in place now? Also, let's see if we can remove the duplicate Geomtry.swift. |
There was a problem hiding this comment.
Does looks like this is a duplicate?
There was a problem hiding this comment.
Deleted these plists because they should be included in the app/example and not the SDK.
There was a problem hiding this comment.
Should we include any translations?
There was a problem hiding this comment.
I removed them temporarily while cleaning up but I think we should keep the translations in here.
aeb4131 to
09c7d9f
Compare
|
@frederoni what do you think about just including this in core instead of requiring an additional pod to install? |
|
@bsudekum It'd be convenient not having to maintain the libs separately and we can only version one of them as long as they live in the same repo, unless we publish. That being said, I still think we should keep them separate. Navigation UI has dependencies we don't want to enforce on all navigation users. Navigation.swift can technically be used on ⌚️ while Navigation UI is📱 only. |
|
@frederoni ah that makes sense, I'll review this today. |
| var currentManeuverArrowPolylines: [ArrowFillPolyline] = [] | ||
| var currentManeuverArrowStrokePolylines: [ArrowFillPolyline] = [] | ||
| let distanceFormatter = DistanceFormatter(approximate: true) | ||
| let secondsBeforeResetTrackingMode:TimeInterval = 25.0 |
There was a problem hiding this comment.
We should pull this out into a constant
|
|
||
| if let camera = pendingCamera { | ||
| camera.altitude = 1_000 | ||
| camera.pitch = 45 |
There was a problem hiding this comment.
If a developer sends through a camera with a custom pitch and altitude, we should honor these values.
There was a problem hiding this comment.
Default camera with pitch 45 and 1000m but not overriding if pendingCamera != nil.
| } | ||
|
|
||
| let imageName = imageNamePattern.replacingOccurrences(of: " ", with: "_").replacingOccurrences(of: "{ref}", with: number) | ||
| let apiURL = URL(string: "https://commons.wikimedia.org/w/api.php?action=query&format=json&maxage=86400&prop=imageinfo&titles=File%3A\(imageName)&iiprop=url%7Csize&iiurlheight=\(Int(round(height)))")! |
There was a problem hiding this comment.
This is part of the public Wikimedia Commons API. The maxage parameter should keep repeated requests from being expensive, but we should ensure that we’re calling the API only as frequently as necessary.
| } | ||
|
|
||
| func giveLocalNotification(_ step: RouteStep) { | ||
| if UIApplication.shared.applicationState == .background { |
There was a problem hiding this comment.
We should make notifications an option.
There was a problem hiding this comment.
Added sendNotifications: Bool
| // Generated by PaintCode (www.paintcodeapp.com) | ||
| // | ||
|
|
||
|
|
There was a problem hiding this comment.
Should we check in the paint code project?
| class ArrowStrokePolyline: ArrowFillPolyline {} | ||
|
|
||
| struct RouteControllerNotification { | ||
| static let didReceiveNewRoute = Notification.Name("RouteControllerDidReceiveNewRoute") |
There was a problem hiding this comment.
This should either be removed or added where other notifications are defined
1ec5
left a comment
There was a problem hiding this comment.
Not having taken a look at this PR until now, it’s a bit overwhelming to review the code closely. So I started by reviewing the example view controllers for symptoms of architectural and ergonomic problems, then did a spot check over some of the remaining files. A more thorough review will take a bit more time.
Aside from the comments below, the main README.md should refer to the UI/ folder, so developers know to look there.
| | --- | --- | | ||
|
|
||
| ### Examples | ||
| We provide examples in Swift and Objective-C. Run `pod install` from the Example folder and open `Example.xcworkspace` to try it out. |
There was a problem hiding this comment.
FYI it’s now possible to obtain the map SDK via Carthage: mapbox/mapbox-gl-native#1623 (comment).
| // Pass through a | ||
| // 1. the route the user will take | ||
| // 2. A `Directions` class, used for rerouting. | ||
| let controller = NavigationUI.instantiate(route: route, directions: directions) |
There was a problem hiding this comment.
Can you explain what “a navigation UI” is and how this object fits into an MVC architecture? It seems to be a factory for RouteViewController objects. Why not initialize a RouteViewController directly?
There was a problem hiding this comment.
I first added the NavigationUI to handle the theme only, but because of the way Pulley is set up with designated initializer which I can't override conveniently, a factory method was the most appropriate I could come up with. The terminology is inherited from
UIStoryboard.instantiateInitialViewController()
UIStoryboard.instantiateViewController(withIdentifier:)That being said, I agree with you, I'd prefer an init method on RouteViewController. The problem is supporting initializing it programmatically and through storyboard without using a factory method. I guess I could fork Pulley although the intention is to replace it eventually.
There was a problem hiding this comment.
UIStoryboard performs a very different role than NavigationUI. The initial view controller is essentially a singleton, whereas RouteViewController is not. If we stick with a factory method, we should name it something like routeViewController(for:).
| // Pass through a | ||
| // 1. the route the user will take | ||
| // 2. A `Directions` class, used for rerouting. | ||
| let controller = NavigationUI.instantiate(route: route, directions: directions) |
There was a problem hiding this comment.
controller is a local variable that isn’t referenced anywhere else – does that mean the object gets deinitialized immediately after creation? If not, ViewController should hang onto it.
There was a problem hiding this comment.
controller is actually a view controller that gets pushed into the navigation stack which hangs onto it.
| // Pass through a | ||
| // 1. the route the user will take | ||
| // 2. A `Directions` class, used for rerouting. | ||
| let controller = NavigationUI.instantiate(route: route, directions: directions) |
There was a problem hiding this comment.
Swift and Objective-C favor the term “init” over the term “instantiate”.
| let controller = NavigationUI.instantiate(route: route, directions: directions) | ||
| present(controller, animated: true, completion: nil) | ||
|
|
||
| controller.willDismissNavigationHandler = { |
There was a problem hiding this comment.
Forcing RouteViewController to own callbacks makes it all too easy for a developer to write a reference cycle that leaks memory. The two most common patterns for “handlers” are:
- Subclassing. If the application wants to customize the dismissal experience, it can subclass RouteViewController to override
dismiss(animated:completion:)andviewDidDisappear(_:). - Delegation. Add a RouteViewControllerDelegate protocol that ViewController can conform to by implementing
routeViewControllerWillDismiss(_:)androuteViewControllerDidDismiss(_:).
Also, is there anything we can do to facilitate the use of an unwind segue to dismiss RouteViewController all the way to a starting point?
|
|
||
| let distanceFormatter = DistanceFormatter() | ||
|
|
||
| extension MapboxGeocoder.GeocodedPlacemark { |
There was a problem hiding this comment.
Is there a conflict that would force us to qualify GeocodedPlacemark with the MapboxGeocoder module here?
| // TODO: Show country if not the current country. | ||
| // Cut off country and postal code and add abbreviated state/region code at the end. | ||
|
|
||
| let stitle = lines.prefix(upTo: 2).joined(separator: NSLocalizedString("ADDRESS_LINE_SEPARATOR", value: ", ", comment: "Delimiter between lines in an address when displayed inline")) |
There was a problem hiding this comment.
There are multiple references to localized strings, but this PR doesn’t include a .strings file.
| return string(for: obj, markUpWithSSML: false) | ||
| } | ||
|
|
||
| func string(for obj: Any?, markUpWithSSML: Bool) -> String? { |
There was a problem hiding this comment.
This SSML markup code is unused. I take it it’s for the Polly integration being added in #42.
| } | ||
| } | ||
|
|
||
| class OSRMInstructionFormatter: Formatter { |
There was a problem hiding this comment.
As I pointed out in #42 (review), I think it’s very important for the Swift port of OSRMTextInstructions to live independently of the Mapbox navigation SDK. The instructions included in this PR are also out of date compared to what’s in Transifex that could be transformed via the existing script to plist format.
| let number = components[1] | ||
| if var imageName = ShieldImageNamesByPrefix[network] { | ||
| imageName = imageName.replacingOccurrences(of: " ", with: "_").replacingOccurrences(of: "{ref}", with: number) | ||
| let url = URL(string: "https://commons.wikimedia.org/w/thumb.php?f=\(imageName)&w=\(imageView.bounds.width * UIScreen.main.scale)") |
There was a problem hiding this comment.
Frankly, our use of thumb.php is more problematic than our use of the Wikimedia Commons API. One problem is that thumb.php has no maxage parameter like the API does. Does SDWebImage do a good job of avoiding duplicate requests for the same thumbnail image as the user scrolls a particular row in and out?
There was a problem hiding this comment.
Yes. It will only request once per url in this case. Even after restarting the process, it will not make the request again but instead fetch it from disk. maxage defaults to one week.
32fad0d to
34ce2cf
Compare
Rewrote the library to more closely parallel mapbox/MapboxGeocoder.swift#41 and mapbox/MapboxStatic.swift#19. Removed the class prefix from Swift but kept it for Objective-C. The goal is no longer to be a (poor) drop-in replacement for MapKit’s MKDirections API but rather to be as idiomatic as possible in Swift and Objective-C, with a priority on Swift. Symbols conform to platform naming conventions but in some cases eschew MapKit terminology in favor of Geocoding API terminology, so that api-documentation makes sense in the context of this library. Removed the dependency on RequestKit. This library chooses reasonable default networking behavior; if you need anything more sophisticated, you can access the URL request information to use with a custom NSURLSession. Directions no longer needs to be strongly held in order for the request to finish. Instead, the request is made against the shared URL session; to use a custom URL session, make the request yourself using the URL returned by the URLForCalculatingDirections(options:) method. Removed the cancel() method; instead, directly cancel the NSURLSessionDataTask returned by calculateDirections(options:completionHandler:). Added a shared (singleton) Directions object. Use the shared object if you’ve set your Mapbox access token in the MGLMapboxAccessToken key of your application’s Info.plist file. Otherwise, create a Directions object with the access token explicitly. A single directions object can handle multiple requests concurrently (since it just passes the requests off to the shared URL session). Eliminated the separate APIs for calculating ETAs. Instead, all the options supported by the Directions API, including flags for including steps and the overview geometry, are now exposed through a new RouteOptions class. Effectively, this change adds support for the geometries, overview, radiuses, steps, and continue_straight query parameters and allows the heading accuracy of any waypoint to be customized. However, note that steps are no longer returned by default, and the overview geometry is simplified by default. The access_token parameter is now the last URL parameter instead of the first. Broke out MBDirectionsRequest.TransportType into three profile identifier constants. You always specify a profile identifier, not a transport type. That makes the desired mode of transportation more open-ended. Removed the MBDirectionsResponse class in favor of passing the waypoints and routes from the response directly into the completion handler. Renamed Route.geometry to Route.coordinates. For Objective-C compatibility, all enums are backed by integer types instead of String, but they’re CustomStringConvertible to allow for the same expressiveness we’re used to in Swift. Error handling is much more robust now. Various error conditions returned by the API cause the localized failure reason and recovery suggestion to be set in the NSError object that is passed into the completion handler. Updated test fixtures and expectations for the v5 server-side API and the revamped client-side API, and updated examples. Fixes mapbox#41, fixes mapbox#43, fixes mapbox#44.
First draft of the Nav UI