react-native-pointr 9.8.0 → 10.0.0

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.
Files changed (41) hide show
  1. package/API_REFERENCE.md +284 -315
  2. package/CHANGELOG.md +42 -0
  3. package/EXTENDING.md +11 -16
  4. package/README.md +14 -14
  5. package/WAYFINDING_EVENTS.md +5 -3
  6. package/android/build.gradle +1 -1
  7. package/android/src/main/java/com/pointr/PTRCoreExtensions.kt +33 -2
  8. package/android/src/main/java/com/pointr/PTRMapWidgetActionType.kt +17 -0
  9. package/android/src/main/java/com/pointr/PTRMapWidgetManager.kt +162 -406
  10. package/android/src/main/java/com/pointr/{PointrModule.kt → PTRNativeLibrary.kt} +150 -32
  11. package/android/src/main/java/com/pointr/{PointrPackage.kt → PTRPackage.kt} +2 -2
  12. package/ios/PTRMapWidgetContainerView.swift +174 -187
  13. package/ios/PTRMapWidgetManager-Bridging.m +12 -64
  14. package/ios/PTRMapWidgetManager.swift +164 -136
  15. package/ios/PTRNativeLibrary-Bridging.m +38 -2
  16. package/ios/PTRNativeLibrary.swift +206 -26
  17. package/package.json +5 -3
  18. package/react-native-pointr.podspec +1 -1
  19. package/src/NativePointrModule.ts +70 -0
  20. package/src/PTRMapWidgetUtils.ts +67 -144
  21. package/src/actions/index.ts +171 -0
  22. package/src/api/MapWidgetApi.ts +8 -8
  23. package/src/api/PointrSdk.ts +50 -91
  24. package/src/components/index.tsx +27 -26
  25. package/src/constants/index.ts +32 -13
  26. package/src/hooks/index.ts +1 -0
  27. package/src/hooks/usePointrGeofences.ts +37 -0
  28. package/src/hooks/usePointrSdk.ts +12 -5
  29. package/src/index.tsx +37 -70
  30. package/src/managers/PTRPoiManager.ts +2 -2
  31. package/src/types/PTRPoi.ts +5 -2
  32. package/src/types/PTRPosition.ts +15 -5
  33. package/src/types/PTRSite.ts +46 -0
  34. package/src/types/PTRWayfindingEvent.ts +11 -7
  35. package/src/types/config.ts +1 -0
  36. package/src/types/events.ts +1 -0
  37. package/src/types/index.ts +4 -0
  38. package/android/src/main/java/com/pointr/PTRMapWidgetCommandType.kt +0 -20
  39. package/src/PTRCommand.ts +0 -153
  40. package/src/api/index.ts +0 -9
  41. package/src/commands/index.ts +0 -275
@@ -14,43 +14,37 @@ import com.facebook.react.uimanager.ThemedReactContext
14
14
  import com.facebook.react.uimanager.ViewGroupManager
15
15
  import com.facebook.react.uimanager.annotations.ReactProp
16
16
  import com.facebook.react.uimanager.events.RCTEventEmitter
17
- import com.pointrlabs.core.management.DataManager
18
17
  import com.pointrlabs.core.management.Pointr
19
18
  import com.pointrlabs.core.management.interfaces.PointrListener
20
- import com.pointrlabs.core.management.models.ErrorMessage
21
19
  import com.pointrlabs.core.management.models.PTRParams
22
20
  import com.pointrlabs.core.management.models.Site
21
+ import com.pointrlabs.core.management.models.deeplink.PTRIdentifier
23
22
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetAction
24
23
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetBuildingLocation
25
- import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetFocusAction
24
+ import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetCoordinateLocation
25
+ import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetFocusMapAction
26
+ import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetHighlightCategoryAction
27
+ import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetHighlightPoiAction
26
28
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetLevelLocation
27
29
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetMarkMyCarAction
28
30
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetPoiLocation
29
31
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetShowMyCarAction
30
32
  import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetSiteLocation
31
- import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetStaticWayfindingAction
32
- import com.pointrlabs.core.management.models.deeplink.PTRMapWidgetWayfindingAction
33
33
  import com.pointrlabs.core.nativecore.wrappers.Plog
34
34
  import com.pointrlabs.core.poi.models.Poi
35
35
  import com.pointrlabs.core.site.SiteManager
36
36
  import com.pointrlabs.core.util.models.error.PTRError
37
- import com.pointrlabs.core.wayfinding.WayfindingManager
38
- import com.pointrlabs.core.wayfinding.session.RouteSession
39
- import com.pointrlabs.core.wayfinding.session.RouteSessionState
40
- import com.pointrlabs.ui.map.models.PTRMapSymbolLayer
41
37
  import com.pointrlabs.ui.map.models.events_listeners.MapEventsListener
42
- import com.pointrlabs.ui.map.models.events_listeners.MarkMyCarDetailsEvent
43
- import com.pointrlabs.ui.map.models.events_listeners.MarkMyCarDetailsEventsListener
38
+ import com.pointrlabs.ui.map.models.events_listeners.MapWidgetEventsListener
44
39
  import com.pointrlabs.ui.map.models.events_listeners.WayfindingEventsListener
45
40
  import com.pointrlabs.ui.map.views.PTRMapFragment
46
41
  import com.pointrlabs.ui.map.views.PTRMapWidgetFragment
