Skip to content

Commit 2be61c0

Browse files
committed
Update.
1 parent 8b0632c commit 2be61c0

File tree

7 files changed

+408
-209
lines changed

7 files changed

+408
-209
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import CarPlay
2+
3+
// MARK: - CPTemplateApplicationSceneDelegate methods
4+
5+
extension AppDelegate: CPTemplateApplicationSceneDelegate {
6+
7+
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
8+
didConnect interfaceController: CPInterfaceController,
9+
to window: CPWindow) {
10+
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
11+
12+
appDelegate.carPlayManager.delegate = appDelegate
13+
14+
appDelegate.carPlayManager.application(UIApplication.shared,
15+
didConnectCarInterfaceController: interfaceController,
16+
to: window)
17+
18+
appDelegate.carPlayManager.templateApplicationScene(templateApplicationScene,
19+
didConnectCarInterfaceController: interfaceController,
20+
to: window)
21+
}
22+
23+
func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
24+
didDisconnect interfaceController: CPInterfaceController,
25+
from window: CPWindow) {
26+
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
27+
28+
appDelegate.carPlayManager.delegate = nil
29+
30+
appDelegate.carPlayManager.application(UIApplication.shared,
31+
didDisconnectCarInterfaceController: interfaceController,
32+
from: window)
33+
34+
appDelegate.carPlayManager.templateApplicationScene(templateApplicationScene,
35+
didDisconnectCarInterfaceController: interfaceController,
36+
from: window)
37+
}
38+
}
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import CarPlay
2+
import MapboxCoreNavigation
3+
import MapboxNavigation
4+
import MapboxDirections
5+
import MapboxMaps
6+
7+
// MARK: - CarPlayManagerDelegate methods
8+
9+
extension AppDelegate: CarPlayManagerDelegate {
10+
11+
// Delegate method, which allows to provide list of leading `CPBarButton`s for specific `CarPlayActivity`.
12+
// It's possible to provide up to two leading `CPBarButton`s.
13+
func carPlayManager(_ carPlayManager: CarPlayManager,
14+
leadingNavigationBarButtonsCompatibleWith traitCollection: UITraitCollection,
15+
in carPlayTemplate: CPTemplate,
16+
for activity: CarPlayActivity) -> [CPBarButton]? {
17+
guard let interfaceController = self.carPlayManager.interfaceController else { return nil }
18+
19+
switch activity {
20+
21+
case .browsing:
22+
let searchTemplate = CPSearchTemplate()
23+
searchTemplate.delegate = carPlaySearchController
24+
let searchButton = carPlaySearchController.searchTemplateButton(searchTemplate: searchTemplate,
25+
interfaceController: interfaceController,
26+
traitCollection: traitCollection)
27+
return [searchButton]
28+
case .panningInBrowsingMode:
29+
break
30+
31+
case .previewing:
32+
break
33+
34+
case .navigating:
35+
break
36+
}
37+
38+
return []
39+
}
40+
41+
// Delegate method, which allows to provide list of trailing `CPBarButton`s for specific `CarPlayActivity`.
42+
// It's possible to provide up to two trailing `CPBarButton`s.
43+
func carPlayManager(_ carPlayManager: CarPlayManager,
44+
trailingNavigationBarButtonsCompatibleWith traitCollection: UITraitCollection,
45+
in carPlayTemplate: CPTemplate,
46+
for activity: CarPlayActivity) -> [CPBarButton]? {
47+
switch activity {
48+
49+
case .browsing:
50+
break
51+
52+
case .panningInBrowsingMode:
53+
break
54+
55+
case .previewing:
56+
break
57+
58+
case .navigating:
59+
return [carPlayManager.exitButton]
60+
}
61+
62+
return []
63+
}
64+
65+
// Delegate method, which allows to provide a list of `CPMapButton`, which are shown on a map.
66+
// It's possible to provide up to four `CPMapButton`s.
67+
func carPlayManager(_ carPlayManager: CarPlayManager,
68+
mapButtonsCompatibleWith traitCollection: UITraitCollection,
69+
in carPlayTemplate: CPTemplate,
70+
for activity: CarPlayActivity) -> [CPMapButton]? {
71+
switch activity {
72+
73+
case .browsing:
74+
break
75+
76+
case .panningInBrowsingMode:
77+
break
78+
79+
case .previewing:
80+
break
81+
82+
case .navigating:
83+
break
84+
}
85+
86+
return []
87+
}
88+
89+
func carPlayManager(_ carPlayManager: CarPlayManager,
90+
didFailToFetchRouteBetween waypoints: [Waypoint]?,
91+
options: RouteOptions,
92+
error: DirectionsError) -> CPNavigationAlert? {
93+
let alertAction = CPAlertAction(title: "Dismiss", style: .default, handler: { _ in })
94+
95+
let navigationAlert = CPNavigationAlert(titleVariants: ["Failed to fetch"],
96+
subtitleVariants: nil,
97+
image: nil,
98+
primaryAction: alertAction,
99+
secondaryAction: nil,
100+
duration: 2.5)
101+
102+
return navigationAlert
103+
}
104+
105+
func carPlayManager(_ carPlayManager: CarPlayManager,
106+
willPreview trip: CPTrip) -> CPTrip {
107+
return trip
108+
}
109+
110+
func carPlayManager(_ carPlayManager: CarPlayManager,
111+
willPreview trip: CPTrip,
112+
with previewTextConfiguration: CPTripPreviewTextConfiguration) -> CPTripPreviewTextConfiguration {
113+
return previewTextConfiguration
114+
}
115+
116+
func carPlayManager(_ carPlayManager: CarPlayManager,
117+
selectedPreviewFor trip: CPTrip,
118+
using routeChoice: CPRouteChoice) {
119+
120+
}
121+
122+
func carPlayManager(_ carPlayManager: CarPlayManager,
123+
didBeginNavigationWith service: NavigationService) {
124+
125+
}
126+
127+
// Delegate method, which is called after ending active-guidance navigation session and dismissing
128+
// `CarPlayNavigationViewController`.
129+
func carPlayManagerDidEndNavigation(_ carPlayManager: CarPlayManager) {
130+
let alertAction = CPAlertAction(title: "OK",
131+
style: .default,
132+
handler: { [weak self] _ in
133+
self?.carPlayManager.interfaceController?.dismissTemplate(animated: true)
134+
})
135+
136+
let alertTemplate = CPAlertTemplate(titleVariants: ["Did end active-guidance navigation."],
137+
actions: [alertAction])
138+
139+
carPlayManager.interfaceController?.presentTemplate(alertTemplate, animated: true)
140+
}
141+
142+
// Delegate method, which allows to show `CPActionSheetTemplate` or `CPAlertTemplate`
143+
// after arriving to the specific `Waypoint`.
144+
func carPlayManager(_ carPlayManager: CarPlayManager,
145+
shouldPresentArrivalUIFor waypoint: Waypoint) -> Bool {
146+
return true
147+
}
148+
149+
// Delegate method, which provides the ability to disable the idle timer to avert system sleep.
150+
func carPlayManagerShouldDisableIdleTimer(_ carPlayManager: CarPlayManager) -> Bool {
151+
return true
152+
}
153+
154+
// Delegate method, which is called right after starting active-guidance navigation and presenting
155+
// `CarPlayNavigationViewController`.
156+
func carPlayManager(_ carPlayManager: CarPlayManager,
157+
didPresent navigationViewController: CarPlayNavigationViewController) {
158+
let alertAction = CPAlertAction(title: "OK",
159+
style: .default,
160+
handler: { [weak self] _ in
161+
self?.carPlayManager.interfaceController?.dismissTemplate(animated: true)
162+
})
163+
164+
let alertTemplate = CPAlertTemplate(titleVariants: ["Did present CarPlayNavigationViewController."],
165+
actions: [alertAction])
166+
167+
carPlayManager.interfaceController?.presentTemplate(alertTemplate, animated: true)
168+
}
169+
170+
// Delegate method, which allows to modify final destination annotation whenever its added to
171+
// `CarPlayMapViewController` or `CarPlayNavigationViewController`.
172+
func carPlayManager(_ carPlayManager: CarPlayManager,
173+
didAdd finalDestinationAnnotation: PointAnnotation,
174+
to parentViewController: UIViewController,
175+
pointAnnotationManager: PointAnnotationManager) {
176+
var finalDestinationAnnotation = finalDestinationAnnotation
177+
if let image = UIImage(named: "marker") {
178+
finalDestinationAnnotation.image = PointAnnotation.Image.custom(image: image, name: "marker")
179+
} else {
180+
finalDestinationAnnotation.image = .default
181+
}
182+
183+
pointAnnotationManager.syncAnnotations([finalDestinationAnnotation])
184+
}
185+
186+
func carPlayManager(_ carPlayManager: CarPlayManager,
187+
templateWillAppear template: CPTemplate,
188+
animated: Bool) {
189+
190+
}
191+
192+
func carPlayManager(_ carPlayManager: CarPlayManager,
193+
templateDidAppear template: CPTemplate,
194+
animated: Bool) {
195+
196+
}
197+
198+
func carPlayManager(_ carPlayManager: CarPlayManager,
199+
templateWillDisappear template: CPTemplate,
200+
animated: Bool) {
201+
202+
}
203+
204+
func carPlayManager(_ carPlayManager: CarPlayManager,
205+
templateDidDisappear template: CPTemplate,
206+
animated: Bool) {
207+
208+
}
209+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import CarPlay
2+
import MapboxNavigation
3+
import MapboxDirections
4+
import MapboxGeocoder
5+
6+
// MARK: - CarPlaySearchControllerDelegate methods
7+
8+
extension AppDelegate: CarPlaySearchControllerDelegate {
9+
10+
func previewRoutes(to waypoint: Waypoint, completionHandler: @escaping () -> Void) {
11+
carPlayManager.previewRoutes(to: waypoint, completionHandler: completionHandler)
12+
}
13+
14+
func resetPanButtons(_ mapTemplate: CPMapTemplate) {
15+
carPlayManager.resetPanButtons(mapTemplate)
16+
}
17+
18+
func pushTemplate(_ template: CPTemplate, animated: Bool) {
19+
if let listTemplate = template as? CPListTemplate {
20+
listTemplate.delegate = carPlaySearchController
21+
}
22+
carPlayManager.interfaceController?.pushTemplate(template, animated: animated)
23+
}
24+
25+
func popTemplate(animated: Bool) {
26+
carPlayManager.interfaceController?.popTemplate(animated: animated)
27+
}
28+
29+
func recentSearches(with searchText: String) -> [CPListItem] {
30+
if searchText.isEmpty {
31+
return recentItems.map { $0.navigationGeocodedPlacemark.listItem() }
32+
}
33+
34+
return recentItems.filter {
35+
$0.matches(searchText)
36+
}.map {
37+
$0.navigationGeocodedPlacemark.listItem()
38+
}
39+
}
40+
41+
func searchResults(with items: [CPListItem], limit: UInt?) -> [CPListItem] {
42+
recentSearchItems = items
43+
44+
if items.count > 0 {
45+
if let limit = limit {
46+
return Array<CPListItem>(items.prefix(Int(limit)))
47+
}
48+
49+
return items
50+
} else {
51+
let noResultListItem = CPListItem(text: "No results",
52+
detailText: nil,
53+
image: nil,
54+
showsDisclosureIndicator: false)
55+
56+
return [noResultListItem]
57+
}
58+
}
59+
60+
func searchTemplate(_ searchTemplate: CPSearchTemplate,
61+
updatedSearchText searchText: String,
62+
completionHandler: @escaping ([CPListItem]) -> Void) {
63+
recentSearchText = searchText
64+
65+
var items = recentSearches(with: searchText)
66+
let limit: UInt = 2
67+
68+
if searchText.count > 2 {
69+
70+
let forwardGeocodeOptions = ForwardGeocodeOptions(query: searchText)
71+
forwardGeocodeOptions.locale = Locale.autoupdatingCurrent.languageCode == "en" ? nil : .autoupdatingCurrent
72+
73+
var allowedScopes: PlacemarkScope = .all
74+
allowedScopes.remove(.postalCode)
75+
76+
forwardGeocodeOptions.allowedScopes = allowedScopes
77+
forwardGeocodeOptions.maximumResultCount = 10
78+
forwardGeocodeOptions.includesRoutableLocations = true
79+
80+
Geocoder.shared.geocode(forwardGeocodeOptions,
81+
completionHandler: { [weak self] (placemarks, attribution, error) in
82+
guard let self = self else {
83+
completionHandler([])
84+
return
85+
}
86+
87+
guard let placemarks = placemarks else {
88+
completionHandler(self.searchResults(with: items, limit: limit))
89+
return
90+
}
91+
92+
let navigationGeocodedPlacemarks = placemarks.map {
93+
NavigationGeocodedPlacemark(title: $0.formattedName,
94+
subtitle: $0.address,
95+
location: $0.location,
96+
routableLocations: $0.routableLocations)
97+
}
98+
99+
let results = navigationGeocodedPlacemarks.map { $0.listItem() }
100+
items.append(contentsOf: results)
101+
completionHandler(self.searchResults(with: results, limit: limit))
102+
})
103+
} else {
104+
completionHandler(self.searchResults(with: items, limit: limit))
105+
}
106+
}
107+
108+
func searchTemplate(_ searchTemplate: CPSearchTemplate,
109+
selectedResult item: CPListItem,
110+
completionHandler: @escaping () -> Void) {
111+
guard let userInfo = item.userInfo as? [String: Any],
112+
let placemark = userInfo[CarPlaySearchController.CarPlayGeocodedPlacemarkKey] as? NavigationGeocodedPlacemark,
113+
let location = placemark.routableLocations?.first ?? placemark.location else {
114+
completionHandler()
115+
return
116+
}
117+
118+
recentItems.add(RecentItem(placemark))
119+
recentItems.save()
120+
121+
let destinationWaypoint = Waypoint(location: location,
122+
heading: nil,
123+
name: placemark.title)
124+
previewRoutes(to: destinationWaypoint, completionHandler: completionHandler)
125+
}
126+
}

0 commit comments

Comments
 (0)