diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index c057802fe75..9ade0f3942f 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.20+3 + +* Migrates `setZoomLevel` and `setFlashMode` methods to Swift. + ## 0.9.20+2 * Migrates exposure offset and zoom factor limit getters to Swift. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift index 4ebe0efec87..0ea612ce31d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift @@ -45,6 +45,13 @@ final class DefaultCamera: FLTCam, Camera { private var exposureMode = FCPPlatformExposureMode.auto private var focusMode = FCPPlatformFocusMode.auto + private static func flutterErrorFromNSError(_ error: NSError) -> FlutterError { + return FlutterError( + code: "Error \(error.code)", + message: error.localizedDescription, + details: error.domain) + } + func reportInitializationState() { // Get all the state on the current thread, not the main thread. let state = FCPPlatformCameraState.make( @@ -241,6 +248,91 @@ final class DefaultCamera: FLTCam, Camera { return CGPoint(x: x, y: y) } + func setZoomLevel(_ zoom: CGFloat, withCompletion completion: @escaping (FlutterError?) -> Void) { + if zoom < captureDevice.minAvailableVideoZoomFactor + || zoom > captureDevice.maxAvailableVideoZoomFactor + { + completion( + FlutterError( + code: "ZOOM_ERROR", + message: + "Zoom level out of bounds (zoom level should be between \(captureDevice.minAvailableVideoZoomFactor) and \(captureDevice.maxAvailableVideoZoomFactor).", + details: nil)) + return + } + + do { + try captureDevice.lockForConfiguration() + } catch let error as NSError { + completion(DefaultCamera.flutterErrorFromNSError(error)) + return + } + + captureDevice.videoZoomFactor = zoom + captureDevice.unlockForConfiguration() + completion(nil) + } + + func setFlashMode( + _ mode: FCPPlatformFlashMode, + withCompletion completion: @escaping (FlutterError?) -> Void + ) { + switch mode { + case .torch: + guard captureDevice.hasTorch else { + completion( + FlutterError( + code: "setFlashModeFailed", + message: "Device does not support torch mode", + details: nil) + ) + return + } + guard captureDevice.isTorchAvailable else { + completion( + FlutterError( + code: "setFlashModeFailed", + message: "Torch mode is currently not available", + details: nil)) + return + } + if captureDevice.torchMode != .on { + try? captureDevice.lockForConfiguration() + captureDevice.torchMode = .on + captureDevice.unlockForConfiguration() + } + case .off, .auto, .always: + guard captureDevice.hasFlash else { + completion( + FlutterError( + code: "setFlashModeFailed", + message: "Device does not have flash capabilities", + details: nil)) + return + } + let avFlashMode = FCPGetAVCaptureFlashModeForPigeonFlashMode(mode) + guard capturePhotoOutput.supportedFlashModes.contains(NSNumber(value: avFlashMode.rawValue)) + else { + completion( + FlutterError( + code: "setFlashModeFailed", + message: "Device does not support this specific flash mode", + details: nil)) + return + } + if captureDevice.torchMode != .off { + try? captureDevice.lockForConfiguration() + captureDevice.torchMode = .off + captureDevice.unlockForConfiguration() + } + @unknown default: + assertionFailure("Unknown flash mode") + } + + flashMode = mode + completion(nil) + } + func pausePreview() { isPreviewPaused = true } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m index c44b6e184ed..e78375ccbad 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCam.m @@ -55,7 +55,6 @@ @interface FLTCam () *captureDeviceInputFactory; -@property(assign, nonatomic) FCPPlatformFlashMode flashMode; @property(nonatomic, copy) AssetWriterFactory assetWriterFactory; @property(nonatomic, copy) InputPixelBufferAdaptorFactory inputPixelBufferAdaptorFactory; /// Reports the given error message to the Dart side of the plugin. @@ -511,51 +510,6 @@ - (void)stopVideoRecordingWithCompletion:(void (^)(NSString *_Nullable, } } -- (void)setFlashMode:(FCPPlatformFlashMode)mode - withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (mode == FCPPlatformFlashModeTorch) { - if (!_captureDevice.hasTorch) { - completion([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not support torch mode" - details:nil]); - return; - } - if (!_captureDevice.isTorchAvailable) { - completion([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Torch mode is currently not available" - details:nil]); - return; - } - if (_captureDevice.torchMode != AVCaptureTorchModeOn) { - [_captureDevice lockForConfiguration:nil]; - [_captureDevice setTorchMode:AVCaptureTorchModeOn]; - [_captureDevice unlockForConfiguration]; - } - } else { - if (!_captureDevice.hasFlash) { - completion([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not have flash capabilities" - details:nil]); - return; - } - AVCaptureFlashMode avFlashMode = FCPGetAVCaptureFlashModeForPigeonFlashMode(mode); - if (![_capturePhotoOutput.supportedFlashModes - containsObject:[NSNumber numberWithInt:((int)avFlashMode)]]) { - completion([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not support this specific flash mode" - details:nil]); - return; - } - if (_captureDevice.torchMode != AVCaptureTorchModeOff) { - [_captureDevice lockForConfiguration:nil]; - [_captureDevice setTorchMode:AVCaptureTorchModeOff]; - [_captureDevice unlockForConfiguration]; - } - } - _flashMode = mode; - completion(nil); -} - - (void)setDescriptionWhileRecording:(NSString *)cameraName withCompletion:(void (^)(FlutterError *_Nullable))completion { if (!_isRecording) { @@ -667,29 +621,6 @@ - (void)stopImageStream { } } -- (void)setZoomLevel:(CGFloat)zoom withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (_captureDevice.maxAvailableVideoZoomFactor < zoom || - _captureDevice.minAvailableVideoZoomFactor > zoom) { - NSString *errorMessage = [NSString - stringWithFormat:@"Zoom level out of bounds (zoom level should be between %f and %f).", - _captureDevice.minAvailableVideoZoomFactor, - _captureDevice.maxAvailableVideoZoomFactor]; - - completion([FlutterError errorWithCode:@"ZOOM_ERROR" message:errorMessage details:nil]); - return; - } - - NSError *error = nil; - if (![_captureDevice lockForConfiguration:&error]) { - completion(FlutterErrorFromNSError(error)); - return; - } - _captureDevice.videoZoomFactor = zoom; - [_captureDevice unlockForConfiguration]; - - completion(nil); -} - - (BOOL)setupWriterForPath:(NSString *)path { NSError *error = nil; NSURL *outputURL; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h index 6802202e26f..a74b9951be0 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCam.h @@ -50,6 +50,7 @@ NS_ASSUME_NONNULL_BEGIN @property(readonly, nonatomic) NSObject *deviceOrientationProvider; @property(assign, nonatomic) UIDeviceOrientation lockedCaptureOrientation; @property(assign, nonatomic) UIDeviceOrientation deviceOrientation; +@property(assign, nonatomic) FCPPlatformFlashMode flashMode; /// Initializes an `FLTCam` instance with the given configuration. /// @param error report to the caller if any error happened creating the camera. @@ -66,8 +67,6 @@ NS_ASSUME_NONNULL_BEGIN messengerForStreaming:(nullable NSObject *)messenger; - (void)stopVideoRecordingWithCompletion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; -- (void)setFlashMode:(FCPPlatformFlashMode)mode - withCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)setDescriptionWhileRecording:(NSString *)cameraName withCompletion:(void (^)(FlutterError *_Nullable))completion; @@ -75,7 +74,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)startImageStreamWithMessenger:(NSObject *)messenger completion:(nonnull void (^)(FlutterError *_Nullable))completion; - (void)stopImageStream; -- (void)setZoomLevel:(CGFloat)zoom withCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)setUpCaptureSessionForAudioIfNeeded; // Methods exposed for the Swift DefaultCamera subclass diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 779bc7fb09f..efeeb8dfc36 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.20+2 +version: 0.9.20+3 environment: sdk: ^3.6.0