@zelloptt/react-native-zello-sdk 0.1.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 (84) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +21 -0
  3. package/android/build.gradle +122 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/AndroidManifestNew.xml +2 -0
  7. package/android/src/main/java/com/zellosdk/DummyPackage.kt +18 -0
  8. package/android/src/main/java/com/zellosdk/ZelloAndroidSdkModule.kt +437 -0
  9. package/android/src/main/java/com/zellosdk/ZelloAndroidSdkModuleHelper.kt +198 -0
  10. package/ios/Extensions/Date+Extension.swift +5 -0
  11. package/ios/Extensions/UIImage+Extension.swift +9 -0
  12. package/ios/Extensions/ZelloContact+Extension.swift +52 -0
  13. package/ios/Extensions/ZelloHistoryAlertMessage+Extension.swift +18 -0
  14. package/ios/Extensions/ZelloHistoryImageMessage+Extension.swift +17 -0
  15. package/ios/Extensions/ZelloHistoryLocationMessage+Extension.swift +23 -0
  16. package/ios/Extensions/ZelloHistoryTextMessage+Extension.swift +18 -0
  17. package/ios/Extensions/ZelloHistoryVoiceMessage+Extension.swift +18 -0
  18. package/ios/Extensions/ZelloIOSSdkModule+Extension.swift +285 -0
  19. package/ios/Extensions/ZelloIncomingEmergency+Extension.swift +16 -0
  20. package/ios/Extensions/ZelloOutgoingEmergency+Extension.swift +14 -0
  21. package/ios/Extensions/ZelloRecentEntry+Extension.swift +16 -0
  22. package/ios/ZelloIOSSdkModule.swift +209 -0
  23. package/ios/ZelloIOSSdkModuleBridge.h +5 -0
  24. package/ios/ZelloIOSSdkModuleBridge.m +44 -0
  25. package/lib/commonjs/events/index.js +43 -0
  26. package/lib/commonjs/events/index.js.map +1 -0
  27. package/lib/commonjs/index.js +47 -0
  28. package/lib/commonjs/index.js.map +1 -0
  29. package/lib/commonjs/package.json +1 -0
  30. package/lib/commonjs/sdk/index.js +833 -0
  31. package/lib/commonjs/sdk/index.js.map +1 -0
  32. package/lib/commonjs/types/index.js +518 -0
  33. package/lib/commonjs/types/index.js.map +1 -0
  34. package/lib/commonjs/utils/algorithms/index.js +79 -0
  35. package/lib/commonjs/utils/algorithms/index.js.map +1 -0
  36. package/lib/commonjs/utils/index.js +60 -0
  37. package/lib/commonjs/utils/index.js.map +1 -0
  38. package/lib/module/events/index.js +39 -0
  39. package/lib/module/events/index.js.map +1 -0
  40. package/lib/module/index.js +10 -0
  41. package/lib/module/index.js.map +1 -0
  42. package/lib/module/package.json +1 -0
  43. package/lib/module/sdk/index.js +829 -0
  44. package/lib/module/sdk/index.js.map +1 -0
  45. package/lib/module/types/index.js +547 -0
  46. package/lib/module/types/index.js.map +1 -0
  47. package/lib/module/utils/algorithms/index.js +72 -0
  48. package/lib/module/utils/algorithms/index.js.map +1 -0
  49. package/lib/module/utils/index.js +52 -0
  50. package/lib/module/utils/index.js.map +1 -0
  51. package/lib/typescript/commonjs/package.json +1 -0
  52. package/lib/typescript/commonjs/src/events/index.d.ts +192 -0
  53. package/lib/typescript/commonjs/src/events/index.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  55. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  56. package/lib/typescript/commonjs/src/sdk/index.d.ts +221 -0
  57. package/lib/typescript/commonjs/src/sdk/index.d.ts.map +1 -0
  58. package/lib/typescript/commonjs/src/types/index.d.ts +560 -0
  59. package/lib/typescript/commonjs/src/types/index.d.ts.map +1 -0
  60. package/lib/typescript/commonjs/src/utils/algorithms/index.d.ts +21 -0
  61. package/lib/typescript/commonjs/src/utils/algorithms/index.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/src/utils/index.d.ts +8 -0
  63. package/lib/typescript/commonjs/src/utils/index.d.ts.map +1 -0
  64. package/lib/typescript/module/package.json +1 -0
  65. package/lib/typescript/module/src/events/index.d.ts +192 -0
  66. package/lib/typescript/module/src/events/index.d.ts.map +1 -0
  67. package/lib/typescript/module/src/index.d.ts +6 -0
  68. package/lib/typescript/module/src/index.d.ts.map +1 -0
  69. package/lib/typescript/module/src/sdk/index.d.ts +221 -0
  70. package/lib/typescript/module/src/sdk/index.d.ts.map +1 -0
  71. package/lib/typescript/module/src/types/index.d.ts +560 -0
  72. package/lib/typescript/module/src/types/index.d.ts.map +1 -0
  73. package/lib/typescript/module/src/utils/algorithms/index.d.ts +21 -0
  74. package/lib/typescript/module/src/utils/algorithms/index.d.ts.map +1 -0
  75. package/lib/typescript/module/src/utils/index.d.ts +8 -0
  76. package/lib/typescript/module/src/utils/index.d.ts.map +1 -0
  77. package/package.json +195 -0
  78. package/react-native-zello-sdk.podspec +43 -0
  79. package/src/events/index.ts +191 -0
  80. package/src/index.ts +8 -0
  81. package/src/sdk/index.ts +1038 -0
  82. package/src/types/index.ts +818 -0
  83. package/src/utils/algorithms/index.ts +88 -0
  84. package/src/utils/index.ts +145 -0
