@stream-io/react-native-callingx 0.1.0-beta.4 → 0.1.0-beta.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.
Files changed (42) hide show
  1. package/README.md +0 -1
  2. package/android/build.gradle +9 -0
  3. package/android/src/main/java/io/getstream/rn/callingx/CallService.kt +69 -45
  4. package/android/src/main/java/io/getstream/rn/callingx/CallingxEventEmitterAdapter.kt +7 -0
  5. package/android/src/main/java/io/getstream/rn/callingx/{CallingxModule.kt → CallingxModuleImpl.kt} +194 -103
  6. package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt +9 -9
  7. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt +8 -8
  8. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt +7 -7
  9. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt +7 -7
  10. package/android/src/main/java/io/getstream/rn/callingx/repo/TelecomCallRepository.kt +3 -0
  11. package/android/src/newarch/java/io/getstream/rn/callingx/CallingxModule.kt +148 -0
  12. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxModule.kt +177 -0
  13. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxPackage.kt +16 -0
  14. package/dist/module/CallingxModule.js +2 -2
  15. package/dist/module/CallingxModule.js.map +1 -1
  16. package/dist/module/EventManager.js +11 -4
  17. package/dist/module/EventManager.js.map +1 -1
  18. package/dist/module/spec/NativeCallingx.js +4 -2
  19. package/dist/module/spec/NativeCallingx.js.map +1 -1
  20. package/dist/module/utils/utils.js +3 -0
  21. package/dist/module/utils/utils.js.map +1 -1
  22. package/dist/typescript/src/CallingxModule.d.ts +1 -1
  23. package/dist/typescript/src/CallingxModule.d.ts.map +1 -1
  24. package/dist/typescript/src/EventManager.d.ts.map +1 -1
  25. package/dist/typescript/src/spec/NativeCallingx.d.ts +3 -3
  26. package/dist/typescript/src/spec/NativeCallingx.d.ts.map +1 -1
  27. package/dist/typescript/src/types.d.ts +2 -2
  28. package/dist/typescript/src/types.d.ts.map +1 -1
  29. package/dist/typescript/src/utils/utils.d.ts +1 -0
  30. package/dist/typescript/src/utils/utils.d.ts.map +1 -1
  31. package/ios/Callingx.mm +326 -22
  32. package/ios/CallingxCall.swift +105 -0
  33. package/ios/CallingxImpl.swift +136 -70
  34. package/ios/CallingxPublic.h +2 -5
  35. package/ios/UUIDStorage.swift +71 -26
  36. package/package.json +3 -3
  37. package/src/CallingxModule.ts +2 -2
  38. package/src/EventManager.ts +18 -5
  39. package/src/spec/NativeCallingx.ts +12 -3
  40. package/src/types.ts +2 -2
  41. package/src/utils/utils.ts +3 -0
  42. /package/android/src/{main → newarch}/java/io/getstream/rn/callingx/CallingxPackage.kt +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,4EAK5C,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,GAAI,WAAW,MAAM,4EAK5C,CAAC;AAGF,eAAO,MAAM,oBAAoB,SAAgC,CAAC"}
package/ios/Callingx.mm CHANGED
@@ -1,8 +1,14 @@
1
+ #ifdef RCT_NEW_ARCH_ENABLED
1
2
  #import <CallingxSpec/CallingxSpec.h>
3
+ #endif
4
+
5
+ #import <React/RCTBridgeModule.h>
6
+ #import <React/RCTEventEmitter.h>
2
7
  #import <React/RCTBridge+Private.h>
3
8
 
4
9
  #import <AVFoundation/AVAudioSession.h>
5
10
  #import <CallKit/CallKit.h>
11
+ #import "WebRTCModule.h"
6
12
 
7
13
  // Import Swift generated header
8
14
  #if __has_include("Callingx-Swift.h")
@@ -11,9 +17,13 @@
11
17
  #import <Callingx/Callingx-Swift.h>
12
18
  #endif
13
19
 
14
- // MARK: - Callingx Turbo Module Interface
20
+ // MARK: - Callingx Interface
15
21
 
