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

Merge release-v2.0 to main (as of v2.0.0-beta.5) #558

Merged
merged 49 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0351a3b
Turf v2.0.0-alpha.1 (#517)
1ec5 Feb 18, 2021
9af4ddd
Turn Incident.Impact type into an enumeration (#519)
dersim-davaod Feb 18, 2021
ef9d8cd
v2.0.0-alpha.1
1ec5 Feb 19, 2021
075b959
Updated instructions for prereleasing on CocoaPods
1ec5 Feb 19, 2021
1a2cf78
Added podspec for prereleases
1ec5 Feb 19, 2021
b182188
Add fallback access token.
MaximAlien Feb 26, 2021
46e1ef1
Update documentation to mention `MBXAccessToken` instead of `MGLMapbo…
MaximAlien Mar 1, 2021
987f70f
Merge pull request #522 from mapbox/maxim/add-access-token-handling
MaximAlien Mar 1, 2021
7d12e4d
Turf v2.0.0-alpha.3
1ec5 Mar 3, 2021
612e4e9
Restored support for tvOS, watchOS
1ec5 Mar 3, 2021
714c524
Migrated to Turf shims for Core Location types
1ec5 Mar 3, 2021
9364743
Prepare Mapbox Directions v2.0.0-alpha.2.
MaximAlien Mar 3, 2021
e40ab7c
v2.0.0-alpha.2
MaximAlien Mar 4, 2021
f61e24d
Merge branch 'main' into release-v2.0
1ec5 Apr 2, 2021
800f942
Intersections indicate preferred lane usage (#529)
jill-cardamon Apr 2, 2021
c6ea95e
Consolidated v2.0.0 section in changelog
1ec5 Apr 2, 2021
f41f32a
v2.0.0-beta.1
1ec5 Apr 2, 2021
c9411cd
Fix VisualInstruction.component.lane type mismatch (#532)
jill-cardamon Apr 7, 2021
399d28c
v2.0.0-beta.2
1ec5 Apr 9, 2021
ca5148c
Preferred lane direction is now a ManeuverDirection (#535)
jill-cardamon Apr 14, 2021
c2bfe34
v2.0.0-beta.3 (#536)
jill-cardamon Apr 14, 2021
25fd495
Disabled codecov
1ec5 Apr 16, 2021
5e3d3e2
Remove excessive logging from `Intersection` encoder.
MaximAlien Apr 20, 2021
3f6636d
Merge pull request #538 from mapbox/maxim/remove-excessive-logging
MaximAlien Apr 21, 2021
db8646a
Fix typo in Waypoint documentation
S2Ler May 17, 2021
9d60971
v2.0.0-beta.4
chezzdev May 28, 2021
852e80f
Update Turf version
chezzdev May 28, 2021
60b4a02
Merge pull request #545 from mapbox/release-v2.0.0-beta.4
chezzdev May 28, 2021
d569016
Upgrade SPM version to 5.4 for Linux builds
S2Ler May 31, 2021
0a4e054
Update CONTRIBUTING.md removing unneeded step
S2Ler May 31, 2021
d9f5e9c
Migrate to xcframeworks for Carthage based project
S2Ler May 31, 2021
01950f2
Update CircleCI config to use XCFrameworks
S2Ler May 31, 2021
7968ed0
Add Carthage integration job
S2Ler May 31, 2021
6560fe3
Remove Xcode 11 build job
S2Ler May 31, 2021
8e1aeba
Update build job names for better readability
S2Ler May 31, 2021
2e8a79a
Update changelog
S2Ler May 31, 2021
bf3b3d3
Update contributing guide
S2Ler May 31, 2021
2e4f6be
Update readme
S2Ler May 31, 2021
d110c02
Update readme Carthage installation instruction
S2Ler Jun 1, 2021
4b02546
Update Example app to show text representation of the route
S2Ler Jun 1, 2021
ab86272
Bump LastUpgradeCheck to Xcode 12.5
S2Ler Jun 1, 2021
987ca1b
Build example app as part of the CI pipeline
S2Ler May 31, 2021
142bac5
Remove dependency on Maps from Cartfile.private
S2Ler Jun 1, 2021
e9d6cdf
Merge pull request #547 from mapbox/s2ler/SPM-5_4
S2Ler Jun 4, 2021
cbb0e9d
Update CHANGELOG.md
S2Ler Jun 4, 2021
0c6ae5c
Merge pull request #548 from mapbox/s2ler/523-example-update
S2Ler Jun 4, 2021
ff79925
Adds means of injecting accessToken from SPM tests
S2Ler Jun 4, 2021
2d9edce
v2.0.0-beta.5
S2Ler Jun 15, 2021
2a8245b
Merge branch 'main' into release-v2.0
1ec5 Jul 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 57 additions & 19 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,24 @@ commands:
- run:
name: Install Carthage
command: |
curl -OL "https://github.com/Carthage/Carthage/releases/download/0.34.0/Carthage.pkg"
curl -OL "https://github.com/Carthage/Carthage/releases/download/0.38.0/Carthage.pkg"
sudo installer -pkg Carthage.pkg -target /
publish-codecov:
steps:
- run:
name: Publish Code Coverage
command: bash <(curl -s https://codecov.io/bash)
carthage-bootstrap:
steps:
- run:
name: Dependencies
command: carthage bootstrap --platform all --cache-builds --configuration Debug --use-xcframeworks

jobs:
spm-linux-job:
docker:
- image: swift:5.3
- image: swift:5.4
steps:
- checkout
# Limiting number of parallel jobs to avoid build crash bug.
Expand All @@ -57,6 +62,41 @@ jobs:
steps:
- checkout
- run: swift build

carthage-integration-test:
parameters:
xcode:
type: string
macos:
xcode: << parameters.xcode >>
environment:
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- install-mapbox-token
- install-carthage
- run:
name: "Create integration Cartfile"
command: |
echo 'github "mapbox/mapbox-directions-swift"' \"$CIRCLE_SHA1\" > Cartfile
- run:
name: "Build"
command: |
carthage bootstrap --platform all --use-netrc --use-xcframeworks
example-app-build:
macos:
xcode: "12.4.0"
environment:
HOMEBREW_NO_AUTO_UPDATE: 1
steps:
- checkout
- install-mapbox-token
- install-carthage
- restore-cache
- carthage-bootstrap
- run:
name: "Build example app"
command: xcodebuild -sdk iphonesimulator -project MapboxDirections.xcodeproj -scheme 'Example' -destination 'platform=iOS Simulator,OS=14.4,name=iPhone 12 Pro Max' clean build
- save-cache

build-job:
parameters:
Expand Down Expand Up @@ -93,13 +133,7 @@ jobs:
name: Install prerequisites
command: |
if [ $(xcversion simulators | grep -cF "iOS << parameters.iOS >> Simulator (installed)") -eq 0 ]; then xcversion simulators --install="iOS << parameters.iOS >>" || true; fi
- run:
name: Dependencies
command: |
./scripts/wcarthage.sh bootstrap --platform ios --cache-builds --configuration Debug --no-use-binaries
./scripts/wcarthage.sh bootstrap --platform tvos --cache-builds --configuration Debug --no-use-binaries
./scripts/wcarthage.sh bootstrap --platform macos --cache-builds --configuration Debug --no-use-binaries
./scripts/wcarthage.sh bootstrap --platform watchos --cache-builds --configuration Debug --no-use-binaries
- carthage-bootstrap
- run:
name: iOS
command: xcodebuild -sdk iphonesimulator -project MapboxDirections.xcodeproj -scheme 'MapboxDirections iOS' -destination 'platform=iOS Simulator,OS=<< parameters.iOS >>,name=<< parameters.device >>' clean build <<# parameters.test >>test<</ parameters.test >><<# parameters.codecoverage >> -enableCodeCoverage "YES"<</ parameters.codecoverage >>
Expand All @@ -126,20 +160,24 @@ workflows:
workflow:
jobs:
- build-job:
name: "Xcode_12.1"
name: "Dev Build: Xcode 12.0"
xcode: "12.0.0"
iOS: "14.0"
tvOS: "14.0"
watchOS: "7.0"
- build-job:
name: "Xcode_11.1"
xcode: "11.1.0"
iOS: "13.1"
tvOS: "13.0"
watchOS: "6.0"
codecoverage: false
- carthage-integration-test:
name: "Carthage Integration Test 12.0"
xcode: "12.0.0"
- carthage-integration-test:
name: "Carthage Integration Test 12.4"
xcode: "12.4.0"
- spm-job:
name: "SPM_build"
name: "SPM build 12.0.0"
xcode: "12.0.0"
- spm-job:
name: "SPM build 12.4.0"
xcode: "12.4.0"
- spm-linux-job:
name: "SPM_Ubuntu_build"
name: "SPM Ubuntu build"
- example-app-build:
name: "Build example app"
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changes to Mapbox Directions for Swift

## v2.0.0

* To gain access to the Mapbox Directions and Map Matching APIs, set `MBXAccessToken` in your Info.plist. `MGLMapboxAccessToken` is still supported but is now deprecated. ([#522](https://github.com/mapbox/mapbox-directions-swift/pull/522))
* This library requires Turf v2.0.0-alpha.3. ([#525](https://github.com/mapbox/mapbox-directions-swift/pull/525))
* The `Incident.impact` property is now an `Incident.Impact` value instead of a string. ([#519](https://github.com/mapbox/mapbox-directions-swift/pull/519))
* Added the `Intersection.preferredApproachLanes` and `Intersection.usableLaneIndication` properties that indicate preferred lane usage. `VisualInstruction.Component.lane(indications:isUsable:)` has been renamed to `VisualInstruction.Component.lane(indications:isUsable:preferredDirection:)`. ([#529](https://github.com/mapbox/mapbox-directions-swift/pull/529))
* Comparing two `Intersection`s with `==` now considers whether the `Intersection.restStop`, `Intersection.regionCode`, and `Intersection.outletMapboxStreetsRoadClass` properties are equal. ([#529](https://github.com/mapbox/mapbox-directions-swift/pull/529))
* Carthage v0.38 or above is now required for installing this SDK if you use Carthage. ([#548](https://github.com/mapbox/mapbox-directions-swift/pull/548))
* Xcode 12.0 or above is now required to build MapboxDirections from source. ([#548](https://github.com/mapbox/mapbox-directions-swift/pull/548))
* You can fully build this SDK on Macs with Apple Silicon. ([#548](https://github.com/mapbox/mapbox-directions-swift/pull/548))

## v1.2.0

### Packaging
Expand Down
10 changes: 4 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ To contribute code changes to this project, use either Carthage or Swift Package

### Using Carthage

1. Install Xcode 12 and [Carthage](https://github.com/Carthage/Carthage/) v0.35 or above.
1. Run `./scripts/wcarthage.sh bootstrap --cache-builds`. (wcarthage.sh is a temporary workaround for [a linker error in Xcode 12](https://github.com/Carthage/Carthage/issues/3019).)
1. Once the Carthage build finishes, open MapboxDirections.xcodeproj in Xcode and build the MapboxDirections Mac scheme. Switch to the Example scheme to see the Mapbox Directions API in action on iOS.
1. Install Xcode 12 and [Carthage](https://github.com/Carthage/Carthage/) v0.38 or above.
1. Run `carthage bootstrap --platform all --use-xcframeworks`.
1. Once the Carthage build finishes, open MapboxDirections.xcodeproj in Xcode and build the MapboxDirections Mac scheme.

### Using Swift Package Manager

Expand Down Expand Up @@ -54,12 +54,10 @@ To add any type, constant, or member to the package’s public interface:

1. Add a file to Tests/MapboxDirectionsTests/
1. Add a file reference to the MapboxDirectionsTests group in MapboxDirections.xcodeproj.
1. Rerun `swift test --generate-linuxmain`, which updates [XCTestManifests.swift](./Tests/MapboxDirectionsTests/XCTestManifests.swift) for builds that use Swift Package Manager.

### Adding a test case

1. Add a `test*` method to one of the classes in one of the files in [Tests/MapboxDirectionsTests/](./Tests/MapboxDirectionsTests/).
1. Rerun `swift test --generate-linuxmain`, which updates [XCTestManifests.swift](./Tests/MapboxDirectionsTests/XCTestManifests.swift) for builds that use Swift Package Manager.

### Adding a test fixture

Expand All @@ -83,7 +81,7 @@ To release a new version of the MapboxDirections package:
1. Run `./scripts/update-version.sh v#.#.#`, where _#.#.#_ is a new version number conforming to [Semantic Versioning](https://semver.org/). Commit the changes with a commit message like `v#.#.#` and open a pull request to get it reviewed and merged.
1. Tag the merged changes as `v#.#.#`. Push the tag by running `git pull && git push origin v#.#.#`.
1. [Create a new release](https://github.com/mapbox/mapbox-directions-swift/releases/new/). Add release notes based on the release’s section in the changelog. (Unlike the changelog, release notes accept `#123` syntax for linking to PRs.) Title the release `v#.#.#`. Check “This is a pre-release” if applicable, then click “Publish release”.
1. Run `pod repo update && pod trunk push` to publish the release on CocoaPods trunk.
1. Run `pod repo update && pod trunk push MapboxDirections.podspec` (or `pod trunk push MapboxDirections-pre.podspec` for a prerelease) to publish the release on CocoaPods trunk.
1. Run `./scripts/publish-documentation.sh v#.#.#` to generate and publish the documentation. Create a pull request and set the base branch to `publisher-production`.
1. Wait for new documentation to be live. Once you merge the branch into `publisher-production`, the new version will be available within 10 minutes. (Mapbox employees can check the #publisher channel in Slack for a notification of when the commit has been published.)
1. _(Mapbox employees only.)_ [Update various links](https://github.com/mapbox/ios-sdk#mapboxdirectionsswift) to the current docset in the [iOS documentation] site.
Expand Down
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
github "raphaelmor/Polyline" ~> 5.0
github "mapbox/turf-swift" ~> 1.0
github "mapbox/turf-swift" "v2.0.0-beta.1"
github "Udumft/SwiftCLI" "carthage-fix"
1 change: 0 additions & 1 deletion Cartfile.private
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 5.5
github "AliSoftware/OHHTTPStubs" ~> 9.0
github "mapbox/mapbox-events-ios" ~> 0.10
5 changes: 2 additions & 3 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" "5.9.0"
github "AliSoftware/OHHTTPStubs" "9.1.0"
github "Udumft/SwiftCLI" "da19d2a16cd5aa838d8fb7256e28c171bc67dd82"
github "mapbox/mapbox-events-ios" "v0.10.7"
github "mapbox/turf-swift" "v1.2.0"
github "mapbox/mapbox-events-ios" "v0.10.8"
github "mapbox/turf-swift" "v2.0.0-beta.1"
github "raphaelmor/Polyline" "v5.0.2"
18 changes: 7 additions & 11 deletions Directions Example/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import UIKit
import SwiftUI

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window!.rootViewController = ViewController(nibName: nil, bundle: nil)
window!.makeKeyAndVisible()

return true
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView(vm: DirectionsViewModel())
}
}
}
135 changes: 135 additions & 0 deletions Directions Example/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import Foundation
import SwiftUI
import Combine
import MapboxDirections

final class DirectionsViewModel: ObservableObject {
private let distanceFormatter: LengthFormatter = .init()
private let travelTimeFormatter: DateComponentsFormatter = .init()

@Published
var routes: [Route] = []

init() {
travelTimeFormatter.unitsStyle = .short
}

func loadRoutes() {
let startPoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047),
name: "Mapbox")
let stopPoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.89065720, longitude: -77.0090701),
name: "Capitol")
let endPoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365),
name: "White House")
let options = RouteOptions(waypoints: [startPoint, stopPoint, endPoint])
options.includesSteps = true
options.routeShapeResolution = .full
options.attributeOptions = [.congestionLevel, .maximumSpeedLimit]

