@rematter/pylon-react-native 0.1.5 → 0.1.6
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.
|
@@ -18,96 +18,107 @@ import com.pylon.chatwidget.PylonUser
|
|
|
18
18
|
* This is kept as minimal as possible to avoid interfering with touch pass-through.
|
|
19
19
|
*/
|
|
20
20
|
class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
private var pylonChatView: PylonChatView? = null
|
|
23
23
|
private var config: PylonConfig? = null
|
|
24
24
|
private var user: PylonUser? = null
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
// Config properties
|
|
27
27
|
var appId: String? = null
|
|
28
28
|
set(value) {
|
|
29
29
|
field = value
|
|
30
30
|
updateConfig()
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
var widgetBaseUrl: String? = null
|
|
34
34
|
set(value) {
|
|
35
35
|
field = value
|
|
36
36
|
updateConfig()
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
var widgetScriptUrl: String? = null
|
|
40
40
|
set(value) {
|
|
41
41
|
field = value
|
|
42
42
|
updateConfig()
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
var enableLogging: Boolean = true
|
|
46
46
|
set(value) {
|
|
47
47
|
field = value
|
|
48
48
|
updateConfig()
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
var debugMode: Boolean = false
|
|
52
52
|
set(value) {
|
|
53
53
|
field = value
|
|
54
54
|
updateConfig()
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
var primaryColor: String? = null
|
|
58
58
|
set(value) {
|
|
59
59
|
field = value
|
|
60
60
|
updateConfig()
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
// User properties
|
|
64
64
|
var userEmail: String? = null
|
|
65
65
|
set(value) {
|
|
66
66
|
field = value
|
|
67
67
|
updateUser()
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
var userName: String? = null
|
|
71
71
|
set(value) {
|
|
72
72
|
field = value
|
|
73
73
|
updateUser()
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
var userAvatarUrl: String? = null
|
|
77
77
|
set(value) {
|
|
78
78
|
field = value
|
|
79
79
|
updateUser()
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
var userEmailHash: String? = null
|
|
83
83
|
set(value) {
|
|
84
84
|
field = value
|
|
85
85
|
updateUser()
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
var userAccountId: String? = null
|
|
89
89
|
set(value) {
|
|
90
90
|
field = value
|
|
91
91
|
updateUser()
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
var userAccountExternalId: String? = null
|
|
95
95
|
set(value) {
|
|
96
96
|
field = value
|
|
97
97
|
updateUser()
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// Safe area top inset for coordinate space adjustment
|
|
101
|
+
var topInset: Float = 0f
|
|
102
|
+
set(value) {
|
|
103
|
+
field = value
|
|
104
|
+
// Apply to pylonChatView if it exists
|
|
105
|
+
pylonChatView?.let {
|
|
106
|
+
// Note: Android PylonChat doesn't have topInset support yet,
|
|
107
|
+
// but we store it here for future use or coordinate adjustments
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
100
111
|
init {
|
|
101
112
|
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
102
113
|
}
|
|
103
|
-
|
|
114
|
+
|
|
104
115
|
// Track pointer events setting
|
|
105
116
|
private var pointerEventsMode = "auto"
|
|
106
|
-
|
|
117
|
+
|
|
107
118
|
fun setPointerEventsMode(mode: String) {
|
|
108
119
|
pointerEventsMode = mode
|
|
109
120
|
}
|
|
110
|
-
|
|
121
|
+
|
|
111
122
|
/**
|
|
112
123
|
* This is the CRITICAL method for pointerEvents.
|
|
113
124
|
* By returning false here when pointerEvents="none", we tell React Native's
|
|
@@ -139,7 +150,7 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
|
139
150
|
|
|
140
151
|
private fun updateConfig() {
|
|
141
152
|
val id = appId ?: return
|
|
142
|
-
|
|
153
|
+
|
|
143
154
|
config = PylonConfig.build(id) {
|
|
144
155
|
this.enableLogging = this@RNPylonChatView.enableLogging
|
|
145
156
|
this.primaryColor = this@RNPylonChatView.primaryColor
|
|
@@ -147,14 +158,14 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
|
147
158
|
this@RNPylonChatView.widgetBaseUrl?.let { this.widgetBaseUrl = it }
|
|
148
159
|
this@RNPylonChatView.widgetScriptUrl?.let { this.widgetScriptUrl = it }
|
|
149
160
|
}
|
|
150
|
-
|
|
161
|
+
|
|
151
162
|
recreatePylonView()
|
|
152
163
|
}
|
|
153
|
-
|
|
164
|
+
|
|
154
165
|
private fun updateUser() {
|
|
155
166
|
val email = userEmail ?: return
|
|
156
167
|
val name = userName ?: return
|
|
157
|
-
|
|
168
|
+
|
|
158
169
|
user = PylonUser(
|
|
159
170
|
email = email,
|
|
160
171
|
name = name,
|
|
@@ -163,48 +174,48 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
|
163
174
|
accountId = userAccountId,
|
|
164
175
|
accountExternalId = userAccountExternalId
|
|
165
176
|
)
|
|
166
|
-
|
|
177
|
+
|
|
167
178
|
recreatePylonView()
|
|
168
179
|
}
|
|
169
|
-
|
|
180
|
+
|
|
170
181
|
private fun recreatePylonView() {
|
|
171
182
|
val cfg = config ?: return
|
|
172
183
|
val usr = user ?: return
|
|
173
|
-
|
|
184
|
+
|
|
174
185
|
// Remove old view
|
|
175
186
|
pylonChatView?.let { removeView(it) }
|
|
176
|
-
|
|
187
|
+
|
|
177
188
|
// Create new PylonChatView
|
|
178
189
|
val newView = PylonChatView(context, cfg, usr)
|
|
179
190
|
newView.setListener(object : PylonChatListener {
|
|
180
191
|
override fun onPylonLoaded() {
|
|
181
192
|
sendEvent("onPylonLoaded", Arguments.createMap())
|
|
182
193
|
}
|
|
183
|
-
|
|
194
|
+
|
|
184
195
|
override fun onPylonInitialized() {
|
|
185
196
|
sendEvent("onPylonInitialized", Arguments.createMap())
|
|
186
197
|
}
|
|
187
|
-
|
|
198
|
+
|
|
188
199
|
override fun onPylonReady() {
|
|
189
200
|
sendEvent("onPylonReady", Arguments.createMap())
|
|
190
201
|
}
|
|
191
|
-
|
|
202
|
+
|
|
192
203
|
override fun onMessageReceived(message: String) {
|
|
193
204
|
val params = Arguments.createMap()
|
|
194
205
|
params.putString("message", message)
|
|
195
206
|
sendEvent("onMessageReceived", params)
|
|
196
207
|
}
|
|
197
|
-
|
|
208
|
+
|
|
198
209
|
override fun onChatOpened() {
|
|
199
210
|
sendEvent("onChatOpened", Arguments.createMap())
|
|
200
211
|
}
|
|
201
|
-
|
|
212
|
+
|
|
202
213
|
override fun onChatClosed() {
|
|
203
214
|
val params = Arguments.createMap()
|
|
204
215
|
params.putBoolean("wasOpen", true)
|
|
205
216
|
sendEvent("onChatClosed", params)
|
|
206
217
|
}
|
|
207
|
-
|
|
218
|
+
|
|
208
219
|
override fun onInteractiveBoundsChanged(selector: String, left: Float, top: Float, right: Float, bottom: Float) {
|
|
209
220
|
// Convert pixels to density-independent pixels (dp) for React Native.
|
|
210
221
|
val density = resources.displayMetrics.density
|
|
@@ -216,57 +227,57 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
|
216
227
|
params.putDouble("bottom", (bottom / density).toDouble())
|
|
217
228
|
sendEvent("onInteractiveBoundsChanged", params)
|
|
218
229
|
}
|
|
219
|
-
|
|
230
|
+
|
|
220
231
|
override fun onPylonError(error: String) {
|
|
221
232
|
val params = Arguments.createMap()
|
|
222
233
|
params.putString("error", error)
|
|
223
234
|
sendEvent("onPylonError", params)
|
|
224
235
|
}
|
|
225
|
-
|
|
236
|
+
|
|
226
237
|
override fun onUnreadCountChanged(count: Int) {
|
|
227
238
|
val params = Arguments.createMap()
|
|
228
239
|
params.putInt("count", count)
|
|
229
240
|
sendEvent("onUnreadCountChanged", params)
|
|
230
241
|
}
|
|
231
|
-
|
|
242
|
+
|
|
232
243
|
override fun onFileChooserLaunched(requestCode: Int) {
|
|
233
244
|
// Handle file chooser if needed
|
|
234
245
|
}
|
|
235
246
|
})
|
|
236
|
-
|
|
247
|
+
|
|
237
248
|
newView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
238
249
|
addView(newView)
|
|
239
250
|
pylonChatView = newView
|
|
240
251
|
}
|
|
241
|
-
|
|
252
|
+
|
|
242
253
|
private fun sendEvent(eventName: String, params: WritableMap) {
|
|
243
254
|
val reactContext = context as ReactContext
|
|
244
255
|
reactContext
|
|
245
256
|
.getJSModule(RCTEventEmitter::class.java)
|
|
246
257
|
.receiveEvent(id, eventName, params)
|
|
247
258
|
}
|
|
248
|
-
|
|
259
|
+
|
|
249
260
|
// Imperative methods
|
|
250
261
|
fun openChat() {
|
|
251
262
|
pylonChatView?.openChat()
|
|
252
263
|
}
|
|
253
|
-
|
|
264
|
+
|
|
254
265
|
fun closeChat() {
|
|
255
266
|
pylonChatView?.closeChat()
|
|
256
267
|
}
|
|
257
|
-
|
|
268
|
+
|
|
258
269
|
fun showChatBubble() {
|
|
259
270
|
pylonChatView?.showChatBubble()
|
|
260
271
|
}
|
|
261
|
-
|
|
272
|
+
|
|
262
273
|
fun hideChatBubble() {
|
|
263
274
|
pylonChatView?.hideChatBubble()
|
|
264
275
|
}
|
|
265
|
-
|
|
276
|
+
|
|
266
277
|
fun showNewMessage(message: String, isHtml: Boolean) {
|
|
267
278
|
pylonChatView?.showNewMessage(message, isHtml)
|
|
268
279
|
}
|
|
269
|
-
|
|
280
|
+
|
|
270
281
|
fun setNewIssueCustomFields(fields: Map<String, Any?>) {
|
|
271
282
|
@Suppress("UNCHECKED_CAST")
|
|
272
283
|
pylonChatView?.setNewIssueCustomFields(fields as Map<String, Any>)
|
|
@@ -276,19 +287,19 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
|
|
|
276
287
|
@Suppress("UNCHECKED_CAST")
|
|
277
288
|
pylonChatView?.setTicketFormFields(fields as Map<String, Any>)
|
|
278
289
|
}
|
|
279
|
-
|
|
290
|
+
|
|
280
291
|
fun updateEmailHash(emailHash: String?) {
|
|
281
292
|
pylonChatView?.setEmailHash(emailHash)
|
|
282
293
|
}
|
|
283
|
-
|
|
294
|
+
|
|
284
295
|
fun showTicketForm(slug: String) {
|
|
285
296
|
pylonChatView?.showTicketForm(slug)
|
|
286
297
|
}
|
|
287
|
-
|
|
298
|
+
|
|
288
299
|
fun showKnowledgeBaseArticle(articleId: String) {
|
|
289
300
|
pylonChatView?.showKnowledgeBaseArticle(articleId)
|
|
290
301
|
}
|
|
291
|
-
|
|
302
|
+
|
|
292
303
|
fun clickElementAtSelector(selector: String) {
|
|
293
304
|
// Trigger a click on the element with the given ID selector.
|
|
294
305
|
// This is used for Android's proxy-based touch pass-through system.
|
|
@@ -15,7 +15,7 @@ import com.pylon.chatwidget.PylonConfig
|
|
|
15
15
|
import com.pylon.chatwidget.PylonUser
|
|
16
16
|
|
|
17
17
|
class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
companion object {
|
|
20
20
|
const val REACT_CLASS = "RNPylonChatView"
|
|
21
21
|
const val COMMAND_OPEN_CHAT = 1
|
|
@@ -67,7 +67,7 @@ class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
|
|
|
67
67
|
fun setPointerEvents(view: RNPylonChatView, pointerEvents: String?) {
|
|
68
68
|
val mode = pointerEvents ?: "auto"
|
|
69
69
|
view.setPointerEventsMode(mode)
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
when (mode) {
|
|
72
72
|
"none" -> {
|
|
73
73
|
// Don't handle any touches - let them pass through
|
|
@@ -128,6 +128,12 @@ class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
|
|
|
128
128
|
view.userAccountExternalId = id
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// Coordinate space adjustment
|
|
132
|
+
@ReactProp(name = "topInset", defaultFloat = 0f)
|
|
133
|
+
fun setTopInset(view: RNPylonChatView, inset: Float) {
|
|
134
|
+
view.topInset = inset
|
|
135
|
+
}
|
|
136
|
+
|
|
131
137
|
// Event names
|
|
132
138
|
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
133
139
|
return MapBuilder.builder<String, Any>()
|