22
+ #ifdef RCT_NEW_ARCH_ENABLED
16
23
  @interface Callingx : NativeCallingxSpecBase<NativeCallingxSpec, CallingxEventEmitter, VoipNotificationsEventEmitter>
24
+ #else
25
+ @interface Callingx : RCTEventEmitter <RCTBridgeModule, CallingxEventEmitter, VoipNotificationsEventEmitter>
26
+ #endif
17
27
 
18
28
  @property (nonatomic, strong) CXCallController *callKeepCallController;
19
29
  @property (nonatomic, strong) CXProvider *callKeepProvider;
@@ -35,15 +45,21 @@
35
45
  return sharedInstance;
36
46
  }
37
47
 
38
- #pragma mark - Class Methods (Public API)
48
+ #pragma mark - Module Registration
39
49
 
40
50
  + (BOOL)requiresMainQueueSetup {
41
51
  return YES;
42
52
  }
43
53
 
54
+ #ifdef RCT_NEW_ARCH_ENABLED
44
55
  + (NSString *)moduleName {
45
56
  return @"Callingx";
46
57
  }
58
+ #else
59
+ RCT_EXPORT_MODULE(Callingx)
60
+ #endif
61
+
62
+ #pragma mark - Class Methods (Public API)
47
63
 
48
64
  + (void)reportNewIncomingCall:(NSString *)callId
49
65
  handle:(NSString *)handle
@@ -54,10 +70,9 @@
54
70
  supportsDTMF:(BOOL)supportsDTMF
55
71
  supportsGrouping:(BOOL)supportsGrouping
56
72
  supportsUngrouping:(BOOL)supportsUngrouping
57
- fromPushKit:(BOOL)fromPushKit
58
73
  payload:(NSDictionary *_Nullable)payload
59
74
  withCompletionHandler:(void (^_Nullable)(void))completion {
60
-
75
+
61
76
  [CallingxImpl reportNewIncomingCallWithCallId:callId
62
77
  handle:handle
63
78
  handleType:handleType
@@ -67,9 +82,11 @@
67
82
  supportsDTMF:supportsDTMF
68
83
  supportsGrouping:supportsGrouping
69
84
  supportsUngrouping:supportsUngrouping
70
- fromPushKit:fromPushKit
71
85
  payload:payload
72
- completion:completion];
86
+ completion:completion
87
+ resolve:nil
88
+ reject:nil
89
+ ];
73
90
  }
74
91
 
75
92
  + (BOOL)canRegisterCall {
@@ -96,23 +113,59 @@
96
113
  _moduleImpl = nil;
97
114
  }
98
115
 
116
+ #pragma mark - Old Arch Event Support
117
+
118
+ #ifndef RCT_NEW_ARCH_ENABLED
119
+ - (NSArray<NSString *> *)supportedEvents {
120
+ return @[@"onNewEvent", @"onNewVoipEvent"];
121
+ }
122
+ #endif
123
+
124
+ #pragma mark - Turbo Module (New Arch Only)
125
+
126
+ #ifdef RCT_NEW_ARCH_ENABLED
99
127
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
100
128
  (const facebook::react::ObjCTurboModule::InitParams &)params {
101
129
  return std::make_shared<facebook::react::NativeCallingxSpecJSI>(params);
102
130
  }
131
+ #endif
103
132
 
104
- #pragma mark - CallingxEventEmitter Protocol
133
+ #pragma mark - Event Emission
105
134
 
106
135
  - (void)emitEvent:(NSDictionary *)dictionary {
136
+ #ifdef RCT_NEW_ARCH_ENABLED
107
137
  [self emitOnNewEvent:dictionary];
138
+ #else
139
+ [self sendEventWithName:@"onNewEvent" body:dictionary];
140
+ #endif
108
141
  }
109
142
 
110
143
  - (void)emitVoipEvent:(NSDictionary *)dictionary {
144
+ #ifdef RCT_NEW_ARCH_ENABLED
111
145
  [self emitOnNewVoipEvent:dictionary];
146
+ #else
147
+ [self sendEventWithName:@"onNewVoipEvent" body:dictionary];
148
+ #endif
112
149
  }
113
150
 