@@ -0,0 +1,1038 @@
1
+ import {
2
+ EmitterSubscription,
3
+ NativeEventEmitter,
4
+ NativeModules,
5
+ } from 'react-native';
6
+ import { isAndroid } from '../utils';
7
+ import {
8
+ ZelloAccountStatus,
9
+ ZelloAlertMessage,
10
+ ZelloChannel,
11
+ ZelloChannelAlertLevel,
12
+ ZelloChannelUser,
13
+ ZelloConfig,
14
+ ZelloConnectionError,
15
+ ZelloConnectionState,
16
+ ZelloContact,
17
+ ZelloContactType,
18
+ ZelloCredentials,
19
+ ZelloHistoryImageMessage,
20
+ ZelloHistoryMessage,
21
+ ZelloHistoryVoiceMessage,
22
+ ZelloImageMessage,
23
+ ZelloIncomingEmergency,
24
+ ZelloIncomingVoiceMessage,
25
+ ZelloLocationMessage,
26
+ ZelloOutgoingEmergency,
27
+ ZelloOutgoingVoiceMessage,
28
+ ZelloOutgoingVoiceMessageError,
29
+ ZelloOutgoingVoiceMessageState,
30
+ ZelloRecentEntry,
31
+ ZelloTextMessage,
32
+ ZelloUser,
33
+ } from '../types';
34
+ import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';
35
+ import { compareNameAscending, sortedArrayFind } from '../utils/algorithms';
36
+ import {
37
+ bridgeContactToSdkContact,
38
+ bridgeHistoryMessageToSdkHistoryMessage,
39
+ bridgeIncomingEmergencyToSdkIncomingEmergency,
40
+ } from '../utils';
41
+ import { ZelloEvent } from '../events';
42
+
43
+ const { ZelloAndroidSdkModule, ZelloIOSSdkModule } = NativeModules;
44
+
45
+ /**
46
+ * Zello SDK.
47
+ * This class is a singleton, and can be accessed via {@link Zello.getInstance}.
48
+ */
49
+ export class Zello extends EventEmitter {
50
+ private static instance: Zello;
51
+
52
+ public static getInstance(): Zello {
53
+ if (!Zello.instance) {
54
+ Zello.instance = new Zello();
55
+ }
56
+ return Zello.instance;
57
+ }
58
+
59
+ /**
60
+ * The current connection state of the SDK.
61
+ */
62
+ public state: ZelloConnectionState = ZelloConnectionState.Disconnected;
63
+
64
+ /**
65
+ * The currently selected contact.
66
+ */
67
+ public selectedContact: ZelloContact | undefined;
68
+
69
+ /**
70
+ * The list of {@link ZelloUser} in the contact list. Sorted by name, ascending.
71
+ */
72
+ public users: ZelloUser[] = [];
73
+ /**
74
+ * The list of {@link ZelloChannel} in the contact list. Sorted by name, ascending.
75
+ */
76
+ public channels: ZelloChannel[] = [];
77
+
78
+ /**
79
+ * The current account status. undefined when {@link state} is not {@link ZelloConnectionState.Connected}.
80
+ */
81
+ public accountStatus: ZelloAccountStatus | undefined;
82
+
83
+ /**
84
+ * The current incoming voice message.
85
+ */
86
+ public incomingVoiceMessage: ZelloIncomingVoiceMessage | undefined;
87
+ /**
88
+ * The current outgoing voice message.
89
+ */
90
+ public outgoingVoiceMessage: ZelloOutgoingVoiceMessage | undefined;
91
+
92
+ /**
93
+ * The configured emergency channel.
94
+ */
95
+ public emergencyChannel: ZelloChannel | undefined;
96
+ /**
97
+ * The list of incoming emergencies. There can be multiple emergencies on the emergency channel at once.
98
+ * Sorted by start timestamp, ascending.
99
+ */
100
+ public incomingEmergencies: ZelloIncomingEmergency[] = [];
101
+ /**
102
+ * The current outgoing emergency.
103
+ */
104
+ public outgoingEmergency: ZelloOutgoingEmergency | undefined;
105
+
106
+ /**
107
+ * The list of recent entries. Sorted by timestamp, descending.
108
+ */
109
+ public recents: ZelloRecentEntry[] = [];
110
+
111
+ /**
112
+ * The currently playing history voice message.
113
+ */
114
+ public historyVoiceMessage: ZelloHistoryVoiceMessage | undefined;
115
+
116
+ private eventListener: EmitterSubscription | undefined;
117
+
118
+ private constructor() {
119
+ super();
120
+ const sdk = Zello.getSdk();
121
+ if (sdk) {
122
+ let eventEmitter: NativeEventEmitter;
123
+ if (isAndroid) {
124
+ eventEmitter = new NativeEventEmitter();
125
+ } else {
126
+ eventEmitter = new NativeEventEmitter(sdk);
127
+ }
128
+ this.setupEventListener(eventEmitter);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Sets configuration variables for the SDK.
134
+ *
135
+ * At the moment, this is only functional on Android.
136
+ *
137
+ * @param config The configuration to set.
138
+ */
139
+ public configure(config: ZelloConfig) {
140
+ if (isAndroid) {
141
+ ZelloAndroidSdkModule.configure(
142
+ config.android.enableOfflineMessagePushNotifications,
143
+ config.android.enableForegroundService
144
+ );
145
+ } else {
146
+ ZelloIOSSdkModule.configure(config.ios.isDebugBuild);
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Destroys the SDK instance and cleans up resources.
152
+ * Call this when you are done using the SDK instance for good (application quit).
153
+ */
154
+ public destroy() {
155
+ this.removeAllListeners();
156
+ this.eventListener?.remove();
157
+ }
158
+
159
+ /**
160
+ * Signs into to the Zello Work network using the provided credentials.
161
+ * This will typically trigger the {@link ZelloEvent.CONNECT_STARTED} event, followed by either {@link ZelloEvent.CONNECT_SUCCEEDED} or {@link ZelloEvent.CONNECT_FAILED}.
162
+ * However, if the state is incorrect, {@link ZelloEvent.CONNECT_FAILED} will be triggered immediately.
163
+ * @param credentials The credentials to use for signing in.
164
+ */
165
+ public connect(credentials: ZelloCredentials) {
166
+ if (isAndroid) {
167
+ ZelloAndroidSdkModule.connect(
168
+ credentials.network,
169
+ credentials.username,
170
+ credentials.password
171
+ );
172
+ } else {
173
+ ZelloIOSSdkModule.connect(
174
+ credentials.network,
175
+ credentials.username,
176
+ credentials.password
177
+ );
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Signs out of the Zello Work network.
183
+ * This will trigger the {@link ZelloEvent.DISCONNECTED} event.
184
+ */
185
+ public disconnect() {
186
+ if (isAndroid) {
187
+ ZelloAndroidSdkModule.disconnect();
188
+ } else {
189
+ ZelloIOSSdkModule.disconnect();
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Returns the user with the given name. Case-insensitive.
195
+ * @param name The name of the user to search for.
196
+ * @return The user with the given name, or null if no user with that name exists.
197
+ */
198
+ public getUser(name: string): ZelloUser | undefined {
199
+ return sortedArrayFind(this.users, name, compareNameAscending);
200
+ }
201
+
202
+ /**
203
+ * Returns the channel with the given name. Case-insensitive.
204
+ * @param name The name of the channel to search for.
205
+ * @return The channel with the given name, or null if no channel with that name exists.
206
+ */
207
+ public getChannel(name: string): ZelloChannel | undefined {
208
+ return sortedArrayFind(this.channels, name, compareNameAscending);
209
+ }
210
+
211
+ /**
212
+ * Sets the selected contact.
213
+ * While optional, this is typically used for tracking the contact that the user is currently interacting with.
214
+ * This will trigger the {@link ZelloEvent.SELECTED_CONTACT_CHANGED} event.
215
+ * @param contact The contact to set as selected.
216
+ */
217
+ public setSelectedContact(contact: ZelloContact) {
218
+ const isChannel = contact.type === ZelloContactType.Channel;
219
+ if (isAndroid) {
220
+ ZelloAndroidSdkModule.setSelectedContact(contact.name, isChannel);
221
+ } else {
222
+ ZelloIOSSdkModule.selectContact(contact.name, isChannel);
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Sets the user's online account status.
228
+ * This will trigger the {@link ZelloEvent.ACCOUNT_STATUS_CHANGED} event.
229
+ * @param status The account status to set.
230
+ */
231
+ public setAccountStatus(status: ZelloAccountStatus) {
232
+ if (isAndroid) {
233
+ ZelloAndroidSdkModule.setAccountStatus(status);
234
+ } else {
235
+ ZelloIOSSdkModule.setAccountStatus(status);
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Connects to the given channel.
241
+ * Once connected, the user will be able to send and receive messages from the channel.
242
+ * This will trigger the {@link ZelloEvent.CONTACT_LIST_UPDATED} event.
243
+ * @param channel The channel to connect to.
244
+ */
245
+ public connectChannel(channel: ZelloChannel) {
246
+ if (isAndroid) {
247
+ ZelloAndroidSdkModule.connectChannel(channel.name);
248
+ } else {
249
+ ZelloIOSSdkModule.connectChannel(channel.name);
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Disconnects from the given channel.
255
+ * Once disconnected, the user will no longer be able to send or receive messages from the channel.
256
+ * This will trigger the {@link ZelloEvent.CONTACT_LIST_UPDATED} event.
257
+ * @param channel The channel to disconnect from.
258
+ */
259
+ public disconnectChannel(channel: ZelloChannel) {
260
+ if (isAndroid) {
261
+ ZelloAndroidSdkModule.disconnectChannel(channel.name);
262
+ } else {
263
+ ZelloIOSSdkModule.disconnectChannel(channel.name);
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Starts a voice message with the given contact.
269
+ * This will trigger the {@link ZelloEvent.OUTGOING_VOICE_MESSAGE_CONNECTING} event, followed by the {@link ZelloEvent.OUTGOING_VOICE_MESSAGE_STARTED} event.
270
+ * If there is an error, the {@link ZelloEvent.OUTGOING_VOICE_MESSAGE_STOPPED} event will be triggered.
271
+ * @param contact The contact to start the voice message with.
272
+ */
273
+ public startVoiceMessage(contact: ZelloContact) {
274
+ const isChannel = contact.type === ZelloContactType.Channel;
275
+ if (isAndroid) {
276
+ ZelloAndroidSdkModule.startVoiceMessage(contact.name, isChannel);
277
+ } else {
278
+ ZelloIOSSdkModule.startVoiceMessage(contact.name, isChannel);
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Stops the current outgoing voice message.
284
+ * This will trigger the {@link ZelloEvent.OUTGOING_VOICE_MESSAGE_STOPPED} event.
285
+ */
286
+ public stopVoiceMessage() {
287
+ if (isAndroid) {
288
+ ZelloAndroidSdkModule.stopVoiceMessage();
289
+ } else {
290
+ ZelloIOSSdkModule.stopVoiceMessage();
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Sends the image message data to the given contact.
296
+ * This will trigger the {@link ZelloEvent.OUTGOING_IMAGE_MESSAGE_SENT} or {@link ZelloEvent.OUTGOING_IMAGE_MESSAGE_SEND_FAILED} event.
297
+ * @param contact The contact to send the image to.
298
+ * @param data The image data to send.
299
+ */
300
+ public sendImage(contact: ZelloContact, data: number[]) {
301
+ const isChannel = contact.type === ZelloContactType.Channel;
302
+ if (isAndroid) {
303
+ ZelloAndroidSdkModule.sendImage(contact.name, isChannel, data);
304
+ } else {
305
+ ZelloIOSSdkModule.sendImage(contact.name, isChannel, data);
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Sends the alert message to the given contact.
311
+ * This will trigger the {@link ZelloEvent.OUTGOING_ALERT_MESSAGE_SENT} or {@link ZelloEvent.OUTGOING_ALERT_MESSAGE_SEND_FAILED} event.
312
+ * @param contact The contact to send the alert to.
313
+ */
314
+ public sendLocation(contact: ZelloContact) {
315
+ const isChannel = contact.type === ZelloContactType.Channel;
316
+ if (isAndroid) {
317
+ ZelloAndroidSdkModule.sendLocation(contact.name, isChannel);
318
+ } else {
319
+ ZelloIOSSdkModule.sendLocation(contact.name, isChannel);
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Sends the text message to the given contact.
325
+ * This will trigger the {@link ZelloEvent.OUTGOING_TEXT_MESSAGE_SENT} or {@link ZelloEvent.OUTGOING_TEXT_MESSAGE_SEND_FAILED} event.
326
+ * @param contact The contact to send the text to.
327
+ * @param text The text to send.
328
+ */
329
+ public sendText(contact: ZelloContact, text: string) {
330
+ const isChannel = contact.type === ZelloContactType.Channel;
331
+ if (isAndroid) {
332
+ ZelloAndroidSdkModule.sendText(contact.name, isChannel, text);
333
+ } else {
334
+ ZelloIOSSdkModule.sendText(contact.name, isChannel, text);
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Sends the alert message to the given contact.
340
+ * This will trigger the {@link ZelloEvent.OUTGOING_ALERT_MESSAGE_SENT} or {@link ZelloEvent.OUTGOING_ALERT_MESSAGE_SEND_FAILED} event.
341
+ * @param contact The contact to send the alert to.
342
+ * @param text The text to send.
343
+ * @param level Optional; The alert level to send. Only applicable for channels.
344
+ */
345
+ public sendAlert(
346
+ contact: ZelloContact,
347
+ text: string,
348
+ level?: ZelloChannelAlertLevel
349
+ ) {
350
+ const isChannel = contact.type === ZelloContactType.Channel;
351
+ if (isAndroid) {
352
+ ZelloAndroidSdkModule.sendAlert(contact.name, isChannel, text, level);
353
+ } else {
354
+ ZelloIOSSdkModule.sendAlert(contact.name, isChannel, text, level);
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Submits a problem report to Zello.
360
+ * Additionally, please contact us to provide more information on what happened.
361
+ */
362
+ public submitProblemReport() {
363
+ if (isAndroid) {
364
+ ZelloAndroidSdkModule.submitProblemReport();
365
+ } else {
366
+ ZelloIOSSdkModule.submitProblemReport();
367
+ }
368
+ }
369
+
370
+ /**
371
+ * Mutes the given contact. When muted, incoming messages from this contact will not play live, but will still appear in the history.
372
+ * This will trigger the {@link ZelloEvent.CONTACT_LIST_UPDATED} event.
373
+ * @param contact The contact to mute.
374
+ */
375
+ public muteContact(contact: ZelloContact) {
376
+ const isChannel = contact.type === ZelloContactType.Channel;
377
+ if (isAndroid) {
378
+ ZelloAndroidSdkModule.muteContact(contact.name, isChannel);
379
+ } else {
380
+ ZelloIOSSdkModule.muteContact(contact.name, isChannel);
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Unmutes a previously muted contact. When unmuted, incoming messages from this contact will play live.
386
+ * This will trigger the {@link ZelloEvent.CONTACT_LIST_UPDATED} event.
387
+ * @param contact The contact to unmute.
388
+ */
389
+ public unmuteContact(contact: ZelloContact) {
390
+ const isChannel = contact.type === ZelloContactType.Channel;
391
+ if (isAndroid) {
392
+ ZelloAndroidSdkModule.unmuteContact(contact.name, isChannel);
393
+ } else {
394
+ ZelloIOSSdkModule.unmuteContact(contact.name, isChannel);
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Starts an outgoing emergency to the emergency channel.
400
+ * Upon starting, the user's location will be sent, an alert message will be sent, and a 10-second-long voice message will start recording.
401
+ * This will trigger the {@link ZelloEvent.OUTGOING_EMERGENCY_STARTED} event.
402
+ */
403
+ public startEmergency() {
404
+ if (isAndroid) {
405
+ ZelloAndroidSdkModule.startEmergency();
406
+ } else {
407
+ ZelloIOSSdkModule.startEmergency();
408
+ }
409
+ }
410
+
411
+ /**
412
+ * Stops the outgoing emergency.
413
+ * This will trigger the {@link ZelloEvent.OUTGOING_EMERGENCY_STOPPED} event.
414
+ */
415
+ public stopEmergency() {
416
+ if (isAndroid) {
417
+ ZelloAndroidSdkModule.stopEmergency();
418
+ } else {
419
+ ZelloIOSSdkModule.stopEmergency();
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Returns the history messages for the given contact.
425
+ * @param contact The contact to get the history for.
426
+ * @param size Optional; The number of history items to retrieve. Defaults to 50.
427
+ * @return The history items for the given contact.
428
+ */
429
+ public getHistory(
430
+ contact: ZelloContact,
431
+ size?: number
432
+ ): Promise<ZelloHistoryMessage[]> {
433
+ const defaultHistorySize = 50;
434
+ return new Promise((resolve) => {
435
+ const isChannel = contact.type === ZelloContactType.Channel;
436
+ const callback = (history: any[] | undefined) => {
437
+ if (!history) {
438
+ resolve([]);
439
+ return;
440
+ }
441
+ const messages = history
442
+ .map((message) => bridgeHistoryMessageToSdkHistoryMessage(message))
443
+ .filter((item) => item !== undefined) as ZelloHistoryMessage[];
444
+ resolve(messages);
445
+ };
446
+ if (isAndroid) {
447
+ ZelloAndroidSdkModule.getHistory(
448
+ contact.name,
449
+ isChannel,
450
+ size ?? defaultHistorySize,
451
+ callback
452
+ );
453
+ } else {
454
+ ZelloIOSSdkModule.getHistory(
455
+ contact.name,
456
+ isChannel,
457
+ size ?? defaultHistorySize,
458
+ callback
459
+ );
460
+ }
461
+ });
462
+ }
463
+
464
+ /**
465
+ * Plays the given history message.
466
+ * This will trigger the {@link ZelloEvent.HISTORY_PLAYBACK_STARTED} event.
467
+ * @param message The history message to play.
468
+ */
469
+ public playHistoryMessage(message: ZelloHistoryVoiceMessage) {
470
+ const isChannel = message.contact.type === ZelloContactType.Channel;
471
+ if (isAndroid) {
472
+ ZelloAndroidSdkModule.playHistoryMessage(
473
+ message.historyId,
474
+ message.contact.name,
475
+ isChannel
476
+ );
477
+ } else {
478
+ ZelloIOSSdkModule.playHistoryMessage(
479
+ message.historyId,
480
+ message.contact.name,
481
+ isChannel
482
+ );
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Stops the current history message playback.
488
+ * This will trigger the {@link ZelloEvent.HISTORY_PLAYBACK_STOPPED} event.
489
+ */
490
+ public stopHistoryMessagePlayback() {
491
+ if (isAndroid) {
492
+ ZelloAndroidSdkModule.stopHistoryMessagePlayback();
493
+ } else {
494
+ ZelloIOSSdkModule.stopHistoryMessagePlayback();
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Returns the image data for the given history image message.
500
+ * @param message The history image message to get the image data for.
501
+ * @return The image data for the given history image message.
502
+ */
503
+ public getImageDataForHistoryImageMessage(
504
+ message: ZelloHistoryImageMessage
505
+ ): Promise<string | undefined> {
506
+ return new Promise((resolve) => {
507
+ const isChannel = message.contact.type === ZelloContactType.Channel;
508
+ if (isAndroid) {
509
+ ZelloAndroidSdkModule.getImageDataForHistoryImageMessage(
510
+ message.historyId,
511
+ message.contact.name,
512
+ isChannel,
513
+ (data: string | undefined) => resolve(data)
514
+ );
515
+ } else {
516
+ ZelloIOSSdkModule.getHistoryImageData(
517
+ message.historyId,
518
+ message.contact.name,
519
+ isChannel,
520
+ (data: string | undefined) => resolve(data)
521
+ );
522
+ }
523
+ });
524
+ }
525
+
526
+ private setupEventListener(eventEmitter: NativeEventEmitter) {
527
+ this.eventListener = eventEmitter.addListener('zellosdk', (event) => {
528
+ const eventName = event.eventName;
529
+ switch (eventName) {
530
+ case 'onConnectFailed': {
531
+ this.state = ZelloConnectionState.Disconnected;
532
+ const error =
533
+ (event.error?.toLowerCase() as ZelloConnectionError) ??
534
+ ZelloConnectionError.Unknown;
535
+ this.emit(ZelloEvent.CONNECT_FAILED, this.state, error);
536
+ break;
537
+ }
538
+ case 'onConnectStarted': {
539
+ this.state = ZelloConnectionState.Connecting;
540
+ this.emit(ZelloEvent.CONNECT_STARTED, this.state);
541
+ break;
542
+ }
543
+ case 'onConnectSucceeded': {
544
+ this.state = ZelloConnectionState.Connected;
545
+ this.emit(ZelloEvent.CONNECT_SUCCEEDED, this.state);
546
+ break;
547
+ }
548
+ case 'onDisconnected': {
549
+ this.state = ZelloConnectionState.Disconnected;
550
+ this.emit(ZelloEvent.DISCONNECTED, this.state);
551
+ break;
552
+ }
553
+ case 'onWillReconnect': {
554
+ this.state = ZelloConnectionState.Reconnecting;
555
+ this.emit(ZelloEvent.RECONNECTING, this.state);
556
+ break;
557
+ }
558
+ case 'onContactListUpdated': {
559
+ this.clearContactList();
560
+
561
+ this.users = event.users.map((user: any) =>
562
+ bridgeContactToSdkContact(user)
563
+ );
564
+ this.users.sort(compareNameAscending);
565
+
566
+ this.channels = event.channels.map((channel: any) =>
567
+ bridgeContactToSdkContact(channel)
568
+ );
569
+ this.channels.sort(compareNameAscending);
570
+
571
+ if (event.emergencyChannel) {
572
+ this.emergencyChannel = bridgeContactToSdkContact(
573
+ event.emergencyChannel
574
+ ) as ZelloChannel;
575
+ }
576
+
577
+ this.emit(ZelloEvent.CONTACT_LIST_UPDATED, this.users, this.channels);
578
+ break;
579
+ }
580
+ case 'onSelectedContactChanged': {
581
+ this.selectedContact = event.contact
582
+ ? bridgeContactToSdkContact(event.contact)
583
+ : undefined;
584
+ this.emit(ZelloEvent.SELECTED_CONTACT_CHANGED, this.selectedContact);
585
+ break;
586
+ }
587
+ case 'onAccountStatusChanged': {
588
+ const statusValue = event.status?.toLowerCase() as ZelloAccountStatus;
589
+ if (
590
+ !statusValue ||
591
+ Object.values(ZelloAccountStatus).includes(statusValue)
592
+ ) {
593
+ this.accountStatus = statusValue;
594
+ this.emit(ZelloEvent.ACCOUNT_STATUS_CHANGED, this.accountStatus);
595
+ }
596
+ break;
597
+ }
598
+ case 'onIncomingVoiceMessageStarted': {
599
+ const contact = bridgeContactToSdkContact(event.contact);
600
+ if (!contact) {
601
+ break;
602
+ }
603
+ this.incomingVoiceMessage = new ZelloIncomingVoiceMessage(
604
+ contact,
605
+ new ZelloChannelUser(event.channelUserName),
606
+ parseInt(event.timestamp, 10)
607
+ );
608
+ this.emit(
609
+ ZelloEvent.INCOMING_VOICE_MESSAGE_STARTED,
610
+ this.incomingVoiceMessage
611
+ );
612
+ break;
613
+ }
614
+ case 'onIncomingVoiceMessageStopped': {
615
+ this.incomingVoiceMessage = undefined;
616
+ const contact = bridgeContactToSdkContact(event.contact);
617
+ if (!contact) {
618
+ break;
619
+ }
620
+ this.emit(
621
+ ZelloEvent.INCOMING_VOICE_MESSAGE_STOPPED,
622
+ new ZelloIncomingVoiceMessage(
623
+ contact,
624
+ new ZelloChannelUser(event.channelUserName),
625
+ parseInt(event.timestamp, 10)
626
+ )
627
+ );
628
+ break;
629
+ }
630
+ case 'onOutgoingVoiceMessageConnecting': {
631
+ const contact = bridgeContactToSdkContact(event.contact);
632
+ if (!contact) {
633
+ break;
634
+ }
635
+ this.outgoingVoiceMessage = new ZelloOutgoingVoiceMessage(
636
+ contact,
637
+ parseInt(event.timestamp, 10),
638
+ ZelloOutgoingVoiceMessageState.Connecting
639
+ );
640
+ this.emit(
641
+ ZelloEvent.OUTGOING_VOICE_MESSAGE_CONNECTING,
642
+ this.outgoingVoiceMessage
643
+ );
644
+ break;
645
+ }
646
+ case 'onOutgoingVoiceMessageStarted': {
647
+ const contact = bridgeContactToSdkContact(event.contact);
648
+ if (!contact) {
649
+ break;
650
+ }
651
+ this.outgoingVoiceMessage = new ZelloOutgoingVoiceMessage(
652
+ contact,
653
+ parseInt(event.timestamp, 10),
654
+ ZelloOutgoingVoiceMessageState.Sending
655
+ );
656
+ this.emit(
657
+ ZelloEvent.OUTGOING_VOICE_MESSAGE_STARTED,
658
+ this.outgoingVoiceMessage
659
+ );
660
+ break;
661
+ }
662
+ case 'onOutgoingVoiceMessageStopped': {
663
+ this.outgoingVoiceMessage = undefined;
664
+ const contact = bridgeContactToSdkContact(event.contact);
665
+ if (!contact) {
666
+ break;
667
+ }
668
+ const isError = event.error != null; // This checks for both null and undefined
669
+ let error: ZelloOutgoingVoiceMessageError | undefined;
670
+ if (isError) {
671
+ error =
672
+ (event.error?.toLowerCase() as ZelloOutgoingVoiceMessageError) ??
673
+ ZelloOutgoingVoiceMessageError.Unknown;
674
+ }
675
+ this.emit(
676
+ ZelloEvent.OUTGOING_VOICE_MESSAGE_STOPPED,
677
+ new ZelloOutgoingVoiceMessage(
678
+ contact,
679
+ parseInt(event.timestamp, 10),
680
+ isError
681
+ ? ZelloOutgoingVoiceMessageState.Failed
682
+ : ZelloOutgoingVoiceMessageState.Sent
683
+ ),
684
+ error
685
+ );
686
+ break;
687
+ }
688
+ case 'onIncomingImageMessage': {
689
+ const contact = bridgeContactToSdkContact(event.contact);
690
+ if (!contact) {
691
+ break;
692
+ }
693
+ this.emit(
694
+ ZelloEvent.INCOMING_IMAGE_MESSAGE_RECEIVED,
695
+ new ZelloImageMessage(
696
+ contact,
697
+ new ZelloChannelUser(event.channelUserName),
698
+ true,
699
+ parseInt(event.timestamp, 10),
700
+ event.thumbnail,
701
+ event.image
702
+ )
703
+ );
704
+ break;
705
+ }
706
+ case 'onOutgoingImageMessageSent': {
707
+ const contact = bridgeContactToSdkContact(event.contact);
708
+ if (!contact) {
709
+ break;
710
+ }
711
+ this.emit(
712
+ ZelloEvent.OUTGOING_IMAGE_MESSAGE_SENT,
713
+ new ZelloImageMessage(
714
+ contact,
715
+ undefined,
716
+ false,
717
+ parseInt(event.timestamp, 10),
718
+ event.thumbnail,
719
+ event.image
720
+ )
721
+ );
722
+ break;
723
+ }
724
+ case 'onOutgoingImageMessageSendFailed': {
725
+ const contact = bridgeContactToSdkContact(event.contact);
726
+ if (!contact) {
727
+ break;
728
+ }
729
+ this.emit(
730
+ ZelloEvent.OUTGOING_IMAGE_MESSAGE_SEND_FAILED,
731
+ new ZelloImageMessage(
732
+ contact,
733
+ undefined,
734
+ false,
735
+ parseInt(event.timestamp, 10),
736
+ event.thumbnail,
737
+ event.image
738
+ )
739
+ );
740
+ break;
741
+ }
742
+ case 'onIncomingAlertMessage': {
743
+ const contact = bridgeContactToSdkContact(event.contact);
744
+ if (!contact) {
745
+ break;
746
+ }
747
+ this.emit(
748
+ ZelloEvent.INCOMING_ALERT_MESSAGE_RECEIVED,
749
+ new ZelloAlertMessage(
750
+ contact,
751
+ new ZelloChannelUser(event.channelUserName),
752
+ true,
753
+ parseInt(event.timestamp, 10),
754
+ event.text
755
+ )
756
+ );
757
+ break;
758
+ }
759
+ case 'onOutgoingAlertMessageSent': {
760
+ const contact = bridgeContactToSdkContact(event.contact);
761
+ if (!contact) {
762
+ break;
763
+ }
764
+ this.emit(
765
+ ZelloEvent.OUTGOING_ALERT_MESSAGE_SENT,
766
+ new ZelloAlertMessage(
767
+ contact,
768
+ undefined,
769
+ false,
770
+ parseInt(event.timestamp, 10),
771
+ event.text
772
+ )
773
+ );
774
+ break;
775
+ }
776
+ case 'onOutgoingAlertMessageSendFailed': {
777
+ const contact = bridgeContactToSdkContact(event.contact);
778
+ if (!contact) {
779
+ break;
780
+ }
781
+ this.emit(
782
+ ZelloEvent.OUTGOING_ALERT_MESSAGE_SEND_FAILED,
783
+ new ZelloAlertMessage(
784
+ contact,
785
+ undefined,
786
+ false,
787
+ parseInt(event.timestamp, 10),
788
+ event.text
789
+ )
790
+ );
791
+ break;
792
+ }
793
+ case 'onIncomingTextMessage': {
794
+ const contact = bridgeContactToSdkContact(event.contact);
795
+ if (!contact) {
796
+ break;
797
+ }
798
+ this.emit(
799
+ ZelloEvent.INCOMING_TEXT_MESSAGE_RECEIVED,
800
+ new ZelloTextMessage(
801
+ contact,
802
+ new ZelloChannelUser(event.channelUserName),
803
+ true,
804
+ parseInt(event.timestamp, 10),
805
+ event.text
806
+ )
807
+ );
808
+ break;
809
+ }
810
+ case 'onOutgoingTextMessageSent': {
811
+ const contact = bridgeContactToSdkContact(event.contact);
812
+ if (!contact) {
813
+ break;
814
+ }
815
+ this.emit(
816
+ ZelloEvent.OUTGOING_TEXT_MESSAGE_SENT,
817
+ new ZelloTextMessage(
818
+ contact,
819
+ undefined,
820
+ false,
821
+ parseInt(event.timestamp, 10),
822
+ event.text
823
+ )
824
+ );
825
+ break;
826
+ }
827
+ case 'onOutgoingTextMessageSendFailed': {
828
+ const contact = bridgeContactToSdkContact(event.contact);
829
+ if (!contact) {
830
+ break;
831
+ }
832
+ this.emit(
833
+ ZelloEvent.OUTGOING_TEXT_MESSAGE_SEND_FAILED,
834
+ new ZelloTextMessage(
835
+ contact,
836
+ undefined,
837
+ false,
838
+ parseInt(event.timestamp, 10),
839
+ event.text
840
+ )
841
+ );
842
+ break;
843
+ }
844
+ case 'onIncomingLocationMessage': {
845
+ const contact = bridgeContactToSdkContact(event.contact);
846
+ if (!contact) {
847
+ break;
848
+ }
849
+ this.emit(
850
+ ZelloEvent.INCOMING_LOCATION_MESSAGE_RECEIVED,
851
+ new ZelloLocationMessage(
852
+ contact,
853
+ new ZelloChannelUser(event.channelUserName),
854
+ true,
855
+ parseInt(event.timestamp, 10),
856
+ event.latitude,
857
+ event.longitude,
858
+ event.accuracy,
859
+ event.address
860
+ ).contact
861
+ );
862
+ break;
863
+ }
864
+ case 'onOutgoingLocationMessageSent': {
865
+ const contact = bridgeContactToSdkContact(event.contact);
866
+ if (!contact) {
867
+ break;
868
+ }
869
+ this.emit(
870
+ ZelloEvent.OUTGOING_LOCATION_MESSAGE_SENT,
871
+ new ZelloLocationMessage(
872
+ contact,
873
+ undefined,
874
+ false,
875
+ parseInt(event.timestamp, 10),
876
+ event.latitude,
877
+ event.longitude,
878
+ event.accuracy,
879
+ event.address
880
+ )
881
+ );
882
+ break;
883
+ }
884
+ case 'onOutgoingLocationMessageSendFailed': {
885
+ const contact = bridgeContactToSdkContact(event.contact);
886
+ if (!contact) {
887
+ break;
888
+ }
889
+ this.emit(
890
+ ZelloEvent.OUTGOING_LOCATION_MESSAGE_SEND_FAILED,
891
+ new ZelloLocationMessage(
892
+ contact,
893
+ undefined,
894
+ false,
895
+ parseInt(event.timestamp, 10),
896
+ event.latitude,
897
+ event.longitude,
898
+ event.accuracy,
899
+ event.address
900
+ )
901
+ );
902
+ break;
903
+ }
904
+ case 'onIncomingEmergencyStarted': {
905
+ this.incomingEmergencies = [];
906
+ event.emergencies.forEach((emergency: any) => {
907
+ const incomingEmergency =
908
+ bridgeIncomingEmergencyToSdkIncomingEmergency(emergency);
909
+ if (incomingEmergency) {
910
+ this.incomingEmergencies.push(incomingEmergency);
911
+ }
912
+ });
913
+ this.incomingEmergencies.sort(
914
+ (a: ZelloIncomingEmergency, b: ZelloIncomingEmergency) =>
915
+ a.startTimestamp - b.startTimestamp
916
+ );
917
+ this.emit(
918
+ ZelloEvent.INCOMING_EMERGENCY_STARTED,
919
+ bridgeIncomingEmergencyToSdkIncomingEmergency(event.emergency),
920
+ this.incomingEmergencies
921
+ );
922
+ break;
923
+ }
924
+ case 'onIncomingEmergencyStopped': {
925
+ this.incomingEmergencies = [];
926
+ event.emergencies.forEach((emergency: any) => {
927
+ const incomingEmergency =
928
+ bridgeIncomingEmergencyToSdkIncomingEmergency(emergency);
929
+ if (incomingEmergency) {
930
+ this.incomingEmergencies.push(incomingEmergency);
931
+ }
932
+ });
933
+ this.emit(
934
+ ZelloEvent.INCOMING_EMERGENCY_STOPPED,
935
+ bridgeIncomingEmergencyToSdkIncomingEmergency(event.emergency)
936
+ );
937
+ break;
938
+ }
939
+ case 'onOutgoingEmergencyStarted': {
940
+ const channel = bridgeContactToSdkContact(
941
+ event.channel
942
+ ) as ZelloChannel;
943
+ if (!channel) {
944
+ break;
945
+ }
946
+ this.outgoingEmergency = new ZelloOutgoingEmergency(
947
+ channel,
948
+ parseInt(event.startTimestamp, 10),
949
+ undefined
950
+ );
951
+ this.emit(
952
+ ZelloEvent.OUTGOING_EMERGENCY_STARTED,
953
+ this.outgoingEmergency
954
+ );
955
+ break;
956
+ }
957
+ case 'onOutgoingEmergencyStopped': {
958
+ const channel = bridgeContactToSdkContact(
959
+ event.channel
960
+ ) as ZelloChannel;
961
+ if (!channel) {
962
+ break;
963
+ }
964
+ this.outgoingEmergency = undefined;
965
+ this.emit(
966
+ ZelloEvent.OUTGOING_EMERGENCY_STOPPED,
967
+ new ZelloOutgoingEmergency(
968
+ channel,
969
+ parseInt(event.startTimestamp, 10),
970
+ event.endTimestamp
971
+ )
972
+ );
973
+ break;
974
+ }
975
+ case 'onRecentsUpdated': {
976
+ this.recents = event.recents
977
+ .map((recent: any) => {
978
+ const contact = bridgeContactToSdkContact(recent.contact);
979
+ if (!contact) {
980
+ return undefined;
981
+ }
982
+ const channelUser = recent.channelUser
983
+ ? new ZelloChannelUser(recent.channelUser)
984
+ : undefined;
985
+ return new ZelloRecentEntry(
986
+ contact,
987
+ channelUser,
988
+ parseInt(recent.timestamp, 10),
989
+ recent.type.toLowerCase(),
990
+ recent.incoming
991
+ );
992
+ })
993
+ .filter(
994
+ (recent: ZelloRecentEntry | undefined) => recent !== undefined
995
+ );
996
+ this.emit(ZelloEvent.RECENTS_UPDATED, this.recents);
997
+ break;
998
+ }
999
+ case 'onHistoryUpdated': {
1000
+ this.emit(ZelloEvent.HISTORY_UPDATED);
1001
+ break;
1002
+ }
1003
+ case 'onHistoryPlaybackStarted': {
1004
+ this.historyVoiceMessage = bridgeHistoryMessageToSdkHistoryMessage(
1005
+ event
1006
+ ) as ZelloHistoryVoiceMessage;
1007
+ this.emit(
1008
+ ZelloEvent.HISTORY_PLAYBACK_STARTED,
1009
+ this.historyVoiceMessage
1010
+ );
1011
+ break;
1012
+ }
1013
+ case 'onHistoryPlaybackStopped': {
1014
+ this.historyVoiceMessage = undefined;
1015
+ this.emit(
1016
+ ZelloEvent.HISTORY_PLAYBACK_STOPPED,
1017
+ this.historyVoiceMessage
1018
+ );
1019
+ break;
1020
+ }
1021
+ default:
1022
+ break;
1023
+ }
1024
+ });
1025
+ }
1026
+
1027
+ private clearContactList() {
1028
+ this.users = [];
1029
+ this.channels = [];
1030
+ }
1031
+
1032
+ private static getSdk() {
1033
+ if (isAndroid) {
1034
+ return ZelloAndroidSdkModule;
1035
+ }
1036
+ return ZelloIOSSdkModule;
1037
+ }
1038
+ }