From 876f7bc3a10b5ec419ba3946cc0953c613022d0e Mon Sep 17 00:00:00 2001 From: Amanda Date: Wed, 27 Jun 2018 22:20:23 -0700 Subject: [PATCH 1/5] Implemented no dialog option Made AVCam alert optional, added no permissions state to camera view --- Source/SwiftyCamViewController.swift | 92 ++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 1d058ca..94b663b 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -158,6 +158,8 @@ open class SwiftyCamViewController: UIViewController { /// Setting to true will prompt user for access to microphone on View Controller launch. public var audioEnabled = true + public var usePermissionAlert = true + /// Public access to Pinch Gesture fileprivate(set) public var pinchGesture : UIPinchGestureRecognizer! @@ -206,6 +208,31 @@ open class SwiftyCamViewController: UIViewController { /// Variable to store result of capture session setup fileprivate var setupResult = SessionSetupResult.success + + fileprivate lazy var permissionErrorLabel : UILabel = { + let label = UILabel() + label.textColor = UIColor.white + label.font = UIFont.systemFont(ofSize: 17) + label.numberOfLines = 2 + label.textAlignment = .center + label.text = "Please enable this app's\ncamera permissions." + label.translatesAutoresizingMaskIntoConstraints = false + label.isHidden = true + return label + }() + + fileprivate lazy var permissionErrorButton : UIButton = { + let button = UIButton() + button.setTitleColor(UIColor.white, for: .normal) + button.setTitle("Open Settings", for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 14) + button.layer.borderColor = UIColor.white.cgColor + button.layer.borderWidth = 1 + button.translatesAutoresizingMaskIntoConstraints = false + button.isHidden = true + button.addTarget(self, action: #selector(openSettings), for: .touchUpInside) + return button + }() /// BackgroundID variable for video recording @@ -259,6 +286,21 @@ open class SwiftyCamViewController: UIViewController { previewLayer.center = view.center view.addSubview(previewLayer) view.sendSubview(toBack: previewLayer) + + // adds error label and button if camera permissions are denied + view.addSubview(permissionErrorLabel) + view.addSubview(permissionErrorButton) + + // centers error label and button + NSLayoutConstraint.activate([permissionErrorLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + permissionErrorLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), + permissionErrorLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15), + permissionErrorLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -15), + permissionErrorLabel.heightAnchor.constraint(equalToConstant: 50), + permissionErrorButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + permissionErrorButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 55), + permissionErrorButton.heightAnchor.constraint(equalToConstant: 30), + permissionErrorButton.widthAnchor.constraint(equalToConstant: 150)]) // Add Gesture Recognizers @@ -855,25 +897,37 @@ open class SwiftyCamViewController: UIViewController { /// Handle Denied App Privacy Settings - fileprivate func promptToAppSettings() { - // prompt User with UIAlertView - - DispatchQueue.main.async(execute: { [unowned self] in - let message = NSLocalizedString("AVCam doesn't have permission to use the camera, please change privacy settings", comment: "Alert message when the user has denied access to the camera") - let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) - alertController.addAction(UIAlertAction(title: NSLocalizedString("Settings", comment: "Alert button to open Settings"), style: .default, handler: { action in - if #available(iOS 10.0, *) { - UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) - } else { - if let appSettings = URL(string: UIApplicationOpenSettingsURLString) { - UIApplication.shared.openURL(appSettings) - } - } - })) - self.present(alertController, animated: true, completion: nil) - }) - } + fileprivate func promptToAppSettings() { + if usePermissionAlert { + // prompt User with UIAlertView + + DispatchQueue.main.async(execute: { [unowned self] in + let message = NSLocalizedString("AVCam doesn't have permission to use the camera, please change privacy settings", comment: "Alert message when the user has denied access to the camera") + let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: NSLocalizedString("Settings", comment: "Alert button to open Settings"), style: .default, handler: { action in + self.openSettings() + })) + self.present(alertController, animated: true, completion: nil) + }) + } else { + DispatchQueue.main.async { + self.permissionErrorLabel.isHidden = false + self.permissionErrorButton.isHidden = false + } + } + + } + + func openSettings() { + if #available(iOS 10.0, *) { + UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) + } else { + if let appSettings = URL(string: UIApplicationOpenSettingsURLString) { + UIApplication.shared.openURL(appSettings) + } + } + } /** Returns an AVCapturePreset from VideoQuality Enumeration From beab24dab4a4070b8bd4b1332a821bf01d1b0dac Mon Sep 17 00:00:00 2001 From: Amanda Date: Thu, 28 Jun 2018 21:49:46 -0700 Subject: [PATCH 2/5] Fixed camera bleed and brief camera screen flash --- Source/SwiftyCamViewController.swift | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 94b663b..e8d6154 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -275,6 +275,12 @@ open class SwiftyCamViewController: UIViewController { override open var shouldAutorotate: Bool { return allowAutoRotate } + + // makes camera full screen, no bleed or borders + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.videoGravity = .resizeAspectFill + } // MARK: ViewDidLoad @@ -437,19 +443,19 @@ open class SwiftyCamViewController: UIViewController { super.viewDidDisappear(animated) // If session is running, stop the session - if self.isSessionRunning == true { - self.session.stopRunning() - self.isSessionRunning = false - } +// if self.isSessionRunning == true { +// self.session.stopRunning() +// self.isSessionRunning = false +// } //Disble flash if it is currently enabled disableFlash() // Unsubscribe from device rotation notifications - if shouldUseDeviceOrientation { - unsubscribeFromDeviceOrientationChangeNotifications() - } - } +// if shouldUseDeviceOrientation { +// unsubscribeFromDeviceOrientationChangeNotifications() +// } +// } // MARK: Public Functions From f56fdd757f279f807765ca940651dfdc2eb55599 Mon Sep 17 00:00:00 2001 From: Amanda Date: Thu, 28 Jun 2018 22:08:22 -0700 Subject: [PATCH 3/5] Messed with whitespace, changed deployment targets --- Source/SwiftyCamViewController.swift | 1658 +++++++++++++------------- SwiftyCam.podspec | 4 +- 2 files changed, 831 insertions(+), 831 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index e8d6154..017668b 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -23,113 +23,113 @@ import AVFoundation open class SwiftyCamViewController: UIViewController { - // MARK: Enumeration Declaration + // MARK: Enumeration Declaration - /// Enumeration for Camera Selection + /// Enumeration for Camera Selection - public enum CameraSelection { + public enum CameraSelection { - /// Camera on the back of the device - case rear + /// Camera on the back of the device + case rear - /// Camera on the front of the device - case front - } + /// Camera on the front of the device + case front + } - /// Enumeration for video quality of the capture session. Corresponds to a AVCaptureSessionPreset + /// Enumeration for video quality of the capture session. Corresponds to a AVCaptureSessionPreset - public enum VideoQuality { + public enum VideoQuality { - /// AVCaptureSessionPresetHigh - case high + /// AVCaptureSessionPresetHigh + case high - /// AVCaptureSessionPresetMedium - case medium + /// AVCaptureSessionPresetMedium + case medium - /// AVCaptureSessionPresetLow - case low + /// AVCaptureSessionPresetLow + case low - /// AVCaptureSessionPreset352x288 - case resolution352x288 + /// AVCaptureSessionPreset352x288 + case resolution352x288 - /// AVCaptureSessionPreset640x480 - case resolution640x480 + /// AVCaptureSessionPreset640x480 + case resolution640x480 - /// AVCaptureSessionPreset1280x720 - case resolution1280x720 + /// AVCaptureSessionPreset1280x720 + case resolution1280x720 - /// AVCaptureSessionPreset1920x1080 - case resolution1920x1080 + /// AVCaptureSessionPreset1920x1080 + case resolution1920x1080 - /// AVCaptureSessionPreset3840x2160 - case resolution3840x2160 + /// AVCaptureSessionPreset3840x2160 + case resolution3840x2160 - /// AVCaptureSessionPresetiFrame960x540 - case iframe960x540 + /// AVCaptureSessionPresetiFrame960x540 + case iframe960x540 - /// AVCaptureSessionPresetiFrame1280x720 - case iframe1280x720 - } + /// AVCaptureSessionPresetiFrame1280x720 + case iframe1280x720 + } - /** + /** - Result from the AVCaptureSession Setup + Result from the AVCaptureSession Setup - - success: success - - notAuthorized: User denied access to Camera of Microphone - - configurationFailed: Unknown error - */ + - success: success + - notAuthorized: User denied access to Camera of Microphone + - configurationFailed: Unknown error + */ - fileprivate enum SessionSetupResult { - case success - case notAuthorized - case configurationFailed - } + fileprivate enum SessionSetupResult { + case success + case notAuthorized + case configurationFailed + } - // MARK: Public Variable Declarations + // MARK: Public Variable Declarations - /// Public Camera Delegate for the Custom View Controller Subclass + /// Public Camera Delegate for the Custom View Controller Subclass - public weak var cameraDelegate: SwiftyCamViewControllerDelegate? + public weak var cameraDelegate: SwiftyCamViewControllerDelegate? - /// Maxiumum video duration if SwiftyCamButton is used + /// Maxiumum video duration if SwiftyCamButton is used - public var maximumVideoDuration : Double = 0.0 + public var maximumVideoDuration : Double = 0.0 - /// Video capture quality + /// Video capture quality - public var videoQuality : VideoQuality = .high + public var videoQuality : VideoQuality = .high - /// Sets whether flash is enabled for photo and video capture + /// Sets whether flash is enabled for photo and video capture - public var flashEnabled = false + public var flashEnabled = false - /// Sets whether Pinch to Zoom is enabled for the capture session + /// Sets whether Pinch to Zoom is enabled for the capture session - public var pinchToZoom = true + public var pinchToZoom = true - /// Sets the maximum zoom scale allowed during gestures gesture + /// Sets the maximum zoom scale allowed during gestures gesture - public var maxZoomScale = CGFloat.greatestFiniteMagnitude + public var maxZoomScale = CGFloat.greatestFiniteMagnitude - /// Sets whether Tap to Focus and Tap to Adjust Exposure is enabled for the capture session + /// Sets whether Tap to Focus and Tap to Adjust Exposure is enabled for the capture session - public var tapToFocus = true + public var tapToFocus = true - /// Sets whether the capture session should adjust to low light conditions automatically - /// - /// Only supported on iPhone 5 and 5C + /// Sets whether the capture session should adjust to low light conditions automatically + /// + /// Only supported on iPhone 5 and 5C - public var lowLightBoost = true + public var lowLightBoost = true - /// Set whether SwiftyCam should allow background audio from other applications + /// Set whether SwiftyCam should allow background audio from other applications - public var allowBackgroundAudio = true + public var allowBackgroundAudio = true - /// Sets whether a double tap to switch cameras is supported + /// Sets whether a double tap to switch cameras is supported - public var doubleTapCameraSwitch = true + public var doubleTapCameraSwitch = true /// Sets whether swipe vertically to zoom is supported @@ -139,13 +139,13 @@ open class SwiftyCamViewController: UIViewController { public var swipeToZoomInverted = false - /// Set default launch camera + /// Set default launch camera - public var defaultCamera = CameraSelection.rear + public var defaultCamera = CameraSelection.rear - /// Sets wether the taken photo or video should be oriented according to the device orientation + /// Sets wether the taken photo or video should be oriented according to the device orientation - public var shouldUseDeviceOrientation = false + public var shouldUseDeviceOrientation = false /// Sets whether or not View Controller supports auto rotation @@ -167,47 +167,47 @@ open class SwiftyCamViewController: UIViewController { fileprivate(set) public var panGesture : UIPanGestureRecognizer! - // MARK: Public Get-only Variable Declarations + // MARK: Public Get-only Variable Declarations - /// Returns true if video is currently being recorded + /// Returns true if video is currently being recorded - private(set) public var isVideoRecording = false + private(set) public var isVideoRecording = false - /// Returns true if the capture session is currently running + /// Returns true if the capture session is currently running - private(set) public var isSessionRunning = false + private(set) public var isSessionRunning = false - /// Returns the CameraSelection corresponding to the currently utilized camera + /// Returns the CameraSelection corresponding to the currently utilized camera - private(set) public var currentCamera = CameraSelection.rear + private(set) public var currentCamera = CameraSelection.rear - // MARK: Private Constant Declarations + // MARK: Private Constant Declarations - /// Current Capture Session + /// Current Capture Session - public let session = AVCaptureSession() + public let session = AVCaptureSession() - /// Serial queue used for setting up session + /// Serial queue used for setting up session - fileprivate let sessionQueue = DispatchQueue(label: "session queue", attributes: []) + fileprivate let sessionQueue = DispatchQueue(label: "session queue", attributes: []) - // MARK: Private Variable Declarations + // MARK: Private Variable Declarations - /// Variable for storing current zoom scale + /// Variable for storing current zoom scale - fileprivate var zoomScale = CGFloat(1.0) + fileprivate var zoomScale = CGFloat(1.0) - /// Variable for storing initial zoom scale before Pinch to Zoom begins + /// Variable for storing initial zoom scale before Pinch to Zoom begins - fileprivate var beginZoomScale = CGFloat(1.0) + fileprivate var beginZoomScale = CGFloat(1.0) - /// Returns true if the torch (flash) is currently enabled + /// Returns true if the torch (flash) is currently enabled - fileprivate var isCameraTorchOn = false + fileprivate var isCameraTorchOn = false - /// Variable to store result of capture session setup + /// Variable to store result of capture session setup - fileprivate var setupResult = SessionSetupResult.success + fileprivate var setupResult = SessionSetupResult.success fileprivate lazy var permissionErrorLabel : UILabel = { let label = UILabel() @@ -234,60 +234,60 @@ open class SwiftyCamViewController: UIViewController { return button }() - /// BackgroundID variable for video recording + /// BackgroundID variable for video recording - fileprivate var backgroundRecordingID : UIBackgroundTaskIdentifier? = nil + fileprivate var backgroundRecordingID : UIBackgroundTaskIdentifier? = nil - /// Video Input variable + /// Video Input variable - fileprivate var videoDeviceInput : AVCaptureDeviceInput! + fileprivate var videoDeviceInput : AVCaptureDeviceInput! - /// Movie File Output variable + /// Movie File Output variable - fileprivate var movieFileOutput : AVCaptureMovieFileOutput? + fileprivate var movieFileOutput : AVCaptureMovieFileOutput? - /// Photo File Output variable + /// Photo File Output variable - fileprivate var photoFileOutput : AVCaptureStillImageOutput? + fileprivate var photoFileOutput : AVCaptureStillImageOutput? - /// Video Device variable + /// Video Device variable - fileprivate var videoDevice : AVCaptureDevice? + fileprivate var videoDevice : AVCaptureDevice? - /// PreviewView for the capture session + /// PreviewView for the capture session - fileprivate var previewLayer : PreviewView! + fileprivate var previewLayer : PreviewView! - /// UIView for front facing flash + /// UIView for front facing flash - fileprivate var flashView : UIView? + fileprivate var flashView : UIView? /// Pan Translation fileprivate var previousPanTranslation : CGFloat = 0.0 - /// Last changed orientation + /// Last changed orientation - fileprivate var deviceOrientation : UIDeviceOrientation? + fileprivate var deviceOrientation : UIDeviceOrientation? - /// Disable view autorotation for forced portrait recorindg + /// Disable view autorotation for forced portrait recorindg - override open var shouldAutorotate: Bool { - return allowAutoRotate - } + override open var shouldAutorotate: Bool { + return allowAutoRotate + } // makes camera full screen, no bleed or borders - required init?(coder aDecoder: NSCoder) { + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.videoGravity = .resizeAspectFill } - // MARK: ViewDidLoad + // MARK: ViewDidLoad - /// ViewDidLoad Implementation + /// ViewDidLoad Implementation - override open func viewDidLoad() { - super.viewDidLoad() + override open func viewDidLoad() { + super.viewDidLoad() previewLayer = PreviewView(frame: view.frame, videoGravity: videoGravity) previewLayer.center = view.center view.addSubview(previewLayer) @@ -308,38 +308,38 @@ open class SwiftyCamViewController: UIViewController { permissionErrorButton.heightAnchor.constraint(equalToConstant: 30), permissionErrorButton.widthAnchor.constraint(equalToConstant: 150)]) - // Add Gesture Recognizers + // Add Gesture Recognizers addGestureRecognizers() - previewLayer.session = session + previewLayer.session = session - // Test authorization status for Camera and Micophone + // Test authorization status for Camera and Micophone - switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo){ - case .authorized: + switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo){ + case .authorized: - // already authorized - break - case .notDetermined: + // already authorized + break + case .notDetermined: - // not yet determined - sessionQueue.suspend() - AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { [unowned self] granted in - if !granted { - self.setupResult = .notAuthorized - } - self.sessionQueue.resume() - }) - default: + // not yet determined + sessionQueue.suspend() + AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { [unowned self] granted in + if !granted { + self.setupResult = .notAuthorized + } + self.sessionQueue.resume() + }) + default: - // already been asked. Denied access - setupResult = .notAuthorized - } - sessionQueue.async { [unowned self] in - self.configureSession() - } - } + // already been asked. Denied access + setupResult = .notAuthorized + } + sessionQueue.async { [unowned self] in + self.configureSession() + } + } // MARK: ViewDidLayoutSubviews @@ -389,431 +389,431 @@ open class SwiftyCamViewController: UIViewController { } } } - // MARK: ViewDidAppear + // MARK: ViewDidAppear - /// ViewDidAppear(_ animated:) Implementation + /// ViewDidAppear(_ animated:) Implementation - override open func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) + override open func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) - // Subscribe to device rotation notifications + // Subscribe to device rotation notifications - if shouldUseDeviceOrientation { - subscribeToDeviceOrientationChangeNotifications() - } + if shouldUseDeviceOrientation { + subscribeToDeviceOrientationChangeNotifications() + } - // Set background audio preference + // Set background audio preference - setBackgroundAudioPreference() + setBackgroundAudioPreference() - sessionQueue.async { - switch self.setupResult { - case .success: - // Begin Session - self.session.startRunning() - self.isSessionRunning = self.session.isRunning + sessionQueue.async { + switch self.setupResult { + case .success: + // Begin Session + self.session.startRunning() + self.isSessionRunning = self.session.isRunning // Preview layer video orientation can be set only after the connection is created DispatchQueue.main.async { self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.getPreviewLayerOrientation() } - case .notAuthorized: - // Prompt to App Settings - self.promptToAppSettings() - case .configurationFailed: - // Unknown Error - DispatchQueue.main.async(execute: { [unowned self] in - let message = NSLocalizedString("Unable to capture media", comment: "Alert message when something goes wrong during capture session configuration") - let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) - self.present(alertController, animated: true, completion: nil) - }) - } - } - } - - // MARK: ViewDidDisappear - - /// ViewDidDisappear(_ animated:) Implementation - - - override open func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - // If session is running, stop the session + case .notAuthorized: + // Prompt to App Settings + self.promptToAppSettings() + case .configurationFailed: + // Unknown Error + DispatchQueue.main.async(execute: { [unowned self] in + let message = NSLocalizedString("Unable to capture media", comment: "Alert message when something goes wrong during capture session configuration") + let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) + self.present(alertController, animated: true, completion: nil) + }) + } + } + } + + // MARK: ViewDidDisappear + + /// ViewDidDisappear(_ animated:) Implementation + + + override open func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + // If session is running, stop the session // if self.isSessionRunning == true { // self.session.stopRunning() // self.isSessionRunning = false // } - //Disble flash if it is currently enabled - disableFlash() + //Disble flash if it is currently enabled + disableFlash() - // Unsubscribe from device rotation notifications + // Unsubscribe from device rotation notifications // if shouldUseDeviceOrientation { // unsubscribeFromDeviceOrientationChangeNotifications() // } -// } - - // MARK: Public Functions - - /** + } - Capture photo from current session + // MARK: Public Functions - UIImage will be returned with the SwiftyCamViewControllerDelegate function SwiftyCamDidTakePhoto(photo:) + /** - */ + Capture photo from current session - public func takePhoto() { + UIImage will be returned with the SwiftyCamViewControllerDelegate function SwiftyCamDidTakePhoto(photo:) - guard let device = videoDevice else { - return - } + */ - if device.hasFlash == true && flashEnabled == true /* TODO: Add Support for Retina Flash and add front flash */ { - changeFlashSettings(device: device, mode: .on) - capturePhotoAsyncronously(completionHandler: { (_) in }) + public func takePhoto() { - } else if device.hasFlash == false && flashEnabled == true && currentCamera == .front { - flashView = UIView(frame: view.frame) - flashView?.alpha = 0.0 - flashView?.backgroundColor = UIColor.white - previewLayer.addSubview(flashView!) - - UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { - self.flashView?.alpha = 1.0 - - }, completion: { (_) in - self.capturePhotoAsyncronously(completionHandler: { (success) in - UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { - self.flashView?.alpha = 0.0 - }, completion: { (_) in - self.flashView?.removeFromSuperview() - }) - }) - }) - } else { - if device.isFlashActive == true { - changeFlashSettings(device: device, mode: .off) - } - capturePhotoAsyncronously(completionHandler: { (_) in }) - } - } + guard let device = videoDevice else { + return + } - /** + if device.hasFlash == true && flashEnabled == true /* TODO: Add Support for Retina Flash and add front flash */ { + changeFlashSettings(device: device, mode: .on) + capturePhotoAsyncronously(completionHandler: { (_) in }) + + } else if device.hasFlash == false && flashEnabled == true && currentCamera == .front { + flashView = UIView(frame: view.frame) + flashView?.alpha = 0.0 + flashView?.backgroundColor = UIColor.white + previewLayer.addSubview(flashView!) + + UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { + self.flashView?.alpha = 1.0 + + }, completion: { (_) in + self.capturePhotoAsyncronously(completionHandler: { (success) in + UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { + self.flashView?.alpha = 0.0 + }, completion: { (_) in + self.flashView?.removeFromSuperview() + }) + }) + }) + } else { + if device.isFlashActive == true { + changeFlashSettings(device: device, mode: .off) + } + capturePhotoAsyncronously(completionHandler: { (_) in }) + } + } - Begin recording video of current session + /** - SwiftyCamViewControllerDelegate function SwiftyCamDidBeginRecordingVideo() will be called + Begin recording video of current session - */ + SwiftyCamViewControllerDelegate function SwiftyCamDidBeginRecordingVideo() will be called - public func startVideoRecording() { - guard let movieFileOutput = self.movieFileOutput else { - return - } + */ - if currentCamera == .rear && flashEnabled == true { - enableFlash() - } + public func startVideoRecording() { + guard let movieFileOutput = self.movieFileOutput else { + return + } - if currentCamera == .front && flashEnabled == true { - flashView = UIView(frame: view.frame) - flashView?.backgroundColor = UIColor.white - flashView?.alpha = 0.85 - previewLayer.addSubview(flashView!) - } + if currentCamera == .rear && flashEnabled == true { + enableFlash() + } - sessionQueue.async { [unowned self] in - if !movieFileOutput.isRecording { - if UIDevice.current.isMultitaskingSupported { - self.backgroundRecordingID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) - } + if currentCamera == .front && flashEnabled == true { + flashView = UIView(frame: view.frame) + flashView?.backgroundColor = UIColor.white + flashView?.alpha = 0.85 + previewLayer.addSubview(flashView!) + } - // Update the orientation on the movie file output video connection before starting recording. - let movieFileOutputConnection = self.movieFileOutput?.connection(withMediaType: AVMediaTypeVideo) + sessionQueue.async { [unowned self] in + if !movieFileOutput.isRecording { + if UIDevice.current.isMultitaskingSupported { + self.backgroundRecordingID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) + } + // Update the orientation on the movie file output video connection before starting recording. + let movieFileOutputConnection = self.movieFileOutput?.connection(withMediaType: AVMediaTypeVideo) - //flip video output if front facing camera is selected - if self.currentCamera == .front { - movieFileOutputConnection?.isVideoMirrored = true - } - movieFileOutputConnection?.videoOrientation = self.getVideoOrientation() + //flip video output if front facing camera is selected + if self.currentCamera == .front { + movieFileOutputConnection?.isVideoMirrored = true + } - // Start recording to a temporary file. - let outputFileName = UUID().uuidString - let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!) - movieFileOutput.startRecording(toOutputFileURL: URL(fileURLWithPath: outputFilePath), recordingDelegate: self) - self.isVideoRecording = true - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didBeginRecordingVideo: self.currentCamera) - } - } - else { - movieFileOutput.stopRecording() - } - } - } + movieFileOutputConnection?.videoOrientation = self.getVideoOrientation() - /** - - Stop video recording video of current session - - SwiftyCamViewControllerDelegate function SwiftyCamDidFinishRecordingVideo() will be called - - When video has finished processing, the URL to the video location will be returned by SwiftyCamDidFinishProcessingVideoAt(url:) - - */ - - public func stopVideoRecording() { - if self.movieFileOutput?.isRecording == true { - self.isVideoRecording = false - movieFileOutput!.stopRecording() - disableFlash() - - if currentCamera == .front && flashEnabled == true && flashView != nil { - UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { - self.flashView?.alpha = 0.0 - }, completion: { (_) in - self.flashView?.removeFromSuperview() - }) - } - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didFinishRecordingVideo: self.currentCamera) - } - } - } - - /** - - Switch between front and rear camera - - SwiftyCamViewControllerDelegate function SwiftyCamDidSwitchCameras(camera: will be return the current camera selection - - */ + // Start recording to a temporary file. + let outputFileName = UUID().uuidString + let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!) + movieFileOutput.startRecording(toOutputFileURL: URL(fileURLWithPath: outputFilePath), recordingDelegate: self) + self.isVideoRecording = true + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didBeginRecordingVideo: self.currentCamera) + } + } + else { + movieFileOutput.stopRecording() + } + } + } + + /** + + Stop video recording video of current session + + SwiftyCamViewControllerDelegate function SwiftyCamDidFinishRecordingVideo() will be called + + When video has finished processing, the URL to the video location will be returned by SwiftyCamDidFinishProcessingVideoAt(url:) + + */ + + public func stopVideoRecording() { + if self.movieFileOutput?.isRecording == true { + self.isVideoRecording = false + movieFileOutput!.stopRecording() + disableFlash() + + if currentCamera == .front && flashEnabled == true && flashView != nil { + UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveEaseInOut, animations: { + self.flashView?.alpha = 0.0 + }, completion: { (_) in + self.flashView?.removeFromSuperview() + }) + } + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didFinishRecordingVideo: self.currentCamera) + } + } + } + + /** + Switch between front and rear camera - public func switchCamera() { - guard isVideoRecording != true else { - //TODO: Look into switching camera during video recording - print("[SwiftyCam]: Switching between cameras while recording video is not supported") - return - } + SwiftyCamViewControllerDelegate function SwiftyCamDidSwitchCameras(camera: will be return the current camera selection + + */ + + + public func switchCamera() { + guard isVideoRecording != true else { + //TODO: Look into switching camera during video recording + print("[SwiftyCam]: Switching between cameras while recording video is not supported") + return + } guard session.isRunning == true else { return } - switch currentCamera { - case .front: - currentCamera = .rear - case .rear: - currentCamera = .front - } - - session.stopRunning() - - sessionQueue.async { [unowned self] in - - // remove and re-add inputs and outputs - - for input in self.session.inputs { - self.session.removeInput(input as! AVCaptureInput) - } - - self.addInputs() - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didSwitchCameras: self.currentCamera) - } - - self.session.startRunning() - } - - // If flash is enabled, disable it as the torch is needed for front facing camera - disableFlash() - } - - // MARK: Private Functions - - /// Configure session, add inputs and outputs - - fileprivate func configureSession() { - guard setupResult == .success else { - return - } - - // Set default camera - - currentCamera = defaultCamera - - // begin configuring session - - session.beginConfiguration() - configureVideoPreset() - addVideoInput() - addAudioInput() - configureVideoOutput() - configurePhotoOutput() - - session.commitConfiguration() - } - - /// Add inputs after changing camera() - - fileprivate func addInputs() { - session.beginConfiguration() - configureVideoPreset() - addVideoInput() - addAudioInput() - session.commitConfiguration() - } - - - // Front facing camera will always be set to VideoQuality.high - // If set video quality is not supported, videoQuality variable will be set to VideoQuality.high - /// Configure image quality preset - - fileprivate func configureVideoPreset() { - if currentCamera == .front { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) - } else { - if session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality)) { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: videoQuality) - } else { - session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) - } - } - } - - /// Add Video Inputs - - fileprivate func addVideoInput() { - switch currentCamera { - case .front: - videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .front) - case .rear: - videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .back) - } - - if let device = videoDevice { - do { - try device.lockForConfiguration() - if device.isFocusModeSupported(.continuousAutoFocus) { - device.focusMode = .continuousAutoFocus - if device.isSmoothAutoFocusSupported { - device.isSmoothAutoFocusEnabled = true - } - } - - if device.isExposureModeSupported(.continuousAutoExposure) { - device.exposureMode = .continuousAutoExposure - } - - if device.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) { - device.whiteBalanceMode = .continuousAutoWhiteBalance - } - - if device.isLowLightBoostSupported && lowLightBoost == true { - device.automaticallyEnablesLowLightBoostWhenAvailable = true - } - - device.unlockForConfiguration() - } catch { - print("[SwiftyCam]: Error locking configuration") - } - } - - do { - let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) - - if session.canAddInput(videoDeviceInput) { - session.addInput(videoDeviceInput) - self.videoDeviceInput = videoDeviceInput - } else { - print("[SwiftyCam]: Could not add video device input to the session") - print(session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality))) - setupResult = .configurationFailed - session.commitConfiguration() - return - } - } catch { - print("[SwiftyCam]: Could not create video device input: \(error)") - setupResult = .configurationFailed - return - } - } - - /// Add Audio Inputs - - fileprivate func addAudioInput() { + switch currentCamera { + case .front: + currentCamera = .rear + case .rear: + currentCamera = .front + } + + session.stopRunning() + + sessionQueue.async { [unowned self] in + + // remove and re-add inputs and outputs + + for input in self.session.inputs { + self.session.removeInput(input as! AVCaptureInput) + } + + self.addInputs() + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didSwitchCameras: self.currentCamera) + } + + self.session.startRunning() + } + + // If flash is enabled, disable it as the torch is needed for front facing camera + disableFlash() + } + + // MARK: Private Functions + + /// Configure session, add inputs and outputs + + fileprivate func configureSession() { + guard setupResult == .success else { + return + } + + // Set default camera + + currentCamera = defaultCamera + + // begin configuring session + + session.beginConfiguration() + configureVideoPreset() + addVideoInput() + addAudioInput() + configureVideoOutput() + configurePhotoOutput() + + session.commitConfiguration() + } + + /// Add inputs after changing camera() + + fileprivate func addInputs() { + session.beginConfiguration() + configureVideoPreset() + addVideoInput() + addAudioInput() + session.commitConfiguration() + } + + + // Front facing camera will always be set to VideoQuality.high + // If set video quality is not supported, videoQuality variable will be set to VideoQuality.high + /// Configure image quality preset + + fileprivate func configureVideoPreset() { + if currentCamera == .front { + session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) + } else { + if session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality)) { + session.sessionPreset = videoInputPresetFromVideoQuality(quality: videoQuality) + } else { + session.sessionPreset = videoInputPresetFromVideoQuality(quality: .high) + } + } + } + + /// Add Video Inputs + + fileprivate func addVideoInput() { + switch currentCamera { + case .front: + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .front) + case .rear: + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .back) + } + + if let device = videoDevice { + do { + try device.lockForConfiguration() + if device.isFocusModeSupported(.continuousAutoFocus) { + device.focusMode = .continuousAutoFocus + if device.isSmoothAutoFocusSupported { + device.isSmoothAutoFocusEnabled = true + } + } + + if device.isExposureModeSupported(.continuousAutoExposure) { + device.exposureMode = .continuousAutoExposure + } + + if device.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) { + device.whiteBalanceMode = .continuousAutoWhiteBalance + } + + if device.isLowLightBoostSupported && lowLightBoost == true { + device.automaticallyEnablesLowLightBoostWhenAvailable = true + } + + device.unlockForConfiguration() + } catch { + print("[SwiftyCam]: Error locking configuration") + } + } + + do { + let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) + + if session.canAddInput(videoDeviceInput) { + session.addInput(videoDeviceInput) + self.videoDeviceInput = videoDeviceInput + } else { + print("[SwiftyCam]: Could not add video device input to the session") + print(session.canSetSessionPreset(videoInputPresetFromVideoQuality(quality: videoQuality))) + setupResult = .configurationFailed + session.commitConfiguration() + return + } + } catch { + print("[SwiftyCam]: Could not create video device input: \(error)") + setupResult = .configurationFailed + return + } + } + + /// Add Audio Inputs + + fileprivate func addAudioInput() { guard audioEnabled == true else { return } - do { - let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) - let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) - - if session.canAddInput(audioDeviceInput) { - session.addInput(audioDeviceInput) - } - else { - print("[SwiftyCam]: Could not add audio device input to the session") - } - } - catch { - print("[SwiftyCam]: Could not create audio device input: \(error)") - } - } - - /// Configure Movie Output - - fileprivate func configureVideoOutput() { - let movieFileOutput = AVCaptureMovieFileOutput() - - if self.session.canAddOutput(movieFileOutput) { - self.session.addOutput(movieFileOutput) - if let connection = movieFileOutput.connection(withMediaType: AVMediaTypeVideo) { - if connection.isVideoStabilizationSupported { - connection.preferredVideoStabilizationMode = .auto - } - } - self.movieFileOutput = movieFileOutput - } - } - - /// Configure Photo Output - - fileprivate func configurePhotoOutput() { - let photoFileOutput = AVCaptureStillImageOutput() - - if self.session.canAddOutput(photoFileOutput) { - photoFileOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] - self.session.addOutput(photoFileOutput) - self.photoFileOutput = photoFileOutput - } - } - - /// Orientation management - - fileprivate func subscribeToDeviceOrientationChangeNotifications() { - self.deviceOrientation = UIDevice.current.orientation - NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - } - - fileprivate func unsubscribeFromDeviceOrientationChangeNotifications() { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - self.deviceOrientation = nil - } - - @objc fileprivate func deviceDidRotate() { - if !UIDevice.current.orientation.isFlat { - self.deviceOrientation = UIDevice.current.orientation - } - } + do { + let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) + let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) + + if session.canAddInput(audioDeviceInput) { + session.addInput(audioDeviceInput) + } + else { + print("[SwiftyCam]: Could not add audio device input to the session") + } + } + catch { + print("[SwiftyCam]: Could not create audio device input: \(error)") + } + } + + /// Configure Movie Output + + fileprivate func configureVideoOutput() { + let movieFileOutput = AVCaptureMovieFileOutput() + + if self.session.canAddOutput(movieFileOutput) { + self.session.addOutput(movieFileOutput) + if let connection = movieFileOutput.connection(withMediaType: AVMediaTypeVideo) { + if connection.isVideoStabilizationSupported { + connection.preferredVideoStabilizationMode = .auto + } + } + self.movieFileOutput = movieFileOutput + } + } + + /// Configure Photo Output + + fileprivate func configurePhotoOutput() { + let photoFileOutput = AVCaptureStillImageOutput() + + if self.session.canAddOutput(photoFileOutput) { + photoFileOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] + self.session.addOutput(photoFileOutput) + self.photoFileOutput = photoFileOutput + } + } + + /// Orientation management + + fileprivate func subscribeToDeviceOrientationChangeNotifications() { + self.deviceOrientation = UIDevice.current.orientation + NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + } + + fileprivate func unsubscribeFromDeviceOrientationChangeNotifications() { + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + self.deviceOrientation = nil + } + + @objc fileprivate func deviceDidRotate() { + if !UIDevice.current.orientation.isFlat { + self.deviceOrientation = UIDevice.current.orientation + } + } fileprivate func getPreviewLayerOrientation() -> AVCaptureVideoOrientation { // Depends on layout orientation, not device orientation @@ -829,79 +829,79 @@ open class SwiftyCamViewController: UIViewController { } } - fileprivate func getVideoOrientation() -> AVCaptureVideoOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection.videoOrientation } - - switch deviceOrientation { - case .landscapeLeft: - return .landscapeRight - case .landscapeRight: - return .landscapeLeft - case .portraitUpsideDown: - return .portraitUpsideDown - default: - return .portrait - } - } - - fileprivate func getImageOrientation(forCamera: CameraSelection) -> UIImageOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } - - switch deviceOrientation { - case .landscapeLeft: - return forCamera == .rear ? .up : .downMirrored - case .landscapeRight: - return forCamera == .rear ? .down : .upMirrored - case .portraitUpsideDown: - return forCamera == .rear ? .left : .rightMirrored - default: - return forCamera == .rear ? .right : .leftMirrored - } - } - - /** - Returns a UIImage from Image Data. - - - Parameter imageData: Image Data returned from capturing photo from the capture session. - - - Returns: UIImage from the image data, adjusted for proper orientation. - */ - - fileprivate func processPhoto(_ imageData: Data) -> UIImage { - let dataProvider = CGDataProvider(data: imageData as CFData) - let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) - - // Set proper orientation for photo - // If camera is currently set to front camera, flip image - - let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.getImageOrientation(forCamera: self.currentCamera)) - - return image - } - - fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) { - if let videoConnection = photoFileOutput?.connection(withMediaType: AVMediaTypeVideo) { - - photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in - if (sampleBuffer != nil) { - let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) - let image = self.processPhoto(imageData!) - - // Call delegate and return new image - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didTake: image) - } - completionHandler(true) - } else { - completionHandler(false) - } - }) - } else { - completionHandler(false) - } - } - - /// Handle Denied App Privacy Settings + fileprivate func getVideoOrientation() -> AVCaptureVideoOrientation { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection.videoOrientation } + + switch deviceOrientation { + case .landscapeLeft: + return .landscapeRight + case .landscapeRight: + return .landscapeLeft + case .portraitUpsideDown: + return .portraitUpsideDown + default: + return .portrait + } + } + + fileprivate func getImageOrientation(forCamera: CameraSelection) -> UIImageOrientation { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } + + switch deviceOrientation { + case .landscapeLeft: + return forCamera == .rear ? .up : .downMirrored + case .landscapeRight: + return forCamera == .rear ? .down : .upMirrored + case .portraitUpsideDown: + return forCamera == .rear ? .left : .rightMirrored + default: + return forCamera == .rear ? .right : .leftMirrored + } + } + + /** + Returns a UIImage from Image Data. + + - Parameter imageData: Image Data returned from capturing photo from the capture session. + + - Returns: UIImage from the image data, adjusted for proper orientation. + */ + + fileprivate func processPhoto(_ imageData: Data) -> UIImage { + let dataProvider = CGDataProvider(data: imageData as CFData) + let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) + + // Set proper orientation for photo + // If camera is currently set to front camera, flip image + + let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.getImageOrientation(forCamera: self.currentCamera)) + + return image + } + + fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) { + if let videoConnection = photoFileOutput?.connection(withMediaType: AVMediaTypeVideo) { + + photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in + if (sampleBuffer != nil) { + let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) + let image = self.processPhoto(imageData!) + + // Call delegate and return new image + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didTake: image) + } + completionHandler(true) + } else { + completionHandler(false) + } + }) + } else { + completionHandler(false) + } + } + + /// Handle Denied App Privacy Settings fileprivate func promptToAppSettings() { if usePermissionAlert { @@ -935,266 +935,266 @@ open class SwiftyCamViewController: UIViewController { } } - /** - Returns an AVCapturePreset from VideoQuality Enumeration - - - Parameter quality: ViewQuality enum - - - Returns: String representing a AVCapturePreset - */ - - fileprivate func videoInputPresetFromVideoQuality(quality: VideoQuality) -> String { - switch quality { - case .high: return AVCaptureSessionPresetHigh - case .medium: return AVCaptureSessionPresetMedium - case .low: return AVCaptureSessionPresetLow - case .resolution352x288: return AVCaptureSessionPreset352x288 - case .resolution640x480: return AVCaptureSessionPreset640x480 - case .resolution1280x720: return AVCaptureSessionPreset1280x720 - case .resolution1920x1080: return AVCaptureSessionPreset1920x1080 - case .iframe960x540: return AVCaptureSessionPresetiFrame960x540 - case .iframe1280x720: return AVCaptureSessionPresetiFrame1280x720 - case .resolution3840x2160: - if #available(iOS 9.0, *) { - return AVCaptureSessionPreset3840x2160 - } - else { - print("[SwiftyCam]: Resolution 3840x2160 not supported") - return AVCaptureSessionPresetHigh - } - } - } - - /// Get Devices - - fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevicePosition) -> AVCaptureDevice? { - if let devices = AVCaptureDevice.devices(withMediaType: mediaType) as? [AVCaptureDevice] { - return devices.filter({ $0.position == position }).first - } - return nil - } - - /// Enable or disable flash for photo - - fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: AVCaptureFlashMode) { - do { - try device.lockForConfiguration() - device.flashMode = mode - device.unlockForConfiguration() - } catch { - print("[SwiftyCam]: \(error)") - } - } - - /// Enable flash - - fileprivate func enableFlash() { - if self.isCameraTorchOn == false { - toggleFlash() - } - } - - /// Disable flash - - fileprivate func disableFlash() { - if self.isCameraTorchOn == true { - toggleFlash() - } - } - - /// Toggles between enabling and disabling flash - - fileprivate func toggleFlash() { - guard self.currentCamera == .rear else { - // Flash is not supported for front facing camera - return - } - - let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) - // Check if device has a flash - if (device?.hasTorch)! { - do { - try device?.lockForConfiguration() - if (device?.torchMode == AVCaptureTorchMode.on) { - device?.torchMode = AVCaptureTorchMode.off - self.isCameraTorchOn = false - } else { - do { - try device?.setTorchModeOnWithLevel(1.0) - self.isCameraTorchOn = true - } catch { - print("[SwiftyCam]: \(error)") - } - } - device?.unlockForConfiguration() - } catch { - print("[SwiftyCam]: \(error)") - } - } - } - - /// Sets whether SwiftyCam should enable background audio from other applications or sources - - fileprivate func setBackgroundAudioPreference() { - guard allowBackgroundAudio == true else { - return - } + /** + Returns an AVCapturePreset from VideoQuality Enumeration + + - Parameter quality: ViewQuality enum + + - Returns: String representing a AVCapturePreset + */ + + fileprivate func videoInputPresetFromVideoQuality(quality: VideoQuality) -> String { + switch quality { + case .high: return AVCaptureSessionPresetHigh + case .medium: return AVCaptureSessionPresetMedium + case .low: return AVCaptureSessionPresetLow + case .resolution352x288: return AVCaptureSessionPreset352x288 + case .resolution640x480: return AVCaptureSessionPreset640x480 + case .resolution1280x720: return AVCaptureSessionPreset1280x720 + case .resolution1920x1080: return AVCaptureSessionPreset1920x1080 + case .iframe960x540: return AVCaptureSessionPresetiFrame960x540 + case .iframe1280x720: return AVCaptureSessionPresetiFrame1280x720 + case .resolution3840x2160: + if #available(iOS 9.0, *) { + return AVCaptureSessionPreset3840x2160 + } + else { + print("[SwiftyCam]: Resolution 3840x2160 not supported") + return AVCaptureSessionPresetHigh + } + } + } + + /// Get Devices + + fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevicePosition) -> AVCaptureDevice? { + if let devices = AVCaptureDevice.devices(withMediaType: mediaType) as? [AVCaptureDevice] { + return devices.filter({ $0.position == position }).first + } + return nil + } + + /// Enable or disable flash for photo + + fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: AVCaptureFlashMode) { + do { + try device.lockForConfiguration() + device.flashMode = mode + device.unlockForConfiguration() + } catch { + print("[SwiftyCam]: \(error)") + } + } + + /// Enable flash + + fileprivate func enableFlash() { + if self.isCameraTorchOn == false { + toggleFlash() + } + } + + /// Disable flash + + fileprivate func disableFlash() { + if self.isCameraTorchOn == true { + toggleFlash() + } + } + + /// Toggles between enabling and disabling flash + + fileprivate func toggleFlash() { + guard self.currentCamera == .rear else { + // Flash is not supported for front facing camera + return + } + + let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) + // Check if device has a flash + if (device?.hasTorch)! { + do { + try device?.lockForConfiguration() + if (device?.torchMode == AVCaptureTorchMode.on) { + device?.torchMode = AVCaptureTorchMode.off + self.isCameraTorchOn = false + } else { + do { + try device?.setTorchModeOnWithLevel(1.0) + self.isCameraTorchOn = true + } catch { + print("[SwiftyCam]: \(error)") + } + } + device?.unlockForConfiguration() + } catch { + print("[SwiftyCam]: \(error)") + } + } + } + + /// Sets whether SwiftyCam should enable background audio from other applications or sources + + fileprivate func setBackgroundAudioPreference() { + guard allowBackgroundAudio == true else { + return + } guard audioEnabled == true else { return } - do{ - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, - with: [.duckOthers, .defaultToSpeaker]) + do{ + try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, + with: [.duckOthers, .defaultToSpeaker]) - session.automaticallyConfiguresApplicationAudioSession = false - } - catch { - print("[SwiftyCam]: Failed to set background audio preference") + session.automaticallyConfiguresApplicationAudioSession = false + } + catch { + print("[SwiftyCam]: Failed to set background audio preference") - } - } + } + } } extension SwiftyCamViewController : SwiftyCamButtonDelegate { - /// Sets the maximum duration of the SwiftyCamButton + /// Sets the maximum duration of the SwiftyCamButton - public func setMaxiumVideoDuration() -> Double { - return maximumVideoDuration - } + public func setMaxiumVideoDuration() -> Double { + return maximumVideoDuration + } - /// Set UITapGesture to take photo + /// Set UITapGesture to take photo - public func buttonWasTapped() { - takePhoto() - } + public func buttonWasTapped() { + takePhoto() + } - /// Set UILongPressGesture start to begin video + /// Set UILongPressGesture start to begin video - public func buttonDidBeginLongPress() { - startVideoRecording() - } + public func buttonDidBeginLongPress() { + startVideoRecording() + } - /// Set UILongPressGesture begin to begin end video + /// Set UILongPressGesture begin to begin end video - public func buttonDidEndLongPress() { - stopVideoRecording() - } + public func buttonDidEndLongPress() { + stopVideoRecording() + } - /// Called if maximum duration is reached + /// Called if maximum duration is reached - public func longPressDidReachMaximumDuration() { - stopVideoRecording() - } + public func longPressDidReachMaximumDuration() { + stopVideoRecording() + } } // MARK: AVCaptureFileOutputRecordingDelegate extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { - /// Process newly captured video and write it to temporary directory + /// Process newly captured video and write it to temporary directory - public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) { - if let currentBackgroundRecordingID = backgroundRecordingID { - backgroundRecordingID = UIBackgroundTaskInvalid + public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) { + if let currentBackgroundRecordingID = backgroundRecordingID { + backgroundRecordingID = UIBackgroundTaskInvalid - if currentBackgroundRecordingID != UIBackgroundTaskInvalid { - UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) - } - } - if error != nil { - print("[SwiftyCam]: Movie file finishing error: \(error)") + if currentBackgroundRecordingID != UIBackgroundTaskInvalid { + UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) + } + } + if error != nil { + print("[SwiftyCam]: Movie file finishing error: \(error)") DispatchQueue.main.async { self.cameraDelegate?.swiftyCam(self, didFailToRecordVideo: error) } - } else { - //Call delegate function with the URL of the outputfile - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didFinishProcessVideoAt: outputFileURL) - } - } - } + } else { + //Call delegate function with the URL of the outputfile + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didFinishProcessVideoAt: outputFileURL) + } + } + } } // Mark: UIGestureRecognizer Declarations extension SwiftyCamViewController { - /// Handle pinch gesture - - @objc fileprivate func zoomGesture(pinch: UIPinchGestureRecognizer) { - guard pinchToZoom == true && self.currentCamera == .rear else { - //ignore pinch - return - } - do { - let captureDevice = AVCaptureDevice.devices().first as? AVCaptureDevice - try captureDevice?.lockForConfiguration() - - zoomScale = min(maxZoomScale, max(1.0, min(beginZoomScale * pinch.scale, captureDevice!.activeFormat.videoMaxZoomFactor))) - - captureDevice?.videoZoomFactor = zoomScale - - // Call Delegate function with current zoom scale - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didChangeZoomLevel: self.zoomScale) - } - - captureDevice?.unlockForConfiguration() - - } catch { - print("[SwiftyCam]: Error locking configuration") - } - } - - /// Handle single tap gesture - - @objc fileprivate func singleTapGesture(tap: UITapGestureRecognizer) { - guard tapToFocus == true else { - // Ignore taps - return - } - - let screenSize = previewLayer!.bounds.size - let tapPoint = tap.location(in: previewLayer!) - let x = tapPoint.y / screenSize.height - let y = 1.0 - tapPoint.x / screenSize.width - let focusPoint = CGPoint(x: x, y: y) - - if let device = videoDevice { - do { - try device.lockForConfiguration() - - if device.isFocusPointOfInterestSupported == true { - device.focusPointOfInterest = focusPoint - device.focusMode = .autoFocus - } - device.exposurePointOfInterest = focusPoint - device.exposureMode = AVCaptureExposureMode.continuousAutoExposure - device.unlockForConfiguration() - //Call delegate function and pass in the location of the touch - - DispatchQueue.main.async { - self.cameraDelegate?.swiftyCam(self, didFocusAtPoint: tapPoint) - } - } - catch { - // just ignore - } - } - } - - /// Handle double tap gesture - - @objc fileprivate func doubleTapGesture(tap: UITapGestureRecognizer) { - guard doubleTapCameraSwitch == true else { - return - } - switchCamera() - } + /// Handle pinch gesture + + @objc fileprivate func zoomGesture(pinch: UIPinchGestureRecognizer) { + guard pinchToZoom == true && self.currentCamera == .rear else { + //ignore pinch + return + } + do { + let captureDevice = AVCaptureDevice.devices().first as? AVCaptureDevice + try captureDevice?.lockForConfiguration() + + zoomScale = min(maxZoomScale, max(1.0, min(beginZoomScale * pinch.scale, captureDevice!.activeFormat.videoMaxZoomFactor))) + + captureDevice?.videoZoomFactor = zoomScale + + // Call Delegate function with current zoom scale + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didChangeZoomLevel: self.zoomScale) + } + + captureDevice?.unlockForConfiguration() + + } catch { + print("[SwiftyCam]: Error locking configuration") + } + } + + /// Handle single tap gesture + + @objc fileprivate func singleTapGesture(tap: UITapGestureRecognizer) { + guard tapToFocus == true else { + // Ignore taps + return + } + + let screenSize = previewLayer!.bounds.size + let tapPoint = tap.location(in: previewLayer!) + let x = tapPoint.y / screenSize.height + let y = 1.0 - tapPoint.x / screenSize.width + let focusPoint = CGPoint(x: x, y: y) + + if let device = videoDevice { + do { + try device.lockForConfiguration() + + if device.isFocusPointOfInterestSupported == true { + device.focusPointOfInterest = focusPoint + device.focusMode = .autoFocus + } + device.exposurePointOfInterest = focusPoint + device.exposureMode = AVCaptureExposureMode.continuousAutoExposure + device.unlockForConfiguration() + //Call delegate function and pass in the location of the touch + + DispatchQueue.main.async { + self.cameraDelegate?.swiftyCam(self, didFocusAtPoint: tapPoint) + } + } + catch { + // just ignore + } + } + } + + /// Handle double tap gesture + + @objc fileprivate func doubleTapGesture(tap: UITapGestureRecognizer) { + guard doubleTapCameraSwitch == true else { + return + } + switchCamera() + } @objc private func panGesture(pan: UIPanGestureRecognizer) { @@ -1238,32 +1238,32 @@ extension SwiftyCamViewController { } } - /** - Add pinch gesture recognizer and double tap gesture recognizer to currentView + /** + Add pinch gesture recognizer and double tap gesture recognizer to currentView - - Parameter view: View to add gesture recognzier + - Parameter view: View to add gesture recognzier - */ + */ - fileprivate func addGestureRecognizers() { - pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(zoomGesture(pinch:))) - pinchGesture.delegate = self - previewLayer.addGestureRecognizer(pinchGesture) + fileprivate func addGestureRecognizers() { + pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(zoomGesture(pinch:))) + pinchGesture.delegate = self + previewLayer.addGestureRecognizer(pinchGesture) - let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(singleTapGesture(tap:))) - singleTapGesture.numberOfTapsRequired = 1 - singleTapGesture.delegate = self - previewLayer.addGestureRecognizer(singleTapGesture) + let singleTapGesture = UITapGestureRecognizer(target: self, action: #selector(singleTapGesture(tap:))) + singleTapGesture.numberOfTapsRequired = 1 + singleTapGesture.delegate = self + previewLayer.addGestureRecognizer(singleTapGesture) - let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGesture(tap:))) - doubleTapGesture.numberOfTapsRequired = 2 - doubleTapGesture.delegate = self - previewLayer.addGestureRecognizer(doubleTapGesture) + let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGesture(tap:))) + doubleTapGesture.numberOfTapsRequired = 2 + doubleTapGesture.delegate = self + previewLayer.addGestureRecognizer(doubleTapGesture) panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGesture(pan:))) panGesture.delegate = self previewLayer.addGestureRecognizer(panGesture) - } + } } @@ -1271,14 +1271,14 @@ extension SwiftyCamViewController { extension SwiftyCamViewController : UIGestureRecognizerDelegate { - /// Set beginZoomScale when pinch begins + /// Set beginZoomScale when pinch begins - public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - if gestureRecognizer.isKind(of: UIPinchGestureRecognizer.self) { - beginZoomScale = zoomScale; - } - return true - } + public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + if gestureRecognizer.isKind(of: UIPinchGestureRecognizer.self) { + beginZoomScale = zoomScale; + } + return true + } } diff --git a/SwiftyCam.podspec b/SwiftyCam.podspec index 0b1ecee..6700dad 100644 --- a/SwiftyCam.podspec +++ b/SwiftyCam.podspec @@ -10,7 +10,7 @@ Pod::Spec.new do |s| s.name = 'SwiftyCam' s.version = '2.7.0' s.summary = 'A Simple, Snapchat inspired camera Framework written in Swift' - s.ios.deployment_target = '8.0' + s.ios.deployment_target = '10.0' # This description is used to generate tags and improve search results. @@ -30,7 +30,7 @@ A drop in Camera View Controller for capturing photos and videos from one AVSess s.source = { :git => 'https://github.com/Awalz/SwiftyCam.git', :tag => s.version.to_s } # s.social_media_url = 'https://twitter.com/' - s.ios.deployment_target = '8.0' + s.ios.deployment_target = '10.0' s.source_files = 'Source/**/*' From 3a3871d282e9fa5f2e9855bf9cebfcb638bf17d2 Mon Sep 17 00:00:00 2001 From: Josh Guffey Date: Sat, 24 Aug 2019 10:27:43 -0700 Subject: [PATCH 4/5] working on device --- Source/SwiftyCamViewController.swift | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 67b5422..f297177 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -311,15 +311,23 @@ open class SwiftyCamViewController: UIViewController { view.addSubview(permissionErrorButton) // centers error label and button - NSLayoutConstraint.activate([permissionErrorLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), - permissionErrorLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), - permissionErrorLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15), - permissionErrorLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -15), - permissionErrorLabel.heightAnchor.constraint(equalToConstant: 50), - permissionErrorButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - permissionErrorButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 55), - permissionErrorButton.heightAnchor.constraint(equalToConstant: 30), - permissionErrorButton.widthAnchor.constraint(equalToConstant: 150)]) + if #available(iOS 9.0, *) { + NSLayoutConstraint.activate( + [ + permissionErrorLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), + permissionErrorLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor), + permissionErrorLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15), + permissionErrorLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -15), + permissionErrorLabel.heightAnchor.constraint(equalToConstant: 50), + permissionErrorButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + permissionErrorButton.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 55), + permissionErrorButton.heightAnchor.constraint(equalToConstant: 30), + permissionErrorButton.widthAnchor.constraint(equalToConstant: 150) + ] + ) + } else { + // Fallback on earlier versions + } // Add Gesture Recognizers From 302ed4a704c9ac420dd6cf54e311f5c955305f15 Mon Sep 17 00:00:00 2001 From: Josh Guffey Date: Sat, 24 Aug 2019 10:40:12 -0700 Subject: [PATCH 5/5] migrate to swift5 --- .../DemoSwiftyCam.xcodeproj/project.pbxproj | 13 +++++++------ DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift | 2 +- .../DemoSwiftyCam/PhotoViewController.swift | 4 ++-- .../DemoSwiftyCam/VideoViewController.swift | 8 ++++---- .../DemoSwiftyCam/ViewController.swift | 4 ++-- Source/Orientation.swift | 2 +- Source/SwiftyCamViewController.swift | 17 +++++++++-------- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj index d020416..814ab8d 100644 --- a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -198,6 +198,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -300,7 +301,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.Cappsule.SwiftyCam-iOS"; PRODUCT_NAME = SwiftyCam; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -323,7 +324,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.Cappsule.SwiftyCam-iOS"; PRODUCT_NAME = SwiftyCam; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -384,7 +385,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -434,7 +435,7 @@ SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -450,7 +451,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -466,7 +467,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.Walzy.DemoSwiftyCam1; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift index dfee801..322b74d 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift @@ -22,7 +22,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } diff --git a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift index 4333a1f..82e2f4d 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/PhotoViewController.swift @@ -36,11 +36,11 @@ class PhotoViewController: UIViewController { super.viewDidLoad() self.view.backgroundColor = UIColor.gray let backgroundImageView = UIImageView(frame: view.frame) - backgroundImageView.contentMode = UIViewContentMode.scaleAspectFit + backgroundImageView.contentMode = UIView.ContentMode.scaleAspectFit backgroundImageView.image = backgroundImage view.addSubview(backgroundImageView) let cancelButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)) - cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState()) + cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControl.State()) cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) view.addSubview(cancelButton) } diff --git a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift index 0423a71..2befa16 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/VideoViewController.swift @@ -49,20 +49,20 @@ class VideoViewController: UIViewController { playerController!.showsPlaybackControls = false playerController!.player = player! - self.addChildViewController(playerController!) + self.addChild(playerController!) self.view.addSubview(playerController!.view) playerController!.view.frame = view.frame NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player!.currentItem) let cancelButton = UIButton(frame: CGRect(x: 10.0, y: 10.0, width: 30.0, height: 30.0)) - cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControlState()) + cancelButton.setImage(#imageLiteral(resourceName: "cancel"), for: UIControl.State()) cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside) view.addSubview(cancelButton) // Allow background audio to continue to play do { - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient) + try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient) } catch let error as NSError { print(error) } @@ -85,7 +85,7 @@ class VideoViewController: UIViewController { @objc fileprivate func playerItemDidReachEnd(_ notification: Notification) { if self.player != nil { - self.player!.seek(to: kCMTimeZero) + self.player!.seek(to: CMTime.zero) self.player!.play() } } diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift index 67b2b8f..06a5d9b 100644 --- a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -153,9 +153,9 @@ extension ViewController { fileprivate func toggleFlashAnimation() { if flashEnabled == true { - flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControlState()) + flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControl.State()) } else { - flashButton.setImage(#imageLiteral(resourceName: "flashOutline"), for: UIControlState()) + flashButton.setImage(#imageLiteral(resourceName: "flashOutline"), for: UIControl.State()) } } } diff --git a/Source/Orientation.swift b/Source/Orientation.swift index f51030e..578d475 100644 --- a/Source/Orientation.swift +++ b/Source/Orientation.swift @@ -45,7 +45,7 @@ class Orientation { self.deviceOrientation = nil } - func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation { + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImage.Orientation { guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } switch deviceOrientation { diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index f297177..ce7eb1f 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -304,7 +304,7 @@ open class SwiftyCamViewController: UIViewController { previewLayer = PreviewView(frame: view.frame, videoGravity: videoGravity) previewLayer.center = view.center view.addSubview(previewLayer) - view.sendSubview(toBack: previewLayer) + view.sendSubviewToBack(previewLayer) // adds error label and button if camera permissions are denied view.addSubview(permissionErrorLabel) @@ -941,9 +941,9 @@ extension SwiftyCamViewController { @objc func openSettings() { if #available(iOS 10.0, *) { - UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) + UIApplication.shared.openURL(URL(string: UIApplication.openSettingsURLString)!) } else { - if let appSettings = URL(string: UIApplicationOpenSettingsURLString) { + if let appSettings = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.openURL(appSettings) } } @@ -1063,9 +1063,10 @@ extension SwiftyCamViewController { } do{ - try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, - with: [.duckOthers, .defaultToSpeaker]) - + try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: [ + .duckOthers, + .defaultToSpeaker + ]) session.automaticallyConfiguresApplicationAudioSession = false } catch { @@ -1083,9 +1084,9 @@ extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { public func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { if let currentBackgroundRecordingID = backgroundRecordingID { - backgroundRecordingID = UIBackgroundTaskInvalid + backgroundRecordingID = UIBackgroundTaskIdentifier.invalid - if currentBackgroundRecordingID != UIBackgroundTaskInvalid { + if currentBackgroundRecordingID != UIBackgroundTaskIdentifier.invalid { UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) } }