114
- #pragma mark - Turbo Module Methods
151
+ #pragma mark - Internal Helpers
152
+
153
+ - (void)_setupiOSWithOptions:(NSDictionary *)optionsDict {
154
+ [_moduleImpl setupWithOptions:optionsDict];
115
155
 
156
+ // Inject WebRTCModule so CallingxImpl can access AudioDeviceModule.
157
+ // self.bridge is NOT available on TurboModules — use currentBridge instead,
158
+ // which returns the real RCTBridge or RCTBridgeProxy (bridgeless interop).
159
+ WebRTCModule *webrtcModule = [[RCTBridge currentBridge] moduleForName:@"WebRTCModule"];
160
+ _moduleImpl.webRTCModule = webrtcModule;
161
+
162
+ self.callKeepCallController = _moduleImpl.callKeepCallController;
163
+ self.callKeepProvider = _moduleImpl.callKeepProvider;
164
+ }
165
+
166
+ #pragma mark - setupiOS
167
+
168
+ #ifdef RCT_NEW_ARCH_ENABLED
116
169
  - (void)setupiOS:(JS::NativeCallingx::SpecSetupiOSOptions &)options {
117
170
  NSDictionary *optionsDict = @{
118
171
  @"supportsVideo" : @(options.supportsVideo()),
@@ -125,35 +178,106 @@
125
178
  @"displayCallTimeout" : @(options.displayCallTimeout())
126
179
  };
127
180
 
128
- [_moduleImpl setupWithOptions:optionsDict];
129
-
130
- self.callKeepCallController = _moduleImpl.callKeepCallController;
131
- self.callKeepProvider = _moduleImpl.callKeepProvider;
181
+ [self _setupiOSWithOptions:optionsDict];
182
+ }
183
+ #else
184
+ RCT_EXPORT_METHOD(setupiOS:(NSDictionary *)options) {
185
+ NSDictionary *optionsDict = @{
186
+ @"supportsVideo" : options[@"supportsVideo"] ?: @(NO),
187
+ @"maximumCallsPerCallGroup" : options[@"maximumCallsPerCallGroup"] ?: @(1),
188
+ @"maximumCallGroups" : options[@"maximumCallGroups"] ?: @(1),
189
+ @"handleType" : options[@"handleType"] ?: @"generic",
190
+ @"ringtoneSound" : options[@"sound"] ?: @"",
191
+ @"imageName" : options[@"imageName"] ?: @"",
192
+ @"includesCallsInRecents" : options[@"callsHistory"] ?: @(NO),
193
+ @"displayCallTimeout" : options[@"displayCallTimeout"] ?: @(0)
194
+ };
195
+
196
+ [self _setupiOSWithOptions:optionsDict];
197
+ }
198
+ #endif
199
+
200
+ #pragma mark - setupAndroid
201
+
202
+ #ifdef RCT_NEW_ARCH_ENABLED
203
+ - (void)setupAndroid:(JS::NativeCallingx::SpecSetupAndroidOptions &)options {
204
+ // iOS only - leave empty
205
+ }
206
+ #else
207
+ RCT_EXPORT_METHOD(setupAndroid:(NSDictionary *)options) {
208
+ // iOS only - leave empty
132
209
  }
210
+ #endif
133
211
 
212
+ #pragma mark - setShouldRejectCallWhenBusy
213
+
214
+ #ifdef RCT_NEW_ARCH_ENABLED
134
215
  - (void)setShouldRejectCallWhenBusy:(BOOL)shouldReject {
135
216
  [Settings setShouldRejectCallWhenBusy:shouldReject];
136
217
  }
218
+ #else
219
+ RCT_EXPORT_METHOD(setShouldRejectCallWhenBusy:(BOOL)shouldReject) {
220
+ [Settings setShouldRejectCallWhenBusy:shouldReject];
221
+ }
222
+ #endif
223
+
224
+ #pragma mark - getInitialEvents
137
225
 
226
+ #ifdef RCT_NEW_ARCH_ENABLED
138
227
  - (NSArray<NSDictionary *> *)getInitialEvents {
139
228
  return [_moduleImpl getInitialEvents];
140
229
  }
