@capgo/camera-preview 7.4.0-beta.6 → 7.4.0-beta.8
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/README.md +98 -30
- 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/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/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +170 -30
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +510 -15
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +2 -0
- package/dist/docs.json +100 -9
- package/dist/esm/definitions.d.ts +64 -8
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +34 -4
- package/dist/esm/web.js +94 -16
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +94 -16
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +94 -16
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +129 -30
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +334 -79
- package/package.json +1 -1
|
@@ -60,11 +60,16 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
60
60
|
CAPPluginMethod(name: "setDeviceId", returnType: CAPPluginReturnPromise),
|
|
61
61
|
CAPPluginMethod(name: "getDeviceId", returnType: CAPPluginReturnPromise),
|
|
62
62
|
CAPPluginMethod(name: "setAspectRatio", returnType: CAPPluginReturnPromise),
|
|
63
|
-
CAPPluginMethod(name: "getAspectRatio", returnType: CAPPluginReturnPromise)
|
|
63
|
+
CAPPluginMethod(name: "getAspectRatio", returnType: CAPPluginReturnPromise),
|
|
64
|
+
CAPPluginMethod(name: "setGridMode", returnType: CAPPluginReturnPromise),
|
|
65
|
+
CAPPluginMethod(name: "getGridMode", returnType: CAPPluginReturnPromise),
|
|
66
|
+
CAPPluginMethod(name: "getPreviewSize", returnType: CAPPluginReturnPromise),
|
|
67
|
+
CAPPluginMethod(name: "setPreviewSize", returnType: CAPPluginReturnPromise)
|
|
64
68
|
]
|
|
65
69
|
// Camera state tracking
|
|
66
70
|
private var isInitializing: Bool = false
|
|
67
71
|
private var isInitialized: Bool = false
|
|
72
|
+
private var backgroundSession: AVCaptureSession?
|
|
68
73
|
|
|
69
74
|
var previewView: UIView!
|
|
70
75
|
var cameraPosition = String()
|
|
@@ -83,7 +88,8 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
83
88
|
var locationManager: CLLocationManager?
|
|
84
89
|
var currentLocation: CLLocation?
|
|
85
90
|
private var aspectRatio: String?
|
|
86
|
-
|
|
91
|
+
private var gridMode: String = "none"
|
|
92
|
+
|
|
87
93
|
// MARK: - Transparency Methods
|
|
88
94
|
|
|
89
95
|
|
|
@@ -135,14 +141,26 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
135
141
|
let paddingBottom = self.paddingBottom ?? 0
|
|
136
142
|
let height = heightValue - paddingBottom
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// Handle auto-centering during rotation
|
|
145
|
+
if posX == -1 || posY == -1 {
|
|
146
|
+
// Trigger full recalculation for auto-centered views
|
|
147
|
+
self.updateCameraFrame()
|
|
148
|
+
} else {
|
|
149
|
+
// Manual positioning - use original rotation logic with no animation
|
|
150
|
+
CATransaction.begin()
|
|
151
|
+
CATransaction.setDisableActions(true)
|
|
152
|
+
|
|
153
|
+
if UIWindow.isLandscape {
|
|
154
|
+
previewView.frame = CGRect(x: posY, y: posX, width: max(height, width), height: min(height, width))
|
|
155
|
+
self.cameraController.previewLayer?.frame = previewView.bounds
|
|
156
|
+
}
|
|
142
157
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
if UIWindow.isPortrait {
|
|
159
|
+
previewView.frame = CGRect(x: posX, y: posY, width: min(height, width), height: max(height, width))
|
|
160
|
+
self.cameraController.previewLayer?.frame = previewView.bounds
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
CATransaction.commit()
|
|
146
164
|
}
|
|
147
165
|
|
|
148
166
|
if let connection = self.cameraController.fileVideoOutput?.connection(with: .video) {
|
|
@@ -162,11 +180,14 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
162
180
|
|
|
163
181
|
cameraController.updateVideoOrientation()
|
|
164
182
|
|
|
165
|
-
|
|
183
|
+
cameraController.updateVideoOrientation()
|
|
166
184
|
|
|
167
|
-
// Update grid overlay frame if it exists
|
|
185
|
+
// Update grid overlay frame if it exists - no animation
|
|
168
186
|
if let gridOverlay = self.cameraController.gridOverlayView {
|
|
187
|
+
CATransaction.begin()
|
|
188
|
+
CATransaction.setDisableActions(true)
|
|
169
189
|
gridOverlay.frame = previewView.bounds
|
|
190
|
+
CATransaction.commit()
|
|
170
191
|
}
|
|
171
192
|
|
|
172
193
|
// Ensure webview remains transparent after rotation
|
|
@@ -174,15 +195,71 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
174
195
|
self.makeWebViewTransparent()
|
|
175
196
|
}
|
|
176
197
|
}
|
|
177
|
-
|
|
198
|
+
|
|
178
199
|
@objc func setAspectRatio(_ call: CAPPluginCall) {
|
|
179
200
|
guard self.isInitialized else {
|
|
180
201
|
call.reject("camera not started")
|
|
181
202
|
return
|
|
182
203
|
}
|
|
183
|
-
|
|
204
|
+
|
|
205
|
+
guard let newAspectRatio = call.getString("aspectRatio") else {
|
|
206
|
+
call.reject("aspectRatio parameter is required")
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
self.aspectRatio = newAspectRatio
|
|
211
|
+
|
|
212
|
+
// When aspect ratio changes, calculate maximum size possible from current position
|
|
213
|
+
if let posX = self.posX, let posY = self.posY {
|
|
214
|
+
let webViewWidth = self.webView?.frame.width ?? UIScreen.main.bounds.width
|
|
215
|
+
let webViewHeight = self.webView?.frame.height ?? UIScreen.main.bounds.height
|
|
216
|
+
let paddingBottom = self.paddingBottom ?? 0
|
|
217
|
+
|
|
218
|
+
// Calculate available space from current position
|
|
219
|
+
let availableWidth: CGFloat
|
|
220
|
+
let availableHeight: CGFloat
|
|
221
|
+
|
|
222
|
+
if posX == -1 || posY == -1 {
|
|
223
|
+
// Auto-centering mode - use full dimensions
|
|
224
|
+
availableWidth = webViewWidth
|
|
225
|
+
availableHeight = webViewHeight - paddingBottom
|
|
226
|
+
} else {
|
|
227
|
+
// Manual positioning - calculate remaining space
|
|
228
|
+
availableWidth = webViewWidth - posX
|
|
229
|
+
availableHeight = webViewHeight - posY - paddingBottom
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Parse aspect ratio - convert to portrait orientation for camera use
|
|
233
|
+
let ratioParts = newAspectRatio.split(separator: ":").map { Double($0) ?? 1.0 }
|
|
234
|
+
// For camera, we want portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
235
|
+
let ratio = ratioParts[1] / ratioParts[0]
|
|
236
|
+
|
|
237
|
+
// Calculate maximum size that fits the aspect ratio in available space
|
|
238
|
+
let maxWidthByHeight = availableHeight * CGFloat(ratio)
|
|
239
|
+
let maxHeightByWidth = availableWidth / CGFloat(ratio)
|
|
240
|
+
|
|
241
|
+
if maxWidthByHeight <= availableWidth {
|
|
242
|
+
// Height is the limiting factor
|
|
243
|
+
self.width = maxWidthByHeight
|
|
244
|
+
self.height = availableHeight
|
|
245
|
+
} else {
|
|
246
|
+
// Width is the limiting factor
|
|
247
|
+
self.width = availableWidth
|
|
248
|
+
self.height = maxHeightByWidth
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
print("[CameraPreview] Aspect ratio changed to \(newAspectRatio), new size: \(self.width!)x\(self.height!)")
|
|
252
|
+
}
|
|
253
|
+
|
|
184
254
|
self.updateCameraFrame()
|
|
185
|
-
|
|
255
|
+
|
|
256
|
+
// Return the actual preview bounds
|
|
257
|
+
var result = JSObject()
|
|
258
|
+
result["x"] = Double(self.previewView.frame.origin.x)
|
|
259
|
+
result["y"] = Double(self.previewView.frame.origin.y)
|
|
260
|
+
result["width"] = Double(self.previewView.frame.width)
|
|
261
|
+
result["height"] = Double(self.previewView.frame.height)
|
|
262
|
+
call.resolve(result)
|
|
186
263
|
}
|
|
187
264
|
|
|
188
265
|
@objc func getAspectRatio(_ call: CAPPluginCall) {
|
|
@@ -190,9 +267,42 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
190
267
|
call.reject("camera not started")
|
|
191
268
|
return
|
|
192
269
|
}
|
|
193
|
-
call.resolve(["aspectRatio": self.aspectRatio ?? "
|
|
270
|
+
call.resolve(["aspectRatio": self.aspectRatio ?? "4:3"])
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
@objc func setGridMode(_ call: CAPPluginCall) {
|
|
274
|
+
guard self.isInitialized else {
|
|
275
|
+
call.reject("camera not started")
|
|
276
|
+
return
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
guard let gridMode = call.getString("gridMode") else {
|
|
280
|
+
call.reject("gridMode parameter is required")
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
self.gridMode = gridMode
|
|
285
|
+
|
|
286
|
+
// Update grid overlay
|
|
287
|
+
DispatchQueue.main.async {
|
|
288
|
+
if gridMode == "none" {
|
|
289
|
+
self.cameraController.removeGridOverlay()
|
|
290
|
+
} else {
|
|
291
|
+
self.cameraController.addGridOverlay(to: self.previewView, gridMode: gridMode)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
call.resolve()
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@objc func getGridMode(_ call: CAPPluginCall) {
|
|
299
|
+
guard self.isInitialized else {
|
|
300
|
+
call.reject("camera not started")
|
|
301
|
+
return
|
|
302
|
+
}
|
|
303
|
+
call.resolve(["gridMode": self.gridMode])
|
|
194
304
|
}
|
|
195
|
-
|
|
305
|
+
|
|
196
306
|
@objc func appDidBecomeActive() {
|
|
197
307
|
if self.isInitialized {
|
|
198
308
|
DispatchQueue.main.async {
|
|
@@ -308,18 +418,33 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
308
418
|
self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
|
|
309
419
|
self.cameraController.highResolutionOutput = self.highResolutionOutput
|
|
310
420
|
|
|
311
|
-
|
|
312
|
-
|
|
421
|
+
// Set width - use screen width if not provided or if 0
|
|
422
|
+
if let width = call.getInt("width"), width > 0 {
|
|
423
|
+
self.width = CGFloat(width)
|
|
313
424
|
} else {
|
|
314
425
|
self.width = UIScreen.main.bounds.size.width
|
|
315
426
|
}
|
|
316
|
-
|
|
317
|
-
|
|
427
|
+
|
|
428
|
+
// Set height - use screen height if not provided or if 0
|
|
429
|
+
if let height = call.getInt("height"), height > 0 {
|
|
430
|
+
self.height = CGFloat(height)
|
|
318
431
|
} else {
|
|
319
432
|
self.height = UIScreen.main.bounds.size.height
|
|
320
433
|
}
|
|
321
|
-
|
|
322
|
-
|
|
434
|
+
|
|
435
|
+
// Set x position - use exact CSS pixel value from web view, or mark for centering
|
|
436
|
+
if let x = call.getInt("x") {
|
|
437
|
+
self.posX = CGFloat(x)
|
|
438
|
+
} else {
|
|
439
|
+
self.posX = -1 // Use -1 to indicate auto-centering
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Set y position - use exact CSS pixel value from web view, or mark for centering
|
|
443
|
+
if let y = call.getInt("y") {
|
|
444
|
+
self.posY = CGFloat(y)
|
|
445
|
+
} else {
|
|
446
|
+
self.posY = -1 // Use -1 to indicate auto-centering
|
|
447
|
+
}
|
|
323
448
|
if call.getInt("paddingBottom") != nil {
|
|
324
449
|
self.paddingBottom = CGFloat(call.getInt("paddingBottom")!)
|
|
325
450
|
}
|
|
@@ -330,7 +455,15 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
330
455
|
self.enableZoom = call.getBool("enableZoom") ?? false
|
|
331
456
|
self.disableAudio = call.getBool("disableAudio") ?? true
|
|
332
457
|
self.aspectRatio = call.getString("aspectRatio")
|
|
333
|
-
|
|
458
|
+
self.gridMode = call.getString("gridMode") ?? "none"
|
|
459
|
+
if self.aspectRatio != nil && (call.getInt("width") != nil || call.getInt("height") != nil) {
|
|
460
|
+
call.reject("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start.")
|
|
461
|
+
return
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
print("[CameraPreview] Camera start parameters - aspectRatio: \(String(describing: self.aspectRatio)), gridMode: \(self.gridMode)")
|
|
465
|
+
print("[CameraPreview] Screen dimensions: \(UIScreen.main.bounds.size)")
|
|
466
|
+
print("[CameraPreview] Final frame dimensions - width: \(self.width), height: \(self.height), x: \(self.posX), y: \(self.posY)")
|
|
334
467
|
|
|
335
468
|
AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
|
|
336
469
|
guard granted else {
|
|
@@ -348,55 +481,73 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
348
481
|
call.reject(error.localizedDescription)
|
|
349
482
|
return
|
|
350
483
|
}
|
|
351
|
-
self.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
484
|
+
self.completeStartCamera(call: call)
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
}
|
|
355
490
|
|
|
491
|
+
override public func load() {
|
|
492
|
+
super.load()
|
|
493
|
+
// Initialize camera session in background for faster startup
|
|
494
|
+
prepareBackgroundCamera()
|
|
495
|
+
}
|
|
356
496
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
497
|
+
private func prepareBackgroundCamera() {
|
|
498
|
+
DispatchQueue.global(qos: .background).async {
|
|
499
|
+
AVCaptureDevice.requestAccess(for: .video) { granted in
|
|
500
|
+
guard granted else { return }
|
|
501
|
+
|
|
502
|
+
// Pre-initialize camera controller for faster startup
|
|
503
|
+
DispatchQueue.main.async {
|
|
504
|
+
self.cameraController.prepareBasicSession()
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
362
509
|
|
|
363
|
-
|
|
364
|
-
|
|
510
|
+
private func completeStartCamera(call: CAPPluginCall) {
|
|
511
|
+
// Create and configure the preview view first
|
|
512
|
+
self.updateCameraFrame()
|
|
365
513
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
self.cameraController.addGridOverlay(to: self.previewView, gridMode: gridMode)
|
|
369
|
-
}
|
|
514
|
+
// Make webview transparent - comprehensive approach
|
|
515
|
+
self.makeWebViewTransparent()
|
|
370
516
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
517
|
+
// Add the preview view to the webview itself to use same coordinate system
|
|
518
|
+
self.webView?.addSubview(self.previewView)
|
|
519
|
+
if self.toBack! {
|
|
520
|
+
self.webView?.sendSubviewToBack(self.previewView)
|
|
521
|
+
}
|
|
375
522
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
523
|
+
// Display the camera preview on the configured view
|
|
524
|
+
try? self.cameraController.displayPreview(on: self.previewView)
|
|
525
|
+
|
|
526
|
+
let frontView = self.toBack! ? self.webView : self.previewView
|
|
527
|
+
self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom!)
|
|
379
528
|
|
|
529
|
+
// Add grid overlay if enabled
|
|
530
|
+
if self.gridMode != "none" {
|
|
531
|
+
self.cameraController.addGridOverlay(to: self.previewView, gridMode: self.gridMode)
|
|
532
|
+
}
|
|
380
533
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
534
|
+
if self.rotateWhenOrientationChanged == true {
|
|
535
|
+
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.rotated), name: UIDevice.orientationDidChangeNotification, object: nil)
|
|
536
|
+
}
|
|
384
537
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
var returnedObject = JSObject()
|
|
389
|
-
returnedObject["width"] = self.previewView.frame.width as any JSValue
|
|
390
|
-
returnedObject["height"] = self.previewView.frame.height as any JSValue
|
|
391
|
-
returnedObject["x"] = self.previewView.frame.origin.x as any JSValue
|
|
392
|
-
returnedObject["y"] = self.previewView.frame.origin.y as any JSValue
|
|
393
|
-
call.resolve(returnedObject)
|
|
538
|
+
// Add observers for app state changes to maintain transparency
|
|
539
|
+
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.appDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
|
|
540
|
+
NotificationCenter.default.addObserver(self, selector: #selector(CameraPreview.appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
|
|
394
541
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
})
|
|
542
|
+
self.isInitializing = false
|
|
543
|
+
self.isInitialized = true
|
|
399
544
|
|
|
545
|
+
var returnedObject = JSObject()
|
|
546
|
+
returnedObject["width"] = self.previewView.frame.width as any JSValue
|
|
547
|
+
returnedObject["height"] = self.previewView.frame.height as any JSValue
|
|
548
|
+
returnedObject["x"] = self.previewView.frame.origin.x as any JSValue
|
|
549
|
+
returnedObject["y"] = self.previewView.frame.origin.y as any JSValue
|
|
550
|
+
call.resolve(returnedObject)
|
|
400
551
|
}
|
|
401
552
|
|
|
402
553
|
@objc func flip(_ call: CAPPluginCall) {
|
|
@@ -424,8 +575,13 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
424
575
|
try self.cameraController.switchCameras()
|
|
425
576
|
|
|
426
577
|
DispatchQueue.main.async {
|
|
578
|
+
// Update preview layer frame without animation
|
|
579
|
+
CATransaction.begin()
|
|
580
|
+
CATransaction.setDisableActions(true)
|
|
427
581
|
self.cameraController.previewLayer?.frame = self.previewView.bounds
|
|
428
582
|
self.cameraController.previewLayer?.videoGravity = .resizeAspectFill
|
|
583
|
+
CATransaction.commit()
|
|
584
|
+
|
|
429
585
|
self.previewView.isUserInteractionEnabled = true
|
|
430
586
|
|
|
431
587
|
|
|
@@ -876,8 +1032,13 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
876
1032
|
try self.cameraController.swapToDevice(deviceId: deviceId)
|
|
877
1033
|
|
|
878
1034
|
DispatchQueue.main.async {
|
|
1035
|
+
// Update preview layer frame without animation
|
|
1036
|
+
CATransaction.begin()
|
|
1037
|
+
CATransaction.setDisableActions(true)
|
|
879
1038
|
self.cameraController.previewLayer?.frame = self.previewView.bounds
|
|
880
1039
|
self.cameraController.previewLayer?.videoGravity = .resizeAspectFill
|
|
1040
|
+
CATransaction.commit()
|
|
1041
|
+
|
|
881
1042
|
self.previewView.isUserInteractionEnabled = true
|
|
882
1043
|
|
|
883
1044
|
|
|
@@ -921,36 +1082,130 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
921
1082
|
}
|
|
922
1083
|
|
|
923
1084
|
private func updateCameraFrame() {
|
|
924
|
-
guard let width = self.width, var height = self.height, let posX = self.posX, let posY = self.posY else {
|
|
1085
|
+
guard let width = self.width, var height = self.height, let posX = self.posX, let posY = self.posY else {
|
|
1086
|
+
return
|
|
1087
|
+
}
|
|
1088
|
+
|
|
925
1089
|
let paddingBottom = self.paddingBottom ?? 0
|
|
926
1090
|
height -= paddingBottom
|
|
927
1091
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1092
|
+
// Cache webView dimensions for performance
|
|
1093
|
+
let webViewWidth = self.webView?.frame.width ?? UIScreen.main.bounds.width
|
|
1094
|
+
let webViewHeight = self.webView?.frame.height ?? UIScreen.main.bounds.height
|
|
1095
|
+
|
|
1096
|
+
var finalX = posX
|
|
1097
|
+
var finalY = posY
|
|
1098
|
+
var finalWidth = width
|
|
1099
|
+
var finalHeight = height
|
|
1100
|
+
|
|
1101
|
+
// Handle auto-centering when position is -1
|
|
1102
|
+
if posX == -1 || posY == -1 {
|
|
1103
|
+
finalWidth = webViewWidth
|
|
1104
|
+
|
|
1105
|
+
// Calculate height based on aspect ratio or use provided height
|
|
1106
|
+
if let aspectRatio = self.aspectRatio {
|
|
1107
|
+
let ratioParts = aspectRatio.split(separator: ":").compactMap { Double($0) }
|
|
1108
|
+
if ratioParts.count == 2 {
|
|
1109
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
1110
|
+
let ratio = ratioParts[1] / ratioParts[0]
|
|
1111
|
+
finalHeight = finalWidth / CGFloat(ratio)
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
finalX = posX == -1 ? 0 : posX
|
|
1116
|
+
|
|
1117
|
+
if posY == -1 {
|
|
1118
|
+
let availableHeight = webViewHeight - paddingBottom
|
|
1119
|
+
finalY = finalHeight < availableHeight ? (availableHeight - finalHeight) / 2 : 0
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
935
1122
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1123
|
+
var frame = CGRect(x: finalX, y: finalY, width: finalWidth, height: finalHeight)
|
|
1124
|
+
|
|
1125
|
+
// Apply aspect ratio adjustments only if not auto-centering
|
|
1126
|
+
if posX != -1 && posY != -1, let aspectRatio = self.aspectRatio {
|
|
1127
|
+
let ratioParts = aspectRatio.split(separator: ":").compactMap { Double($0) }
|
|
1128
|
+
if ratioParts.count == 2 {
|
|
1129
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
1130
|
+
let ratio = ratioParts[1] / ratioParts[0]
|
|
1131
|
+
let currentRatio = Double(finalWidth) / Double(finalHeight)
|
|
1132
|
+
|
|
1133
|
+
if currentRatio > ratio {
|
|
1134
|
+
let newWidth = Double(finalHeight) * ratio
|
|
1135
|
+
frame.origin.x = finalX + (Double(finalWidth) - newWidth) / 2
|
|
1136
|
+
frame.size.width = CGFloat(newWidth)
|
|
1137
|
+
} else {
|
|
1138
|
+
let newHeight = Double(finalWidth) / ratio
|
|
1139
|
+
frame.origin.y = finalY + (Double(finalHeight) - newHeight) / 2
|
|
1140
|
+
frame.size.height = CGFloat(newHeight)
|
|
1141
|
+
}
|
|
944
1142
|
}
|
|
945
1143
|
}
|
|
1144
|
+
|
|
1145
|
+
// Disable ALL animations for frame updates - we want instant positioning
|
|
1146
|
+
CATransaction.begin()
|
|
1147
|
+
CATransaction.setDisableActions(true)
|
|
946
1148
|
|
|
1149
|
+
// Batch UI updates for better performance
|
|
947
1150
|
if self.previewView == nil {
|
|
948
1151
|
self.previewView = UIView(frame: frame)
|
|
1152
|
+
self.previewView.backgroundColor = UIColor.clear
|
|
949
1153
|
} else {
|
|
950
1154
|
self.previewView.frame = frame
|
|
951
1155
|
}
|
|
1156
|
+
|
|
1157
|
+
// Update preview layer frame efficiently
|
|
1158
|
+
if let previewLayer = self.cameraController.previewLayer {
|
|
1159
|
+
previewLayer.frame = self.previewView.bounds
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Update grid overlay frame if it exists
|
|
1163
|
+
if let gridOverlay = self.cameraController.gridOverlayView {
|
|
1164
|
+
gridOverlay.frame = self.previewView.bounds
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
CATransaction.commit()
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
@objc func getPreviewSize(_ call: CAPPluginCall) {
|
|
1171
|
+
guard self.isInitialized else {
|
|
1172
|
+
call.reject("camera not started")
|
|
1173
|
+
return
|
|
1174
|
+
}
|
|
1175
|
+
var result = JSObject()
|
|
1176
|
+
result["x"] = Double(self.previewView.frame.origin.x)
|
|
1177
|
+
result["y"] = Double(self.previewView.frame.origin.y)
|
|
1178
|
+
result["width"] = Double(self.previewView.frame.width)
|
|
1179
|
+
result["height"] = Double(self.previewView.frame.height)
|
|
1180
|
+
call.resolve(result)
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
@objc func setPreviewSize(_ call: CAPPluginCall) {
|
|
1184
|
+
guard self.isInitialized else {
|
|
1185
|
+
call.reject("camera not started")
|
|
1186
|
+
return
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// Only update position if explicitly provided, otherwise keep auto-centering
|
|
1190
|
+
if let x = call.getInt("x") {
|
|
1191
|
+
self.posX = CGFloat(x)
|
|
1192
|
+
}
|
|
1193
|
+
if let y = call.getInt("y") {
|
|
1194
|
+
self.posY = CGFloat(y)
|
|
1195
|
+
}
|
|
1196
|
+
if let width = call.getInt("width") { self.width = CGFloat(width) }
|
|
1197
|
+
if let height = call.getInt("height") { self.height = CGFloat(height) }
|
|
1198
|
+
|
|
1199
|
+
// Direct update without animation for better performance
|
|
1200
|
+
self.updateCameraFrame()
|
|
1201
|
+
self.makeWebViewTransparent()
|
|
952
1202
|
|
|
953
|
-
//
|
|
954
|
-
|
|
1203
|
+
// Return the actual preview bounds
|
|
1204
|
+
var result = JSObject()
|
|
1205
|
+
result["x"] = Double(self.previewView.frame.origin.x)
|
|
1206
|
+
result["y"] = Double(self.previewView.frame.origin.y)
|
|
1207
|
+
result["width"] = Double(self.previewView.frame.width)
|
|
1208
|
+
result["height"] = Double(self.previewView.frame.height)
|
|
1209
|
+
call.resolve(result)
|
|
955
1210
|
}
|
|
956
1211
|
}
|