Address warnings, rip out photos, and make the button responsive

This commit is contained in:
Sami Samhuri 2023-10-26 13:56:52 -07:00
parent 707bf2292c
commit 54a288b661
8 changed files with 56 additions and 371 deletions

View file

@ -25,7 +25,6 @@
1675A98F1E00A74A00B80903 /* SwiftyCamViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */; };
1675A9901E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98C1E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift */; };
168505E81E288B4C005B4537 /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 168505E71E288B4C005B4537 /* VideoViewController.swift */; };
168505EA1E288D80005B4537 /* PhotoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 168505E91E288D80005B4537 /* PhotoViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -46,7 +45,6 @@
1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyCamViewController.swift; path = ../../Source/SwiftyCamViewController.swift; sourceTree = "<group>"; };
1675A98C1E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyCamViewControllerDelegate.swift; path = ../../Source/SwiftyCamViewControllerDelegate.swift; sourceTree = "<group>"; };
168505E71E288B4C005B4537 /* VideoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = "<group>"; };
168505E91E288D80005B4537 /* PhotoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -102,7 +100,6 @@
1675A9771E00A68300B80903 /* ViewController.swift */,
16298B551E2703DC0056D413 /* SwiftyRecordButton.swift */,
168505E71E288B4C005B4537 /* VideoViewController.swift */,
168505E91E288D80005B4537 /* PhotoViewController.swift */,
1675A9791E00A68300B80903 /* Main.storyboard */,
1675A97C1E00A68300B80903 /* Assets.xcassets */,
1675A97E1E00A68300B80903 /* LaunchScreen.storyboard */,
@ -255,7 +252,6 @@
168505E81E288B4C005B4537 /* VideoViewController.swift in Sources */,
1675A9761E00A68300B80903 /* AppDelegate.swift in Sources */,
1675A98F1E00A74A00B80903 /* SwiftyCamViewController.swift in Sources */,
168505EA1E288D80005B4537 /* PhotoViewController.swift in Sources */,
056AAB091F97CB1700F6A978 /* Orientation.swift in Sources */,
16298B561E2703DC0056D413 /* SwiftyRecordButton.swift in Sources */,
1675A98D1E00A74A00B80903 /* PreviewView.swift in Sources */,

View file