230
+ #else
231
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getInitialEvents) {
232
+ return [_moduleImpl getInitialEvents];
233
+ }
234
+ #endif
235
+
236
+ #pragma mark - getInitialVoipEvents
141
237
 
238
+ #ifdef RCT_NEW_ARCH_ENABLED
142
239
  - (NSArray<NSDictionary *> *)getInitialVoipEvents {
143
240
  return [[VoipNotificationsManager shared] getInitialEvents];
144
241
  }
242
+ #else
243
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getInitialVoipEvents) {
244
+ return [[VoipNotificationsManager shared] getInitialEvents];
245
+ }
246
+ #endif
145
247
 
248
+ #pragma mark - registerVoipToken
249
+
250
+ #ifdef RCT_NEW_ARCH_ENABLED
146
251
  - (void)registerVoipToken {
147
252
  [[VoipNotificationsManager shared] registerVoipToken];
148
253
  }
254
+ #else
255
+ RCT_EXPORT_METHOD(registerVoipToken) {
256
+ [[VoipNotificationsManager shared] registerVoipToken];
257
+ }
258
+ #endif
149
259
 
260
+ #pragma mark - answerIncomingCall
261
+
262
+ #ifdef RCT_NEW_ARCH_ENABLED
150
263
  - (void)answerIncomingCall:(nonnull NSString *)callId
151
264
  resolve:(nonnull RCTPromiseResolveBlock)resolve
152
265
  reject:(nonnull RCTPromiseRejectBlock)reject {
153
266
  BOOL result = [_moduleImpl answerIncomingCall:callId];
154
267
  resolve(@(result));
155
268
  }
269
+ #else
270
+ RCT_EXPORT_METHOD(answerIncomingCall:(NSString *)callId
271
+ resolve:(RCTPromiseResolveBlock)resolve
272
+ reject:(RCTPromiseRejectBlock)reject) {
273
+ BOOL result = [_moduleImpl answerIncomingCall:callId];
274
+ resolve(@(result));
275
+ }
276
+ #endif
277
+
278
+ #pragma mark - displayIncomingCall
156
279
 
280
+ #ifdef RCT_NEW_ARCH_ENABLED
157
281
  - (void)displayIncomingCall:(nonnull NSString *)callId
158
282
  phoneNumber:(nonnull NSString *)phoneNumber
159
283
  callerName:(nonnull NSString *)callerName
@@ -161,13 +285,35 @@
161
285
  displayOptions:(JS::NativeCallingx::SpecDisplayIncomingCallDisplayOptions &)displayOptions
162
286
  resolve:(nonnull RCTPromiseResolveBlock)resolve
163
287
  reject:(nonnull RCTPromiseRejectBlock)reject {
164
- BOOL result = [_moduleImpl displayIncomingCallWithCallId:callId
165
- phoneNumber:phoneNumber
166
- callerName:callerName
167
- hasVideo:hasVideo];
168
- resolve(@(result));
288
+ [_moduleImpl displayIncomingCallWithCallId:callId
289
+ phoneNumber:phoneNumber
290
+ callerName:callerName
291
+ hasVideo:hasVideo
292
+ resolve:resolve
293
+ reject:reject
294
+ ];
295
+ }
296
+ #else
297
+ RCT_EXPORT_METHOD(displayIncomingCall:(NSString *)callId
298
+ phoneNumber:(NSString *)phoneNumber
299
+ callerName:(NSString *)callerName
300
+ hasVideo:(BOOL)hasVideo
301
+ displayOptions:(NSDictionary *)displayOptions
302
+ resolve:(RCTPromiseResolveBlock)resolve
303
+ reject:(RCTPromiseRejectBlock)reject) {
304
+ [_moduleImpl displayIncomingCallWithCallId:callId
305
+ phoneNumber:phoneNumber
306
+ callerName:callerName
307
+ hasVideo:hasVideo
308
+ resolve:resolve
309
+ reject:reject
310
+ ];
169
311
  }
312
+ #endif
170
313
 
314
+ #pragma mark - endCallWithReason
315
+
316
+ #ifdef RCT_NEW_ARCH_ENABLED
171
317
  - (void)endCallWithReason:(nonnull NSString *)callId
