Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Commit

Permalink
Merge branch 'release/1.1.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexLittlejohn committed Mar 26, 2016
2 parents 47ec297 + 70b8ee0 commit 191270c
Show file tree
Hide file tree
Showing 20 changed files with 518 additions and 303 deletions.
2 changes: 1 addition & 1 deletion ALCameraViewController.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "ALCameraViewController"
spec.version = "1.1.7"
spec.version = "1.1.8"
spec.summary = "A camera view controller with custom image picker and image cropping. Written in Swift."
spec.source = { :git => "https://github.com/AlexLittlejohn/ALCameraViewController.git", :tag => spec.version.to_s }
spec.requires_arc = true
Expand Down
12 changes: 12 additions & 0 deletions ALCameraViewController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
C40665481C73B72D00EB9751 /* SingleImageFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40665471C73B72D00EB9751 /* SingleImageFetcher.swift */; };
C41E42B51BEC6F680028B993 /* ImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41E42B41BEC6F680028B993 /* ImageExtensions.swift */; };
C41E42B71BEC98520028B993 /* ConfirmViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C41E42B61BEC98520028B993 /* ConfirmViewController.xib */; };
C44543211CA68DDE00644380 /* VolumeControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44543201CA68DDE00644380 /* VolumeControl.swift */; };
C4D9BA451CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9BA441CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift */; };
C4D9BA471CA73163004F70F7 /* UIButtonExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4D9BA461CA73163004F70F7 /* UIButtonExtensions.swift */; };
FA52EE0B1B44129B00E16B6F /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FA52EE0A1B44129B00E16B6F /* ViewController.xib */; };
FA5FA3431B3AFA2B00497C62 /* PermissionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */; };
FA5FA3451B3AFEB300497C62 /* ALCameraViewAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA5FA3441B3AFEB300497C62 /* ALCameraViewAssets.xcassets */; };
Expand Down Expand Up @@ -48,6 +51,9 @@
C40665471C73B72D00EB9751 /* SingleImageFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleImageFetcher.swift; sourceTree = "<group>"; };
C41E42B41BEC6F680028B993 /* ImageExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageExtensions.swift; sourceTree = "<group>"; };
C41E42B61BEC98520028B993 /* ConfirmViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ConfirmViewController.xib; sourceTree = "<group>"; };
C44543201CA68DDE00644380 /* VolumeControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VolumeControl.swift; sourceTree = "<group>"; };
C4D9BA441CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoLibraryAuthorizer.swift; sourceTree = "<group>"; };
C4D9BA461CA73163004F70F7 /* UIButtonExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExtensions.swift; sourceTree = "<group>"; };
FA52EE0A1B44129B00E16B6F /* ViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = "<group>"; };
FA5FA3421B3AFA2B00497C62 /* PermissionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsView.swift; sourceTree = "<group>"; };
FA5FA3441B3AFEB300497C62 /* ALCameraViewAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ALCameraViewAssets.xcassets; sourceTree = "<group>"; };
Expand Down Expand Up @@ -122,6 +128,9 @@
FAF058691B317894008E5592 /* CameraShot.swift */,
C41E42B41BEC6F680028B993 /* ImageExtensions.swift */,
C40665451C73A94100EB9751 /* CameraGlobals.swift */,
C44543201CA68DDE00644380 /* VolumeControl.swift */,
C4D9BA441CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift */,
C4D9BA461CA73163004F70F7 /* UIButtonExtensions.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -300,6 +309,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C44543211CA68DDE00644380 /* VolumeControl.swift in Sources */,
FA7E6B9B1B429012000E1B14 /* ConfirmViewController.swift in Sources */,
FA5FA3431B3AFA2B00497C62 /* PermissionsView.swift in Sources */,
FAB50BFC1B413E8C009905B9 /* ImageFetcher.swift in Sources */,
Expand All @@ -308,10 +318,12 @@
FAF0586A1B317894008E5592 /* CameraShot.swift in Sources */,
FAF058661B316695008E5592 /* ALCameraViewController.swift in Sources */,
C41E42B51BEC6F680028B993 /* ImageExtensions.swift in Sources */,
C4D9BA451CA7224B004F70F7 /* PhotoLibraryAuthorizer.swift in Sources */,
FAB50BFB1B413E8C009905B9 /* ImageCell.swift in Sources */,
C40665481C73B72D00EB9751 /* SingleImageFetcher.swift in Sources */,
FAF058471B31618D008E5592 /* ViewController.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 */,
Expand Down
3 changes: 2 additions & 1 deletion ALCameraViewController/CameraView.strings
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@

