@jacques_gordon/expo-mapbox-navigation 2.0.7 → 2.0.8
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.
|
@@ -8,6 +8,7 @@ class ExpoMapboxNavigationModule : Module() {
|
|
|
8
8
|
Name("ExpoMapboxNavigation")
|
|
9
9
|
|
|
10
10
|
View(ExpoMapboxNavigationView::class) {
|
|
11
|
+
// Events must be declared here — they correspond to EventDispatcher fields in the View
|
|
11
12
|
Events(
|
|
12
13
|
"onRouteProgressChanged",
|
|
13
14
|
"onRoutesReady",
|
|
@@ -17,70 +18,42 @@ class ExpoMapboxNavigationModule : Module() {
|
|
|
17
18
|
"onArrival"
|
|
18
19
|
)
|
|
19
20
|
|
|
20
|
-
// Coordinates: Array of {latitude, longitude} objects
|
|
21
21
|
Prop("coordinates") { view: ExpoMapboxNavigationView, coordinates: List<Map<String, Double>> ->
|
|
22
22
|
view.setCoordinates(coordinates)
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
// Waypoint indices
|
|
26
24
|
Prop("waypointIndices") { view: ExpoMapboxNavigationView, indices: List<Int>? ->
|
|
27
25
|
view.setWaypointIndices(indices)
|
|
28
26
|
}
|
|
29
|
-
|
|
30
|
-
// Language/locale
|
|
31
27
|
Prop("language") { view: ExpoMapboxNavigationView, language: String? ->
|
|
32
28
|
view.setLanguage(language)
|
|
33
29
|
}
|
|
34
|
-
|
|
35
|
-
// ─────────────────────────────────────────────────────────────
|
|
36
|
-
// voiceUnits prop — fixes Issue #31 (metric/imperial selection)
|
|
37
|
-
// Accepts: "metric" | "imperial" | null (auto from locale)
|
|
38
|
-
// ─────────────────────────────────────────────────────────────
|
|
39
30
|
Prop("voiceUnits") { view: ExpoMapboxNavigationView, units: String? ->
|
|
40
31
|
view.setVoiceUnits(units)
|
|
41
32
|
}
|
|
42
|
-
|
|
43
|
-
// Navigation profile
|
|
44
33
|
Prop("navigationProfile") { view: ExpoMapboxNavigationView, profile: String? ->
|
|
45
34
|
view.setNavigationProfile(profile)
|
|
46
35
|
}
|
|
47
|
-
|
|
48
|
-
// Excluded road types
|
|
49
36
|
Prop("excludeTypes") { view: ExpoMapboxNavigationView, types: List<String>? ->
|
|
50
37
|
view.setExcludeTypes(types)
|
|
51
38
|
}
|
|
52
|
-
|
|
53
|
-
// Map style URL
|
|
54
39
|
Prop("mapStyle") { view: ExpoMapboxNavigationView, style: String? ->
|
|
55
40
|
view.setMapStyle(style)
|
|
56
41
|
}
|
|
57
|
-
|
|
58
|
-
// Mute navigation audio
|
|
59
42
|
Prop("mute") { view: ExpoMapboxNavigationView, mute: Boolean ->
|
|
60
43
|
view.setMute(mute)
|
|
61
44
|
}
|
|
62
|
-
|
|
63
|
-
// Vehicle height restriction (meters)
|
|
64
45
|
Prop("maxHeight") { view: ExpoMapboxNavigationView, height: Double? ->
|
|
65
46
|
view.setMaxHeight(height)
|
|
66
47
|
}
|
|
67
|
-
|
|
68
|
-
// Vehicle width restriction (meters)
|
|
69
48
|
Prop("maxWidth") { view: ExpoMapboxNavigationView, width: Double? ->
|
|
70
49
|
view.setMaxWidth(width)
|
|
71
50
|
}
|
|
72
|
-
|
|
73
|
-
// Map matching mode
|
|
74
51
|
Prop("useMapMatching") { view: ExpoMapboxNavigationView, use: Boolean ->
|
|
75
52
|
view.setUseMapMatching(use)
|
|
76
53
|
}
|
|
77
|
-
|
|
78
|
-
// Custom raster tile URL
|
|
79
54
|
Prop("customRasterTileUrl") { view: ExpoMapboxNavigationView, url: String? ->
|
|
80
55
|
view.setCustomRasterTileUrl(url)
|
|
81
56
|
}
|
|
82
|
-
|
|
83
|
-
// Layer ID above which custom raster goes
|
|
84
57
|
Prop("customRasterAboveLayerId") { view: ExpoMapboxNavigationView, layerId: String? ->
|
|
85
58
|
view.setCustomRasterAboveLayerId(layerId)
|
|
86
59
|
}
|
|
@@ -7,8 +7,7 @@ import com.mapbox.api.directions.v5.models.RouteOptions
|
|
|
7
7
|
import com.mapbox.geojson.Point
|
|
8
8
|
import com.mapbox.maps.MapView
|
|
9
9
|
import com.mapbox.maps.Style
|
|
10
|
-
import com.mapbox.maps.plugin.animation.camera
|
|
11
|
-
import com.mapbox.maps.plugin.locationcomponent.location
|
|
10
|
+
import com.mapbox.maps.plugin.animation.camera
|
|
12
11
|
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
|
|
13
12
|
import com.mapbox.navigation.base.options.NavigationOptions
|
|
14
13
|
import com.mapbox.navigation.base.route.NavigationRoute
|
|
@@ -28,6 +27,7 @@ import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
|
|
|
28
27
|
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineApiOptions
|
|
29
28
|
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineViewOptions
|
|
30
29
|
import expo.modules.kotlin.AppContext
|
|
30
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
31
31
|
import expo.modules.kotlin.views.ExpoView
|
|
32
32
|
import java.util.Locale
|
|
33
33
|
|
|
@@ -36,6 +36,16 @@ private const val TAG = "ExpoMapboxNavigation"
|
|
|
36
36
|
class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
37
37
|
ExpoView(context, appContext) {
|
|
38
38
|
|
|
39
|
+
// ── EventDispatchers — the correct Expo Modules API for View events ───────
|
|
40
|
+
// Each event declared here must match the Events(...) list in ExpoMapboxNavigationModule
|
|
41
|
+
private val onRouteProgressChanged by EventDispatcher()
|
|
42
|
+
private val onRoutesReady by EventDispatcher()
|
|
43
|
+
private val onNavigationFinished by EventDispatcher()
|
|
44
|
+
private val onNavigationCancelled by EventDispatcher()
|
|
45
|
+
private val onRoutesFailed by EventDispatcher()
|
|
46
|
+
private val onArrival by EventDispatcher()
|
|
47
|
+
|
|
48
|
+
// ── Map & Navigation ──────────────────────────────────────────────────────
|
|
39
49
|
private val mapView: MapView = MapView(context)
|
|
40
50
|
private var navigationCamera: NavigationCamera? = null
|
|
41
51
|
private var viewportDataSource: MapboxNavigationViewportDataSource? = null
|
|
@@ -43,7 +53,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
43
53
|
private var routeLineView: MapboxRouteLineView? = null
|
|
44
54
|
private var mapboxNavigation: MapboxNavigation? = null
|
|
45
55
|
|
|
46
|
-
// Props
|
|
56
|
+
// ── Props ─────────────────────────────────────────────────────────────────
|
|
47
57
|
private var coordinates: List<Map<String, Double>> = emptyList()
|
|
48
58
|
private var waypointIndices: List<Int>? = null
|
|
49
59
|
private var language: String? = null
|
|
@@ -68,22 +78,17 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
68
78
|
val navigationOptions = NavigationOptions.Builder(context).build()
|
|
69
79
|
mapboxNavigation = MapboxNavigationProvider.create(navigationOptions)
|
|
70
80
|
|
|
71
|
-
mapView.mapboxMap.loadStyle(mapStyle ?: Style.MAPBOX_STREETS) {
|
|
72
|
-
// Route line components
|
|
81
|
+
mapView.mapboxMap.loadStyle(mapStyle ?: Style.MAPBOX_STREETS) { _ ->
|
|
73
82
|
routeLineApi = MapboxRouteLineApi(MapboxRouteLineApiOptions.Builder().build())
|
|
74
83
|
routeLineView = MapboxRouteLineView(
|
|
75
84
|
MapboxRouteLineViewOptions.Builder(context).build()
|
|
76
85
|
)
|
|
77
|
-
|
|
78
|
-
// NavigationCamera — exactly as in official Mapbox example:
|
|
79
|
-
// NavigationCamera(mapboxMap, mapView.camera, viewportDataSource)
|
|
80
86
|
viewportDataSource = MapboxNavigationViewportDataSource(mapView.mapboxMap)
|
|
81
87
|
navigationCamera = NavigationCamera(
|
|
82
88
|
mapView.mapboxMap,
|
|
83
|
-
mapView.camera,
|
|
89
|
+
mapView.camera,
|
|
84
90
|
viewportDataSource!!
|
|
85
91
|
)
|
|
86
|
-
|
|
87
92
|
registerObservers()
|
|
88
93
|
}
|
|
89
94
|
}
|
|
@@ -91,7 +96,6 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
91
96
|
private fun registerObservers() {
|
|
92
97
|
val nav = mapboxNavigation ?: return
|
|
93
98
|
|
|
94
|
-
// Routes observer
|
|
95
99
|
nav.registerRoutesObserver(object : RoutesObserver {
|
|
96
100
|
override fun onRoutesChanged(result: RoutesUpdatedResult) {
|
|
97
101
|
val routes = result.navigationRoutes
|
|
@@ -101,14 +105,11 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
101
105
|
routeLineView?.renderRouteDrawData(style, value)
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
// Update viewport data source with the route
|
|
105
108
|
viewportDataSource?.onRouteChanged(routes.first())
|
|
106
109
|
viewportDataSource?.evaluate()
|
|
107
|
-
|
|
108
|
-
// Issue #43 fix: safe camera following transition
|
|
109
110
|
safeCameraFollowing()
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
onRoutesReady(mapOf(
|
|
112
113
|
"routeCount" to routes.size,
|
|
113
114
|
"distanceMeters" to (routes.first().directionsRoute.distance() ?: 0.0),
|
|
114
115
|
"durationSeconds" to (routes.first().directionsRoute.duration() ?: 0.0)
|
|
@@ -125,13 +126,11 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
125
126
|
}
|
|
126
127
|
})
|
|
127
128
|
|
|
128
|
-
// Route progress observer
|
|
129
129
|
nav.registerRouteProgressObserver(RouteProgressObserver { routeProgress ->
|
|
130
|
-
// Update viewport data source with progress
|
|
131
130
|
viewportDataSource?.onRouteProgressChanged(routeProgress)
|
|
132
131
|
viewportDataSource?.evaluate()
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
onRouteProgressChanged(mapOf(
|
|
135
134
|
"distanceRemaining" to routeProgress.distanceRemaining,
|
|
136
135
|
"durationRemaining" to routeProgress.durationRemaining,
|
|
137
136
|
"distanceTraveled" to routeProgress.distanceTraveled,
|
|
@@ -143,7 +142,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
143
142
|
})
|
|
144
143
|
}
|
|
145
144
|
|
|
146
|
-
// ── Issue #43: safe camera
|
|
145
|
+
// ── Issue #43: safe camera ────────────────────────────────────────────────
|
|
147
146
|
private fun safeCameraFollowing() {
|
|
148
147
|
try {
|
|
149
148
|
navigationCamera?.requestNavigationCameraToFollowing(
|
|
@@ -163,8 +162,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
163
162
|
"imperial" -> "imperial"
|
|
164
163
|
else -> {
|
|
165
164
|
val locale = language?.let { Locale.forLanguageTag(it) } ?: Locale.getDefault()
|
|
166
|
-
|
|
167
|
-
if (locale.country in imperialCountries) "imperial" else "metric"
|
|
165
|
+
if (locale.country in setOf("US", "GB", "LR", "MM")) "imperial" else "metric"
|
|
168
166
|
}
|
|
169
167
|
}
|
|
170
168
|
}
|
|
@@ -183,7 +181,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
183
181
|
val builder = RouteOptions.builder()
|
|
184
182
|
.applyDefaultNavigationOptions()
|
|
185
183
|
.language(locale.toLanguageTag())
|
|
186
|
-
.voiceUnits(resolveVoiceUnits())
|
|
184
|
+
.voiceUnits(resolveVoiceUnits())
|
|
187
185
|
.coordinatesList(points)
|
|
188
186
|
|
|
189
187
|
waypointIndices?.let { builder.waypointIndicesList(it) }
|
|
@@ -196,7 +194,6 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
196
194
|
maxHeight?.let { builder.maxHeight(it) }
|
|
197
195
|
maxWidth?.let { builder.maxWidth(it) }
|
|
198
196
|
|
|
199
|
-
// Exact Nav SDK v3 callback signature from official Mapbox docs
|
|
200
197
|
nav.requestRoutes(
|
|
201
198
|
builder.build(),
|
|
202
199
|
object : NavigationRouterCallback {
|
|
@@ -205,7 +202,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
205
202
|
@RouterOrigin routerOrigin: String
|
|
206
203
|
) {
|
|
207
204
|
if (routes.isEmpty()) {
|
|
208
|
-
|
|
205
|
+
onRoutesFailed(mapOf("message" to "No routes returned"))
|
|
209
206
|
return
|
|
210
207
|
}
|
|
211
208
|
nav.setNavigationRoutes(routes)
|
|
@@ -218,7 +215,7 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
218
215
|
) {
|
|
219
216
|
val msg = reasons.firstOrNull()?.message ?: "Unknown error"
|
|
220
217
|
Log.e(TAG, "Route request failed: $msg")
|
|
221
|
-
|
|
218
|
+
onRoutesFailed(mapOf("message" to msg))
|
|
222
219
|
}
|
|
223
220
|
|
|
224
221
|
override fun onCanceled(
|
|
@@ -231,17 +228,6 @@ class ExpoMapboxNavigationView(context: Context, appContext: AppContext) :
|
|
|
231
228
|
)
|
|
232
229
|
}
|
|
233
230
|
|
|
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
|
-
|
|
245
231
|
// ── Prop setters ──────────────────────────────────────────────────────────
|
|
246
232
|
fun setCoordinates(coords: List<Map<String, Double>>) {
|
|
247
233
|
coordinates = coords
|
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.8",
|
|
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",
|