172
318
  reason:(double)reason
173
319
  resolve:(nonnull RCTPromiseResolveBlock)resolve
@@ -175,29 +321,79 @@
175
321
  [CallingxImpl endCall:callId reason:(int)reason];
176
322
  resolve(@YES);
177
323
  }
324
+ #else
325
+ RCT_EXPORT_METHOD(endCallWithReason:(NSString *)callId
326
+ reason:(double)reason
327
+ resolve:(RCTPromiseResolveBlock)resolve
328
+ reject:(RCTPromiseRejectBlock)reject) {
329
+ [CallingxImpl endCall:callId reason:(int)reason];
330
+ resolve(@YES);
331
+ }
332
+ #endif
333
+
334
+ #pragma mark - endCall
178
335
 
336
+ #ifdef RCT_NEW_ARCH_ENABLED
179
337
  - (void)endCall:(nonnull NSString *)callId
180
338
  resolve:(nonnull RCTPromiseResolveBlock)resolve
181
339
  reject:(nonnull RCTPromiseRejectBlock)reject {
182
340
  BOOL result = [_moduleImpl endCall:callId];
183
341
  resolve(@(result));
184
342
  }
343
+ #else
344
+ RCT_EXPORT_METHOD(endCall:(NSString *)callId
345
+ resolve:(RCTPromiseResolveBlock)resolve
346
+ reject:(RCTPromiseRejectBlock)reject) {
347
+ BOOL result = [_moduleImpl endCall:callId];
348
+ resolve(@(result));
349
+ }
350
+ #endif
351
+
352
+ #pragma mark - isCallRegistered
185
353
 
186
- - (NSNumber *)isCallRegistered:(nonnull NSString *)callId {
187
- return @([_moduleImpl isCallRegistered:callId]);
354
+ #ifdef RCT_NEW_ARCH_ENABLED
355
+ - (NSNumber *)isCallTracked:(nonnull NSString *)callId {
356
+ return @([_moduleImpl isCallTracked:callId]);
188
357
  }
358
+ #else
359
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isCallTracked:(NSString *)callId) {
360
+ return @([_moduleImpl isCallTracked:callId]);
361
+ }
362
+ #endif
189
363
 
364
+ #pragma mark - hasRegisteredCall
365
+
366
+ #ifdef RCT_NEW_ARCH_ENABLED
190
367
  - (NSNumber *)hasRegisteredCall {
191
368
  return @([CallingxImpl hasRegisteredCall]);
192
369
  }
370
+ #else
371
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hasRegisteredCall) {
372
+ return @([CallingxImpl hasRegisteredCall]);
373
+ }
374
+ #endif
375
+
376
+ #pragma mark - setCurrentCallActive
193
377
 
378
+ #ifdef RCT_NEW_ARCH_ENABLED
194
379
  - (void)setCurrentCallActive:(nonnull NSString *)callId
195
380
  resolve:(nonnull RCTPromiseResolveBlock)resolve
196
381
  reject:(nonnull RCTPromiseRejectBlock)reject {
197
382
  BOOL result = [_moduleImpl setCurrentCallActive:callId];
198
383
  resolve(@(result));
199
384
  }
385
+ #else
386
+ RCT_EXPORT_METHOD(setCurrentCallActive:(NSString *)callId
387
+ resolve:(RCTPromiseResolveBlock)resolve
388
+ reject:(RCTPromiseRejectBlock)reject) {
389
+ BOOL result = [_moduleImpl setCurrentCallActive:callId];
390
+ resolve(@(result));
391
+ }
392
+ #endif
393
+
394
+ #pragma mark - setMutedCall
200
395
 
396
+ #ifdef RCT_NEW_ARCH_ENABLED
201
397
  - (void)setMutedCall:(nonnull NSString *)callId
202
398
  isMuted:(BOOL)isMuted
203
399
  resolve:(nonnull RCTPromiseResolveBlock)resolve
@@ -205,7 +401,19 @@
205
401
  BOOL result = [_moduleImpl setMutedCall:callId isMuted:isMuted];
206
402
  resolve(@(result));