"permissions.settings" = "Settings";

"error.cant-fetch-photo" = "Unable to fetch image with asset identifier";
"error.cant-fetch-photo" = "Unable to fetch image";
"error.cant-fetch-photo.description" = "Please check your network settings";
32 changes: 16 additions & 16 deletions ALCameraViewController/Utilities/CameraShot.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// ALCameraShot.swift
// CameraShot.swift
// ALCameraViewController
//
// Created by Alex Littlejohn on 2015/06/17.
Expand All @@ -9,24 +9,24 @@
import UIKit
import AVFoundation

public typealias ALCameraShotCompletion = (UIImage) -> Void
public typealias CameraShotCompletion = (UIImage?) -> Void

internal class CameraShot: NSObject {
func takePhoto(stillImageOutput: AVCaptureStillImageOutput, videoOrientation: AVCaptureVideoOrientation, cropSize: CGSize, completion: ALCameraShotCompletion) {
public func takePhoto(stillImageOutput: AVCaptureStillImageOutput, videoOrientation: AVCaptureVideoOrientation, cropSize: CGSize, completion: CameraShotCompletion) {

guard let videoConnection: AVCaptureConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) else {
completion(nil)
return
}

videoConnection.videoOrientation = videoOrientation

stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { buffer, error in

guard let videoConnection: AVCaptureConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) else {
guard let buffer = buffer, imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer), image = UIImage(data: imageData) else {
completion(nil)
return
}

videoConnection.videoOrientation = videoOrientation

stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: { buffer, error in

guard let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer), image = UIImage(data: imageData) else {
return
}

completion(image)
})
}
completion(image)
})
}
36 changes: 9 additions & 27 deletions ALCameraViewController/Utilities/ImageFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class ImageFetcher {

let libraryQueue = dispatch_queue_create("com.zero.ALCameraViewController.LibraryQueue", DISPATCH_QUEUE_SERIAL);

public init() { }

public func onSuccess(success: ImageFetcherSuccess) -> Self {
self.success = success
return self
Expand All @@ -39,7 +41,13 @@ public class ImageFetcher {
}

public func fetch() -> Self {
handleAuthorization(PHPhotoLibrary.authorizationStatus())
_ = PhotoLibraryAuthorizer { error in
if error == nil {
self.onAuthorized()
} else {
self.failure?(error: error!)
}
}
return self
}

Expand All @@ -53,30 +61,4 @@ public class ImageFetcher {
}
}
}

private func onDeniedOrRestricted() {
let error = errorWithKey("error.access-denied", domain: errorDomain)
dispatch_async(dispatch_get_main_queue()) {
self.failure?(error: error)
}
}

private func handleAuthorization(status: PHAuthorizationStatus) -> Void {
switch status {
case .NotDetermined:
if !authRequested {
PHPhotoLibrary.requestAuthorization(handleAuthorization)
authRequested = true
} else {
onDeniedOrRestricted()
}
break
case .Authorized:
onAuthorized()
break
case .Denied, .Restricted:
onDeniedOrRestricted()
break
}
}
}
46 changes: 46 additions & 0 deletions ALCameraViewController/Utilities/PhotoLibraryAuthorizer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// PhotoLibraryAuthorizer.swift
// ALCameraViewController
//
// Created by Alex Littlejohn on 2016/03/26.
// Copyright © 2016 zero. All rights reserved.
//

import UIKit
import Photos

public typealias PhotoLibraryAuthorizerCompletion = (error: NSError?) -> Void