Directions.shared.calculate(options) { (session, result) in
switch result {
case let .failure(error):
print("Error calculating directions: \(error)")
case let .success(response):
self.routes = response.routes ?? []
}
}
}

func formattedDistance(for route: Route) -> String {
return distanceFormatter.string(fromMeters: route.distance)
}

func formattedTravelTime(for route: Route) -> String {
return travelTimeFormatter.string(from: route.expectedTravelTime)!
}

func formattedTypicalTravelTime(for route: Route) -> String {
if let typicalTravelTime = route.typicalTravelTime,
let formattedTypicalTravelTime = travelTimeFormatter.string(from: typicalTravelTime) {
return formattedTypicalTravelTime
}
else {
return "Not available"
}
}

func stepDescriptions(for step: RouteStep) -> String {
var description: String = ""
let direction = step.maneuverDirection?.rawValue ?? "none"
description.append("\(step.instructions) [\(step.maneuverType) \(direction)]")
if step.distance > 0 {
let formattedDistance = distanceFormatter.string(fromMeters: step.distance)
description.append(" (\(step.transportType) for \(formattedDistance))")
}
return description
}
}

struct ContentView: View {
@ObservedObject
var vm: DirectionsViewModel

var body: some View {
ScrollView {
LazyVStack(spacing: 10, content: {
ForEach(vm.routes, id: \.routeIdentifier) { route in
VStack(alignment: .leading, spacing: 3) {
headerView(for: route)
ForEach(0..<route.legs.count, id: \.self) { legIdx in
if let source = route.legs[legIdx].source?.name,
let destination = route.legs[legIdx].destination?.name {
Text("From '\(source)' to '\(destination)'").font(.title2)
}
else {
Text("Steps:").font(.title2)
}
stepsView(for: route.legs[legIdx])
}
}
}
})
}
.padding(5)
.onAppear { vm.loadRoutes() }
}

@ViewBuilder
private func headerView(for route: Route) -> some View {
VStack(alignment: .leading, spacing: 10) {
HStack {
Text("Route: ").fontWeight(.bold)
Text(route.description)
.fixedSize(horizontal: false, vertical: true)
}
HStack {
Text("Distance: ").fontWeight(.bold)
Text(vm.formattedDistance(for:route))
}
HStack {
Text("ETA: ").fontWeight(.bold)
Text(vm.formattedTravelTime(for: route))
}
HStack {
Text("Typical travel time: ").fontWeight(.bold)
Text(vm.formattedTypicalTravelTime(for: route))
}
Divider()
}
}

@ViewBuilder
private func stepsView(for leg: RouteLeg) -> some View {
LazyVStack(alignment: .leading, spacing: 5, content: {
ForEach(0..<leg.steps.count, id: \.self) { stepIdx in
HStack {
Text("\(stepIdx + 1). ").fontWeight(.bold)
Text(vm.stepDescriptions(for: leg.steps[stepIdx]))
}
.padding([.top, .bottom], 3)

Divider()
}
})
}
}
4 changes: 2 additions & 2 deletions Directions Example/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.0</string>
<string>2.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>61</string>
<string>68</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
Expand Down
16 changes: 6 additions & 10 deletions Directions Example/Launch Screen.storyboard
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1217" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand All @@ -22,8 +18,8 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View route steps in the console." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="20" y="626.5" width="335" height="21"/>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View route steps." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
<rect key="frame" x="20" y="626" width="335" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand Down
Loading