207
403
  }
404
+ #else
405
+ RCT_EXPORT_METHOD(setMutedCall:(NSString *)callId
406
+ isMuted:(BOOL)isMuted
407
+ resolve:(RCTPromiseResolveBlock)resolve
408
+ reject:(RCTPromiseRejectBlock)reject) {
409
+ BOOL result = [_moduleImpl setMutedCall:callId isMuted:isMuted];
410
+ resolve(@(result));
411
+ }
412
+ #endif
413
+
414
+ #pragma mark - setOnHoldCall
208
415
 
416
+ #ifdef RCT_NEW_ARCH_ENABLED
209
417
  - (void)setOnHoldCall:(nonnull NSString *)callId
210
418
  isOnHold:(BOOL)isOnHold
211
419
  resolve:(nonnull RCTPromiseResolveBlock)resolve
@@ -213,7 +421,19 @@
213
421
  BOOL result = [_moduleImpl setOnHoldCall:callId isOnHold:isOnHold];
214
422
  resolve(@(result));
215
423
  }
424
+ #else
425
+ RCT_EXPORT_METHOD(setOnHoldCall:(NSString *)callId
426
+ isOnHold:(BOOL)isOnHold
427
+ resolve:(RCTPromiseResolveBlock)resolve
428
+ reject:(RCTPromiseRejectBlock)reject) {
429
+ BOOL result = [_moduleImpl setOnHoldCall:callId isOnHold:isOnHold];
430
+ resolve(@(result));
431
+ }
432
+ #endif
216
433
 
434
+ #pragma mark - startCall
435
+
436
+ #ifdef RCT_NEW_ARCH_ENABLED
217
437
  - (void)startCall:(nonnull NSString *)callId
218
438
  phoneNumber:(nonnull NSString *)phoneNumber
219
439
  callerName:(nonnull NSString *)callerName
@@ -227,7 +447,25 @@
227
447
  hasVideo:hasVideo];
228
448
  resolve(@YES);
229
449
  }
450
+ #else
451
+ RCT_EXPORT_METHOD(startCall:(NSString *)callId
452
+ phoneNumber:(NSString *)phoneNumber
453
+ callerName:(NSString *)callerName
454
+ hasVideo:(BOOL)hasVideo
455
+ displayOptions:(NSDictionary *)displayOptions
456
+ resolve:(RCTPromiseResolveBlock)resolve
457
+ reject:(RCTPromiseRejectBlock)reject) {
458
+ [_moduleImpl startCallWithCallId:callId
459
+ phoneNumber:phoneNumber
460
+ callerName:callerName
461
+ hasVideo:hasVideo];
462
+ resolve(@YES);
463
+ }
464
+ #endif
465
+
466
+ #pragma mark - updateDisplay
230
467
 
468
+ #ifdef RCT_NEW_ARCH_ENABLED
231
469
  - (void)updateDisplay:(nonnull NSString *)callId
232
470
  phoneNumber:(nonnull NSString *)phoneNumber
233
471
  callerName:(nonnull NSString *)callerName
@@ -239,15 +477,35 @@
239
477
  callerName:callerName];
240
478
  resolve(@(result));
241
479
  }
480
+ #else
481
+ RCT_EXPORT_METHOD(updateDisplay:(NSString *)callId
482
+ phoneNumber:(NSString *)phoneNumber
483
+ callerName:(NSString *)callerName
484
+ displayOptions:(NSDictionary *)displayOptions
485
+ resolve:(RCTPromiseResolveBlock)resolve
486
+ reject:(RCTPromiseRejectBlock)reject) {
487
+ BOOL result = [_moduleImpl updateDisplayWithCallId:callId
488
+ phoneNumber:phoneNumber
489
+ callerName:callerName];
490
+ resolve(@(result));
491
+ }
492
+ #endif
493
+
494
+ #pragma mark - log
242
495
 
496
+ #ifdef RCT_NEW_ARCH_ENABLED
243
497
  - (void)log:(NSString *)message level:(NSString *)level {
244
498
  NSLog(@"[Callingx][log] %@, %@", message, level);
245
499
  }
