@capgo/camera-preview 7.3.8 → 7.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapgoCameraPreview.podspec +16 -13
- package/README.md +298 -68
- package/android/.gradle/8.14.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.2/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/8.14.2/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +9 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +239 -545
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +848 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraDevice.java +54 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraLens.java +70 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraSessionConfiguration.java +65 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/LensInfo.java +34 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/ZoomFactors.java +34 -0
- package/dist/docs.json +702 -151
- package/dist/esm/definitions.d.ts +326 -80
- package/dist/esm/definitions.js +10 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +27 -1
- package/dist/esm/web.js +244 -4
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +254 -4
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +254 -4
- package/dist/plugin.js.map +1 -1
- package/ios/{Plugin → Sources/CapgoCameraPreview}/CameraController.swift +359 -34
- package/ios/{Plugin → Sources/CapgoCameraPreview}/Plugin.swift +307 -16
- package/ios/Tests/CameraPreviewPluginTests/CameraPreviewPluginTests.swift +15 -0
- package/package.json +1 -1
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +0 -1279
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +0 -29
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +0 -39
- package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +0 -461
- package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +0 -24
- package/ios/Plugin/Info.plist +0 -24
- package/ios/Plugin/Plugin.h +0 -10
- package/ios/Plugin/Plugin.m +0 -18
- package/ios/Plugin.xcodeproj/project.pbxproj +0 -593
- package/ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/Plugin.xcworkspace/contents.xcworkspacedata +0 -10
- package/ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/PluginTests/Info.plist +0 -22
- package/ios/PluginTests/PluginTests.swift +0 -83
- package/ios/Podfile +0 -13
- package/ios/Podfile.lock +0 -23
|
@@ -47,7 +47,14 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
47
47
|
CAPPluginMethod(name: "startRecordVideo", returnType: CAPPluginReturnPromise),
|
|
48
48
|
CAPPluginMethod(name: "stopRecordVideo", returnType: CAPPluginReturnPromise),
|
|
49
49
|
CAPPluginMethod(name: "getTempFilePath", returnType: CAPPluginReturnPromise),
|
|
50
|
-
CAPPluginMethod(name: "getSupportedPictureSizes", returnType: CAPPluginReturnPromise)
|
|
50
|
+
CAPPluginMethod(name: "getSupportedPictureSizes", returnType: CAPPluginReturnPromise),
|
|
51
|
+
CAPPluginMethod(name: "isRunning", returnType: CAPPluginReturnPromise),
|
|
52
|
+
CAPPluginMethod(name: "getAvailableDevices", returnType: CAPPluginReturnPromise),
|
|
53
|
+
CAPPluginMethod(name: "getZoom", returnType: CAPPluginReturnPromise),
|
|
54
|
+
CAPPluginMethod(name: "setZoom", returnType: CAPPluginReturnPromise),
|
|
55
|
+
CAPPluginMethod(name: "getFlashMode", returnType: CAPPluginReturnPromise),
|
|
56
|
+
CAPPluginMethod(name: "setDeviceId", returnType: CAPPluginReturnPromise),
|
|
57
|
+
CAPPluginMethod(name: "getDeviceId", returnType: CAPPluginReturnPromise)
|
|
51
58
|
]
|
|
52
59
|
// Camera state tracking
|
|
53
60
|
private var isInitializing: Bool = false
|
|
@@ -68,6 +75,39 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
68
75
|
var highResolutionOutput: Bool = false
|
|
69
76
|
var disableAudio: Bool = false
|
|
70
77
|
|
|
78
|
+
// MARK: - Transparency Methods
|
|
79
|
+
|
|
80
|
+
private func makeWebViewTransparent() {
|
|
81
|
+
guard let webView = self.webView else { return }
|
|
82
|
+
|
|
83
|
+
// Define a recursive function to traverse the view hierarchy
|
|
84
|
+
func makeSubviewsTransparent(_ view: UIView) {
|
|
85
|
+
// Set the background color to clear
|
|
86
|
+
view.backgroundColor = .clear
|
|
87
|
+
|
|
88
|
+
// Recurse for all subviews
|
|
89
|
+
for subview in view.subviews {
|
|
90
|
+
makeSubviewsTransparent(subview)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Set the main webView to be transparent
|
|
95
|
+
webView.isOpaque = false
|
|
96
|
+
webView.backgroundColor = .clear
|
|
97
|
+
|
|
98
|
+
// Recursively make all subviews transparent
|
|
99
|
+
makeSubviewsTransparent(webView)
|
|
100
|
+
|
|
101
|
+
// Also ensure the webview's container is transparent
|
|
102
|
+
webView.superview?.backgroundColor = .clear
|
|
103
|
+
|
|
104
|
+
// Force a layout pass to apply changes
|
|
105
|
+
DispatchQueue.main.async {
|
|
106
|
+
webView.setNeedsLayout()
|
|
107
|
+
webView.layoutIfNeeded()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
71
111
|
@objc func rotated() {
|
|
72
112
|
guard let previewView = self.previewView,
|
|
73
113
|
let posX = self.posX,
|
|
@@ -105,6 +145,27 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
105
145
|
}
|
|
106
146
|
|
|
107
147
|
cameraController.updateVideoOrientation()
|
|
148
|
+
|
|
149
|
+
// Ensure webview remains transparent after rotation
|
|
150
|
+
if self.isInitialized {
|
|
151
|
+
self.makeWebViewTransparent()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@objc func appDidBecomeActive() {
|
|
156
|
+
if self.isInitialized {
|
|
157
|
+
DispatchQueue.main.async {
|
|
158
|
+
self.makeWebViewTransparent()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@objc func appWillEnterForeground() {
|
|
164
|
+
if self.isInitialized {
|
|
165
|
+
DispatchQueue.main.async {
|
|
166
|
+
self.makeWebViewTransparent()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
108
169
|
}
|
|
109
170
|
|
|
110
171
|
struct CameraInfo {
|
|
@@ -119,8 +180,11 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
119
180
|
// Discover all available cameras
|
|
120
181
|
let deviceTypes: [AVCaptureDevice.DeviceType] = [
|
|
121
182
|
.builtInWideAngleCamera,
|
|
122
|
-
.builtInTelephotoCamera,
|
|
123
183
|
.builtInUltraWideCamera,
|
|
184
|
+
.builtInTelephotoCamera,
|
|
185
|
+
.builtInDualCamera,
|
|
186
|
+
.builtInDualWideCamera,
|
|
187
|
+
.builtInTripleCamera,
|
|
124
188
|
.builtInTrueDepthCamera
|
|
125
189
|
]
|
|
126
190
|
|
|
@@ -197,6 +261,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
197
261
|
self.isInitializing = true
|
|
198
262
|
|
|
199
263
|
self.cameraPosition = call.getString("position") ?? "rear"
|
|
264
|
+
let deviceId = call.getString("deviceId")
|
|
200
265
|
let cameraMode = call.getBool("cameraMode") ?? false
|
|
201
266
|
self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
|
|
202
267
|
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
@@ -218,7 +283,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
218
283
|
}
|
|
219
284
|
|
|
220
285
|
self.rotateWhenOrientationChanged = call.getBool("rotateWhenOrientationChanged") ?? true
|
|
221
|
-
self.toBack = call.getBool("toBack") ??
|
|
286
|
+
self.toBack = call.getBool("toBack") ?? true
|
|
222
287
|
self.storeToFile = call.getBool("storeToFile") ?? false
|
|
223
288
|
self.enableZoom = call.getBool("enableZoom") ?? false
|
|
224
289
|
self.disableAudio = call.getBool("disableAudio") ?? false
|
|
@@ -233,7 +298,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
233
298
|
if self.cameraController.captureSession?.isRunning ?? false {
|
|
234
299
|
call.reject("camera already started")
|
|
235
300
|
} else {
|
|
236
|
-
self.cameraController.prepare(cameraPosition: self.cameraPosition, disableAudio: self.disableAudio, cameraMode: cameraMode) {error in
|
|
301
|
+
self.cameraController.prepare(cameraPosition: self.cameraPosition, deviceId: deviceId, disableAudio: self.disableAudio, cameraMode: cameraMode) {error in
|
|
237
302
|
if let error = error {
|
|
238
303
|
print(error)
|
|
239
304
|
call.reject(error.localizedDescription)
|
|
@@ -241,9 +306,10 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
241
306
|
}
|
|
242
307
|
let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!
|
|
243
308
|
self.previewView = UIView(frame: CGRect(x: self.posX ?? 0, y: self.posY ?? 0, width: self.width!, height: height))
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
self.
|
|
309
|
+
|
|
310
|
+
// Make webview transparent - comprehensive approach
|
|
311
|
+
self.makeWebViewTransparent()
|
|
312
|
+
|
|
247
313
|
self.webView?.superview?.addSubview(self.previewView)
|
|
248
314
|
if self.toBack! {
|
|
249
315
|
self.webView?.superview?.bringSubviewToFront(self.webView!)
|
|
@@ -256,6 +322,10 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
256
322
|
if self.rotateWhenOrientationChanged == true {
|
|
257
323
|
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
|
|
258
324
|
}
|
|
325
|
+
|
|
326
|
+
// Add observers for app state changes to maintain transparency
|
|
327
|
+
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
|
|
328
|
+
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
|
|
259
329
|
|
|
260
330
|
self.isInitializing = false
|
|
261
331
|
self.isInitialized = true
|
|
@@ -273,34 +343,38 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
273
343
|
call.reject("Camera not initialized")
|
|
274
344
|
return
|
|
275
345
|
}
|
|
276
|
-
|
|
346
|
+
|
|
277
347
|
DispatchQueue.main.async { [weak self] in
|
|
278
348
|
guard let self = self else {
|
|
279
349
|
call.reject("Camera controller deallocated")
|
|
280
350
|
return
|
|
281
351
|
}
|
|
282
|
-
|
|
352
|
+
|
|
283
353
|
// Disable user interaction during flip
|
|
284
354
|
self.previewView.isUserInteractionEnabled = false
|
|
285
|
-
|
|
355
|
+
|
|
286
356
|
// Perform camera switch on background thread
|
|
287
357
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
288
358
|
var retryCount = 0
|
|
289
359
|
let maxRetries = 3
|
|
290
|
-
|
|
360
|
+
|
|
291
361
|
func attemptFlip() {
|
|
292
362
|
do {
|
|
293
363
|
try self.cameraController.switchCameras()
|
|
294
|
-
|
|
364
|
+
|
|
295
365
|
DispatchQueue.main.async {
|
|
296
366
|
self.cameraController.previewLayer?.frame = self.previewView.bounds
|
|
297
367
|
self.cameraController.previewLayer?.videoGravity = .resizeAspectFill
|
|
298
368
|
self.previewView.isUserInteractionEnabled = true
|
|
369
|
+
|
|
370
|
+
// Ensure webview remains transparent after flip
|
|
371
|
+
self.makeWebViewTransparent()
|
|
372
|
+
|
|
299
373
|
call.resolve()
|
|
300
374
|
}
|
|
301
375
|
} catch {
|
|
302
376
|
retryCount += 1
|
|
303
|
-
|
|
377
|
+
|
|
304
378
|
if retryCount < maxRetries {
|
|
305
379
|
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.5) {
|
|
306
380
|
attemptFlip()
|
|
@@ -314,7 +388,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
314
388
|
}
|
|
315
389
|
}
|
|
316
390
|
}
|
|
317
|
-
|
|
391
|
+
|
|
318
392
|
attemptFlip()
|
|
319
393
|
}
|
|
320
394
|
}
|
|
@@ -330,18 +404,21 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
330
404
|
call.reject("camera not initialized")
|
|
331
405
|
return
|
|
332
406
|
}
|
|
333
|
-
|
|
407
|
+
|
|
334
408
|
// Always attempt to stop and clean up, regardless of captureSession state
|
|
335
409
|
if let previewView = self.previewView {
|
|
336
410
|
previewView.removeFromSuperview()
|
|
337
411
|
self.previewView = nil
|
|
338
412
|
}
|
|
339
|
-
|
|
413
|
+
|
|
340
414
|
self.webView?.isOpaque = true
|
|
341
415
|
self.isInitialized = false
|
|
342
416
|
self.isInitializing = false
|
|
343
417
|
self.cameraController.cleanup()
|
|
344
418
|
|
|
419
|
+
// Remove notification observers
|
|
420
|
+
NotificationCenter.default.removeObserver(self)
|
|
421
|
+
|
|
345
422
|
call.resolve()
|
|
346
423
|
}
|
|
347
424
|
}
|
|
@@ -508,4 +585,218 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
508
585
|
}
|
|
509
586
|
}
|
|
510
587
|
|
|
588
|
+
@objc func isRunning(_ call: CAPPluginCall) {
|
|
589
|
+
let isRunning = self.isInitialized && (self.cameraController.captureSession?.isRunning ?? false)
|
|
590
|
+
call.resolve(["isRunning": isRunning])
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
@objc func getAvailableDevices(_ call: CAPPluginCall) {
|
|
594
|
+
let deviceTypes: [AVCaptureDevice.DeviceType] = [
|
|
595
|
+
.builtInWideAngleCamera,
|
|
596
|
+
.builtInUltraWideCamera,
|
|
597
|
+
.builtInTelephotoCamera,
|
|
598
|
+
.builtInDualCamera,
|
|
599
|
+
.builtInDualWideCamera,
|
|
600
|
+
.builtInTripleCamera,
|
|
601
|
+
.builtInTrueDepthCamera
|
|
602
|
+
]
|
|
603
|
+
|
|
604
|
+
let session = AVCaptureDevice.DiscoverySession(
|
|
605
|
+
deviceTypes: deviceTypes,
|
|
606
|
+
mediaType: .video,
|
|
607
|
+
position: .unspecified
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
var devices: [[String: Any]] = []
|
|
611
|
+
|
|
612
|
+
// Collect all devices by position
|
|
613
|
+
for device in session.devices {
|
|
614
|
+
var lenses: [[String: Any]] = []
|
|
615
|
+
|
|
616
|
+
let constituentDevices = device.isVirtualDevice ? device.constituentDevices : [device]
|
|
617
|
+
|
|
618
|
+
for lensDevice in constituentDevices {
|
|
619
|
+
var deviceType: String
|
|
620
|
+
switch lensDevice.deviceType {
|
|
621
|
+
case .builtInWideAngleCamera: deviceType = "wideAngle"
|
|
622
|
+
case .builtInUltraWideCamera: deviceType = "ultraWide"
|
|
623
|
+
case .builtInTelephotoCamera: deviceType = "telephoto"
|
|
624
|
+
case .builtInDualCamera: deviceType = "dual"
|
|
625
|
+
case .builtInDualWideCamera: deviceType = "dualWide"
|
|
626
|
+
case .builtInTripleCamera: deviceType = "triple"
|
|
627
|
+
case .builtInTrueDepthCamera: deviceType = "trueDepth"
|
|
628
|
+
default: deviceType = "unknown"
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
var baseZoomRatio: Float = 1.0
|
|
632
|
+
if lensDevice.deviceType == .builtInUltraWideCamera {
|
|
633
|
+
baseZoomRatio = 0.5
|
|
634
|
+
} else if lensDevice.deviceType == .builtInTelephotoCamera {
|
|
635
|
+
baseZoomRatio = 2.0 // A common value for telephoto lenses
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
let lensInfo: [String: Any] = [
|
|
639
|
+
"label": lensDevice.localizedName,
|
|
640
|
+
"deviceType": deviceType,
|
|
641
|
+
"focalLength": 4.25, // Placeholder
|
|
642
|
+
"baseZoomRatio": baseZoomRatio,
|
|
643
|
+
"minZoom": Float(lensDevice.minAvailableVideoZoomFactor),
|
|
644
|
+
"maxZoom": Float(lensDevice.maxAvailableVideoZoomFactor)
|
|
645
|
+
]
|
|
646
|
+
lenses.append(lensInfo)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
let deviceData: [String: Any] = [
|
|
650
|
+
"deviceId": device.uniqueID,
|
|
651
|
+
"label": device.localizedName,
|
|
652
|
+
"position": device.position == .front ? "front" : "rear",
|
|
653
|
+
"lenses": lenses,
|
|
654
|
+
"minZoom": Float(device.minAvailableVideoZoomFactor),
|
|
655
|
+
"maxZoom": Float(device.maxAvailableVideoZoomFactor),
|
|
656
|
+
"isLogical": device.isVirtualDevice
|
|
657
|
+
]
|
|
658
|
+
|
|
659
|
+
devices.append(deviceData)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
call.resolve(["devices": devices])
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
@objc func getZoom(_ call: CAPPluginCall) {
|
|
666
|
+
guard isInitialized else {
|
|
667
|
+
call.reject("Camera not initialized")
|
|
668
|
+
return
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
do {
|
|
672
|
+
let zoomInfo = try self.cameraController.getZoom()
|
|
673
|
+
let lensInfo = try self.cameraController.getCurrentLensInfo()
|
|
674
|
+
|
|
675
|
+
var minZoom = zoomInfo.min
|
|
676
|
+
var maxZoom = zoomInfo.max
|
|
677
|
+
var currentZoom = zoomInfo.current
|
|
678
|
+
|
|
679
|
+
// If using the multi-lens camera, translate the native zoom values for JS
|
|
680
|
+
if self.cameraController.isUsingMultiLensVirtualCamera {
|
|
681
|
+
minZoom -= 0.5
|
|
682
|
+
maxZoom -= 0.5
|
|
683
|
+
currentZoom -= 0.5
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
call.resolve([
|
|
687
|
+
"min": minZoom,
|
|
688
|
+
"max": maxZoom,
|
|
689
|
+
"current": currentZoom,
|
|
690
|
+
"lens": [
|
|
691
|
+
"focalLength": lensInfo.focalLength,
|
|
692
|
+
"deviceType": lensInfo.deviceType,
|
|
693
|
+
"baseZoomRatio": lensInfo.baseZoomRatio,
|
|
694
|
+
"digitalZoom": Float(currentZoom) / lensInfo.baseZoomRatio
|
|
695
|
+
]
|
|
696
|
+
])
|
|
697
|
+
} catch {
|
|
698
|
+
call.reject("Failed to get zoom: \(error.localizedDescription)")
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
@objc func setZoom(_ call: CAPPluginCall) {
|
|
703
|
+
guard isInitialized else {
|
|
704
|
+
call.reject("Camera not initialized")
|
|
705
|
+
return
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
guard var level = call.getFloat("level") else {
|
|
709
|
+
call.reject("level parameter is required")
|
|
710
|
+
return
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// If using the multi-lens camera, translate the JS zoom value for the native layer
|
|
714
|
+
if self.cameraController.isUsingMultiLensVirtualCamera {
|
|
715
|
+
level += 0.5
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
let ramp = call.getBool("ramp") ?? true
|
|
719
|
+
|
|
720
|
+
do {
|
|
721
|
+
try self.cameraController.setZoom(level: CGFloat(level), ramp: ramp)
|
|
722
|
+
call.resolve()
|
|
723
|
+
} catch {
|
|
724
|
+
call.reject("Failed to set zoom: \(error.localizedDescription)")
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
@objc func getFlashMode(_ call: CAPPluginCall) {
|
|
729
|
+
guard isInitialized else {
|
|
730
|
+
call.reject("Camera not initialized")
|
|
731
|
+
return
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
do {
|
|
735
|
+
let flashMode = try self.cameraController.getFlashMode()
|
|
736
|
+
call.resolve(["flashMode": flashMode])
|
|
737
|
+
} catch {
|
|
738
|
+
call.reject("Failed to get flash mode: \(error.localizedDescription)")
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
@objc func setDeviceId(_ call: CAPPluginCall) {
|
|
743
|
+
guard isInitialized else {
|
|
744
|
+
call.reject("Camera not initialized")
|
|
745
|
+
return
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
guard let deviceId = call.getString("deviceId") else {
|
|
749
|
+
call.reject("deviceId parameter is required")
|
|
750
|
+
return
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
DispatchQueue.main.async { [weak self] in
|
|
754
|
+
guard let self = self else {
|
|
755
|
+
call.reject("Camera controller deallocated")
|
|
756
|
+
return
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Disable user interaction during device swap
|
|
760
|
+
self.previewView.isUserInteractionEnabled = false
|
|
761
|
+
|
|
762
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
763
|
+
do {
|
|
764
|
+
try self.cameraController.swapToDevice(deviceId: deviceId)
|
|
765
|
+
|
|
766
|
+
DispatchQueue.main.async {
|
|
767
|
+
self.cameraController.previewLayer?.frame = self.previewView.bounds
|
|
768
|
+
self.cameraController.previewLayer?.videoGravity = .resizeAspectFill
|
|
769
|
+
self.previewView.isUserInteractionEnabled = true
|
|
770
|
+
|
|
771
|
+
// Ensure webview remains transparent after device switch
|
|
772
|
+
self.makeWebViewTransparent()
|
|
773
|
+
|
|
774
|
+
call.resolve()
|
|
775
|
+
}
|
|
776
|
+
} catch {
|
|
777
|
+
DispatchQueue.main.async {
|
|
778
|
+
self.previewView.isUserInteractionEnabled = true
|
|
779
|
+
call.reject("Failed to swap to device \(deviceId): \(error.localizedDescription)")
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
@objc func getDeviceId(_ call: CAPPluginCall) {
|
|
787
|
+
guard isInitialized else {
|
|
788
|
+
call.reject("Camera not initialized")
|
|
789
|
+
return
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
do {
|
|
793
|
+
let deviceId = try self.cameraController.getCurrentDeviceId()
|
|
794
|
+
call.resolve(["deviceId": deviceId])
|
|
795
|
+
} catch {
|
|
796
|
+
call.reject("Failed to get device ID: \(error.localizedDescription)")
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
511
802
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import CameraViewPlugin
|
|
3
|
+
|
|
4
|
+
class CameraViewTests: XCTestCase {
|
|
5
|
+
func testEcho() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
|
|
9
|
+
let implementation = CameraView()
|
|
10
|
+
let value = "Hello, World!"
|
|
11
|
+
let result = implementation.echo(value)
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(value, result)
|
|
14
|
+
}
|
|
15
|
+
}
|