47
- import com.pointrlabs.ui.map.views.wayfinding.MarkMyCarBottomSheet
48
42
  import java.util.concurrent.Semaphore
49
43
 
50
44
 
51
45
  @SuppressLint("LogNotTimber")
52
46
  class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
53
- ViewGroupManager<FrameLayout>(), MapEventsListener, MarkMyCarDetailsEventsListener, WayfindingEventsListener {
47
+ ViewGroupManager<FrameLayout>(), MapEventsListener, WayfindingEventsListener, MapWidgetEventsListener {
54
48
 
55
49
  override fun getName() = REACT_CLASS
56
50
 
@@ -61,22 +55,21 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
61
55
  // Declarative prop support -----------------------------------------------
62
56
  // When a `command` JSON prop is passed on <PTRMapWidget />, the manager
63
57
  // auto-executes it once the view is attached rather than requiring a JS
64
- // imperative command dispatch.
58
+ // imperative action dispatch.
65
59
  //
66
- // JSON shape: { "type": "site"|"building"|"level"|"poi"|"path"|"staticPath"|"staticWayfinding",
60
+ // JSON shape: { "type": "focusMap"|"highlightPoi"|"displayRoute"|"startWayfinding"|"markMyCar"|"showMyCar"|"focusCoordinate"|"highlightCategory",
67
61
  // "site": String, "building"?: String, "level"?: Int,
68
- // "poi"?: String, "fromPoi"?: String, "toPoi"?: String,
69
- // "sourcePoi"?: String, "destinationPoi"?: String }
70
- private var pendingCommandJson: String? = null
62
+ // "poi"?: String, "fromPoi"?: String, "toPoi"?: String }
63
+ private var pendingActionJson: String? = null
71
64
  private var pendingSdkConfigJson: String? = null
72
- private var commandDidExecute = false
65
+ private var actionDidExecute = false
73
66
  // Reset per view instance in createViewInstance so re-navigation works.
74
- private var commandTriggered = false
67
+ private var actionTriggered = false
75
68
 
76
- @ReactProp(name = "command")
77
- fun setCommand(view: FrameLayout, commandJson: String?) {
78
- pendingCommandJson = commandJson
79
- commandDidExecute = false
69
+ @ReactProp(name = "action")
70
+ fun setAction(view: FrameLayout, actionJson: String?) {
71
+ pendingActionJson = actionJson
72
+ actionDidExecute = false
80
73
  }
81
74
 
82
75
  @ReactProp(name = "sdkConfig")
@@ -90,7 +83,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
90
83
  if (configJson == null) return
91
84
  try {
92
85
  val obj = org.json.JSONObject(configJson)
93
- val cfg = PointrModule.mapWidgetConfiguration
86
+ val cfg = PTRNativeLibrary.mapWidgetConfiguration
94
87
  cfg::class.members.filterIsInstance<kotlin.reflect.KMutableProperty1<*, *>>().forEach { prop ->
95
88
  val jsonKey = if (prop.name == "isBuildingLevelSelectorEnabled") "isLevelSelectorEnabled" else prop.name
96
89
  if (!obj.has(jsonKey)) return@forEach
@@ -120,7 +113,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
120
113
  } catch (_: Exception) {
121
114
  Plog.LogLevel.ERROR
122
115
  }
123
- PointrModule.mapWidgetConfiguration.sdkParams = params
116
+ PTRNativeLibrary.mapWidgetConfiguration.sdkParams = params
124
117
  // Initialize the Pointr SDK if it has not been initialized yet
125
118
  // (covers the case where sdkConfig is used without a prior pointrSdk.initialize() call).
126
119
  if (Pointr.getPointr() == null) {
@@ -133,9 +126,9 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
133
126
  }
134
127
 
135
128
  private fun executePendingCommandIfNeeded() {
136
- val json = pendingCommandJson ?: return
137
- if (commandDidExecute) return
138
- commandDidExecute = true
129
+ val json = pendingActionJson ?: return
130
+ if (actionDidExecute) return
131
+ actionDidExecute = true
139
132
  Thread {
140
133
  // Block on background thread until Pointr is running (semaphore wait).
141
134
  // If Pointr never reaches RUNNING (e.g. SDK not initialized), skip entirely
@@ -160,43 +153,67 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
160
153
  val poi = obj.optString("poi", "")
161
154
  val fromPoi = obj.optString("fromPoi", "")
162
155
  val toPoi = obj.optString("toPoi", "")
163
- val sourcePoi = obj.optString("sourcePoi", "")
164
- val destinationPoi = obj.optString("destinationPoi", "")
165
156
 
166
157
  val args = com.facebook.react.bridge.Arguments.createArray()
158
+ val shouldShowPopup = obj.optBoolean("shouldShowPopup", true)
167
159
  when (type) {
168
- PTRMapWidgetCommandType.SITE -> {
169
- args.pushString(site)
170
- executeCommand(PTRMapWidgetCommandType.SITE, args)
160
+ PTRMapWidgetActionType.FOCUS_MAP -> {
161
+ if (building.isNotEmpty() && obj.has("level")) {
162
+ args.pushString(site); args.pushString(building); args.pushInt(level)
163
+ executeCommand("level", args)
164
+ } else if (building.isNotEmpty()) {
165
+ args.pushString(site); args.pushString(building)
166
+ executeCommand("building", args)
167
+ } else {
168
+ args.pushString(site)
169
+ executeCommand("site", args)
170
+ }
171
171
  }
172
- PTRMapWidgetCommandType.BUILDING -> {
173
- args.pushString(site); args.pushString(building)
174
- executeCommand(PTRMapWidgetCommandType.BUILDING, args)
172
+ PTRMapWidgetActionType.HIGHLIGHT_POI -> {
173
+ args.pushString(site); args.pushString(poi)
174
+ executeCommand("poi", args)
175
175
  }
176
- PTRMapWidgetCommandType.LEVEL -> {
177
- args.pushString(site); args.pushString(building); args.pushInt(level)
178
- executeCommand(PTRMapWidgetCommandType.LEVEL, args)
176
+ PTRMapWidgetActionType.DISPLAY_ROUTE -> {
177
+ args.pushString(site); args.pushString(fromPoi); args.pushString(toPoi)
178
+ executeCommand(PTRMapWidgetActionType.DISPLAY_ROUTE, args)
179
179
  }
180
- PTRMapWidgetCommandType.POI -> {
181
- args.pushString(site); args.pushString(poi)
182
- executeCommand(PTRMapWidgetCommandType.POI, args)
180
+ PTRMapWidgetActionType.START_WAYFINDING -> {
181
+ args.pushString(site); args.pushString(toPoi)
182
+ executeCommand(PTRMapWidgetActionType.START_WAYFINDING, args)
183
183
  }
184
- PTRMapWidgetCommandType.PATH -> {
185
- args.pushString(site); args.pushString(poi)
186
- executeCommand(PTRMapWidgetCommandType.PATH, args)
184
+ PTRMapWidgetActionType.MARK_MY_CAR -> {
185
+ if (building.isNotEmpty() && obj.has("level")) {
186
+ args.pushString(site); args.pushString(building); args.pushInt(level); args.pushBoolean(shouldShowPopup)
187
+ executeCommand("markMyCarForLevel", args)
188
+ } else {
189
+ args.pushString(site); args.pushBoolean(shouldShowPopup)
190
+ executeCommand("markMyCarForSite", args)
191
+ }
187
192
  }
188
- PTRMapWidgetCommandType.STATIC_PATH -> {
189
- args.pushString(site); args.pushString(fromPoi); args.pushString(toPoi)
190
- executeCommand(PTRMapWidgetCommandType.STATIC_PATH, args)
193
+ PTRMapWidgetActionType.SHOW_MY_CAR -> {
194
+ args.pushString(site); args.pushBoolean(shouldShowPopup)
195
+ executeCommand("showMyCarForSite", args)
196
+ }
197
+ PTRMapWidgetActionType.FOCUS_COORDINATE -> {
198
+ val lat = obj.optDouble("latitude", 0.0)
199
+ val lon = obj.optDouble("longitude", 0.0)
200
+ val lvl = obj.optInt("levelIndex", -1)
201
+ args.pushString(site); args.pushDouble(lat); args.pushDouble(lon); args.pushInt(lvl)
202
+ executeCommand(PTRMapWidgetActionType.FOCUS_COORDINATE, args)
191
203
  }
192
- PTRMapWidgetCommandType.STATIC_WAYFINDING -> {
193
- args.pushString(site); args.pushString(sourcePoi); args.pushString(destinationPoi)
194
- executeCommand(PTRMapWidgetCommandType.STATIC_WAYFINDING, args)
204
+ PTRMapWidgetActionType.HIGHLIGHT_CATEGORY -> {
205
+ val catArr = com.facebook.react.bridge.Arguments.createArray()
206
+ val jsonArr = obj.optJSONArray("categoryIds")
207
+ if (jsonArr != null) {
208
+ for (i in 0 until jsonArr.length()) catArr.pushString(jsonArr.optString(i))
209
+ }
210
+ args.pushString(site); args.pushArray(catArr)
211
+ executeCommand(PTRMapWidgetActionType.HIGHLIGHT_CATEGORY, args)
195
212
  }
196
- else -> Log.w(name, "Unknown command type in command prop: $type")
213
+ else -> Log.w(name, "Unknown action type in action prop: $type")
197
214
  }
198
215
  } catch (e: Exception) {
199
- Log.e(name, "Failed to execute command prop: ${e.message}")
216
+ Log.e(name, "Failed to execute action prop: ${e.message}")
200
217
  }
201
218
  }
202
219
  }.start()
@@ -215,7 +232,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
215
232
  ptrMapWidgetFragment = PTRMapWidgetFragment.newInstance(
216
233
  (reactContext.currentActivity as FragmentActivity).supportFragmentManager,
217
234
  frameLayout.id,
218
- PointrModule.mapWidgetConfiguration,
235
+ PTRNativeLibrary.mapWidgetConfiguration,
219
236
  action
220
237
  )
221
238
  Choreographer.getInstance().postFrameCallback(frameCallback)
@@ -231,9 +248,9 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
231
248
  ptrMapWidgetFragment?.removeListener(this)
232
249
  ptrMapWidgetFragment = null
233
250
  frameLayout = FrameLayout(reactContext)
234
- commandDidExecute = false
235
- commandTriggered = false // reset so re-navigation triggers the command again
236
- // Start the frame loop immediately so the declarative command prop can
251
+ actionDidExecute = false
252
+ actionTriggered = false // reset so re-navigation triggers the command again
253
+ // Start the frame loop immediately so the declarative action prop can
237
254
  // fire once the view has been measured and laid out by React Native.
238
255
  Choreographer.getInstance().postFrameCallback(frameCallback)
239
256
  return frameLayout
@@ -255,154 +272,115 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
255
272
  args: ReadableArray
256
273
  ) {
257
274
  val action: PTRMapWidgetAction = when (command) {
258
- PTRMapWidgetCommandType.SITE -> {
275
+ "site" -> {
259
276
  val siteId = args.getString(0).orEmpty()
260
- val location = PTRMapWidgetSiteLocation(siteId, isExternal = true)
261
- PTRMapWidgetFocusAction(location)
277
+ val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
278
+ PTRMapWidgetAction.focusMap(location)
262
279
  }
263
280
 
264
- PTRMapWidgetCommandType.BUILDING -> {
281
+ "building" -> {
265
282
  val siteId = args.getString(0).orEmpty()
266
283
  val buildingId = args.getString(1).orEmpty()
267
- val location =
268
- PTRMapWidgetBuildingLocation(siteId, buildingId, isExternalIdentifier = true)
269
- PTRMapWidgetFocusAction(location)
284
+ val location = PTRMapWidgetBuildingLocation(
285
+ PTRIdentifier(siteId, isExternal = true),
286
+ PTRIdentifier(buildingId, isExternal = true)
287
+ )
288
+ PTRMapWidgetAction.focusMap(location)
270
289
  }
271
290
 
272
- PTRMapWidgetCommandType.LEVEL -> {
291
+ "level" -> {
273
292
  val siteId = args.getString(0).orEmpty()
274
293
  val buildingId = args.getString(1).orEmpty()
275
294
  val location = PTRMapWidgetLevelLocation(
276
- siteId,
277
- buildingId,
278
- args.getInt(2),
279
- isExternalIdentifier = true
295
+ PTRIdentifier(siteId, isExternal = true),
296
+ PTRIdentifier(buildingId, isExternal = true),
297
+ args.getInt(2)
280
298
  )
281
- PTRMapWidgetFocusAction(location)
299
+ PTRMapWidgetAction.focusMap(location)
282
300
  }
283
301
 
284
- PTRMapWidgetCommandType.POI -> {
302
+ "poi" -> {
285
303
  val siteId = args.getString(0).orEmpty()
286
304
  val poiId = args.getString(1).orEmpty()
287
- val location = PTRMapWidgetPoiLocation(siteId, poiId, isExternalIdentifier = true)
288
- PTRMapWidgetFocusAction(location)
305
+ val location = PTRMapWidgetPoiLocation(
306
+ PTRIdentifier(siteId, isExternal = true),
307
+ PTRIdentifier(poiId, isExternal = true)
308
+ )
309
+ PTRMapWidgetAction.highlightPoi(location)
289
310
  }
290
311
 
291
- PTRMapWidgetCommandType.PATH -> {
312
+ PTRMapWidgetActionType.START_WAYFINDING -> {
292
313
  val siteId = args.getString(0).orEmpty()
293
314
  val poiId = args.getString(1).orEmpty()
294
- val location = PTRMapWidgetPoiLocation(siteId, poiId, isExternalIdentifier = true)
295
- PTRMapWidgetWayfindingAction(location)
296
- }
297
-
298
- PTRMapWidgetCommandType.STATIC_PATH -> {
299
- val siteId = args.getString(0).orEmpty()
300
- val fromPoiId = args.getString(1).orEmpty()
301
- val toPoiId = args.getString(2).orEmpty()
302
- val location =
303
- PTRMapWidgetPoiLocation(siteId, fromPoiId, isExternalIdentifier = true)
304
- val action1 = PTRMapWidgetFocusAction(location)
305
- val ptrMapWidgetFragment = getMapWidgetFragment(action1)
306
- action1.onComplete = onComplete@{ error ->
307
- if (error != null) {
308
- mapWidgetDidEndLoading(
309
- command,
310
- *args.toArrayList().mapNotNull { it }.toTypedArray(),
311
- error
312
- )
313
- return@onComplete
314
- }
315
- Log.i(name, "Focus action completed, showing static path")
316
-
317
- showStaticPath(
318
- ptrMapWidgetFragment,
319
- siteId,
320
- fromPoiId,
321
- toPoiId
322
- )
323
- }
324
- return
315
+ val location = PTRMapWidgetPoiLocation(
316
+ PTRIdentifier(siteId, isExternal = true),
317
+ PTRIdentifier(poiId, isExternal = true)
318
+ )
319
+ PTRMapWidgetAction.startWayfinding(location)
325
320
  }
326
321
 
327
- PTRMapWidgetCommandType.STATIC_WAYFINDING -> {
322
+ PTRMapWidgetActionType.DISPLAY_ROUTE -> {
328
323
  val siteId = args.getString(0).orEmpty()
329
324
  val sourcePoiId = args.getString(1).orEmpty()
330
325
  val destinationPoiId = args.getString(2).orEmpty()
331
- val sourceLocation = PTRMapWidgetPoiLocation(siteId, sourcePoiId, isExternalIdentifier = true)
332
- val destinationLocation = PTRMapWidgetPoiLocation(siteId, destinationPoiId, isExternalIdentifier = true)
333
- PTRMapWidgetStaticWayfindingAction(sourceLocation, destinationLocation)
326
+ val sourceLocation = PTRMapWidgetPoiLocation(
327
+ PTRIdentifier(siteId, isExternal = true),
328
+ PTRIdentifier(sourcePoiId, isExternal = true)
329
+ )
330
+ val destinationLocation = PTRMapWidgetPoiLocation(
331
+ PTRIdentifier(siteId, isExternal = true),
332
+ PTRIdentifier(destinationPoiId, isExternal = true)
333
+ )
334
+ PTRMapWidgetAction.displayRoute(sourceLocation, destinationLocation)
334
335
  }
335
336
 
336
- PTRMapWidgetCommandType.MARK_MY_CAR_SITE -> {
337
+ "markMyCarForSite" -> {
337
338
  val siteId = args.getString(0).orEmpty()
338
- val location = PTRMapWidgetSiteLocation(siteId, isExternal = true)
339
- PTRMapWidgetMarkMyCarAction(location, shouldShowPopup = args.getBoolean(1))
339
+ val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
340
+ PTRMapWidgetAction.markMyCar(location, args.getBoolean(1))
340
341
  }
341
342
 
342
- PTRMapWidgetCommandType.MARK_MY_CAR_LEVEL -> {
343
+ "markMyCarForLevel" -> {
343
344
  val siteId = args.getString(0).orEmpty()
345
+ val buildingId = args.getString(1).orEmpty()
344
346
  val location = PTRMapWidgetLevelLocation(
345
- siteId,
346
- args.getString(1).orEmpty(),
347
- args.getInt(2),
348
- isExternalIdentifier = true
347
+ PTRIdentifier(siteId, isExternal = true),
348
+ PTRIdentifier(buildingId, isExternal = true),
349
+ args.getInt(2)
349
350
  )
350
351
  PTRMapWidgetMarkMyCarAction(location, shouldShowPopup = args.getBoolean(3))
351
352
  }
352
353
 
353
- PTRMapWidgetCommandType.SHOW_MY_CAR_SITE -> {
354
+ "showMyCarForSite" -> {
354
355
  val siteId = args.getString(0).orEmpty()
355
- val location = PTRMapWidgetSiteLocation(siteId, isExternal = true)
356
- PTRMapWidgetShowMyCarAction(location, shouldShowPopup = args.getBoolean(1))
356
+ val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
357
+ PTRMapWidgetAction.showMyCar(location, shouldShowPopup = args.getBoolean(1))
357
358
  }
358
359
 
359
- PTRMapWidgetCommandType.START_AND_FOCUS -> {
360
- // First 4 parameters are initialization parameters
361
- val clientId = args.getString(0).orEmpty()
362
- val licenceKey = args.getString(1).orEmpty()
363
- val baseUrl = args.getString(2).orEmpty()
364
- val logLevel = args.getInt(3)
365
-
366
- val ptrParams = PTRParams(clientId, licenceKey, baseUrl)
367
- ptrParams.logLevel = try {
368
- Plog.LogLevel.entries[logLevel]
369
- } catch (_: IllegalArgumentException) {
370
- Plog.LogLevel.ERROR
371
- }
372
- PointrModule.mapWidgetConfiguration.sdkParams = ptrParams
373
-
374
- // Next parameter is focus type (site, building, level, poi)
375
- val focusType = args.getString(4).orEmpty()
360
+ PTRMapWidgetActionType.FOCUS_COORDINATE -> {
361
+ val siteId = args.getString(0).orEmpty()
362
+ val latitude = args.getDouble(1)
363
+ val longitude = args.getDouble(2)
364
+ val levelIndex = if (args.size() > 3) args.getInt(3) else -1
365
+ val location = PTRMapWidgetCoordinateLocation(
366
+ siteId = PTRIdentifier(siteId, isExternal = true),
367
+ buildingId = null,
368
+ levelIndex = if (levelIndex >= 0) levelIndex else null,
369
+ latitude = latitude,
370
+ longitude = longitude
371
+ )
372
+ PTRMapWidgetAction.focusMap(location)
373
+ }
376
374
 
377
- // Create focus action based on type
378
- val location = when (focusType) {
379
- PTRMapWidgetCommandType.SITE -> {
380
- val siteId = args.getString(5).orEmpty()
381
- PTRMapWidgetSiteLocation(siteId, isExternal = true)
382
- }
383
- PTRMapWidgetCommandType.BUILDING -> {
384
- val siteId = args.getString(5).orEmpty()
385
- val buildingId = args.getString(6).orEmpty()
386
- PTRMapWidgetBuildingLocation(siteId, buildingId, isExternalIdentifier = true)
387
- }
388
- PTRMapWidgetCommandType.LEVEL -> {
389
- val siteId = args.getString(5).orEmpty()
390
- val buildingId = args.getString(6).orEmpty()
391
- val levelIndex = args.getInt(7)
392
- PTRMapWidgetLevelLocation(siteId, buildingId, levelIndex, isExternalIdentifier = true)
393
- }
394
- PTRMapWidgetCommandType.POI -> {
395
- val siteId = args.getString(5).orEmpty()
396
- val poiId = args.getString(6).orEmpty()
397
- PTRMapWidgetPoiLocation(siteId, poiId, isExternalIdentifier = true)
398
- }
399
- else -> {
400
- // Default to site if invalid focus type
401
- val siteId = args.getString(5).orEmpty()
402
- PTRMapWidgetSiteLocation(siteId, isExternal = true)
403
- }
375
+ PTRMapWidgetActionType.HIGHLIGHT_CATEGORY -> {
376
+ val siteId = args.getString(0).orEmpty()
377
+ val categoryIds = mutableListOf<String>()
378
+ val arr = args.getArray(1)
379
+ if (arr != null) {
380
+ for (i in 0 until arr.size()) categoryIds.add(arr.getString(i).orEmpty())
404
381
  }
405
- PTRMapWidgetFocusAction(location)
382
+ val site = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
383
+ PTRMapWidgetAction.highlightCategory(site, categoryIds.firstOrNull() ?: "")
406
384
  }
407
385
 
408
386
  else -> return
@@ -420,64 +398,57 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
420
398
  }
421
399
 
422
400
  private fun mapWidgetDidEndLoading(
423
- @PTRMapWidgetCommandType command: String,
401
+ @PTRMapWidgetActionType command: String,
424
402
  vararg args: Any
425
403
  ) {
426
404
  val event: WritableMap = WritableNativeMap()
427
405
  event.putString("command", command)
428
406
  when (command) {
429
- PTRMapWidgetCommandType.SITE -> {
407
+ "site" -> {
430
408
  event.putString("siteExternalIdentifier", args[0] as String)
431
409
  event.putString("error", args[1] as String)
432
410
  }
433
411
 
434
- PTRMapWidgetCommandType.BUILDING -> {
412
+ "building" -> {
435
413
  event.putString("siteExternalIdentifier", args[0] as String)
436
414
  event.putString("buildingExternalIdentifier", args[1] as String)
437
415
  event.putString("error", args[2] as String)
438
416
  }
439
417
 
440
- PTRMapWidgetCommandType.LEVEL -> {
418
+ "level" -> {
441
419
  event.putString("siteExternalIdentifier", args[0] as String)
442
420
  event.putString("buildingExternalIdentifier", args[1] as String)
443
421
  event.putInt("levelIndex", (args[2] as Number).toInt())
444
422
  event.putString("error", args[3] as String)
445
423
  }
446
424
 
447
- PTRMapWidgetCommandType.POI -> {
425
+ "poi" -> {
448
426
  event.putString("siteExternalIdentifier", args[0] as String)
449
427
  event.putString("poiExternalIdentifier", args[1] as String)
450
428
  event.putString("error", args[2] as String)
451
429
  }
452
430
 
453
- PTRMapWidgetCommandType.PATH -> {
431
+ PTRMapWidgetActionType.START_WAYFINDING -> {
454
432
  event.putString("siteExternalIdentifier", args[0] as String)
455
433
  event.putString("poiExternalIdentifier", args[1] as String)
456
434
  event.putString("error", args[2] as String)
457
435
  }
458
436
 
459
- PTRMapWidgetCommandType.STATIC_PATH -> {
437
+ PTRMapWidgetActionType.DISPLAY_ROUTE -> {
460
438
  event.putString("siteExternalIdentifier", args[0] as String)
461
439
  event.putString("fromPoiExternalIdentifier", args[1] as String)
462
440
  event.putString("toPoiExternalIdentifier", args[2] as String)
463
441
  event.putString("error", args[3] as String)
464
442
  }
465
443
 
466
- PTRMapWidgetCommandType.STATIC_WAYFINDING -> {
467
- event.putString("siteExternalIdentifier", args[0] as String)
468
- event.putString("sourcePoiExternalIdentifier", args[1] as String)
469
- event.putString("destinationPoiExternalIdentifier", args[2] as String)
470
- event.putString("error", args[3] as String)
471
- }
472
-
473
- PTRMapWidgetCommandType.MARK_MY_CAR_SITE -> {
444
+ "markMyCarForSite" -> {
474
445
  event.putString("siteExternalIdentifier", args[0] as String)
475
446
  event.putBoolean("shouldShowPopup", args[1] as Boolean)
476
447
  event.putInt("animationType", (args[2] as Number).toInt())
477
448
  event.putString("error", args[3] as String)
478
449
  }
479
450
 
480
- PTRMapWidgetCommandType.MARK_MY_CAR_LEVEL -> {
451
+ "markMyCarForLevel" -> {
481
452
  event.putString("siteExternalIdentifier", args[0] as String)
482
453
  event.putString("buildingExternalIdentifier", args[1] as String)
483
454
  event.putInt("levelIndex", (args[2] as Number).toInt())
@@ -486,50 +457,13 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
486
457
  event.putString("error", args[5] as String)
487
458
  }
488
459
 
489
- PTRMapWidgetCommandType.SHOW_MY_CAR_SITE -> {
460
+ "showMyCarForSite" -> {
490
461
  event.putString("siteExternalIdentifier", args[0] as String)
491
462
  event.putBoolean("shouldShowPopup", args[1] as Boolean)
492
463
  event.putInt("animationType", (args[2] as Number).toInt())
493
464
  event.putString("error", args[3] as String)
494
465
  }
495
466
 
496
- PTRMapWidgetCommandType.START_AND_FOCUS -> {
497
- event.putString("clientId", args[0] as String)
498
- event.putString("licenceKey", args[1] as String)
499
- event.putString("baseUrl", args[2] as String)
500
- event.putInt("logLevel", (args[3] as Number).toInt())
501
- event.putString("focusType", args[4] as String)
502
-
503
- // Add focus-specific parameters based on focus type
504
- val focusType = args[4] as String
505
- when (focusType) {
506
- PTRMapWidgetCommandType.SITE -> {
507
- event.putString("siteExternalIdentifier", args[5] as String)
508
- event.putString("error", args.last().toString())
509
- }
510
- PTRMapWidgetCommandType.BUILDING -> {
511
- event.putString("siteExternalIdentifier", args[5] as String)
512
- event.putString("buildingExternalIdentifier", args[6] as String)
513
- event.putString("error", args.last().toString())
514
- }
515
- PTRMapWidgetCommandType.LEVEL -> {
516
- event.putString("siteExternalIdentifier", args[5] as String)
517
- event.putString("buildingExternalIdentifier", args[6] as String)
518
- event.putInt("levelIndex", (args[7] as Number).toInt())
519
- event.putString("error", args.last().toString())
520
- }
521
- PTRMapWidgetCommandType.POI -> {
522
- event.putString("siteExternalIdentifier", args[5] as String)
523
- event.putString("poiExternalIdentifier", args[6] as String)
524
- event.putString("error", args.last().toString())
525
- }
526
- else -> {
527
- event.putString("siteExternalIdentifier", args[5] as String)
528
- event.putString("error", args.last().toString())
529
- }
530
- }
531
- }
532
-
533
467
  else -> {
534
468
  return
535
469
  }
@@ -555,185 +489,14 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
555
489
  }
556
490
 
557
491
  override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
492
+ fun bubbled(name: String) = mapOf("phasedRegistrationNames" to mapOf("bubbled" to name))
558
493
  return mapOf(
559
- "onMapWidgetDidEndLoading" to mapOf(
560
- "phasedRegistrationNames" to mapOf(
561
- "bubbled" to "onMapWidgetDidEndLoading"
562
- )
563
- ),
564
- "onWayfindingEvent" to mapOf(
565
- "phasedRegistrationNames" to mapOf(
566
- "bubbled" to "onWayfindingEvent"
567
- )
568
- )
494
+ "onMapWidgetDidEndLoading" to bubbled("onMapWidgetDidEndLoading"),
495
+ "onWayfindingEvent" to bubbled("onWayfindingEvent")
569
496
  )
570
497
  }
571
498
 
572
499
 
573
- private fun showStaticPath(
574
- ptrMapWidgetFragment: PTRMapWidgetFragment,
575
- site: String,
576
- fromPoi: String,
577
- toPoi: String
578
- ) {
579
- val siteObject = getSite(site) ?: run {
580
- mapWidgetDidEndLoading(
581
- PTRMapWidgetCommandType.STATIC_PATH,
582
- site,
583
- fromPoi,
584
- toPoi,
585
- "Site not found"
586
- )
587
- return
588
- }
589
- if (!waitForSiteData(siteObject)) {
590
- mapWidgetDidEndLoading(
591
- PTRMapWidgetCommandType.STATIC_PATH,
592
- site,
593
- fromPoi,
594
- toPoi,
595
- "Site data not found"
596
- )
597
- return
598
- }
599
- val source = Pointr.getPointr()?.poiManager?.getPoiByExternalIdentifier(siteObject, fromPoi)
600
- ?: run {
601
- mapWidgetDidEndLoading(
602
- PTRMapWidgetCommandType.STATIC_PATH,
603
- site,
604
- fromPoi,
605
- toPoi,
606
- "Source POI not found"
607
- )
608
- return
609
- }
610
- val target =
611
- Pointr.getPointr()?.poiManager?.getPoiByExternalIdentifier(siteObject, toPoi) ?: run {
612
- mapWidgetDidEndLoading(
613
- PTRMapWidgetCommandType.STATIC_PATH,
614
- site,
615
- fromPoi,
616
- toPoi,
617
- "Target POI not found"
618
- )
619
- return
620
- }
621
- if (!waitForPathManager(siteObject)) {
622
- mapWidgetDidEndLoading(
623
- PTRMapWidgetCommandType.STATIC_PATH,
624
- site,
625
- fromPoi,
626
- toPoi,
627
- "Path manager not ready"
628
- )
629
- return
630
- }
631
- val wayfindingManager = Pointr.getPointr()?.wayfindingManager ?: run {
632
- mapWidgetDidEndLoading(
633
- PTRMapWidgetCommandType.STATIC_PATH,
634
- site,
635
- fromPoi,
636
- toPoi,
637
- "Path manager not found"
638
- )
639
- return
640
- }
641
- val route = wayfindingManager.calculateRoute(source, listOf(target)) ?: run {
642
- mapWidgetDidEndLoading(
643
- PTRMapWidgetCommandType.STATIC_PATH,
644
- site,
645
- fromPoi,
646
- toPoi,
647
- "Path not found"
648
- )
649
- return
650
- }
651
- val layer = PTRMapSymbolLayer(
652
- LAYER_STATIC_PATH
653
- )
654
- ptrMapWidgetFragment.mapFragment?.addLayer(layer) { isSuccess, message ->
655
- if (!isSuccess) {
656
- mapWidgetDidEndLoading(
657
- PTRMapWidgetCommandType.STATIC_PATH,
658
- site,
659
- fromPoi,
660
- toPoi,
661
- "Failed to add static path layer: $message"
662
- )
663
- return@addLayer
664
- }
665
- Log.i(name, "Static path layer added successfully")
666
-
667
- ptrMapWidgetFragment.mapFragment?.addFeatures(
668
- listOf(source, target),
669
- LAYER_STATIC_PATH
670
- ) { isSuccess1, message1 ->
671
- if (!isSuccess1) {
672
- mapWidgetDidEndLoading(
673
- PTRMapWidgetCommandType.STATIC_PATH,
674
- site,
675
- fromPoi,
676
- toPoi,
677
- "Failed to add POI features: $message1"
678
- )
679
- return@addFeatures
680
- }
681
- Log.i(name, "POI features added successfully")
682
- ptrMapWidgetFragment.mapFragment?.currentRoute = route
683
- mapWidgetDidEndLoading(
684
- PTRMapWidgetCommandType.STATIC_PATH,
685
- site,
686
- fromPoi,
687
- toPoi,
688
- ""
689
- )
690
- }
691
- }
692
- }
693
-
694
- // region Show path
695
-
696
- private fun waitForPathManager(theSite: Site): Boolean {
697
- val wayfindingManager = Pointr.getPointr()?.wayfindingManager ?: return false
698
- val semaphore = Semaphore(0)
699
- val listener = object : WayfindingManager.Listener {
700
- override fun onWayfindingManagerReadyForSite(site: Site) {
701
- if (site != theSite) return
702
- semaphore.release()
703
- }
704
- }
705
- wayfindingManager.addListener(listener)
706
- if (!wayfindingManager.isReadyForSite(theSite)) {
707
- semaphore.tryAcquire(15, java.util.concurrent.TimeUnit.SECONDS)
708
- }
709
- wayfindingManager.removeListener(listener)
710
- return wayfindingManager.isReadyForSite(theSite)
711
- }
712
-
713
- private fun waitForSiteData(theSite: Site): Boolean {
714
- val dataManager = Pointr.getPointr()?.dataManager ?: return false
715
- val semaphore = Semaphore(0)
716
- val listener = object : DataManager.Listener {
717
- override fun onDataManagerCompleteAllForSite(
718
- site: Site,
719
- isSuccessful: Boolean,
720
- isOnlineData: Boolean,
721
- errors: List<ErrorMessage?>?
722
- ) {
723
- if (site != theSite) return
724
- if (!isOnlineData) return
725
- semaphore.release()
726
- }
727
- }
728
- dataManager.addListener(listener)
729
- if (Pointr.getPointr()?.poiManager?.hasContentForSite(theSite) != true) {
730
- dataManager.loadDataForSite(theSite)
731
- semaphore.tryAcquire(15, java.util.concurrent.TimeUnit.SECONDS)
732
- }
733
- dataManager.removeListener(listener)
734
- return Pointr.getPointr()?.poiManager?.hasContentForSite(theSite) == true
735
- }
736
-
737
500
  private fun getSite(siteExternalId: String): Site? {
738
501
  val siteManager = Pointr.getPointr()?.siteManager ?: return null
739
502
  val semaphore = Semaphore(0)
@@ -750,8 +513,6 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
750
513
  return siteManager.getSiteByExternalIdentifier(siteExternalId)
751
514
  }
752
515
 
753
- // endregion
754
-
755
516
  private fun waitForPointrToRun(): Boolean {
756
517
  Log.e(
757
518
  "PTRMapWidgetManager",
@@ -816,12 +577,8 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
816
577
  Log.e(name, "Map failed to load: $ptrError")
817
578
  }
818
579
 
819
- override fun onMarkMyCarDetailsEvent(
820
- markMyCarSheet: MarkMyCarBottomSheet,
821
- markMyCarDetailsEvent: MarkMyCarDetailsEvent
822
- ) {
823
- super.onMarkMyCarDetailsEvent(markMyCarSheet, markMyCarDetailsEvent)
824
- Log.i(name, "Mark my car details event: $markMyCarDetailsEvent")
580
+ override fun onDidEndLoading(error: String?) {
581
+ Log.i(name, "Map widget finished loading, error=$error")
825
582
  }
826
583
 
827
584
  private val frameCallback = object : Choreographer.FrameCallback {
@@ -837,9 +594,9 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
837
594
  frameLayout.bottom
838
595
  )
839
596
  frameLayout.viewTreeObserver.dispatchOnGlobalLayout()
840
- // Execute a declarative command prop once the view has non-zero dimensions.
841
- if (!commandTriggered && frameLayout.width > 0 && frameLayout.height > 0) {
842
- commandTriggered = true
597
+ // Execute a declarative action prop once the view has non-zero dimensions.
598
+ if (!actionTriggered && frameLayout.width > 0 && frameLayout.height > 0) {
599
+ actionTriggered = true
843
600
  executePendingCommandIfNeeded()
844
601
  }
845
602
  Choreographer.getInstance().postFrameCallback(this)
@@ -867,7 +624,6 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
867
624
 
868
625
  companion object {
869
626
  const val REACT_CLASS = "PTRMapWidget"
870
- const val LAYER_STATIC_PATH = "sym-static-path"
871
627
  }
872
628
 
873
629
  }