246
-
247
- - (void)setupAndroid:(JS::NativeCallingx::SpecSetupAndroidOptions &)options {
248
- // iOS only - leave empty
500
+ #else
501
+ RCT_EXPORT_METHOD(log:(NSString *)message level:(NSString *)level) {
502
+ NSLog(@"[Callingx][log] %@, %@", message, level);
249
503
  }
504
+ #endif
505
+
506
+ #pragma mark - startBackgroundTask
250
507
 
508
+ #ifdef RCT_NEW_ARCH_ENABLED
251
509
  - (void)startBackgroundTask:(NSString *)taskName
252
510
  timeout:(double)timeout
253
511
  resolve:(RCTPromiseResolveBlock)resolve
@@ -255,26 +513,72 @@
255
513
  // Not implemented on iOS
256
514
  resolve(@YES);
257
515
  }
516
+ #else
517
+ RCT_EXPORT_METHOD(startBackgroundTask:(NSString *)taskName
518
+ timeout:(double)timeout
519
+ resolve:(RCTPromiseResolveBlock)resolve
520
+ reject:(RCTPromiseRejectBlock)reject) {
521
+ // Not implemented on iOS
522
+ resolve(@YES);
523
+ }
524
+ #endif
525
+
526
+ #pragma mark - stopBackgroundTask
258
527
 
528
+ #ifdef RCT_NEW_ARCH_ENABLED
259
529
  - (void)stopBackgroundTask:(NSString *)taskName
260
530
  resolve:(RCTPromiseResolveBlock)resolve
261
531
  reject:(RCTPromiseRejectBlock)reject {
262
532
  // Not implemented on iOS
263
533
  resolve(@YES);
264
534
  }
535
+ #else
536
+ RCT_EXPORT_METHOD(stopBackgroundTask:(NSString *)taskName
537
+ resolve:(RCTPromiseResolveBlock)resolve
538
+ reject:(RCTPromiseRejectBlock)reject) {
539
+ // Not implemented on iOS
540
+ resolve(@YES);
541
+ }
542
+ #endif
265
543
 
544
+ #pragma mark - registerBackgroundTaskAvailable
545
+
546
+ #ifdef RCT_NEW_ARCH_ENABLED
266
547
  - (void)registerBackgroundTaskAvailable {
267
548
  // Not implemented on iOS - background tasks work differently on iOS
268
549
  }
550
+ #else
551
+ RCT_EXPORT_METHOD(registerBackgroundTaskAvailable) {
552
+ // Not implemented on iOS - background tasks work differently on iOS
553
+ }
554
+ #endif
269
555
 
556
+ #pragma mark - isServiceStarted
557
+
558
+ #ifdef RCT_NEW_ARCH_ENABLED
270
559
  - (void)isServiceStarted:(RCTPromiseResolveBlock)resolve
271
560
  reject:(RCTPromiseRejectBlock)reject {
272
561
  // iOS doesn't use a service like Android, always return true
273
562
  resolve(@YES);
274
563
  }
564
+ #else
565
+ RCT_EXPORT_METHOD(isServiceStarted:(RCTPromiseResolveBlock)resolve
566
+ reject:(RCTPromiseRejectBlock)reject) {
567
+ // iOS doesn't use a service like Android, always return true
568
+ resolve(@YES);
569
+ }
570
+ #endif
275
571
 
572
+ #pragma mark - canPostNotifications
573
+
574
+ #ifdef RCT_NEW_ARCH_ENABLED
276
575
  - (nonnull NSNumber *)canPostNotifications {
277
576
  return @YES;
278
577
  }
578
+ #else
579
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(canPostNotifications) {
580
+ return @YES;
581
+ }
582
+ #endif
279
583
 
280
584
  @end