@ -1,51 +0,0 @@
/*Copyright (c) 2016, Andrew Walz.
Redistribution and use in source and binary forms, with or without modification,are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
import UIKit
class PhotoViewController: UIViewController {
override var prefersStatusBarHidden: Bool {
return true
}
private var backgroundImage: UIImage
init(image: UIImage) {
self.backgroundImage = image
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.gray
let backgroundImageView = UIImageView(frame: view.frame)
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: UIControl.State())
cancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside)
view.addSubview(cancelButton)
}
@objc func cancel() {
dismiss(animated: true, completion: nil)
}
}

View file

@ -62,10 +62,7 @@ class VideoViewController: UIViewController {
// Allow background audio to continue to play
do {
if #available(iOS 10.0, *) {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: [])
} else {
}
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: [])
} catch let error as NSError {
print(error)
}

View file

@ -27,7 +27,6 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate {
super.viewDidLoad()
shouldPrompToAppSettings = true
cameraDelegate = self
maximumVideoDuration = 10.0
shouldUseDeviceOrientation = true
allowAutoRotate = true
audioEnabled = true
@ -56,11 +55,6 @@ class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate {
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage) {
let newVC = PhotoViewController(image: photo)
self.present(newVC, animated: true, completion: nil)
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didBeginRecordingVideo camera: SwiftyCamViewController.CameraSelection) {
print("Did Begin Recording")
captureButton.growButton()

View file

@ -71,6 +71,8 @@ class Orientation {
return AVCaptureVideoOrientation.landscapeRight
case .portraitUpsideDown:
return AVCaptureVideoOrientation.portraitUpsideDown
@unknown default:
return .portrait
}
}

View file

@ -20,33 +20,21 @@ import UIKit
/// Delegate for SwiftyCamButton
public protocol SwiftyCamButtonDelegate: class {
public protocol SwiftyCamButtonDelegate: AnyObject {
/// Called when UITapGestureRecognizer begins
func buttonWasTapped()
/// Called When UILongPressGestureRecognizer enters UIGestureRecognizerState.began
func buttonDidBeginLongPress()
/// Called When UILongPressGestureRecognizer enters UIGestureRecognizerState.end
/// Called when the button is first pressed
func buttonDidEndLongPress()
func buttonDidBeginPress()
/// Called when the maximum duration is reached
func longPressDidReachMaximumDuration()
/// Sets the maximum duration of the video recording
func setMaxiumVideoDuration() -> Double
/// Called when the button is released
func buttonDidEndPress()
}
// MARK: Public View Declaration
/// UIButton Subclass for Capturing Photo and Video with SwiftyCamViewController
/// UIButton Subclass for Capturing Video with SwiftyCamViewController
open class SwiftyCamButton: UIButton {
@ -58,84 +46,27 @@ open class SwiftyCamButton: UIButton {
public var buttonEnabled = true
/// Maximum duration variable
fileprivate var timer : Timer?
/// Initialization Declaration
override public init(frame: CGRect) {
super.init(frame: frame)
createGestureRecognizers()
}
/// Initialization Declaration
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createGestureRecognizers()
}
/// UITapGestureRecognizer Function
@objc fileprivate func Tap() {
guard buttonEnabled == true else {
return
}
delegate?.buttonWasTapped()
}
/// UILongPressGestureRecognizer Function
@objc fileprivate func LongPress(_ sender:UILongPressGestureRecognizer!) {
guard buttonEnabled == true else {
return
}
switch sender.state {
case .began:
delegate?.buttonDidBeginLongPress()
startTimer()
case .cancelled, .ended, .failed:
invalidateTimer()
delegate?.buttonDidEndLongPress()
default:
break
if buttonEnabled {
delegate?.buttonDidBeginPress()
}
}
/// Timer Finished
@objc fileprivate func timerFinished() {
invalidateTimer()
delegate?.longPressDidReachMaximumDuration()
}
/// Start Maximum Duration Timer
fileprivate func startTimer() {
if let duration = delegate?.setMaxiumVideoDuration() {
//Check if duration is set, and greater than zero
if duration != 0.0 && duration > 0.0 {
timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(SwiftyCamButton.timerFinished), userInfo: nil, repeats: false)
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
if buttonEnabled {
delegate?.buttonDidEndPress()
}
}
// End timer if UILongPressGestureRecognizer is ended before time has ended
fileprivate func invalidateTimer() {
timer?.invalidate()
timer = nil
}
// Add Tap and LongPress gesture recognizers
fileprivate func createGestureRecognizers() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SwiftyCamButton.Tap))
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(SwiftyCamButton.LongPress))
self.addGestureRecognizer(tapGesture)
self.addGestureRecognizer(longGesture)
open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
if buttonEnabled {
delegate?.buttonDidEndPress()
}
}
}

View file

@ -115,22 +115,10 @@ open class SwiftyCamViewController: UIViewController {
public weak var cameraDelegate: SwiftyCamViewControllerDelegate?
/// Maxiumum video duration if SwiftyCamButton is used
public var maximumVideoDuration : Double = 0.0
/// Video capture quality
public var videoQuality : VideoQuality = .high
/// Sets whether flash is enabled for photo and video capture
@available(*, deprecated, message: "use flashMode .on or .off") //use flashMode
public var flashEnabled: Bool = false {
didSet{
self.flashMode = self.flashEnabled ? .on : .off
}
}
// Flash Mode
public var flashMode:FlashMode = .off
@ -172,7 +160,7 @@ open class SwiftyCamViewController: UIViewController {
public var defaultCamera = CameraSelection.rear
/// Sets wether the taken photo or video should be oriented according to the device orientation
/// Sets wether the taken video should be oriented according to the device orientation
public var shouldUseDeviceOrientation = false {
didSet {
@ -259,10 +247,6 @@ open class SwiftyCamViewController: UIViewController {
fileprivate var movieFileOutput : AVCaptureMovieFileOutput?
/// Photo File Output variable
fileprivate var photoFileOutput : AVCaptureStillImageOutput?
/// Video Device variable
fileprivate var videoDevice : AVCaptureDevice?
@ -477,31 +461,6 @@ open class SwiftyCamViewController: UIViewController {
/**
Capture photo from current session
UIImage will be returned with the SwiftyCamViewControllerDelegate function SwiftyCamDidTakePhoto(photo:)
*/
public func takePhoto() {
guard let device = videoDevice else {
return
}
if device.hasFlash == true && flashMode != .off /* TODO: Add Support for Retina Flash and add front flash */ {
changeFlashSettings(device: device, mode: flashMode)
capturePhotoAsyncronously(completionHandler: { (_) in })
}else{
if device.isFlashActive == true {
changeFlashSettings(device: device, mode: flashMode)
}
capturePhotoAsyncronously(completionHandler: { (_) in })
}
}
/**
Begin recording video of current session
SwiftyCamViewControllerDelegate function SwiftyCamDidBeginRecordingVideo() will be called
@ -662,7 +621,6 @@ open class SwiftyCamViewController: UIViewController {
addVideoInput()
addAudioInput()
configureVideoOutput()
configurePhotoOutput()
session.commitConfiguration()
}
@ -790,12 +748,10 @@ open class SwiftyCamViewController: UIViewController {
connection.preferredVideoStabilizationMode = .auto
}
if #available(iOS 11.0, *) {
if let videoCodecType = videoCodecType {
if movieFileOutput.availableVideoCodecTypes.contains(videoCodecType) == true {
// Use the H.264 codec to encode the video.
movieFileOutput.setOutputSettings([AVVideoCodecKey: videoCodecType], for: connection)
}
if let videoCodecType = videoCodecType {
if movieFileOutput.availableVideoCodecTypes.contains(videoCodecType) == true {
// Use the H.264 codec to encode the video.
movieFileOutput.setOutputSettings([AVVideoCodecKey: videoCodecType], for: connection)
}
}
}
@ -803,67 +759,6 @@ open class SwiftyCamViewController: UIViewController {
}
}
/// 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
}
}
/**
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.orientation.getImageOrientation(forCamera: self.currentCamera))
return image
}
fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) {
guard sessionRunning == true else {
print("[SwiftyCam]: Cannot take photo. Capture session is not running")
return
}
if let videoConnection = photoFileOutput?.connection(with: AVMediaType.video) {
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() {
@ -874,13 +769,7 @@ open class SwiftyCamViewController: UIViewController {
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: UIApplication.openSettingsURLString)!)
} else {
if let appSettings = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.openURL(appSettings)
}
}
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}))
self.present(alertController, animated: true, completion: nil)
})
@ -905,52 +794,15 @@ open class SwiftyCamViewController: UIViewController {
case .resolution1920x1080: return AVCaptureSession.Preset.hd1920x1080.rawValue
case .iframe960x540: return AVCaptureSession.Preset.iFrame960x540.rawValue
case .iframe1280x720: return AVCaptureSession.Preset.iFrame1280x720.rawValue
case .resolution3840x2160:
if #available(iOS 9.0, *) {
return AVCaptureSession.Preset.hd4K3840x2160.rawValue
}
else {
print("[SwiftyCam]: Resolution 3840x2160 not supported")
return AVCaptureSession.Preset.high.rawValue
}
case .resolution3840x2160: return AVCaptureSession.Preset.hd4K3840x2160.rawValue
}
}
/// Get Devices
fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevice.Position) -> AVCaptureDevice? {
if #available(iOS 10.0, *) {
let avDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType(rawValue: mediaType), position: position)
return avDevice
} else {
// Fallback on earlier versions
let avDevice = AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType))
var avDeviceNum = 0
for device in avDevice {
print("deviceWithMediaType Position: \(device.position.rawValue)")
if device.position == position {
break
} else {
avDeviceNum += 1
}
}
return avDevice[avDeviceNum]
}
//return AVCaptureDevice.devices(for: AVMediaType(rawValue: mediaType), position: position).first
}
/// Enable or disable flash for photo
fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: FlashMode) {
do {
try device.lockForConfiguration()
device.flashMode = mode.AVFlashMode
device.unlockForConfiguration()
} catch {
print("[SwiftyCam]: \(error)")
}
let avDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType(rawValue: mediaType), position: position)
return avDevice
}
/// Enable flash
@ -1012,14 +864,7 @@ fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: FlashMode) {
}
do{
if #available(iOS 10.0, *) {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
} else {
let options: [AVAudioSession.CategoryOptions] = [.mixWithOthers, .allowBluetooth]
let category = AVAudioSession.Category.playAndRecord
let selector = NSSelectorFromString("setCategory:withOptions:error:")
AVAudioSession.sharedInstance().perform(selector, with: category, with: options)
}
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
try AVAudioSession.sharedInstance().setActive(true)
session.automaticallyConfiguresApplicationAudioSession = false
}
@ -1050,34 +895,15 @@ fileprivate func changeFlashSettings(device: AVCaptureDevice, mode: FlashMode) {
extension SwiftyCamViewController : SwiftyCamButtonDelegate {
/// Sets the maximum duration of the SwiftyCamButton
/// Begin video when the button is pressed down
public func setMaxiumVideoDuration() -> Double {
return maximumVideoDuration
}
/// Set UITapGesture to take photo
public func buttonWasTapped() {
takePhoto()
}
/// Set UILongPressGesture start to begin video
public func buttonDidBeginLongPress() {
public func buttonDidBeginPress() {
startVideoRecording()
}
/// Set UILongPressGesture begin to begin end video
/// End video when the button is released
public func buttonDidEndLongPress() {
stopVideoRecording()
}
/// Called if maximum duration is reached
public func longPressDidReachMaximumDuration() {
public func buttonDidEndPress() {
stopVideoRecording()
}
}
@ -1117,13 +943,21 @@ extension SwiftyCamViewController {
/// Handle pinch gesture
private var firstCaptureDevice: AVCaptureDevice? {
AVCaptureDevice.DiscoverySession(
deviceTypes: [.builtInDualCamera, .builtInWideAngleCamera],
mediaType: .video,
position: .unspecified
).devices.first
}
@objc fileprivate func zoomGesture(pinch: UIPinchGestureRecognizer) {
guard pinchToZoom == true && self.currentCamera == .rear else {
//ignore pinch
return
}
do {
let captureDevice = AVCaptureDevice.devices().first
let captureDevice = firstCaptureDevice
try captureDevice?.lockForConfiguration()
zoomScale = min(maxZoomScale, max(1.0, min(beginZoomScale * pinch.scale, captureDevice!.activeFormat.videoMaxZoomFactor)))
@ -1198,7 +1032,7 @@ extension SwiftyCamViewController {
let translationDifference = currentTranslation - previousPanTranslation
do {
let captureDevice = AVCaptureDevice.devices().first
let captureDevice = firstCaptureDevice
try captureDevice?.lockForConfiguration()
let currentZoom = captureDevice?.videoZoomFactor ?? 0.0

View file

@ -21,12 +21,12 @@ import AVFoundation
/// Delegate for SwiftyCamViewController
public protocol SwiftyCamViewControllerDelegate: class {
public protocol SwiftyCamViewControllerDelegate: AnyObject {
/**
SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController session did start running.
Photos and video capture will be enabled.
Video capture will be enabled.
- Parameter swiftyCam: Current SwiftyCamViewController
*/
@ -34,22 +34,13 @@ public protocol SwiftyCamViewControllerDelegate: class {
/**
SwiftyCamViewControllerDelegate function called when when SwiftyCamViewController session did stops running.
Photos and video capture will be disabled.
Video capture will be disabled.
- Parameter swiftyCam: Current SwiftyCamViewController
*/
func swiftyCamSessionDidStopRunning(_ swiftyCam: SwiftyCamViewController)
/**
SwiftyCamViewControllerDelegate function called when the takePhoto() function is called.
- Parameter swiftyCam: Current SwiftyCamViewController session
- Parameter photo: UIImage captured from the current session
*/
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage)
/**
SwiftyCamViewControllerDelegate function called when SwiftyCamViewController begins recording video.
@ -142,21 +133,14 @@ public extension SwiftyCamViewControllerDelegate {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage) {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didBeginRecordingVideo camera: SwiftyCamViewController.CameraSelection) {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishRecordingVideo camera: SwiftyCamViewController.CameraSelection) {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishProcessVideoAt url: URL) {
// Optional
}
@ -168,13 +152,11 @@ public extension SwiftyCamViewControllerDelegate {
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didSwitchCameras camera: SwiftyCamViewController.CameraSelection) {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFocusAtPoint point: CGPoint) {
// Optional
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didChangeZoomLevel zoom: CGFloat) {
// Optional
}