diff --git a/ALCameraViewController.podspec b/ALCameraViewController.podspec index d7dd9899..c2a26ab3 100644 --- a/ALCameraViewController.podspec +++ b/ALCameraViewController.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |spec| - spec.name = "ALCameraViewController" - spec.version = "3.0.3" + spec.name = "ALCameraViewController-Tulleb" + spec.version = "3.1" spec.summary = "A camera view controller with custom image picker and image cropping." - spec.source = { :git => "https://github.com/AlexLittlejohn/ALCameraViewController.git", :tag => spec.version.to_s } + spec.source = { :git => "https://github.com/Tulleb/ALCameraViewController.git", :tag => spec.version.to_s } spec.requires_arc = true spec.platform = :ios, "8.0" spec.license = "MIT" spec.source_files = "ALCameraViewController/**/*.{swift}" spec.resources = ["ALCameraViewController/ViewController/ConfirmViewController.xib", "ALCameraViewController/CameraViewAssets.xcassets", "ALCameraViewController/CameraView.strings"] - spec.homepage = "https://github.com/AlexLittlejohn/ALCameraViewController" - spec.author = { "Alex Littlejohn" => "alexlittlejohn@me.com" } - spec.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.0' } + spec.homepage = "https://github.com/Tulleb/ALCameraViewController" + spec.author = { "Alex Littlejohn" => "alexlittlejohn@me.com", "Guillaume Bellut" => "guillaume@bellut.com" } + spec.pod_target_xcconfig = { 'SWIFT_VERSION' => '5.0' } end diff --git a/ALCameraViewController.xcodeproj/project.pbxproj b/ALCameraViewController.xcodeproj/project.pbxproj index 720f06f0..9c02f1f9 100644 --- a/ALCameraViewController.xcodeproj/project.pbxproj +++ b/ALCameraViewController.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 1F3C56291F701CA7009667E9 /* CroppingParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */; }; 7AC96FA21F5B5166003E53F4 /* CroppingParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */; }; + 7AD3B52D23521955002BAD73 /* CropOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AD3B52C23521955002BAD73 /* CropOverlay.swift */; }; 7C6AF41F1FB340CA006CB4ED /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7C6AF41E1FB340CA006CB4ED /* LaunchScreen.xib */; }; C40665441C73A47C00EB9751 /* SingleImageSaver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665431C73A47C00EB9751 /* SingleImageSaver.swift */; }; C40665461C73A94100EB9751 /* CameraGlobals.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665451C73A94100EB9751 /* CameraGlobals.swift */; }; @@ -32,7 +33,6 @@ C482A00F1CAEB18D00541D08 /* ImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAB50BEE1B413E8C009905B9 /* ImageCell.swift */; }; C482A0101CAEB18D00541D08 /* PermissionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */; }; C482A0111CAEB18D00541D08 /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAF058671B3175C5008E5592 /* CameraView.swift */; }; - C482A0121CAEB18D00541D08 /* CropOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA787F1B1B4326F100B6B86E /* CropOverlay.swift */; }; C482A0141CAEB1B100541D08 /* CameraView.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA8231371B3BF8F700A837BE /* CameraView.strings */; }; C482A0151CAEB1B100541D08 /* CameraViewAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5FA3441B3AFEB300497C62 /* CameraViewAssets.xcassets */; }; C484580B1D0AA44400ECDB15 /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBFE097C1CAF1D1A00A8C637 /* UIViewExtensions.swift */; }; @@ -45,7 +45,6 @@ FA5FA3431B3AFA2B00497C62 /* PermissionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */; }; FA5FA3451B3AFEB300497C62 /* CameraViewAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5FA3441B3AFEB300497C62 /* CameraViewAssets.xcassets */; }; FA778A411B8319D8005807E7 /* image.jpg in Resources */ = {isa = PBXBuildFile; fileRef = FA778A401B8319D8005807E7 /* image.jpg */; }; - FA787F1C1B4326F100B6B86E /* CropOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA787F1B1B4326F100B6B86E /* CropOverlay.swift */; }; FA7E6B9B1B429012000E1B14 /* ConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7E6B9A1B429012000E1B14 /* ConfirmViewController.swift */; }; FA8231381B3BF8F700A837BE /* CameraView.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA8231371B3BF8F700A837BE /* CameraView.strings */; }; FA82313A1B3C296C00A837BE /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8231391B3C296C00A837BE /* Utilities.swift */; }; @@ -62,6 +61,7 @@ /* Begin PBXFileReference section */ 7AC96FA11F5B5166003E53F4 /* CroppingParameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CroppingParameters.swift; sourceTree = ""; }; + 7AD3B52C23521955002BAD73 /* CropOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CropOverlay.swift; sourceTree = ""; }; 7C6AF41E1FB340CA006CB4ED /* LaunchScreen.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; C40665431C73A47C00EB9751 /* SingleImageSaver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleImageSaver.swift; sourceTree = ""; }; C40665451C73A94100EB9751 /* CameraGlobals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraGlobals.swift; sourceTree = ""; }; @@ -79,7 +79,6 @@ FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsView.swift; sourceTree = ""; }; FA5FA3441B3AFEB300497C62 /* CameraViewAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = CameraViewAssets.xcassets; sourceTree = ""; }; FA778A401B8319D8005807E7 /* image.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image.jpg; sourceTree = ""; }; - FA787F1B1B4326F100B6B86E /* CropOverlay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropOverlay.swift; sourceTree = ""; }; FA7E6B9A1B429012000E1B14 /* ConfirmViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfirmViewController.swift; sourceTree = ""; }; FA8231371B3BF8F700A837BE /* CameraView.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = CameraView.strings; sourceTree = ""; }; FA8231391B3C296C00A837BE /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; tabWidth = 4; }; @@ -141,7 +140,7 @@ FAB50BEE1B413E8C009905B9 /* ImageCell.swift */, FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */, FAF058671B3175C5008E5592 /* CameraView.swift */, - FA787F1B1B4326F100B6B86E /* CropOverlay.swift */, + 7AD3B52C23521955002BAD73 /* CropOverlay.swift */, ); path = Views; sourceTree = ""; @@ -283,8 +282,8 @@ }; FAF0583E1B31618D008E5592 = { CreatedOnToolsVersion = 6.3.2; - DevelopmentTeam = 2466624KEK; - LastSwiftMigration = 0900; + DevelopmentTeam = 9E43V6CC9L; + LastSwiftMigration = 1110; ProvisioningStyle = Automatic; }; }; @@ -294,6 +293,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -358,7 +358,6 @@ C482A00F1CAEB18D00541D08 /* ImageCell.swift in Sources */, C482A0101CAEB18D00541D08 /* PermissionsView.swift in Sources */, C482A0111CAEB18D00541D08 /* CameraView.swift in Sources */, - C482A0121CAEB18D00541D08 /* CropOverlay.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -381,12 +380,12 @@ EBFE097D1CAF1D1A00A8C637 /* UIViewExtensions.swift in Sources */, C40665481C73B72D00EB9751 /* SingleImageFetcher.swift in Sources */, FAF058471B31618D008E5592 /* ViewController.swift in Sources */, + 7AD3B52D23521955002BAD73 /* CropOverlay.swift in Sources */, FAF058681B3175C5008E5592 /* CameraView.swift in Sources */, C4D9BA471CA73163004F70F7 /* UIButtonExtensions.swift in Sources */, C40665461C73A94100EB9751 /* CameraGlobals.swift in Sources */, FAF058451B31618D008E5592 /* AppDelegate.swift in Sources */, C40665441C73A47C00EB9751 /* SingleImageSaver.swift in Sources */, - FA787F1C1B4326F100B6B86E /* CropOverlay.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -408,6 +407,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 3.1; PRODUCT_BUNDLE_IDENTIFIER = com.zero.CameraViewController; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -432,6 +432,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MARKETING_VERSION = 3.1; PRODUCT_BUNDLE_IDENTIFIER = com.zero.CameraViewController; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -548,14 +549,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = 2466624KEK; + DEVELOPMENT_TEAM = 9E43V6CC9L; INFOPLIST_FILE = "Example/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 3.1; PRODUCT_BUNDLE_IDENTIFIER = com.alx.zero.CameraViewController; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -564,14 +566,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEVELOPMENT_TEAM = 2466624KEK; + DEVELOPMENT_TEAM = 9E43V6CC9L; INFOPLIST_FILE = "Example/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + MARKETING_VERSION = 3.1; PRODUCT_BUNDLE_IDENTIFIER = com.alx.zero.CameraViewController; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; diff --git a/ALCameraViewController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ALCameraViewController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/ALCameraViewController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ALCameraViewController/Utilities/Utilities.swift b/ALCameraViewController/Utilities/Utilities.swift index 804ad970..707cc5c7 100644 --- a/ALCameraViewController/Utilities/Utilities.swift +++ b/ALCameraViewController/Utilities/Utilities.swift @@ -68,7 +68,7 @@ internal func errorWithKey(_ key: String, domain: String) -> NSError { return error } -internal func normalizedRect(_ rect: CGRect, orientation: UIImageOrientation) -> CGRect { +internal func normalizedRect(_ rect: CGRect, orientation: UIImage.Orientation) -> CGRect { let normalizedX = rect.origin.x let normalizedY = rect.origin.y diff --git a/ALCameraViewController/Utilities/VolumeControl.swift b/ALCameraViewController/Utilities/VolumeControl.swift index 36172f8a..f66e2bc6 100644 --- a/ALCameraViewController/Utilities/VolumeControl.swift +++ b/ALCameraViewController/Utilities/VolumeControl.swift @@ -27,7 +27,7 @@ public class VolumeControl { init(view: UIView, onVolumeChange: VolumeChangeAction?) { self.onVolumeChange = onVolumeChange view.addSubview(volumeView) - view.sendSubview(toBack: volumeView) + view.sendSubviewToBack(volumeView) try? AVAudioSession.sharedInstance().setActive(true) NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: NSNotification.Name(rawValue: changeKey), object: nil) diff --git a/ALCameraViewController/ViewController/CameraViewController.swift b/ALCameraViewController/ViewController/CameraViewController.swift index d9e07099..cdf394fb 100644 --- a/ALCameraViewController/ViewController/CameraViewController.swift +++ b/ALCameraViewController/ViewController/CameraViewController.swift @@ -56,7 +56,7 @@ open class CameraViewController: UIViewController { var animationDuration: TimeInterval = 0.5 var animationSpring: CGFloat = 0.5 - var rotateAnimation: UIViewAnimationOptions = .curveLinear + var rotateAnimation: UIView.AnimationOptions = .curveLinear var cameraButtonEdgeConstraint: NSLayoutConstraint? var cameraButtonGravityConstraint: NSLayoutConstraint? @@ -78,23 +78,12 @@ open class CameraViewController: UIViewController { var flashButtonEdgeConstraint: NSLayoutConstraint? var flashButtonGravityConstraint: NSLayoutConstraint? - - var cameraOverlayEdgeOneConstraint: NSLayoutConstraint? - var cameraOverlayEdgeTwoConstraint: NSLayoutConstraint? - var cameraOverlayWidthConstraint: NSLayoutConstraint? - var cameraOverlayCenterConstraint: NSLayoutConstraint? - + let cameraView : CameraView = { let cameraView = CameraView() cameraView.translatesAutoresizingMaskIntoConstraints = false return cameraView }() - - let cameraOverlay : CropOverlay = { - let cameraOverlay = CropOverlay() - cameraOverlay.translatesAutoresizingMaskIntoConstraints = false - return cameraOverlay - }() let cameraButton : UIButton = { let button = UIButton(frame: CGRect(x: 0, y: 0, width: 64, height: 64)) @@ -170,8 +159,6 @@ open class CameraViewController: UIViewController { self.allowVolumeButtonCapture = allowVolumeButtonCapture super.init(nibName: nil, bundle: nil) onCompletion = completion - cameraOverlay.isHidden = !croppingParameters.isEnabled - cameraOverlay.isUserInteractionEnabled = false libraryButton.isEnabled = allowsLibraryAccess libraryButton.isHidden = !allowsLibraryAccess swapButton.isEnabled = allowsSwapCameraOrientation @@ -199,7 +186,6 @@ open class CameraViewController: UIViewController { super.loadView() view.backgroundColor = UIColor.black [cameraView, - cameraOverlay, cameraButton, closeButton, flashButton, @@ -247,14 +233,7 @@ open class CameraViewController: UIViewController { configFlashEdgeButtonConstraint(statusBarOrientation) configFlashGravityButtonConstraint(statusBarOrientation) - - let padding : CGFloat = portrait ? 16.0 : -16.0 - removeCameraOverlayEdgesConstraints() - configCameraOverlayEdgeOneContraint(portrait, padding: padding) - configCameraOverlayEdgeTwoConstraint(portrait, padding: padding) - configCameraOverlayWidthConstraint(portrait) - configCameraOverlayCenterConstraint(portrait) - + rotate(actualInterfaceOrientation: statusBarOrientation) super.updateViewConstraints() @@ -273,7 +252,6 @@ open class CameraViewController: UIViewController { super.viewDidLoad() setupActions() checkPermissions() - cameraView.configureFocus() cameraView.configureZoom() } @@ -349,7 +327,7 @@ open class CameraViewController: UIViewController { NotificationCenter.default.addObserver( self, selector: #selector(rotateCameraView), - name: NSNotification.Name.UIDeviceOrientationDidChange, + name: UIDevice.orientationDidChangeNotification, object: nil) } @@ -631,12 +609,12 @@ open class CameraViewController: UIViewController { private func showSpinner() -> UIActivityIndicatorView { let spinner = UIActivityIndicatorView() - spinner.activityIndicatorViewStyle = .white + spinner.style = .white spinner.center = view.center spinner.startAnimating() view.addSubview(spinner) - view.bringSubview(toFront: spinner) + view.bringSubviewToFront(spinner) return spinner } diff --git a/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift b/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift index 37e518c9..b0523b1a 100644 --- a/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift +++ b/ALCameraViewController/ViewController/CameraViewControllerConstraint.swift @@ -44,7 +44,7 @@ extension CameraViewController { func configCameraButtonEdgeConstraint(_ statusBarOrientation: UIInterfaceOrientation) { view.autoRemoveConstraint(cameraButtonEdgeConstraint) - let attribute : NSLayoutAttribute = { + let attribute : NSLayoutConstraint.Attribute = { switch statusBarOrientation { case .portrait: return .bottomMargin case .landscapeRight: return .rightMargin @@ -72,7 +72,7 @@ extension CameraViewController { */ func configCameraButtonGravityConstraint(_ portrait: Bool) { view.autoRemoveConstraint(cameraButtonGravityConstraint) - let attribute : NSLayoutAttribute = portrait ? .centerX : .centerY + let attribute : NSLayoutConstraint.Attribute = portrait ? .centerX : .centerY cameraButtonGravityConstraint = NSLayoutConstraint( item: cameraButton, attribute: attribute, @@ -100,8 +100,8 @@ extension CameraViewController { */ func configContainerEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attributeOne : NSLayoutAttribute - let attributeTwo : NSLayoutAttribute + let attributeOne : NSLayoutConstraint.Attribute + let attributeTwo : NSLayoutConstraint.Attribute switch statusBarOrientation { case .portrait: @@ -149,7 +149,7 @@ extension CameraViewController { * orientation of the device. */ func configContainerGravityConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attributeCenter : NSLayoutAttribute = statusBarOrientation.isPortrait ? .centerY : .centerX + let attributeCenter : NSLayoutConstraint.Attribute = statusBarOrientation.isPortrait ? .centerY : .centerX containerButtonsGravityConstraint = NSLayoutConstraint( item: containerSwapLibraryButton, attribute: attributeCenter, @@ -179,8 +179,8 @@ extension CameraViewController { */ func configSwapButtonEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attributeOne : NSLayoutAttribute - let attributeTwo : NSLayoutAttribute + let attributeOne : NSLayoutConstraint.Attribute + let attributeTwo : NSLayoutConstraint.Attribute switch statusBarOrientation { case .portrait: @@ -249,7 +249,7 @@ extension CameraViewController { */ func configCloseButtonEdgeConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attribute : NSLayoutAttribute = { + let attribute : NSLayoutConstraint.Attribute = { switch statusBarOrientation { case .portrait: return .left case .landscapeRight, .landscapeLeft: return .centerX @@ -278,7 +278,7 @@ extension CameraViewController { */ func configCloseButtonGravityConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attribute : NSLayoutAttribute + let attribute : NSLayoutConstraint.Attribute let constant : CGFloat switch statusBarOrientation { @@ -331,8 +331,8 @@ extension CameraViewController { */ func configLibraryEdgeButtonConstraint(_ statusBarOrientation : UIInterfaceOrientation) { - let attributeOne : NSLayoutAttribute - let attributeTwo : NSLayoutAttribute + let attributeOne : NSLayoutConstraint.Attribute + let attributeTwo : NSLayoutConstraint.Attribute switch statusBarOrientation { case .portrait: @@ -401,7 +401,7 @@ extension CameraViewController { view.autoRemoveConstraint(flashButtonEdgeConstraint) let constraintRight = statusBarOrientation == .portrait || statusBarOrientation == .landscapeRight - let attribute : NSLayoutAttribute = constraintRight ? .topMargin : .bottomMargin + let attribute : NSLayoutConstraint.Attribute = constraintRight ? .topMargin : .bottomMargin flashButtonEdgeConstraint = NSLayoutConstraint( item: flashButton, @@ -425,7 +425,7 @@ extension CameraViewController { view.autoRemoveConstraint(flashButtonGravityConstraint) let constraintRight = statusBarOrientation == .portrait || statusBarOrientation == .landscapeLeft - let attribute : NSLayoutAttribute = constraintRight ? .right : .left + let attribute : NSLayoutConstraint.Attribute = constraintRight ? .right : .left flashButtonGravityConstraint = NSLayoutConstraint( item: flashButton, @@ -437,92 +437,5 @@ extension CameraViewController { constant: constraintRight ? -8 : 8) view.addConstraint(flashButtonGravityConstraint!) } - - /** - * Used to create a perfect square for CameraOverlay. - * This method will determinate the size of CameraOverlay, - * if portrait, it will use the width of superview to - * determinate the height of the view. Else if landscape, - * it uses the height of the superview to create the width - * of the CameraOverlay. - */ - func configCameraOverlayWidthConstraint(_ portrait: Bool) { - view.autoRemoveConstraint(cameraOverlayWidthConstraint) - cameraOverlayWidthConstraint = NSLayoutConstraint( - item: cameraOverlay, - attribute: portrait ? .height : .width, - relatedBy: .equal, - toItem: cameraOverlay, - attribute: portrait ? .width : .height, - multiplier: 1.0, - constant: 0) - view.addConstraint(cameraOverlayWidthConstraint!) - } - - /** - * This method will center the relative position of - * CameraOverlay, based on the biggest size of the - * superview. - */ - func configCameraOverlayCenterConstraint(_ portrait: Bool) { - view.autoRemoveConstraint(cameraOverlayCenterConstraint) - let attribute : NSLayoutAttribute = portrait ? .centerY : .centerX - cameraOverlayCenterConstraint = NSLayoutConstraint( - item: cameraOverlay, - attribute: attribute, - relatedBy: .equal, - toItem: view, - attribute: attribute, - multiplier: 1.0, - constant: 0) - view.addConstraint(cameraOverlayCenterConstraint!) - } - - /** - * Remove the CameraOverlay constraints to be updated when - * the device was rotated. - */ - func removeCameraOverlayEdgesConstraints() { - view.autoRemoveConstraint(cameraOverlayEdgeOneConstraint) - view.autoRemoveConstraint(cameraOverlayEdgeTwoConstraint) - } - - /** - * It needs to get a determined smallest size of the screen - to create the smallest size to be used on CameraOverlay. - It uses the orientation of the screen to determinate where - the view will be pinned. - */ - func configCameraOverlayEdgeOneContraint(_ portrait: Bool, padding: CGFloat) { - let attribute : NSLayoutAttribute = portrait ? .left : .bottom - cameraOverlayEdgeOneConstraint = NSLayoutConstraint( - item: cameraOverlay, - attribute: attribute, - relatedBy: .equal, - toItem: view, - attribute: attribute, - multiplier: 1.0, - constant: padding) - view.addConstraint(cameraOverlayEdgeOneConstraint!) - } - - /** - * It needs to get a determined smallest size of the screen - to create the smallest size to be used on CameraOverlay. - It uses the orientation of the screen to determinate where - the view will be pinned. - */ - func configCameraOverlayEdgeTwoConstraint(_ portrait: Bool, padding: CGFloat) { - let attributeTwo : NSLayoutAttribute = portrait ? .right : .top - cameraOverlayEdgeTwoConstraint = NSLayoutConstraint( - item: cameraOverlay, - attribute: attributeTwo, - relatedBy: .equal, - toItem: view, - attribute: attributeTwo, - multiplier: 1.0, - constant: -padding) - view.addConstraint(cameraOverlayEdgeTwoConstraint!) - } - + } diff --git a/ALCameraViewController/ViewController/ConfirmViewController.swift b/ALCameraViewController/ViewController/ConfirmViewController.swift index 5c7fb257..a8cd1ce9 100644 --- a/ALCameraViewController/ViewController/ConfirmViewController.swift +++ b/ALCameraViewController/ViewController/ConfirmViewController.swift @@ -9,14 +9,21 @@ import UIKit import Photos -public class ConfirmViewController: UIViewController, UIScrollViewDelegate { +public class ConfirmViewController: UIViewController { let imageView = UIImageView() @IBOutlet weak var scrollView: UIScrollView! - @IBOutlet weak var cropOverlay: CropOverlay! @IBOutlet weak var cancelButton: UIButton! @IBOutlet weak var confirmButton: UIButton! - @IBOutlet weak var centeringView: UIView! + @IBOutlet weak var centeredView: UIView! + + private let cropOverlay = CropOverlay() + private var spinner: UIActivityIndicatorView? = nil + private var cropOverlayLeftConstraint = NSLayoutConstraint() + private var cropOverlayTopConstraint = NSLayoutConstraint() + private var cropOverlayWidthConstraint = NSLayoutConstraint() + private var cropOverlayHeightConstraint = NSLayoutConstraint() + private var isFirstLayout = true var croppingParameters: CroppingParameters { didSet { @@ -25,8 +32,45 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } } - var verticalPadding: CGFloat = 30 - var horizontalPadding: CGFloat = 30 + private var scrollViewVisibleSize: CGSize { + let contentInset = scrollView.contentInset + let scrollViewSize = scrollView.bounds.standardized.size + let width = scrollViewSize.width - contentInset.left - contentInset.right + let height = scrollViewSize.height - contentInset.top - contentInset.bottom + return CGSize(width:width, height:height) + } + + private var scrollViewCenter: CGPoint { + let scrollViewSize = scrollViewVisibleSize + return CGPoint(x: scrollViewSize.width / 2.0, + y: scrollViewSize.height / 2.0) + } + + private let cropOverlayDefaultPadding: CGFloat = 20 + private var cropOverlayDefaultFrame: CGRect { + let buttonsViewGap: CGFloat = 20 * 2 + 64 + let centeredViewBounds: CGRect + if view.bounds.size.height > view.bounds.size.width { + centeredViewBounds = CGRect(x: 0, + y: 0, + width: view.bounds.size.width, + height: view.bounds.size.height - buttonsViewGap) + } else { + centeredViewBounds = CGRect(x: 0, + y: 0, + width: view.bounds.size.width - buttonsViewGap, + height: view.bounds.size.height) + } + + let cropOverlayWidth = min(centeredViewBounds.size.width, centeredViewBounds.size.height) - 2 * cropOverlayDefaultPadding + let cropOverlayX = centeredViewBounds.size.width / 2 - cropOverlayWidth / 2 + let cropOverlayY = centeredViewBounds.size.height / 2 - cropOverlayWidth / 2 + + return CGRect(x: cropOverlayX, + y: cropOverlayY, + width: cropOverlayWidth, + height: cropOverlayWidth) + } public var onComplete: CameraViewCompletion? @@ -63,17 +107,11 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { super.viewDidLoad() view.backgroundColor = UIColor.black - - scrollView.addSubview(imageView) - scrollView.delegate = self - scrollView.maximumZoomScale = 1 - - cropOverlay.isHidden = true - cropOverlay.isResizable = croppingParameters.allowResizing - cropOverlay.isMovable = croppingParameters.allowMoving - cropOverlay.minimumSize = croppingParameters.minimumSize - let spinner = showSpinner() + loadScrollView() + loadCropOverlay() + + showSpinner() disable() @@ -83,82 +121,86 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { .setTargetSize(largestPhotoSize()) .onSuccess { [weak self] image in self?.configureWithImage(image) - self?.hideSpinner(spinner) + self?.hideSpinner() self?.enable() } .onFailure { [weak self] error in - self?.hideSpinner(spinner) + self?.hideSpinner() } .fetch() } else if let image = image { configureWithImage(image) - hideSpinner(spinner) + hideSpinner() enable() } } - - public override func viewWillLayoutSubviews() { - super.viewWillLayoutSubviews() - let scale = calculateMinimumScale(view.frame.size) - let frame = croppingParameters.isEnabled ? cropOverlay.frame : view.bounds - - scrollView.contentInset = calculateScrollViewInsets(frame) - scrollView.minimumZoomScale = scale - scrollView.zoomScale = scale - centerScrollViewContents() - } - - public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransition(to: size, with: coordinator) - - let scale = calculateMinimumScale(size) - var frame = view.bounds - - if croppingParameters.isEnabled { - frame = cropOverlay.frame - let centeringFrame = centeringView.frame - var origin: CGPoint - - if size.width > size.height { // landscape - let offset = (size.width - centeringFrame.height) - let expectedX = (centeringFrame.height/2 - frame.height/2) + offset - origin = CGPoint(x: expectedX, y: frame.origin.x) - } else { - let expectedY = (centeringFrame.width/2 - frame.width/2) - origin = CGPoint(x: frame.origin.y, y: expectedY) - } - - frame.origin = origin - } else { - frame.size = size - } - - let insets = calculateScrollViewInsets(frame) - - coordinator.animate(alongsideTransition: { [weak self] context in - self?.scrollView.contentInset = insets - self?.scrollView.minimumZoomScale = scale - self?.scrollView.zoomScale = scale - self?.centerScrollViewContents() - self?.centerImageViewOnRotate() - }, completion: nil) - } + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if isFirstLayout { + isFirstLayout = false + activateCropOverlayConstraint() + spinner?.center = centeredView.center + } + } + + private func activateCropOverlayConstraint() { + cropOverlayLeftConstraint.constant = cropOverlayDefaultFrame.origin.x + cropOverlayTopConstraint.constant = cropOverlayDefaultFrame.origin.y + cropOverlayWidthConstraint.constant = cropOverlayDefaultFrame.size.width + cropOverlayHeightConstraint.constant = cropOverlayDefaultFrame.size.height + + cropOverlayLeftConstraint.isActive = true + cropOverlayTopConstraint.isActive = true + cropOverlayWidthConstraint.isActive = true + cropOverlayHeightConstraint.isActive = true + } + + private func loadScrollView() { + scrollView.addSubview(imageView) + scrollView.delegate = self + scrollView.maximumZoomScale = 1 + } + + private func prepareScrollView() { + let scale = calculateMinimumScale(view.bounds.size) + + scrollView.minimumZoomScale = scale + scrollView.zoomScale = scale + + centerScrollViewContent() + } + + private func loadCropOverlay() { + cropOverlay.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(cropOverlay) + + cropOverlayLeftConstraint = cropOverlay.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0) + cropOverlayTopConstraint = cropOverlay.topAnchor.constraint(equalTo: view.topAnchor, constant: 0) + cropOverlayWidthConstraint = cropOverlay.widthAnchor.constraint(equalToConstant: 0) + cropOverlayHeightConstraint = cropOverlay.heightAnchor.constraint(equalToConstant: 0) + + cropOverlay.delegate = self + cropOverlay.isHidden = !croppingParameters.isEnabled + cropOverlay.isResizable = croppingParameters.allowResizing + cropOverlay.isMovable = croppingParameters.allowMoving + cropOverlay.minimumSize = croppingParameters.minimumSize + } private func configureWithImage(_ image: UIImage) { - cropOverlay.isHidden = !croppingParameters.isEnabled - buttonActions() imageView.image = image imageView.sizeToFit() - view.setNeedsLayout() + prepareScrollView() } private func calculateMinimumScale(_ size: CGSize) -> CGFloat { var _size = size if croppingParameters.isEnabled { - _size = cropOverlay.frame.size + _size = cropOverlayDefaultFrame.size } guard let image = imageView.image else { @@ -171,39 +213,32 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { return min(scaleWidth, scaleHeight) } - private func calculateScrollViewInsets(_ frame: CGRect) -> UIEdgeInsets { - let bottom = view.frame.height - (frame.origin.y + frame.height) - let right = view.frame.width - (frame.origin.x + frame.width) - let insets = UIEdgeInsets(top: frame.origin.y, left: frame.origin.x, bottom: bottom, right: right) - return insets - } - - private func centerImageViewOnRotate() { - if croppingParameters.isEnabled { - let size = cropOverlay.frame.size - let scrollInsets = scrollView.contentInset - let imageSize = imageView.frame.size - var contentOffset = CGPoint(x: -scrollInsets.left, y: -scrollInsets.top) - contentOffset.x -= (size.width - imageSize.width) / 2 - contentOffset.y -= (size.height - imageSize.height) / 2 - scrollView.contentOffset = contentOffset - } - } - - private func centerScrollViewContents() { - let size = croppingParameters.isEnabled ? cropOverlay.frame.size : scrollView.frame.size - let imageSize = imageView.frame.size - var imageOrigin = CGPoint.zero - - if imageSize.width < size.width { - imageOrigin.x = (size.width - imageSize.width) / 2 - } - - if imageSize.height < size.height { - imageOrigin.y = (size.height - imageSize.height) / 2 - } - - imageView.frame.origin = imageOrigin + private func centerScrollViewContent() { + guard let image = imageView.image else { + return + } + + let imgViewSize = imageView.frame.size + let imageSize = image.size + + var realImgSize: CGSize + if imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height { + realImgSize = CGSize(width: imgViewSize.width,height: imgViewSize.width / imageSize.width * imageSize.height) + } else { + realImgSize = CGSize(width: imgViewSize.height / imageSize.height * imageSize.width, height: imgViewSize.height) + } + + var frame = CGRect.zero + frame.size = realImgSize + imageView.frame = frame + + let screenSize = scrollView.frame.size + let offx = screenSize.width > realImgSize.width ? (screenSize.width - realImgSize.width) / 2 : 0 + let offy = screenSize.height > realImgSize.height ? (screenSize.height - realImgSize.height) / 2 : 0 + scrollView.contentInset = UIEdgeInsets(top: offy, + left: offx, + bottom: offy, + right: offx) } private func buttonActions() { @@ -225,17 +260,17 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { imageView.isHidden = true - let spinner = showSpinner() + showSpinner() if let asset = asset { var fetcher = SingleImageFetcher() .onSuccess { [weak self] image in self?.onComplete?(image, self?.asset) - self?.hideSpinner(spinner) + self?.hideSpinner() self?.enable() } .onFailure { [weak self] error in - self?.hideSpinner(spinner) + self?.hideSpinner() self?.showNoImageScreen(error) } .setAsset(asset) @@ -258,34 +293,24 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } onComplete?(newImage, nil) - hideSpinner(spinner) + hideSpinner() enable() } } - public func viewForZooming(in scrollView: UIScrollView) -> UIView? { - return imageView - } - - public func scrollViewDidZoom(_ scrollView: UIScrollView) { - centerScrollViewContents() - } - - func showSpinner() -> UIActivityIndicatorView { - let spinner = UIActivityIndicatorView() - spinner.activityIndicatorViewStyle = .white - spinner.center = view.center - spinner.startAnimating() - - view.addSubview(spinner) - view.bringSubview(toFront: spinner) - - return spinner - } + func showSpinner() { + spinner = UIActivityIndicatorView() + spinner!.style = .white + spinner!.center = centeredView.center + spinner!.startAnimating() + + view.addSubview(spinner!) + view.bringSubviewToFront(spinner!) + } - func hideSpinner(_ spinner: UIActivityIndicatorView) { - spinner.stopAnimating() - spinner.removeFromSuperview() + func hideSpinner() { + spinner?.stopAnimating() + spinner?.removeFromSuperview() } func disable() { @@ -305,10 +330,7 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } private func makeProportionalCropRect() -> CGRect { - var cropRect = CGRect(x: cropOverlay.frame.origin.x + cropOverlay.outterGap, - y: cropOverlay.frame.origin.y + cropOverlay.outterGap, - width: cropOverlay.frame.size.width - 2 * cropOverlay.outterGap, - height: cropOverlay.frame.size.height - 2 * cropOverlay.outterGap) + var cropRect = cropOverlay.croppedRect cropRect.origin.x += scrollView.contentOffset.x - imageView.frame.origin.x cropRect.origin.y += scrollView.contentOffset.y - imageView.frame.origin.y @@ -326,6 +348,27 @@ public class ConfirmViewController: UIViewController, UIScrollViewDelegate { } +extension ConfirmViewController: UIScrollViewDelegate { + + public func viewForZooming(in scrollView: UIScrollView) -> UIView? { + return imageView + } + + public func scrollViewDidZoom(_ scrollView: UIScrollView) { + centerScrollViewContent() + } +} + +extension ConfirmViewController: CropOverlayDelegate { + + func didMoveCropOverlay(newFrame: CGRect) { + cropOverlayLeftConstraint.constant = newFrame.origin.x + cropOverlayTopConstraint.constant = newFrame.origin.y + cropOverlayWidthConstraint.constant = newFrame.size.width + cropOverlayHeightConstraint.constant = newFrame.size.height + } +} + extension UIImage { func crop(rect: CGRect) -> UIImage { diff --git a/ALCameraViewController/ViewController/ConfirmViewController.xib b/ALCameraViewController/ViewController/ConfirmViewController.xib index c3f3a9dc..705c686b 100644 --- a/ALCameraViewController/ViewController/ConfirmViewController.xib +++ b/ALCameraViewController/ViewController/ConfirmViewController.xib @@ -1,21 +1,16 @@ - - - - + + - - - + - + - @@ -28,19 +23,11 @@ - - - - - - - + + - - + + - - - - +