react-native-pointr 10.7.0 → 10.7.1
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.
- package/CHANGELOG.md +15 -0
- package/EXTENDING.md +56 -0
- package/android/src/main/java/com/pointr/PTRBridgeKeys.kt +153 -0
- package/android/src/main/java/com/pointr/PTRMapWidgetManager.kt +120 -101
- package/ios/PTRBridgeKeys.swift +110 -0
- package/ios/PTRMapWidgetContainerView.swift +46 -41
- package/ios/PTRMapWidgetManager.swift +14 -11
- package/package.json +1 -1
- package/src/PTRMapWidgetUtils.ts +12 -12
- package/src/actions/index.ts +85 -1
- package/src/components/index.tsx +5 -3
- package/src/constants/bridgeKeys.ts +127 -0
- package/src/constants/index.ts +15 -14
- package/src/index.tsx +12 -0
- package/android/src/main/java/com/pointr/PTRMapWidgetActionType.kt +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [10.7.1] - 2026-08-05
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Mobile SDK 10.7.0 integration.
|
|
11
|
+
|
|
12
|
+
|
|
7
13
|
## [10.7.0] - 2026-07-31
|
|
8
14
|
|
|
9
15
|
### Changed
|
|
@@ -32,6 +38,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
32
38
|
|
|
33
39
|
### Added
|
|
34
40
|
- **`PointrSdk` methods** exposing previously native-only capabilities: `shouldRequestPermissionsAtStartup`, `requestPermissions`, `getPois`, `searchPois`, `getSites`, `getBuildings`, `getSiteByExternalId`, `getClientName`, `isWayfindingReady`, `calculateDistance`, `isMyCarMarked`.
|
|
41
|
+
- **Shared bridge key constants** — every string crossing the JS ↔ native boundary for a map widget action (action types, `action` and `sdkConfig` payload keys, view manager command names) is now declared in one constants file per platform: `src/constants/bridgeKeys.ts`, `android/src/main/java/com/pointr/PTRBridgeKeys.kt` and `ios/PTRBridgeKeys.swift`. No literals remain in the action serializer or in either native reader, so a key can no longer be renamed on one side only. `PTRActionParamKeys`, `PTRSdkConfigKeys` and `PTRCommandNames` are exported from the package.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- **Actions serialize through `toPayload()`** — `PTRAction` subclasses now build their JSON payload from `PTRActionParamKeys` instead of the component spreading their class fields, so a field rename can no longer silently change the wire format.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- **Imperative `focusCoordinate` and `showMyCar` on Android** — the native side matched `focusCoordinate` / `showMyCarForSite` while JS dispatches `coordinate` / `myCarForSite`, so both commands were silently ignored. All three platforms now use the shared command names.
|
|
48
|
+
- **`markMyCar` / `showMyCar` via the declarative `action` prop on Android** — the completion event read an argument slot the declarative path never pushed, throwing inside the callback. Argument reads are now type-checked with defaults.
|
|
49
|
+
- **`personaId` in the `sdkConfig` prop on iOS** — the key was written by JS but never read, so the persona was ignored when the widget initialised the SDK.
|
|
35
50
|
|
|
36
51
|
|
|
37
52
|
## [10.3.0] - 2026-06-30
|
package/EXTENDING.md
CHANGED
|
@@ -358,6 +358,62 @@ Ensure both iOS and Android implementations return the same data structure:
|
|
|
358
358
|
}
|
|
359
359
|
```
|
|
360
360
|
|
|
361
|
+
### 7. Never Hard-code Bridge Strings
|
|
362
|
+
|
|
363
|
+
Map widget actions cross the bridge as JSON, so a key that JS writes and native
|
|
364
|
+
reads is matched by string only — rename it on one side and the other side
|
|
365
|
+
silently reads an empty value, with no compile error anywhere. Every such string
|
|
366
|
+
lives in a constants file, one per language, and the three are kept identical:
|
|
367
|
+
|
|
368
|
+
| Side | File |
|
|
369
|
+
| ---------- | --------------------------------------------------- |
|
|
370
|
+
| TypeScript | `src/constants/bridgeKeys.ts` |
|
|
371
|
+
| Android | `android/src/main/java/com/pointr/PTRBridgeKeys.kt` |
|
|
372
|
+
| iOS | `ios/PTRBridgeKeys.swift` |
|
|
373
|
+
|
|
374
|
+
They cover four groups:
|
|
375
|
+
|
|
376
|
+
- **Action types** — the `type` discriminator of the `action` prop
|
|
377
|
+
- **Action param keys** — every other field of the `action` prop payload
|
|
378
|
+
- **SDK config keys** — the fields of the `sdkConfig` prop
|
|
379
|
+
- **Command names** — the view manager commands `executeMapAction` dispatches
|
|
380
|
+
|
|
381
|
+
When adding an action or a parameter:
|
|
382
|
+
|
|
383
|
+
1. Add the constant to all three files (same name, same value).
|
|
384
|
+
2. In TypeScript, build the payload from `PTRActionParamKeys` by overriding
|
|
385
|
+
`toPayload()` on the action class — never rely on the class field names.
|
|
386
|
+
3. Read it back through `PTRBridgeKeys.ActionParamKeys` in both Kotlin and Swift.
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// src/actions/index.ts
|
|
390
|
+
export class PTRMyNewAction extends PTRAction {
|
|
391
|
+
constructor(readonly site: string, readonly poi: string) {
|
|
392
|
+
super(PTRActionType.MY_NEW_ACTION);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
override toPayload(): Record<string, unknown> {
|
|
396
|
+
return {
|
|
397
|
+
...super.toPayload(),
|
|
398
|
+
[Keys.SITE]: this.site,
|
|
399
|
+
[Keys.POI]: this.poi,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
```kotlin
|
|
406
|
+
// PTRMapWidgetManager.kt
|
|
407
|
+
val site = obj.optString(ActionParamKeys.SITE, "")
|
|
408
|
+
val poi = obj.optString(ActionParamKeys.POI, "")
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```swift
|
|
412
|
+
// PTRMapWidgetContainerView.swift
|
|
413
|
+
let siteId = json[Keys.site] as? String ?? ""
|
|
414
|
+
let poiId = json[Keys.poi] as? String ?? ""
|
|
415
|
+
```
|
|
416
|
+
|
|
361
417
|
## Adding Event Listeners
|
|
362
418
|
|
|
363
419
|
For continuous data streams or callbacks, use event emitters:
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
package com.pointr
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.StringDef
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Every string that crosses the JS <-> native boundary when an action is sent
|
|
7
|
+
* to the map widget: action type discriminators, `action` / `sdkConfig` payload
|
|
8
|
+
* keys and view manager command names.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here may be hard-coded anywhere else — a key renamed on one side only
|
|
11
|
+
* fails silently (`optString` returns an empty string), so all three sides read
|
|
12
|
+
* them from a constants file:
|
|
13
|
+
*
|
|
14
|
+
* TypeScript src/constants/bridgeKeys.ts
|
|
15
|
+
* Android android/src/main/java/com/pointr/PTRBridgeKeys.kt (this file)
|
|
16
|
+
* iOS ios/PTRBridgeKeys.swift
|
|
17
|
+
*
|
|
18
|
+
* Changing a value here means changing it in the other two files as well.
|
|
19
|
+
*/
|
|
20
|
+
object PTRBridgeKeys {
|
|
21
|
+
|
|
22
|
+
/** Discriminator written to the `type` field of the serialized `action` prop. */
|
|
23
|
+
object ActionTypes {
|
|
24
|
+
/** Focus the map on a site, building or level */
|
|
25
|
+
const val FOCUS_MAP = "focusMap"
|
|
26
|
+
/** Highlight a single POI */
|
|
27
|
+
const val HIGHLIGHT_POI = "highlightPoi"
|
|
28
|
+
/** Draw a static route between two POIs */
|
|
29
|
+
const val DISPLAY_ROUTE = "displayRoute"
|
|
30
|
+
/** Start live wayfinding to a destination POI */
|
|
31
|
+
const val START_WAYFINDING = "startWayfinding"
|
|
32
|
+
/** Mark the parked car location */
|
|
33
|
+
const val MARK_MY_CAR = "markMyCar"
|
|
34
|
+
/** Show the previously marked car location */
|
|
35
|
+
const val SHOW_MY_CAR = "showMyCar"
|
|
36
|
+
/** Focus the map on a geographic coordinate */
|
|
37
|
+
const val FOCUS_COORDINATE = "focusCoordinate"
|
|
38
|
+
/** Highlight POIs of one or more categories */
|
|
39
|
+
const val HIGHLIGHT_CATEGORY = "highlightCategory"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Field names of the JSON payload carried by the `action` view prop.
|
|
44
|
+
* JS writes them, Android and iOS read them back out.
|
|
45
|
+
*/
|
|
46
|
+
object ActionParamKeys {
|
|
47
|
+
/** Action discriminator — one of [ActionTypes] */
|
|
48
|
+
const val TYPE = "type"
|
|
49
|
+
/** Site external identifier */
|
|
50
|
+
const val SITE = "site"
|
|
51
|
+
/** Building external identifier */
|
|
52
|
+
const val BUILDING = "building"
|
|
53
|
+
/** Level index used by focusMap / markMyCar */
|
|
54
|
+
const val LEVEL = "level"
|
|
55
|
+
/** POI external identifier — destination for highlightPoi and startWayfinding */
|
|
56
|
+
const val POI = "poi"
|
|
57
|
+
/** Source POI external identifier for displayRoute */
|
|
58
|
+
const val FROM_POI = "fromPoi"
|
|
59
|
+
/** Destination POI external identifier for displayRoute */
|
|
60
|
+
const val TO_POI = "toPoi"
|
|
61
|
+
/** Whether the car popup is shown */
|
|
62
|
+
const val SHOULD_SHOW_POPUP = "shouldShowPopup"
|
|
63
|
+
/** Animation applied to the car marker */
|
|
64
|
+
const val ANIMATION_TYPE = "animationType"
|
|
65
|
+
/** Latitude for focusCoordinate */
|
|
66
|
+
const val LATITUDE = "latitude"
|
|
67
|
+
/** Longitude for focusCoordinate */
|
|
68
|
+
const val LONGITUDE = "longitude"
|
|
69
|
+
/** Level index for focusCoordinate */
|
|
70
|
+
const val LEVEL_INDEX = "levelIndex"
|
|
71
|
+
/** Category identifiers for highlightCategory */
|
|
72
|
+
const val CATEGORY_IDS = "categoryIds"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Field names of the JSON payload carried by the `sdkConfig` view prop. */
|
|
76
|
+
object SdkConfigKeys {
|
|
77
|
+
/** Client identifier issued by Pointr */
|
|
78
|
+
const val CLIENT_ID = "clientId"
|
|
79
|
+
/** License key issued by Pointr */
|
|
80
|
+
const val LICENSE_KEY = "licenseKey"
|
|
81
|
+
/** Base URL of the Pointr environment */
|
|
82
|
+
const val BASE_URL = "baseUrl"
|
|
83
|
+
/** Persona identifier applied to the SDK params */
|
|
84
|
+
const val PERSONA_ID = "personaId"
|
|
85
|
+
/** Log level ordinal */
|
|
86
|
+
const val LOG_LEVEL = "logLevel"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* View manager command names used by the imperative `executeMapAction` path.
|
|
91
|
+
* JS dispatches them, Android matches them in `receiveCommand` and iOS
|
|
92
|
+
* exports them as `@objc` methods — the names must match on all three sides.
|
|
93
|
+
*/
|
|
94
|
+
object CommandNames {
|
|
95
|
+
/** Focus the map on a site */
|
|
96
|
+
const val FOCUS_SITE = "site"
|
|
97
|
+
/** Focus the map on a building */
|
|
98
|
+
const val FOCUS_BUILDING = "building"
|
|
99
|
+
/** Focus the map on a level */
|
|
100
|
+
const val FOCUS_LEVEL = "level"
|
|
101
|
+
/** Highlight a POI */
|
|
102
|
+
const val HIGHLIGHT_POI = "poi"
|
|
103
|
+
/** Draw a static route between two POIs */
|
|
104
|
+
const val DISPLAY_ROUTE = "displayRoute"
|
|
105
|
+
/** Start live wayfinding */
|
|
106
|
+
const val START_WAYFINDING = "startWayfinding"
|
|
107
|
+
/** Mark the car at site level */
|
|
108
|
+
const val MARK_MY_CAR_FOR_SITE = "markMyCarForSite"
|
|
109
|
+
/** Mark the car at a specific level */
|
|
110
|
+
const val MARK_MY_CAR_FOR_LEVEL = "markMyCarForLevel"
|
|
111
|
+
/** Show the marked car at site level */
|
|
112
|
+
const val SHOW_MY_CAR_FOR_SITE = "myCarForSite"
|
|
113
|
+
/** Focus the map on a coordinate */
|
|
114
|
+
const val FOCUS_COORDINATE = "coordinate"
|
|
115
|
+
/** Highlight a category */
|
|
116
|
+
const val HIGHLIGHT_CATEGORY = "highlightCategory"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Restricts a String parameter to the [PTRBridgeKeys.ActionTypes] values. */
|
|
121
|
+
@Retention(AnnotationRetention.SOURCE)
|
|
122
|
+
@StringDef(
|
|
123
|
+
value = [
|
|
124
|
+
PTRBridgeKeys.ActionTypes.FOCUS_MAP,
|
|
125
|
+
PTRBridgeKeys.ActionTypes.HIGHLIGHT_POI,
|
|
126
|
+
PTRBridgeKeys.ActionTypes.DISPLAY_ROUTE,
|
|
127
|
+
PTRBridgeKeys.ActionTypes.START_WAYFINDING,
|
|
128
|
+
PTRBridgeKeys.ActionTypes.MARK_MY_CAR,
|
|
129
|
+
PTRBridgeKeys.ActionTypes.SHOW_MY_CAR,
|
|
130
|
+
PTRBridgeKeys.ActionTypes.FOCUS_COORDINATE,
|
|
131
|
+
PTRBridgeKeys.ActionTypes.HIGHLIGHT_CATEGORY
|
|
132
|
+
]
|
|
133
|
+
)
|
|
134
|
+
annotation class PTRActionTypeDef
|
|
135
|
+
|
|
136
|
+
/** Restricts a String parameter to the [PTRBridgeKeys.CommandNames] values. */
|
|
137
|
+
@Retention(AnnotationRetention.SOURCE)
|
|
138
|
+
@StringDef(
|
|
139
|
+
value = [
|
|
140
|
+
PTRBridgeKeys.CommandNames.FOCUS_SITE,
|
|
141
|
+
PTRBridgeKeys.CommandNames.FOCUS_BUILDING,
|
|
142
|
+
PTRBridgeKeys.CommandNames.FOCUS_LEVEL,
|
|
143
|
+
PTRBridgeKeys.CommandNames.HIGHLIGHT_POI,
|
|
144
|
+
PTRBridgeKeys.CommandNames.DISPLAY_ROUTE,
|
|
145
|
+
PTRBridgeKeys.CommandNames.START_WAYFINDING,
|
|
146
|
+
PTRBridgeKeys.CommandNames.MARK_MY_CAR_FOR_SITE,
|
|
147
|
+
PTRBridgeKeys.CommandNames.MARK_MY_CAR_FOR_LEVEL,
|
|
148
|
+
PTRBridgeKeys.CommandNames.SHOW_MY_CAR_FOR_SITE,
|
|
149
|
+
PTRBridgeKeys.CommandNames.FOCUS_COORDINATE,
|
|
150
|
+
PTRBridgeKeys.CommandNames.HIGHLIGHT_CATEGORY
|
|
151
|
+
]
|
|
152
|
+
)
|
|
153
|
+
annotation class PTRCommandDef
|
|
@@ -8,12 +8,17 @@ import android.widget.FrameLayout
|
|
|
8
8
|
import androidx.fragment.app.FragmentActivity
|
|
9
9
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
10
|
import com.facebook.react.bridge.ReadableArray
|
|
11
|
+
import com.facebook.react.bridge.ReadableType
|
|
11
12
|
import com.facebook.react.bridge.WritableMap
|
|
12
13
|
import com.facebook.react.bridge.WritableNativeMap
|
|
13
14
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
14
15
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
15
16
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
16
17
|
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
18
|
+
import com.pointr.PTRBridgeKeys.ActionParamKeys
|
|
19
|
+
import com.pointr.PTRBridgeKeys.ActionTypes
|
|
20
|
+
import com.pointr.PTRBridgeKeys.CommandNames
|
|
21
|
+
import com.pointr.PTRBridgeKeys.SdkConfigKeys
|
|
17
22
|
import com.pointrlabs.core.management.Pointr
|
|
18
23
|
import com.pointrlabs.core.management.interfaces.PointrListener
|
|
19
24
|
import com.pointrlabs.core.management.models.PTRParams
|
|
@@ -57,9 +62,10 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
57
62
|
// auto-executes it once the view is attached rather than requiring a JS
|
|
58
63
|
// imperative action dispatch.
|
|
59
64
|
//
|
|
60
|
-
// JSON shape
|
|
61
|
-
//
|
|
62
|
-
//
|
|
65
|
+
// The JSON shape is described by PTRBridgeKeys.ActionTypes (the `type`
|
|
66
|
+
// discriminator) and PTRBridgeKeys.ActionParamKeys (every other field).
|
|
67
|
+
// Read the payload only through those constants — the JS side writes it
|
|
68
|
+
// from the matching src/constants/bridgeKeys.ts.
|
|
63
69
|
private var pendingActionJson: String? = null
|
|
64
70
|
private var pendingSdkConfigJson: String? = null
|
|
65
71
|
private var actionDidExecute = false
|
|
@@ -102,16 +108,16 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
102
108
|
val json = pendingSdkConfigJson ?: return
|
|
103
109
|
try {
|
|
104
110
|
val obj = org.json.JSONObject(json)
|
|
105
|
-
val clientId = obj.optString(
|
|
106
|
-
val licenseKey = obj.optString(
|
|
107
|
-
val baseUrl = obj.optString(
|
|
108
|
-
val personaId = obj.optString(
|
|
111
|
+
val clientId = obj.optString(SdkConfigKeys.CLIENT_ID)
|
|
112
|
+
val licenseKey = obj.optString(SdkConfigKeys.LICENSE_KEY)
|
|
113
|
+
val baseUrl = obj.optString(SdkConfigKeys.BASE_URL)
|
|
114
|
+
val personaId = obj.optString(SdkConfigKeys.PERSONA_ID, "")
|
|
109
115
|
if (clientId.isNotEmpty() && licenseKey.isNotEmpty() && baseUrl.isNotEmpty()) {
|
|
110
116
|
val params = PTRParams(clientId, licenseKey, baseUrl)
|
|
111
117
|
if (personaId.isNotEmpty()) {
|
|
112
118
|
params.personaId = personaId
|
|
113
119
|
}
|
|
114
|
-
val logLevel = obj.optInt(
|
|
120
|
+
val logLevel = obj.optInt(SdkConfigKeys.LOG_LEVEL, Plog.LogLevel.ERROR.ordinal)
|
|
115
121
|
params.logLevel = try {
|
|
116
122
|
Plog.LogLevel.entries[logLevel]
|
|
117
123
|
} catch (_: Exception) {
|
|
@@ -150,69 +156,74 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
150
156
|
}
|
|
151
157
|
try {
|
|
152
158
|
val obj = org.json.JSONObject(json)
|
|
153
|
-
val type = obj.optString(
|
|
154
|
-
val site = obj.optString(
|
|
155
|
-
val building = obj.optString(
|
|
156
|
-
val level = obj.optInt(
|
|
157
|
-
val poi = obj.optString(
|
|
158
|
-
val fromPoi = obj.optString(
|
|
159
|
-
val toPoi = obj.optString(
|
|
159
|
+
val type = obj.optString(ActionParamKeys.TYPE)
|
|
160
|
+
val site = obj.optString(ActionParamKeys.SITE, "")
|
|
161
|
+
val building = obj.optString(ActionParamKeys.BUILDING, "")
|
|
162
|
+
val level = obj.optInt(ActionParamKeys.LEVEL, 0)
|
|
163
|
+
val poi = obj.optString(ActionParamKeys.POI, "")
|
|
164
|
+
val fromPoi = obj.optString(ActionParamKeys.FROM_POI, "")
|
|
165
|
+
val toPoi = obj.optString(ActionParamKeys.TO_POI, "")
|
|
160
166
|
|
|
161
167
|
val args = com.facebook.react.bridge.Arguments.createArray()
|
|
162
|
-
val shouldShowPopup = obj.optBoolean(
|
|
168
|
+
val shouldShowPopup = obj.optBoolean(ActionParamKeys.SHOULD_SHOW_POPUP, true)
|
|
169
|
+
val animationType = obj.optInt(ActionParamKeys.ANIMATION_TYPE, 1)
|
|
163
170
|
when (type) {
|
|
164
|
-
|
|
165
|
-
if (building.isNotEmpty() && obj.has(
|
|
171
|
+
ActionTypes.FOCUS_MAP -> {
|
|
172
|
+
if (building.isNotEmpty() && obj.has(ActionParamKeys.LEVEL)) {
|
|
166
173
|
args.pushString(site); args.pushString(building); args.pushInt(level)
|
|
167
|
-
executeCommand(
|
|
174
|
+
executeCommand(CommandNames.FOCUS_LEVEL, args)
|
|
168
175
|
} else if (building.isNotEmpty()) {
|
|
169
176
|
args.pushString(site); args.pushString(building)
|
|
170
|
-
executeCommand(
|
|
177
|
+
executeCommand(CommandNames.FOCUS_BUILDING, args)
|
|
171
178
|
} else {
|
|
172
179
|
args.pushString(site)
|
|
173
|
-
executeCommand(
|
|
180
|
+
executeCommand(CommandNames.FOCUS_SITE, args)
|
|
174
181
|
}
|
|
175
182
|
}
|
|
176
|
-
|
|
183
|
+
ActionTypes.HIGHLIGHT_POI -> {
|
|
177
184
|
args.pushString(site); args.pushString(poi)
|
|
178
|
-
executeCommand(
|
|
185
|
+
executeCommand(CommandNames.HIGHLIGHT_POI, args)
|
|
179
186
|
}
|
|
180
|
-
|
|
187
|
+
ActionTypes.DISPLAY_ROUTE -> {
|
|
181
188
|
args.pushString(site); args.pushString(fromPoi); args.pushString(toPoi)
|
|
182
|
-
executeCommand(
|
|
189
|
+
executeCommand(CommandNames.DISPLAY_ROUTE, args)
|
|
183
190
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
ActionTypes.START_WAYFINDING -> {
|
|
192
|
+
// PTRStartWayfindingAction serialises its destination under
|
|
193
|
+
// ActionParamKeys.POI; TO_POI stays accepted as a fallback for
|
|
194
|
+
// hand-written, deeplink-style payloads.
|
|
195
|
+
args.pushString(site); args.pushString(poi.ifEmpty { toPoi })
|
|
196
|
+
executeCommand(CommandNames.START_WAYFINDING, args)
|
|
187
197
|
}
|
|
188
|
-
|
|
189
|
-
if (building.isNotEmpty() && obj.has(
|
|
190
|
-
args.pushString(site); args.pushString(building); args.pushInt(level)
|
|
191
|
-
|
|
198
|
+
ActionTypes.MARK_MY_CAR -> {
|
|
199
|
+
if (building.isNotEmpty() && obj.has(ActionParamKeys.LEVEL)) {
|
|
200
|
+
args.pushString(site); args.pushString(building); args.pushInt(level)
|
|
201
|
+
args.pushBoolean(shouldShowPopup); args.pushInt(animationType)
|
|
202
|
+
executeCommand(CommandNames.MARK_MY_CAR_FOR_LEVEL, args)
|
|
192
203
|
} else {
|
|
193
|
-
args.pushString(site); args.pushBoolean(shouldShowPopup)
|
|
194
|
-
executeCommand(
|
|
204
|
+
args.pushString(site); args.pushBoolean(shouldShowPopup); args.pushInt(animationType)
|
|
205
|
+
executeCommand(CommandNames.MARK_MY_CAR_FOR_SITE, args)
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
|
-
|
|
198
|
-
args.pushString(site); args.pushBoolean(shouldShowPopup)
|
|
199
|
-
executeCommand(
|
|
208
|
+
ActionTypes.SHOW_MY_CAR -> {
|
|
209
|
+
args.pushString(site); args.pushBoolean(shouldShowPopup); args.pushInt(animationType)
|
|
210
|
+
executeCommand(CommandNames.SHOW_MY_CAR_FOR_SITE, args)
|
|
200
211
|
}
|
|
201
|
-
|
|
202
|
-
val lat = obj.optDouble(
|
|
203
|
-
val lon = obj.optDouble(
|
|
204
|
-
val lvl = obj.optInt(
|
|
212
|
+
ActionTypes.FOCUS_COORDINATE -> {
|
|
213
|
+
val lat = obj.optDouble(ActionParamKeys.LATITUDE, 0.0)
|
|
214
|
+
val lon = obj.optDouble(ActionParamKeys.LONGITUDE, 0.0)
|
|
215
|
+
val lvl = obj.optInt(ActionParamKeys.LEVEL_INDEX, -1)
|
|
205
216
|
args.pushString(site); args.pushDouble(lat); args.pushDouble(lon); args.pushInt(lvl)
|
|
206
|
-
executeCommand(
|
|
217
|
+
executeCommand(CommandNames.FOCUS_COORDINATE, args)
|
|
207
218
|
}
|
|
208
|
-
|
|
219
|
+
ActionTypes.HIGHLIGHT_CATEGORY -> {
|
|
209
220
|
val catArr = com.facebook.react.bridge.Arguments.createArray()
|
|
210
|
-
val jsonArr = obj.optJSONArray(
|
|
221
|
+
val jsonArr = obj.optJSONArray(ActionParamKeys.CATEGORY_IDS)
|
|
211
222
|
if (jsonArr != null) {
|
|
212
223
|
for (i in 0 until jsonArr.length()) catArr.pushString(jsonArr.optString(i))
|
|
213
224
|
}
|
|
214
225
|
args.pushString(site); args.pushArray(catArr)
|
|
215
|
-
executeCommand(
|
|
226
|
+
executeCommand(CommandNames.HIGHLIGHT_CATEGORY, args)
|
|
216
227
|
}
|
|
217
228
|
else -> Log.w(name, "Unknown action type in action prop: $type")
|
|
218
229
|
}
|
|
@@ -272,17 +283,17 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
272
283
|
}
|
|
273
284
|
|
|
274
285
|
private fun executeCommand(
|
|
275
|
-
command: String,
|
|
286
|
+
@PTRCommandDef command: String,
|
|
276
287
|
args: ReadableArray
|
|
277
288
|
) {
|
|
278
289
|
val action: PTRMapWidgetAction = when (command) {
|
|
279
|
-
|
|
290
|
+
CommandNames.FOCUS_SITE -> {
|
|
280
291
|
val siteId = args.getString(0).orEmpty()
|
|
281
292
|
val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
|
|
282
293
|
PTRMapWidgetAction.focusMap(location)
|
|
283
294
|
}
|
|
284
295
|
|
|
285
|
-
|
|
296
|
+
CommandNames.FOCUS_BUILDING -> {
|
|
286
297
|
val siteId = args.getString(0).orEmpty()
|
|
287
298
|
val buildingId = args.getString(1).orEmpty()
|
|
288
299
|
val location = PTRMapWidgetBuildingLocation(
|
|
@@ -292,7 +303,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
292
303
|
PTRMapWidgetAction.focusMap(location)
|
|
293
304
|
}
|
|
294
305
|
|
|
295
|
-
|
|
306
|
+
CommandNames.FOCUS_LEVEL -> {
|
|
296
307
|
val siteId = args.getString(0).orEmpty()
|
|
297
308
|
val buildingId = args.getString(1).orEmpty()
|
|
298
309
|
val location = PTRMapWidgetLevelLocation(
|
|
@@ -303,7 +314,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
303
314
|
PTRMapWidgetAction.focusMap(location)
|
|
304
315
|
}
|
|
305
316
|
|
|
306
|
-
|
|
317
|
+
CommandNames.HIGHLIGHT_POI -> {
|
|
307
318
|
val siteId = args.getString(0).orEmpty()
|
|
308
319
|
val poiId = args.getString(1).orEmpty()
|
|
309
320
|
val location = PTRMapWidgetPoiLocation(
|
|
@@ -313,7 +324,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
313
324
|
PTRMapWidgetAction.highlightPoi(location)
|
|
314
325
|
}
|
|
315
326
|
|
|
316
|
-
|
|
327
|
+
CommandNames.START_WAYFINDING -> {
|
|
317
328
|
val siteId = args.getString(0).orEmpty()
|
|
318
329
|
val poiId = args.getString(1).orEmpty()
|
|
319
330
|
val location = PTRMapWidgetPoiLocation(
|
|
@@ -323,7 +334,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
323
334
|
PTRMapWidgetAction.startWayfinding(location)
|
|
324
335
|
}
|
|
325
336
|
|
|
326
|
-
|
|
337
|
+
CommandNames.DISPLAY_ROUTE -> {
|
|
327
338
|
val siteId = args.getString(0).orEmpty()
|
|
328
339
|
val sourcePoiId = args.getString(1).orEmpty()
|
|
329
340
|
val destinationPoiId = args.getString(2).orEmpty()
|
|
@@ -338,13 +349,13 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
338
349
|
PTRMapWidgetAction.displayRoute(sourceLocation, destinationLocation)
|
|
339
350
|
}
|
|
340
351
|
|
|
341
|
-
|
|
352
|
+
CommandNames.MARK_MY_CAR_FOR_SITE -> {
|
|
342
353
|
val siteId = args.getString(0).orEmpty()
|
|
343
354
|
val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
|
|
344
355
|
PTRMapWidgetAction.markMyCar(location, args.getBoolean(1))
|
|
345
356
|
}
|
|
346
357
|
|
|
347
|
-
|
|
358
|
+
CommandNames.MARK_MY_CAR_FOR_LEVEL -> {
|
|
348
359
|
val siteId = args.getString(0).orEmpty()
|
|
349
360
|
val buildingId = args.getString(1).orEmpty()
|
|
350
361
|
val location = PTRMapWidgetLevelLocation(
|
|
@@ -355,13 +366,18 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
355
366
|
PTRMapWidgetMarkMyCarAction(location, shouldShowPopup = args.getBoolean(3))
|
|
356
367
|
}
|
|
357
368
|
|
|
358
|
-
|
|
369
|
+
CommandNames.SHOW_MY_CAR_FOR_SITE -> {
|
|
359
370
|
val siteId = args.getString(0).orEmpty()
|
|
360
371
|
val location = PTRMapWidgetSiteLocation(PTRIdentifier(siteId, isExternal = true))
|
|
361
|
-
|
|
372
|
+
// The declarative path sends (site, shouldShowPopup, animationType) while the
|
|
373
|
+
// imperative JS path sends (site, animationType) — read index 1 by type so
|
|
374
|
+
// neither shape throws.
|
|
375
|
+
val shouldShowPopup =
|
|
376
|
+
if (args.size() > 1 && args.getType(1) == ReadableType.Boolean) args.getBoolean(1) else true
|
|
377
|
+
PTRMapWidgetAction.showMyCar(location, shouldShowPopup = shouldShowPopup)
|
|
362
378
|
}
|
|
363
379
|
|
|
364
|
-
|
|
380
|
+
CommandNames.FOCUS_COORDINATE -> {
|
|
365
381
|
val siteId = args.getString(0).orEmpty()
|
|
366
382
|
val latitude = args.getDouble(1)
|
|
367
383
|
val longitude = args.getDouble(2)
|
|
@@ -376,7 +392,7 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
376
392
|
PTRMapWidgetAction.focusMap(location)
|
|
377
393
|
}
|
|
378
394
|
|
|
379
|
-
|
|
395
|
+
CommandNames.HIGHLIGHT_CATEGORY -> {
|
|
380
396
|
val siteId = args.getString(0).orEmpty()
|
|
381
397
|
val categoryIds = mutableListOf<String>()
|
|
382
398
|
val arr = args.getArray(1)
|
|
@@ -401,77 +417,80 @@ class PTRMapWidgetManager(private val reactContext: ReactApplicationContext) :
|
|
|
401
417
|
getMapWidgetFragment(action)
|
|
402
418
|
}
|
|
403
419
|
|
|
420
|
+
// The command arguments are positional, and the two dispatch paths (declarative
|
|
421
|
+
// `action` prop vs imperative executeMapAction) do not always push the same
|
|
422
|
+
// number of them. Read them by type with a fallback so a shorter payload
|
|
423
|
+
// degrades to a default instead of throwing inside the completion callback.
|
|
424
|
+
private fun argString(args: Array<out Any>, index: Int) = args.getOrNull(index) as? String ?: ""
|
|
425
|
+
private fun argInt(args: Array<out Any>, index: Int) = (args.getOrNull(index) as? Number)?.toInt() ?: 0
|
|
426
|
+
private fun argBoolean(args: Array<out Any>, index: Int) = args.getOrNull(index) as? Boolean ?: true
|
|
427
|
+
|
|
428
|
+
/** The error is always appended as the last argument by [executeCommand]. */
|
|
429
|
+
private fun argError(args: Array<out Any>) = args.lastOrNull() as? String ?: ""
|
|
430
|
+
|
|
404
431
|
private fun mapWidgetDidEndLoading(
|
|
405
|
-
@
|
|
432
|
+
@PTRCommandDef command: String,
|
|
406
433
|
vararg args: Any
|
|
407
434
|
) {
|
|
408
435
|
val event: WritableMap = WritableNativeMap()
|
|
409
436
|
event.putString("command", command)
|
|
410
437
|
when (command) {
|
|
411
|
-
|
|
412
|
-
event.putString("siteExternalIdentifier", args
|
|
413
|
-
event.putString("error", args[1] as String)
|
|
438
|
+
CommandNames.FOCUS_SITE -> {
|
|
439
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
414
440
|
}
|
|
415
441
|
|
|
416
|
-
|
|
417
|
-
event.putString("siteExternalIdentifier", args
|
|
418
|
-
event.putString("buildingExternalIdentifier", args
|
|
419
|
-
event.putString("error", args[2] as String)
|
|
442
|
+
CommandNames.FOCUS_BUILDING -> {
|
|
443
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
444
|
+
event.putString("buildingExternalIdentifier", argString(args, 1))
|
|
420
445
|
}
|
|
421
446
|
|
|
422
|
-
|
|
423
|
-
event.putString("siteExternalIdentifier", args
|
|
424
|
-
event.putString("buildingExternalIdentifier", args
|
|
425
|
-
event.putInt("levelIndex", (args
|
|
426
|
-
event.putString("error", args[3] as String)
|
|
447
|
+
CommandNames.FOCUS_LEVEL -> {
|
|
448
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
449
|
+
event.putString("buildingExternalIdentifier", argString(args, 1))
|
|
450
|
+
event.putInt("levelIndex", argInt(args, 2))
|
|
427
451
|
}
|
|
428
452
|
|
|
429
|
-
|
|
430
|
-
event.putString("siteExternalIdentifier", args
|
|
431
|
-
event.putString("poiExternalIdentifier", args
|
|
432
|
-
event.putString("error", args[2] as String)
|
|
453
|
+
CommandNames.HIGHLIGHT_POI -> {
|
|
454
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
455
|
+
event.putString("poiExternalIdentifier", argString(args, 1))
|
|
433
456
|
}
|
|
434
457
|
|
|
435
|
-
|
|
436
|
-
event.putString("siteExternalIdentifier", args
|
|
437
|
-
event.putString("poiExternalIdentifier", args
|
|
438
|
-
event.putString("error", args[2] as String)
|
|
458
|
+
CommandNames.START_WAYFINDING -> {
|
|
459
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
460
|
+
event.putString("poiExternalIdentifier", argString(args, 1))
|
|
439
461
|
}
|
|
440
462
|
|
|
441
|
-
|
|
442
|
-
event.putString("siteExternalIdentifier", args
|
|
443
|
-
event.putString("fromPoiExternalIdentifier", args
|
|
444
|
-
event.putString("toPoiExternalIdentifier", args
|
|
445
|
-
event.putString("error", args[3] as String)
|
|
463
|
+
CommandNames.DISPLAY_ROUTE -> {
|
|
464
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
465
|
+
event.putString("fromPoiExternalIdentifier", argString(args, 1))
|
|
466
|
+
event.putString("toPoiExternalIdentifier", argString(args, 2))
|
|
446
467
|
}
|
|
447
468
|
|
|
448
|
-
|
|
449
|
-
event.putString("siteExternalIdentifier", args
|
|
450
|
-
event.putBoolean("shouldShowPopup", args
|
|
451
|
-
event.putInt("animationType", (args
|
|
452
|
-
event.putString("error", args[3] as String)
|
|
469
|
+
CommandNames.MARK_MY_CAR_FOR_SITE -> {
|
|
470
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
471
|
+
event.putBoolean("shouldShowPopup", argBoolean(args, 1))
|
|
472
|
+
event.putInt("animationType", argInt(args, 2))
|
|
453
473
|
}
|
|
454
474
|
|
|
455
|
-
|
|
456
|
-
event.putString("siteExternalIdentifier", args
|
|
457
|
-
event.putString("buildingExternalIdentifier", args
|
|
458
|
-
event.putInt("levelIndex", (args
|
|
459
|
-
event.putBoolean("shouldShowPopup", args
|
|
460
|
-
event.putInt("animationType", (args
|
|
461
|
-
event.putString("error", args[5] as String)
|
|
475
|
+
CommandNames.MARK_MY_CAR_FOR_LEVEL -> {
|
|
476
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
477
|
+
event.putString("buildingExternalIdentifier", argString(args, 1))
|
|
478
|
+
event.putInt("levelIndex", argInt(args, 2))
|
|
479
|
+
event.putBoolean("shouldShowPopup", argBoolean(args, 3))
|
|
480
|
+
event.putInt("animationType", argInt(args, 4))
|
|
462
481
|
}
|
|
463
482
|
|
|
464
|
-
|
|
465
|
-
event.putString("siteExternalIdentifier", args
|
|
466
|
-
event.putBoolean("shouldShowPopup", args
|
|
467
|
-
event.putInt("animationType", (args
|
|
468
|
-
event.putString("error", args[3] as String)
|
|
483
|
+
CommandNames.SHOW_MY_CAR_FOR_SITE -> {
|
|
484
|
+
event.putString("siteExternalIdentifier", argString(args, 0))
|
|
485
|
+
event.putBoolean("shouldShowPopup", argBoolean(args, 1))
|
|
486
|
+
event.putInt("animationType", argInt(args, 2))
|
|
469
487
|
}
|
|
470
488
|
|
|
471
489
|
else -> {
|
|
472
490
|
return
|
|
473
491
|
}
|
|
474
492
|
}
|
|
493
|
+
event.putString("error", argError(args))
|
|
475
494
|
Log.v(name, "sending onMapWidgetDidEndLoading with event: $event")
|
|
476
495
|
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(
|
|
477
496
|
frameLayout.id,
|