@succinctlabs/react-native-zcam1 0.2.5

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 (139) hide show
  1. package/README.md +61 -0
  2. package/Zcam1Sdk.podspec +157 -0
  3. package/app.plugin.js +11 -0
  4. package/cpp/generated/zcam1_c2pa_utils.cpp +4091 -0
  5. package/cpp/generated/zcam1_c2pa_utils.hpp +367 -0
  6. package/cpp/generated/zcam1_certs_utils.cpp +1799 -0
  7. package/cpp/generated/zcam1_certs_utils.hpp +72 -0
  8. package/cpp/generated/zcam1_verify_utils.cpp +1857 -0
  9. package/cpp/generated/zcam1_verify_utils.hpp +79 -0
  10. package/cpp/proving/generated/zcam1_proving_utils.cpp +3661 -0
  11. package/cpp/proving/generated/zcam1_proving_utils.hpp +275 -0
  12. package/cpp/proving/zcam1-proving.cpp +16 -0
  13. package/cpp/proving/zcam1-proving.h +15 -0
  14. package/cpp/zcam1-sdk.cpp +20 -0
  15. package/cpp/zcam1-sdk.h +15 -0
  16. package/ios/Zcam1Camera.swift +2945 -0
  17. package/ios/Zcam1CameraFilmStyle.swift +191 -0
  18. package/ios/Zcam1CameraViewManager.m +86 -0
  19. package/ios/Zcam1Capture.h +13 -0
  20. package/ios/Zcam1Capture.mm +500 -0
  21. package/ios/Zcam1DepthData.swift +417 -0
  22. package/ios/Zcam1Sdk.h +16 -0
  23. package/ios/Zcam1Sdk.mm +66 -0
  24. package/ios/proving/Zcam1Proving.h +16 -0
  25. package/ios/proving/Zcam1Proving.mm +66 -0
  26. package/lib/module/NativeZcam1Capture.js +12 -0
  27. package/lib/module/NativeZcam1Capture.js.map +1 -0
  28. package/lib/module/NativeZcam1Sdk.js +7 -0
  29. package/lib/module/NativeZcam1Sdk.js.map +1 -0
  30. package/lib/module/bindings.js +51 -0
  31. package/lib/module/bindings.js.map +1 -0
  32. package/lib/module/camera.js +522 -0
  33. package/lib/module/camera.js.map +1 -0
  34. package/lib/module/capture.js +120 -0
  35. package/lib/module/capture.js.map +1 -0
  36. package/lib/module/common.js +35 -0
  37. package/lib/module/common.js.map +1 -0
  38. package/lib/module/generated/zcam1_c2pa_utils-ffi.js +43 -0
  39. package/lib/module/generated/zcam1_c2pa_utils-ffi.js.map +1 -0
  40. package/lib/module/generated/zcam1_c2pa_utils.js +1202 -0
  41. package/lib/module/generated/zcam1_c2pa_utils.js.map +1 -0
  42. package/lib/module/generated/zcam1_certs_utils-ffi.js +43 -0
  43. package/lib/module/generated/zcam1_certs_utils-ffi.js.map +1 -0
  44. package/lib/module/generated/zcam1_certs_utils.js +399 -0
  45. package/lib/module/generated/zcam1_certs_utils.js.map +1 -0
  46. package/lib/module/generated/zcam1_proving_utils-ffi.js +43 -0
  47. package/lib/module/generated/zcam1_proving_utils-ffi.js.map +1 -0
  48. package/lib/module/generated/zcam1_proving_utils.js +515 -0
  49. package/lib/module/generated/zcam1_proving_utils.js.map +1 -0
  50. package/lib/module/generated/zcam1_verify_utils-ffi.js +43 -0
  51. package/lib/module/generated/zcam1_verify_utils-ffi.js.map +1 -0
  52. package/lib/module/generated/zcam1_verify_utils.js +252 -0
  53. package/lib/module/generated/zcam1_verify_utils.js.map +1 -0
  54. package/lib/module/index.js +31 -0
  55. package/lib/module/index.js.map +1 -0
  56. package/lib/module/package.json +1 -0
  57. package/lib/module/picker.js +222 -0
  58. package/lib/module/picker.js.map +1 -0
  59. package/lib/module/proving/NativeZcam1Proving.js +7 -0
  60. package/lib/module/proving/NativeZcam1Proving.js.map +1 -0
  61. package/lib/module/proving/bindings.js +46 -0
  62. package/lib/module/proving/bindings.js.map +1 -0
  63. package/lib/module/proving/index.js +5 -0
  64. package/lib/module/proving/index.js.map +1 -0
  65. package/lib/module/proving/prove.js +346 -0
  66. package/lib/module/proving/prove.js.map +1 -0
  67. package/lib/module/utils.js +27 -0
  68. package/lib/module/utils.js.map +1 -0
  69. package/lib/module/verify.js +82 -0
  70. package/lib/module/verify.js.map +1 -0
  71. package/lib/typescript/package.json +1 -0
  72. package/lib/typescript/src/NativeZcam1Capture.d.ts +280 -0
  73. package/lib/typescript/src/NativeZcam1Capture.d.ts.map +1 -0
  74. package/lib/typescript/src/NativeZcam1Sdk.d.ts +8 -0
  75. package/lib/typescript/src/NativeZcam1Sdk.d.ts.map +1 -0
  76. package/lib/typescript/src/bindings.d.ts +14 -0
  77. package/lib/typescript/src/bindings.d.ts.map +1 -0
  78. package/lib/typescript/src/camera.d.ts +300 -0
  79. package/lib/typescript/src/camera.d.ts.map +1 -0
  80. package/lib/typescript/src/capture.d.ts +59 -0
  81. package/lib/typescript/src/capture.d.ts.map +1 -0
  82. package/lib/typescript/src/common.d.ts +10 -0
  83. package/lib/typescript/src/common.d.ts.map +1 -0
  84. package/lib/typescript/src/generated/zcam1_c2pa_utils-ffi.d.ts +175 -0
  85. package/lib/typescript/src/generated/zcam1_c2pa_utils-ffi.d.ts.map +1 -0
  86. package/lib/typescript/src/generated/zcam1_c2pa_utils.d.ts +811 -0
  87. package/lib/typescript/src/generated/zcam1_c2pa_utils.d.ts.map +1 -0
  88. package/lib/typescript/src/generated/zcam1_certs_utils-ffi.d.ts +82 -0
  89. package/lib/typescript/src/generated/zcam1_certs_utils-ffi.d.ts.map +1 -0
  90. package/lib/typescript/src/generated/zcam1_certs_utils.d.ts +413 -0
  91. package/lib/typescript/src/generated/zcam1_certs_utils.d.ts.map +1 -0
  92. package/lib/typescript/src/generated/zcam1_proving_utils-ffi.d.ts +153 -0
  93. package/lib/typescript/src/generated/zcam1_proving_utils-ffi.d.ts.map +1 -0
  94. package/lib/typescript/src/generated/zcam1_proving_utils.d.ts +321 -0
  95. package/lib/typescript/src/generated/zcam1_proving_utils.d.ts.map +1 -0
  96. package/lib/typescript/src/generated/zcam1_verify_utils-ffi.d.ts +84 -0
  97. package/lib/typescript/src/generated/zcam1_verify_utils-ffi.d.ts.map +1 -0
  98. package/lib/typescript/src/generated/zcam1_verify_utils.d.ts +286 -0
  99. package/lib/typescript/src/generated/zcam1_verify_utils.d.ts.map +1 -0
  100. package/lib/typescript/src/index.d.ts +29 -0
  101. package/lib/typescript/src/index.d.ts.map +1 -0
  102. package/lib/typescript/src/picker.d.ts +103 -0
  103. package/lib/typescript/src/picker.d.ts.map +1 -0
  104. package/lib/typescript/src/proving/NativeZcam1Proving.d.ts +8 -0
  105. package/lib/typescript/src/proving/NativeZcam1Proving.d.ts.map +1 -0
  106. package/lib/typescript/src/proving/bindings.d.ts +8 -0
  107. package/lib/typescript/src/proving/bindings.d.ts.map +1 -0
  108. package/lib/typescript/src/proving/index.d.ts +3 -0
  109. package/lib/typescript/src/proving/index.d.ts.map +1 -0
  110. package/lib/typescript/src/proving/prove.d.ts +74 -0
  111. package/lib/typescript/src/proving/prove.d.ts.map +1 -0
  112. package/lib/typescript/src/utils.d.ts +2 -0
  113. package/lib/typescript/src/utils.d.ts.map +1 -0
  114. package/lib/typescript/src/verify.d.ts +45 -0
  115. package/lib/typescript/src/verify.d.ts.map +1 -0
  116. package/package.json +118 -0
  117. package/src/NativeZcam1Capture.ts +335 -0
  118. package/src/NativeZcam1Sdk.ts +10 -0
  119. package/src/bindings.tsx +49 -0
  120. package/src/camera.tsx +705 -0
  121. package/src/capture.tsx +165 -0
  122. package/src/common.tsx +46 -0
  123. package/src/generated/zcam1_c2pa_utils-ffi.ts +456 -0
  124. package/src/generated/zcam1_c2pa_utils.ts +1866 -0
  125. package/src/generated/zcam1_certs_utils-ffi.ts +187 -0
  126. package/src/generated/zcam1_certs_utils.ts +549 -0
  127. package/src/generated/zcam1_proving_utils-ffi.ts +374 -0
  128. package/src/generated/zcam1_proving_utils.ts +804 -0
  129. package/src/generated/zcam1_verify_utils-ffi.ts +196 -0
  130. package/src/generated/zcam1_verify_utils.ts +372 -0
  131. package/src/index.ts +73 -0
  132. package/src/picker.tsx +342 -0
  133. package/src/proving/NativeZcam1Proving.ts +10 -0
  134. package/src/proving/bindings.tsx +50 -0
  135. package/src/proving/index.ts +8 -0
  136. package/src/proving/prove.tsx +492 -0
  137. package/src/utils.ts +38 -0
  138. package/src/verify.tsx +119 -0
  139. package/turbo.json +27 -0
