@jacques_gordon/expo-mapbox-navigation 2.0.6 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
package expo.modules.mapboxnavigation
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import android.util.Log
|
|
5
6
|
import com.mapbox.api.directions.v5.models.RouteOptions
|
|
6
7
|
import com.mapbox.geojson.Point
|
|
7
8
|
import com.mapbox.maps.MapView
|
|
8
9
|
import com.mapbox.maps.Style
|
|
10
|
+
import com.mapbox.maps.plugin.animation.camera // ← correct import for .camera extension
|
|
11
|
+
import com.mapbox.maps.plugin.locationcomponent.location
|
|
9
12
|
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
|
|
10
13
|
import com.mapbox.navigation.base.options.NavigationOptions
|
|
11
14
|
import com.mapbox.navigation.base.route.NavigationRoute
|
|
@@ -65,16 +68,22 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
65
68
|
val navigationOptions = NavigationOptions.Builder(context).build()
|
|
66
69
|
mapboxNavigation = MapboxNavigationProvider.create(navigationOptions)
|
|
67
70
|
|
|
68
|
-
mapView.
|
|
71
|
+
mapView.mapboxMap.loadStyle(mapStyle ?: Style.MAPBOX_STREETS) { style ->
|
|
72
|
+
// Route line components
|
|
69
73
|
routeLineApi = MapboxRouteLineApi(MapboxRouteLineApiOptions.Builder().build())
|
|
70
|
-
routeLineView = MapboxRouteLineView(
|
|
74
|
+
routeLineView = MapboxRouteLineView(
|
|
75
|
+
MapboxRouteLineViewOptions.Builder(context).build()
|
|
76
|
+
)
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
// NavigationCamera — exactly as in official Mapbox example:
|
|
79
|
+
// NavigationCamera(mapboxMap, mapView.camera, viewportDataSource)
|
|
80
|
+
viewportDataSource = MapboxNavigationViewportDataSource(mapView.mapboxMap)
|
|
73
81
|
navigationCamera = NavigationCamera(
|
|
74
|
-
mapView.
|
|
75
|
-
mapView.camera,
|
|
82
|
+
mapView.mapboxMap,
|
|
83
|
+
mapView.camera, // ← mapView.camera (Maps plugin extension)
|
|
76
84
|
viewportDataSource!!
|
|
77
85
|
)
|
|
86
|
+
|
|
78
87
|
registerObservers()
|
|
79
88
|
}
|
|
80
89
|
}
|
|
@@ -82,33 +91,54 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
82
91
|
private fun registerObservers() {
|
|
83
92
|
val nav = mapboxNavigation ?: return
|
|
84
93
|
|
|
94
|
+
// Routes observer
|
|
85
95
|
nav.registerRoutesObserver(object : RoutesObserver {
|
|
86
96
|
override fun onRoutesChanged(result: RoutesUpdatedResult) {
|
|
87
97
|
val routes = result.navigationRoutes
|
|
88
98
|
if (routes.isNotEmpty()) {
|
|
89
99
|
routeLineApi?.setNavigationRoutes(routes) { value ->
|
|
90
|
-
mapView.
|
|
100
|
+
mapView.mapboxMap.style?.let { style ->
|
|
91
101
|
routeLineView?.renderRouteDrawData(style, value)
|
|
92
102
|
}
|
|
93
103
|
}
|
|
104
|
+
// Update viewport data source with the route
|
|
105
|
+
viewportDataSource?.onRouteChanged(routes.first())
|
|
106
|
+
viewportDataSource?.evaluate()
|
|
107
|
+
|
|
108
|
+
// Issue #43 fix: safe camera following transition
|
|
94
109
|
safeCameraFollowing()
|
|
95
|
-
|
|
110
|
+
|
|
111
|
+
emitEvent("onRoutesReady", mapOf(
|
|
96
112
|
"routeCount" to routes.size,
|
|
97
|
-
"distanceMeters" to (routes.
|
|
98
|
-
"durationSeconds" to (routes.
|
|
113
|
+
"distanceMeters" to (routes.first().directionsRoute.distance() ?: 0.0),
|
|
114
|
+
"durationSeconds" to (routes.first().directionsRoute.duration() ?: 0.0)
|
|
99
115
|
))
|
|
116
|
+
} else {
|
|
117
|
+
routeLineApi?.clearRouteLine { value ->
|
|
118
|
+
mapView.mapboxMap.style?.let { style ->
|
|
119
|
+
routeLineView?.renderClearRouteLineValue(style, value)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
viewportDataSource?.clearRouteData()
|
|
123
|
+
viewportDataSource?.evaluate()
|
|
100
124
|
}
|
|
101
125
|
}
|
|
102
126
|
})
|
|
103
127
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
// Route progress observer
|
|
129
|
+
nav.registerRouteProgressObserver(RouteProgressObserver { routeProgress ->
|
|
130
|
+
// Update viewport data source with progress
|
|
131
|
+
viewportDataSource?.onRouteProgressChanged(routeProgress)
|
|
132
|
+
viewportDataSource?.evaluate()
|
|
133
|
+
|
|
134
|
+
emitEvent("onRouteProgressChanged", mapOf(
|
|
135
|
+
"distanceRemaining" to routeProgress.distanceRemaining,
|
|
136
|
+
"durationRemaining" to routeProgress.durationRemaining,
|
|
137
|
+
"distanceTraveled" to routeProgress.distanceTraveled,
|
|
138
|
+
"fractionTraveled" to routeProgress.fractionTraveled,
|
|
110
139
|
"currentStepDistanceRemaining" to
|
|
111
|
-
(
|
|
140
|
+
(routeProgress.currentLegProgress
|
|
141
|
+
?.currentStepProgress?.distanceRemaining ?: 0f)
|
|
112
142
|
))
|
|
113
143
|
})
|
|
114
144
|
}
|
|
@@ -127,7 +157,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
127
157
|
}
|
|
128
158
|
|
|
129
159
|
// ── Issue #31: voice units ────────────────────────────────────────────────
|
|
130
|
-
private fun
|
|
160
|
+
private fun resolveVoiceUnits(): String {
|
|
131
161
|
return when (voiceUnits?.lowercase()) {
|
|
132
162
|
"metric" -> "metric"
|
|
133
163
|
"imperial" -> "imperial"
|
|
@@ -139,6 +169,8 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
139
169
|
}
|
|
140
170
|
}
|
|
141
171
|
|
|
172
|
+
// ── Route request ─────────────────────────────────────────────────────────
|
|
173
|
+
@SuppressLint("MissingPermission")
|
|
142
174
|
private fun fetchRoutes() {
|
|
143
175
|
val nav = mapboxNavigation ?: return
|
|
144
176
|
if (coordinates.size < 2) return
|
|
@@ -146,24 +178,25 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
146
178
|
val points = coordinates.map { coord ->
|
|
147
179
|
Point.fromLngLat(coord["longitude"] ?: 0.0, coord["latitude"] ?: 0.0)
|
|
148
180
|
}
|
|
149
|
-
|
|
150
181
|
val locale = language?.let { Locale.forLanguageTag(it) } ?: Locale.getDefault()
|
|
151
182
|
|
|
152
183
|
val builder = RouteOptions.builder()
|
|
153
184
|
.applyDefaultNavigationOptions()
|
|
154
185
|
.language(locale.toLanguageTag())
|
|
155
|
-
.voiceUnits(
|
|
186
|
+
.voiceUnits(resolveVoiceUnits()) // Issue #31 fix
|
|
156
187
|
.coordinatesList(points)
|
|
157
188
|
|
|
158
189
|
waypointIndices?.let { builder.waypointIndicesList(it) }
|
|
159
190
|
navigationProfile?.let {
|
|
160
191
|
builder.profile(if (it.startsWith("mapbox/")) it else "mapbox/$it")
|
|
161
192
|
}
|
|
162
|
-
excludeTypes?.takeIf { it.isNotEmpty() }?.let {
|
|
193
|
+
excludeTypes?.takeIf { it.isNotEmpty() }?.let {
|
|
194
|
+
builder.exclude(it.joinToString(","))
|
|
195
|
+
}
|
|
163
196
|
maxHeight?.let { builder.maxHeight(it) }
|
|
164
197
|
maxWidth?.let { builder.maxWidth(it) }
|
|
165
198
|
|
|
166
|
-
// Nav SDK v3
|
|
199
|
+
// Exact Nav SDK v3 callback signature from official Mapbox docs
|
|
167
200
|
nav.requestRoutes(
|
|
168
201
|
builder.build(),
|
|
169
202
|
object : NavigationRouterCallback {
|
|
@@ -172,7 +205,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
172
205
|
@RouterOrigin routerOrigin: String
|
|
173
206
|
) {
|
|
174
207
|
if (routes.isEmpty()) {
|
|
175
|
-
|
|
208
|
+
emitEvent("onRoutesFailed", mapOf("message" to "No routes returned"))
|
|
176
209
|
return
|
|
177
210
|
}
|
|
178
211
|
nav.setNavigationRoutes(routes)
|
|
@@ -185,7 +218,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
185
218
|
) {
|
|
186
219
|
val msg = reasons.firstOrNull()?.message ?: "Unknown error"
|
|
187
220
|
Log.e(TAG, "Route request failed: $msg")
|
|
188
|
-
|
|
221
|
+
emitEvent("onRoutesFailed", mapOf("message" to msg))
|
|
189
222
|
}
|
|
190
223
|
|
|
191
224
|
override fun onCanceled(
|
|
@@ -198,6 +231,17 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
198
231
|
)
|
|
199
232
|
}
|
|
200
233
|
|
|
234
|
+
// ── Expo event emitter (SDK 53 compatible) ────────────────────────────────
|
|
235
|
+
private fun emitEvent(name: String, data: Map<String, Any>) {
|
|
236
|
+
try {
|
|
237
|
+
// Expo modules core SDK 53: use appContext.eventEmitter
|
|
238
|
+
val emitter = appContext.eventEmitter
|
|
239
|
+
emitter?.emit(name, data)
|
|
240
|
+
} catch (e: Exception) {
|
|
241
|
+
Log.e(TAG, "Failed to emit event $name: ${e.message}")
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
201
245
|
// ── Prop setters ──────────────────────────────────────────────────────────
|
|
202
246
|
fun setCoordinates(coords: List<Map<String, Double>>) {
|
|
203
247
|
coordinates = coords
|
|
@@ -216,30 +260,13 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
216
260
|
fun setCustomRasterTileUrl(url: String?) { customRasterTileUrl = url }
|
|
217
261
|
fun setCustomRasterAboveLayerId(layerId: String?) { customRasterAboveLayerId = layerId }
|
|
218
262
|
|
|
219
|
-
// ──
|
|
220
|
-
private fun getAccessToken(): String? {
|
|
221
|
-
return try {
|
|
222
|
-
val resId = context.resources.getIdentifier(
|
|
223
|
-
"mapbox_access_token", "string", context.packageName
|
|
224
|
-
)
|
|
225
|
-
if (resId != 0) context.getString(resId) else null
|
|
226
|
-
} catch (e: Exception) { null }
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Correct Expo SDK v53 event emitter API
|
|
230
|
-
private fun emit(name: String, data: Map<String, Any>) {
|
|
231
|
-
try {
|
|
232
|
-
appContext.eventEmitter?.emit(name, data)
|
|
233
|
-
} catch (e: Exception) {
|
|
234
|
-
Log.e(TAG, "Failed to emit event $name: ${e.message}")
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
263
|
+
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
|
238
264
|
override fun onDetachedFromWindow() {
|
|
239
265
|
super.onDetachedFromWindow()
|
|
266
|
+
routeLineApi?.cancel()
|
|
267
|
+
routeLineView?.cancel()
|
|
240
268
|
mapboxNavigation?.stopTripSession()
|
|
241
269
|
MapboxNavigationProvider.destroy()
|
|
242
|
-
routeLineApi?.cancel()
|
|
243
270
|
mapView.onStop()
|
|
244
271
|
mapView.onDestroy()
|
|
245
272
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jacques_gordon/expo-mapbox-navigation",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"description": "Expo module for Mapbox Navigation SDK with 16KB page size support, NDK27, and Mapbox Maps v11.11.0+",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|