-
Notifications
You must be signed in to change notification settings - Fork 322
/
Copy pathNavigation.swift
123 lines (105 loc) · 4.39 KB
/
Navigation.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import Combine
import CoreLocation
import MapboxDirections
import MapboxNavigationCore
@MainActor
final class Navigation: ObservableObject {
let predictiveCacheManager: PredictiveCacheManager?
@Published private(set) var isInActiveNavigation: Bool = false
@Published private(set) var currentPreviewRoutes: NavigationRoutes?
@Published private(set) var activeNavigationRoutes: NavigationRoutes?
@Published private(set) var visualInstruction: VisualInstructionBanner?
@Published private(set) var routeProgress: RouteProgress?
@Published private(set) var currentLocation: CLLocation?
@Published var cameraState: NavigationCameraState = .idle
@Published var profileIdentifier: ProfileIdentifier = .automobileAvoidingTraffic
@Published var shouldRequestMapMatching = false
private var waypoints: [Waypoint] = []
private let core: MapboxNavigation
init() {
let config = CoreConfig(
credentials: .init(), // You can pass a custom token if you need to,
locationSource: .live
)
let navigationProvider = MapboxNavigationProvider(coreConfig: config)
self.core = navigationProvider.mapboxNavigation
self.predictiveCacheManager = navigationProvider.predictiveCacheManager
observeNavigation()
// Provide custom localization.
LocalizationManager.customLocalizationBundle = .main
}
private func observeNavigation() {
core.tripSession().session
.map {
if case .activeGuidance = $0.state { return true }
return false
}
.removeDuplicates()
.assign(to: &$isInActiveNavigation)
core.navigation().bannerInstructions
.map { $0.visualInstruction }
.assign(to: &$visualInstruction)
core.navigation().routeProgress
.map { $0?.routeProgress }
.assign(to: &$routeProgress)
core.tripSession().navigationRoutes
.assign(to: &$activeNavigationRoutes)
core.navigation().locationMatching
.map { $0.enhancedLocation }
.assign(to: &$currentLocation)
}
func startFreeDrive() {
core.tripSession().startFreeDrive()
}
func cancelPreview() {
waypoints = []
currentPreviewRoutes = nil
cameraState = .following
}
func startActiveNavigation() {
guard let previewRoutes = currentPreviewRoutes else { return }
core.tripSession().startActiveGuidance(with: previewRoutes, startLegIndex: 0)
cameraState = .following
currentPreviewRoutes = nil
waypoints = []
}
func stopActiveNavigation() {
core.tripSession().startFreeDrive()
cameraState = .following
}
func selectAlternativeRoute(_ alternativeRoute: AlternativeRoute) async {
if let previewRoutes = currentPreviewRoutes {
currentPreviewRoutes = await previewRoutes.selecting(alternativeRoute: alternativeRoute)
} else {
core.navigation().selectAlternativeRoute(with: alternativeRoute.routeId)
}
}
func requestRoutes(to mapPoint: MapPoint) async throws {
guard !isInActiveNavigation, let currentLocation else { return }
waypoints.append(Waypoint(coordinate: mapPoint.coordinate, name: mapPoint.name))
var userWaypoint = Waypoint(location: currentLocation)
if currentLocation.course >= 0, !shouldRequestMapMatching {
userWaypoint.heading = currentLocation.course
userWaypoint.headingAccuracy = 90
}
var optionsWaypoints = waypoints
optionsWaypoints.insert(userWaypoint, at: 0)
let provider = core.routingProvider()
if shouldRequestMapMatching {
let mapMatchingOptions = NavigationMatchOptions(
waypoints: optionsWaypoints,
profileIdentifier: profileIdentifier
)
let previewRoutes = try await provider.calculateRoutes(options: mapMatchingOptions).value
currentPreviewRoutes = previewRoutes
} else {
let routeOptions = NavigationRouteOptions(
waypoints: optionsWaypoints,
profileIdentifier: profileIdentifier
)
let previewRoutes = try await provider.calculateRoutes(options: routeOptions).value
currentPreviewRoutes = previewRoutes
}
cameraState = .idle
}
}