@@ -0,0 +1,105 @@
1
+ import Foundation
2
+
3
+ /// Represents a call tracked by the CallingxImpl module.
4
+ /// Holds per-call lifecycle state to guard against duplicate actions
5
+ /// and to track timestamps for CallKit reporting.
6
+ @objcMembers public class CallingxCall: NSObject {
7
+ public let uuid: UUID
8
+ public let cid: String
9
+ public let isOutgoing: Bool
10
+
11
+ // MARK: - Action-source flags
12
+ // These flags track whether an action was initiated from the app (vs system UI).
13
+ // They follow a "set-then-read-then-reset" pattern in the CXProviderDelegate methods
14
+ // to determine the event source ("app" vs "sys") before being reset.
15
+
16
+ /// Whether answerIncomingCall was initiated from the app (vs system UI)
17
+ public private(set) var isSelfAnswered: Bool = false
18
+ /// Whether endCall was initiated from the app (vs system UI)
19
+ public private(set) var isSelfEnded: Bool = false
20
+ /// Whether setMutedCall was initiated from the app (vs system UI)
21
+ public private(set) var isSelfMuted: Bool = false
22
+
23
+ // MARK: - Lifecycle timestamps
24
+
25
+ /// When the call started connecting (outgoing: maps to reportOutgoingCall(startedConnectingAt:);
26
+ /// incoming: set when answerIncomingCall is called, internal-only)
27
+ public private(set) var startedConnectingAt: Date?
28
+ /// When the call became connected (outgoing: maps to reportOutgoingCall(connectedAt:);
29
+ /// incoming: set when CXAnswerCallAction delegate fires, internal-only)
30
+ public private(set) var connectedAt: Date?
31
+ /// When the call ended
32
+ public private(set) var endedAt: Date?
33
+
34
+ // MARK: - Derived states
35
+
36
+ public var hasStartedConnecting: Bool { startedConnectingAt != nil }
37
+ public var isConnected: Bool { connectedAt != nil }
38
+ public var hasEnded: Bool { endedAt != nil }
39
+ /// Whether the call has been answered (incoming) or started connecting (outgoing).
40
+ /// Checks both startedConnectingAt (set by answerIncomingCall from app) and connectedAt
41
+ /// (set by CXAnswerCallAction delegate, which fires even when answered from system UI).
42
+ /// Used as the primary guard against duplicate answerIncomingCall invocations.
43
+ public var isAnswered: Bool { startedConnectingAt != nil || connectedAt != nil }
44
+
45
+ // MARK: - Initialization
46
+
47
+ public init(uuid: UUID, cid: String, isOutgoing: Bool = false) {
48
+ self.uuid = uuid
49
+ self.cid = cid
50
+ self.isOutgoing = isOutgoing
51
+ }
52
+
53
+ // MARK: - Action-source flag methods
54
+
55
+ public func markSelfAnswered() { isSelfAnswered = true }
56
+ public func markSelfEnded() { isSelfEnded = true }
57
+ public func markSelfMuted() { isSelfMuted = true }
58
+
59
+ public func resetSelfAnswered() { isSelfAnswered = false }
60
+ public func resetSelfEnded() { isSelfEnded = false }
61
+ public func resetSelfMuted() { isSelfMuted = false }
62
+
63
+ /// Resets all action-source flags. Called when a CXTransaction fails.
64
+ public func resetAllSelfFlags() {
65
+ isSelfAnswered = false
66
+ isSelfEnded = false
67
+ isSelfMuted = false
68
+ }
69
+
70
+ // MARK: - Lifecycle transition methods
71
+
72
+ public func markStartedConnecting() {
73
+ if startedConnectingAt == nil {
74
+ startedConnectingAt = Date()
75
+ }
76
+ }
77
+
78
+ public func markConnected() {
79
+ if connectedAt == nil {
80
+ connectedAt = Date()
81
+ }
82
+ }
83
+
84
+ public func markEnded() {
85
+ if endedAt == nil {
86
+ endedAt = Date()
87
+ }
88
+ }
89
+
90
+ // MARK: - Debug description
91
+
92
+ public override var description: String {
93
+ let state: String
94
+ if hasEnded {
95
+ state = "ended"
96
+ } else if isConnected {
97
+ state = "connected"
98
+ } else if hasStartedConnecting {
99
+ state = "connecting"
100
+ } else {
101
+ state = "ringing"
102
+ }
103
+ return "CallingxCall(cid: \(cid), uuid: \(uuid.uuidString.lowercased()), outgoing: \(isOutgoing), state: \(state))"
104
+ }
105
+ }