@@ -0,0 +1,500 @@
1
+ #import "Zcam1Capture.h"
2
+ #import <Security/Security.h>
3
+ #import <AVFoundation/AVFoundation.h>
4
+ #import <QuickLook/QuickLook.h>
5
+ #import "Zcam1Sdk-Swift.h"
6
+ #import <React/RCTBridgeModule.h>
7
+
8
+ // Static storage for pending promise callbacks - stored outside the instance to ensure they survive.
9
+ static NSMutableDictionary<NSString *, RCTPromiseResolveBlock> *sPendingResolvers = nil;
10
+ static NSMutableDictionary<NSString *, RCTPromiseRejectBlock> *sPendingRejecters = nil;
11
+ static dispatch_once_t sOnceToken;
12
+
13
+ static void ensureStaticStorageInitialized(void) {
14
+ dispatch_once(&sOnceToken, ^{
15
+ sPendingResolvers = [NSMutableDictionary new];
16
+ sPendingRejecters = [NSMutableDictionary new];
17
+ });
18
+ }
19
+
20
+ // MARK: - QLPreviewController helpers
21
+
22
+ @interface Zcam1PreviewItem : NSObject <QLPreviewItem>
23
+ @property (nonatomic, strong) NSURL *previewItemURL;
24
+ - (instancetype)initWithURL:(NSURL *)url;
25
+ @end
26
+
27
+ @implementation Zcam1PreviewItem
28
+ - (instancetype)initWithURL:(NSURL *)url {
29
+ self = [super init];
30
+ if (self) {
31
+ _previewItemURL = url;
32
+ }
33
+ return self;
34
+ }
35
+ @end
36
+
37
+ @interface Zcam1PreviewDataSource : NSObject <QLPreviewControllerDataSource>
38
+ @property (nonatomic, strong) Zcam1PreviewItem *item;
39
+ - (instancetype)initWithItem:(Zcam1PreviewItem *)item;
40
+ @end
41
+
42
+ @implementation Zcam1PreviewDataSource
43
+ - (instancetype)initWithItem:(Zcam1PreviewItem *)item {
44
+ self = [super init];
45
+ if (self) {
46
+ _item = item;
47
+ }
48
+ return self;
49
+ }
50
+ - (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller {
51
+ return 1;
52
+ }
53
+ - (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index {
54
+ return self.item;
55
+ }
56
+ @end
57
+
58
+ @implementation Zcam1Capture
59
+
60
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
61
+ (const facebook::react::ObjCTurboModule::InitParams &)params
62
+ {
63
+ return std::make_shared<facebook::react::NativeZcam1CaptureSpecJSI>(params);
64
+ }
65
+
66
+ + (NSString *)moduleName
67
+ {
68
+ return @"Zcam1Capture";
69
+ }
70
+
71
+
72
+ - (void)takeNativePhoto:(NSString *)format
73
+ position:(NSString *)position
74
+ flash:(NSString *)flash
75
+ includeDepthData:(BOOL)includeDepthData
76
+ aspectRatio:(NSString *)aspectRatio
77
+ orientation:(NSString *)orientation
78
+ skipPostProcessing:(BOOL)skipPostProcessing
79
+ resolve:(RCTPromiseResolveBlock)resolve
80
+ reject:(RCTPromiseRejectBlock)reject
81
+ {
82
+ #if __has_include("Zcam1Sdk-Swift.h")
83
+ if (@available(iOS 16.0, *)) {
84
+ Zcam1CameraService *service = [Zcam1CameraService shared];
85
+
86
+ // If empty strings are passed, let Swift fall back to its defaults.
87
+ NSString *positionString = (position.length > 0) ? position : nil;
88
+ NSString *formatString = (format.length > 0) ? format : nil;
89
+
90
+ // Set flash mode before capture.
91
+ if (flash.length > 0) {
92
+ [service setFlashMode:flash];
93
+ }
94
+
95
+ // Store callbacks in static storage with a unique key.
96
+ // This ensures they survive regardless of TurboModule instance lifecycle.
97
+ ensureStaticStorageInitialized();
98
+ NSString *callbackKey = [[NSUUID UUID] UUIDString];
99
+ @synchronized (sPendingResolvers) {
100
+ sPendingResolvers[callbackKey] = [resolve copy];
101
+ sPendingRejecters[callbackKey] = [reject copy];
102
+ }
103
+
104
+ [service takePhotoWithPositionString:positionString
105
+ formatString:formatString
106
+ includeDepthData:includeDepthData
107
+ aspectRatio:aspectRatio
108
+ orientation:orientation
109
+ skipPostProcessing:skipPostProcessing
110
+ completion:^(NSDictionary *result, NSError *error) {
111
+ // Retrieve and remove callbacks from static storage.
112
+ RCTPromiseResolveBlock storedResolve = nil;
113
+ RCTPromiseRejectBlock storedReject = nil;
114
+ @synchronized (sPendingResolvers) {
115
+ storedResolve = sPendingResolvers[callbackKey];
116
+ storedReject = sPendingRejecters[callbackKey];
117
+ [sPendingResolvers removeObjectForKey:callbackKey];
118
+ [sPendingRejecters removeObjectForKey:callbackKey];
119
+ }
120
+
121
+ if (error != nil) {
122
+ NSString *code = @"CAMERA_CAPTURE_ERROR";
123
+ NSString *message = error.localizedDescription ?: @"Failed to capture photo";
124
+ if (storedReject) storedReject(code, message, error);
125
+ } else if (result != nil) {
126
+ if (storedResolve) storedResolve(result);
127
+ } else {
128
+ if (storedReject) storedReject(@"CAMERA_CAPTURE_ERROR", @"Capture returned no data", nil);
129
+ }
130
+ }];
131
+ return;
132
+ }
133
+
134
+ // iOS version too old for the Swift camera implementation.
135
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS 16+ and Swift component", nil);
136
+ #else
137
+ // Swift-generated header is not available (no Swift camera implementation linked).
138
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS Swift component", nil);
139
+ #endif
140
+ }
141
+
142
+ - (void)setZoom:(double)factor
143
+ {
144
+ #if __has_include("Zcam1Sdk-Swift.h")
145
+ if (@available(iOS 16.0, *)) {
146
+ [[Zcam1CameraService shared] setZoom:factor];
147
+ }
148
+ #endif
149
+ }
150
+
151
+ - (void)setZoomAnimated:(double)factor
152
+ {
153
+ #if __has_include("Zcam1Sdk-Swift.h")
154
+ if (@available(iOS 16.0, *)) {
155
+ // Both paths use the same session queue dispatch for reliable lens switching.
156
+ [[Zcam1CameraService shared] setZoom:factor];
157
+ }
158
+ #endif
159
+ }
160
+
161
+ - (void)getMinZoom:(RCTPromiseResolveBlock)resolve
162
+ reject:(RCTPromiseRejectBlock)reject
163
+ {
164
+ #if __has_include("Zcam1Sdk-Swift.h")
165
+ if (@available(iOS 16.0, *)) {
166
+ CGFloat minZoom = [[Zcam1CameraService shared] getMinZoom];
167
+ resolve(@(minZoom));
168
+ return;
169
+ }
170
+ #endif
171
+ resolve(@(1.0));
172
+ }
173
+
174
+ - (void)getMaxZoom:(RCTPromiseResolveBlock)resolve
175
+ reject:(RCTPromiseRejectBlock)reject
176
+ {
177
+ #if __has_include("Zcam1Sdk-Swift.h")
178
+ if (@available(iOS 16.0, *)) {
179
+ CGFloat maxZoom = [[Zcam1CameraService shared] getMaxZoom];
180
+ resolve(@(maxZoom));
181
+ return;
182
+ }
183
+ #endif
184
+ resolve(@(1.0));
185
+ }
186
+
187
+ - (void)getSwitchOverZoomFactors:(RCTPromiseResolveBlock)resolve
188
+ reject:(RCTPromiseRejectBlock)reject
189
+ {
190
+ #if __has_include("Zcam1Sdk-Swift.h")
191
+ if (@available(iOS 16.0, *)) {
192
+ NSArray<NSNumber *> *factors = [[Zcam1CameraService shared] getSwitchOverZoomFactors];
193
+ resolve(factors);
194
+ return;
195
+ }
196
+ #endif
197
+ resolve(@[]);
198
+ }
199
+
200
+ - (void)hasUltraWideCamera:(RCTPromiseResolveBlock)resolve
201
+ reject:(RCTPromiseRejectBlock)reject
202
+ {
203
+ #if __has_include("Zcam1Sdk-Swift.h")
204
+ if (@available(iOS 16.0, *)) {
205
+ BOOL hasUltraWide = [[Zcam1CameraService shared] hasUltraWideCamera];
206
+ resolve(@(hasUltraWide));
207
+ return;
208
+ }
209
+ #endif
210
+ resolve(@(NO));
211
+ }
212
+
213
+ - (void)focusAtPoint:(double)x
214
+ y:(double)y
215
+ {
216
+ #if __has_include("Zcam1Sdk-Swift.h")
217
+ if (@available(iOS 16.0, *)) {
218
+ CGPoint point = CGPointMake(x, y);
219
+ [[Zcam1CameraService shared] focusAtPoint:point];
220
+ }
221
+ #endif
222
+ }
223
+
224
+ - (void)getExposureRange:(RCTPromiseResolveBlock)resolve
225
+ reject:(RCTPromiseRejectBlock)reject
226
+ {
227
+ #if __has_include("Zcam1Sdk-Swift.h")
228
+ if (@available(iOS 16.0, *)) {
229
+ NSDictionary *range = [[Zcam1CameraService shared] getExposureRange];
230
+ resolve(range);
231
+ return;
232
+ }
233
+ #endif
234
+ resolve(@{@"min": @(0.0), @"max": @(0.0)});
235
+ }
236
+
237
+ - (void)resetExposure
238
+ {
239
+ #if __has_include("Zcam1Sdk-Swift.h")
240
+ if (@available(iOS 16.0, *)) {
241
+ [[Zcam1CameraService shared] resetExposure];
242
+ }
243
+ #endif
244
+ }
245
+
246
+ - (void)getDeviceDiagnostics:(RCTPromiseResolveBlock)resolve
247
+ reject:(RCTPromiseRejectBlock)reject
248
+ {
249
+ #if __has_include("Zcam1Sdk-Swift.h")
250
+ if (@available(iOS 16.0, *)) {
251
+ NSDictionary *diagnostics = [[Zcam1CameraService shared] getDeviceDiagnostics];
252
+ resolve(diagnostics);
253
+ return;
254
+ }
255
+ #endif
256
+ resolve(@{@"error": @"Diagnostics not available"});
257
+ }
258
+
259
+ - (void)isDepthSupported:(RCTPromiseResolveBlock)resolve
260
+ reject:(RCTPromiseRejectBlock)reject
261
+ {
262
+ #if __has_include("Zcam1Sdk-Swift.h")
263
+ if (@available(iOS 16.0, *)) {
264
+ BOOL supported = [[Zcam1CameraService shared] isDepthSupported];
265
+ resolve(@(supported));
266
+ return;
267
+ }
268
+ #endif
269
+ resolve(@(NO));
270
+ }
271
+
272
+ - (void)hasDepthZoomLimitations:(RCTPromiseResolveBlock)resolve
273
+ reject:(RCTPromiseRejectBlock)reject
274
+ {
275
+ #if __has_include("Zcam1Sdk-Swift.h")
276
+ if (@available(iOS 16.0, *)) {
277
+ BOOL hasLimitations = [[Zcam1CameraService shared] hasDepthZoomLimitations];
278
+ resolve(@(hasLimitations));
279
+ return;
280
+ }
281
+ #endif
282
+ resolve(@(NO));
283
+ }
284
+
285
+ - (void)getDepthSupportedZoomRanges:(RCTPromiseResolveBlock)resolve
286
+ reject:(RCTPromiseRejectBlock)reject
287
+ {
288
+ #if __has_include("Zcam1Sdk-Swift.h")
289
+ if (@available(iOS 16.0, *)) {
290
+ NSArray<NSArray<NSNumber *> *> *ranges = [[Zcam1CameraService shared] getDepthSupportedZoomRanges];
291
+ resolve(ranges);
292
+ return;
293
+ }
294
+ #endif
295
+ resolve(@[]);
296
+ }
297
+
298
+ - (void)startNativeVideoRecording:(NSString *)position
299
+ maxDurationSeconds:(double)maxDurationSeconds
300
+ resolve:(RCTPromiseResolveBlock)resolve
301
+ reject:(RCTPromiseRejectBlock)reject
302
+ {
303
+ #if __has_include("Zcam1Sdk-Swift.h")
304
+ if (@available(iOS 16.0, *)) {
305
+ Zcam1CameraService *service = [Zcam1CameraService shared];
306
+
307
+ // If empty strings are passed, let Swift fall back to its defaults.
308
+ NSString *positionString = (position.length > 0) ? position : nil;
309
+
310
+ // Store callbacks in static storage with a unique key.
311
+ ensureStaticStorageInitialized();
312
+ NSString *callbackKey = [[NSUUID UUID] UUIDString];
313
+ @synchronized (sPendingResolvers) {
314
+ sPendingResolvers[callbackKey] = [resolve copy];
315
+ sPendingRejecters[callbackKey] = [reject copy];
316
+ }
317
+
318
+ [service startVideoRecordingWithPositionString:positionString
319
+ maxDurationSeconds:maxDurationSeconds
320
+ completion:^(NSDictionary *result, NSError *error) {
321
+ RCTPromiseResolveBlock storedResolve = nil;
322
+ RCTPromiseRejectBlock storedReject = nil;
323
+ @synchronized (sPendingResolvers) {
324
+ storedResolve = sPendingResolvers[callbackKey];
325
+ storedReject = sPendingRejecters[callbackKey];
326
+ [sPendingResolvers removeObjectForKey:callbackKey];
327
+ [sPendingRejecters removeObjectForKey:callbackKey];
328
+ }
329
+
330
+ if (error != nil) {
331
+ NSString *code = @"VIDEO_RECORDING_START_ERROR";
332
+ NSString *message = error.localizedDescription ?: @"Failed to start video recording";
333
+ if (storedReject) storedReject(code, message, error);
334
+ } else if (result != nil) {
335
+ if (storedResolve) storedResolve(result);
336
+ } else {
337
+ if (storedReject) storedReject(@"VIDEO_RECORDING_START_ERROR", @"Start recording returned no data", nil);
338
+ }
339
+ }];
340
+ return;
341
+ }
342
+
343
+ // iOS version too old for the Swift camera implementation.
344
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS 16+ and Swift component", nil);
345
+ #else
346
+ // Swift-generated header is not available (no Swift camera implementation linked).
347
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS Swift component", nil);
348
+ #endif
349
+ }
350
+
351
+ - (void)stopNativeVideoRecording:(RCTPromiseResolveBlock)resolve
352
+ reject:(RCTPromiseRejectBlock)reject
353
+ {
354
+ #if __has_include("Zcam1Sdk-Swift.h")
355
+ if (@available(iOS 16.0, *)) {
356
+ Zcam1CameraService *service = [Zcam1CameraService shared];
357
+
358
+ // Store callbacks in static storage with a unique key.
359
+ ensureStaticStorageInitialized();
360
+ NSString *callbackKey = [[NSUUID UUID] UUIDString];
361
+ @synchronized (sPendingResolvers) {
362
+ sPendingResolvers[callbackKey] = [resolve copy];
363
+ sPendingRejecters[callbackKey] = [reject copy];
364
+ }
365
+
366
+ [service stopVideoRecordingWithCompletion:^(NSDictionary *result, NSError *error) {
367
+ RCTPromiseResolveBlock storedResolve = nil;
368
+ RCTPromiseRejectBlock storedReject = nil;
369
+ @synchronized (sPendingResolvers) {
370
+ storedResolve = sPendingResolvers[callbackKey];
371
+ storedReject = sPendingRejecters[callbackKey];
372
+ [sPendingResolvers removeObjectForKey:callbackKey];
373
+ [sPendingRejecters removeObjectForKey:callbackKey];
374
+ }
375
+
376
+ if (error != nil) {
377
+ NSString *code = @"VIDEO_RECORDING_STOP_ERROR";
378
+ NSString *message = error.localizedDescription ?: @"Failed to stop video recording";
379
+ if (storedReject) storedReject(code, message, error);
380
+ } else if (result != nil) {
381
+ if (storedResolve) storedResolve(result);
382
+ } else {
383
+ if (storedReject) storedReject(@"VIDEO_RECORDING_STOP_ERROR", @"Stop recording returned no data", nil);
384
+ }
385
+ }];
386
+ return;
387
+ }
388
+
389
+ // iOS version too old for the Swift camera implementation.
390
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS 16+ and Swift component", nil);
391
+ #else
392
+ // Swift-generated header is not available (no Swift camera implementation linked).
393
+ reject(@"CAMERA_UNAVAILABLE", @"Native camera requires iOS Swift component", nil);
394
+ #endif
395
+ }
396
+
397
+ - (void)previewFile:(NSString *)filePath
398
+ resolve:(RCTPromiseResolveBlock)resolve
399
+ reject:(RCTPromiseRejectBlock)reject
400
+ {
401
+ NSURL *fileURL = [NSURL fileURLWithPath:filePath];
402
+
403
+ if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
404
+ reject(@"FILE_NOT_FOUND", [NSString stringWithFormat:@"File not found: %@", filePath], nil);
405
+ return;
406
+ }
407
+
408
+ dispatch_async(dispatch_get_main_queue(), ^{
409
+ Zcam1PreviewItem *item = [[Zcam1PreviewItem alloc] initWithURL:fileURL];
410
+ Zcam1PreviewDataSource *dataSource = [[Zcam1PreviewDataSource alloc] initWithItem:item];
411
+
412
+ // Store data source so it isn't deallocated.
413
+ static Zcam1PreviewDataSource *currentDataSource = nil;
414
+ currentDataSource = dataSource;
415
+
416
+ QLPreviewController *previewController = [[QLPreviewController alloc] init];
417
+ previewController.dataSource = dataSource;
418
+
419
+ // Find the key window using modern scene-based API (iOS 13+).
420
+ UIWindow *keyWindow = nil;
421
+ for (UIWindowScene *scene in [UIApplication sharedApplication].connectedScenes) {
422
+ if (scene.activationState == UISceneActivationStateForegroundActive) {
423
+ for (UIWindow *window in scene.windows) {
424
+ if (window.isKeyWindow) {
425
+ keyWindow = window;
426
+ break;
427
+ }
428
+ }
429
+ if (keyWindow) break;
430
+ }
431
+ }
432
+
433
+ UIViewController *rootVC = keyWindow.rootViewController;
434
+ // Walk to the topmost presented controller.
435
+ while (rootVC.presentedViewController) {
436
+ rootVC = rootVC.presentedViewController;
437
+ }
438
+
439
+ if (!rootVC) {
440
+ reject(@"NO_VIEW_CONTROLLER", @"Could not find a view controller to present from", nil);
441
+ return;
442
+ }
443
+
444
+ [rootVC presentViewController:previewController animated:YES completion:^{
445
+ resolve(nil);
446
+ }];
447
+ });
448
+ }
449
+
450
+ - (void)getDepthSensorInfo:(RCTPromiseResolveBlock)resolve
451
+ reject:(RCTPromiseRejectBlock)reject
452
+ {
453
+ #if __has_include("Zcam1Sdk-Swift.h")
454
+ if (@available(iOS 16.0, *)) {
455
+ // Check if current device supports depth data capture
456
+ AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDualCamera
457
+ mediaType:AVMediaTypeVideo
458
+ position:AVCaptureDevicePositionBack];
459
+
460
+ // Also try triple camera and dual wide camera for broader support
461
+ if (!device) {
462
+ device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInTripleCamera
463
+ mediaType:AVMediaTypeVideo
464
+ position:AVCaptureDevicePositionBack];
465
+ }
466
+
467
+ if (!device) {
468
+ device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInDualWideCamera
469
+ mediaType:AVMediaTypeVideo
470
+ position:AVCaptureDevicePositionBack];
471
+ }
472
+
473
+ BOOL supportsDepth = device != nil;
474
+
475
+ NSMutableArray<NSString *> *formats = [NSMutableArray array];
476
+ if (supportsDepth) {
477
+ [formats addObject:@"depthFloat32"];
478
+ [formats addObject:@"depthFloat16"];
479
+ [formats addObject:@"disparityFloat32"];
480
+ [formats addObject:@"disparityFloat16"];
481
+ }
482
+
483
+ NSDictionary *result = @{
484
+ @"available": @(supportsDepth),
485
+ @"formats": formats,
486
+ };
487
+
488
+ resolve(result);
489
+ return;
490
+ }
491
+
492
+ // iOS version too old
493
+ resolve(nil);
494
+ #else
495
+ // Swift-generated header is not available
496
+ resolve(nil);
497
+ #endif
498
+ }
499
+
500
+ @end