class PhotoLibraryAuthorizer {

private let errorDomain = "com.zero.imageFetcher"
private let completion: PhotoLibraryAuthorizerCompletion

init(completion: PhotoLibraryAuthorizerCompletion) {
self.completion = completion
handleAuthorization(PHPhotoLibrary.authorizationStatus())
}

func onDeniedOrRestricted() {
let error = errorWithKey("error.access-denied", domain: errorDomain)
completion(error: error)
}

func handleAuthorization(status: PHAuthorizationStatus) {
switch status {
case .NotDetermined:
PHPhotoLibrary.requestAuthorization(handleAuthorization)
break
case .Authorized:
dispatch_async(dispatch_get_main_queue()) {
self.completion(error: nil)
}
break
case .Denied, .Restricted:
dispatch_async(dispatch_get_main_queue()) {
self.onDeniedOrRestricted()
}
break
}
}
}
19 changes: 15 additions & 4 deletions ALCameraViewController/Utilities/SingleImageFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class SingleImageFetcher {
private var targetSize = PHImageManagerMaximumSize
private var cropRect: CGRect?

public init() { }

public func onSuccess(success: SingleImageFetcherSuccess) -> Self {
self.success = success
return self
Expand All @@ -48,11 +50,22 @@ public class SingleImageFetcher {
}

public func fetch() -> Self {

_ = PhotoLibraryAuthorizer { error in
if error == nil {
self._fetch()
} else {
self.failure?(error: error!)
}
}
return self
}

private func _fetch() {

guard let asset = asset else {
let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
failure?(error: error)
return self
return
}

let options = PHImageRequestOptions()
Expand All @@ -79,7 +92,5 @@ public class SingleImageFetcher {
self.failure?(error: error)
}
}

return self
}
}
48 changes: 33 additions & 15 deletions ALCameraViewController/Utilities/SingleImageSaver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class SingleImageSaver {

private var image: UIImage?

public init() { }

public func onSuccess(success: SingleImageSaverSuccess) -> Self {
self.success = success
return self
Expand All @@ -37,10 +39,21 @@ public class SingleImageSaver {

public func save() -> Self {

_ = PhotoLibraryAuthorizer { error in
if error == nil {
self._save()
} else {
self.failure?(error: error!)
}
}

return self
}

private func _save() {
guard let image = image else {
let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
failure?(error: error)
return self
self.invokeFailure()
return
}

var assetIdentifier: PHObjectPlaceholder?
Expand All @@ -50,27 +63,32 @@ public class SingleImageSaver {
let request = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
assetIdentifier = request.placeholderForCreatedAsset
}) { finished, error in
if let assetIdentifier = assetIdentifier where finished {
self.fetch(assetIdentifier)

guard let assetIdentifier = assetIdentifier where finished else {
self.invokeFailure()
return
}
}

return self
self.fetch(assetIdentifier)
}
}

private func fetch(assetIdentifier: PHObjectPlaceholder) {

let assets = PHAsset.fetchAssetsWithLocalIdentifiers([assetIdentifier.localIdentifier], options: nil)

guard let asset = assets.firstObject as? PHAsset else {
let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
dispatch_async(dispatch_get_main_queue()) {
self.failure?(error: error)
}
return
}
dispatch_async(dispatch_get_main_queue()) {
guard let asset = assets.firstObject as? PHAsset else {
self.invokeFailure()
return
}

self.success?(asset: asset)
}
}

private func invokeFailure() {
let error = errorWithKey("error.cant-fetch-photo", domain: errorDomain)
failure?(error: error)
}
}
52 changes: 52 additions & 0 deletions ALCameraViewController/Utilities/UIButtonExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// UIButtonExtensions.swift
// ALCameraViewController
//
// Created by Alex Littlejohn on 2016/03/26.
// Copyright © 2016 zero. All rights reserved.
//

import UIKit

typealias ButtonAction = () -> Void

extension UIButton {

private struct AssociatedKeys {
static var ActionKey = "ActionKey"
}

private class ActionWrapper {
let action: ButtonAction
init(action: ButtonAction) {
self.action = action
}
}

var action: ButtonAction? {
set(newValue) {
removeTarget(self, action: #selector(UIButton.performAction), forControlEvents: UIControlEvents.TouchUpInside)
var wrapper: ActionWrapper?
if let newValue = newValue {
wrapper = ActionWrapper(action: newValue)
addTarget(self, action: #selector(UIButton.performAction), forControlEvents: UIControlEvents.TouchUpInside)
}

objc_setAssociatedObject(self, &AssociatedKeys.ActionKey, wrapper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
guard let wrapper = objc_getAssociatedObject(self, &AssociatedKeys.ActionKey) as? ActionWrapper else {
return nil
}

return wrapper.action
}
}

func performAction() {
if let a = action {
a()
}
}
}

Loading

0 comments on commit 191270c

Please sign in to comment.