diff --git a/Pod/Pod.xcodeproj/project.pbxproj b/Pod/Pod.xcodeproj/project.pbxproj index 33f0c080..4b7c70ba 100644 --- a/Pod/Pod.xcodeproj/project.pbxproj +++ b/Pod/Pod.xcodeproj/project.pbxproj @@ -8,6 +8,20 @@ /* Begin PBXBuildFile section */ 14A139B41AEFC72B00AD732F /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14A139B31AEFC72B00AD732F /* Tests.swift */; }; + BD9ED5451BBE73FF0032AD75 /* .gitkeep in Resources */ = {isa = PBXBuildFile; fileRef = BD9ED5331BBE73FF0032AD75 /* .gitkeep */; settings = {ASSET_TAGS = (); }; }; + BD9ED5461BBE73FF0032AD75 /* BottomContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5351BBE73FF0032AD75 /* BottomContainerView.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5471BBE73FF0032AD75 /* ButtonPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5361BBE73FF0032AD75 /* ButtonPicker.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5481BBE73FF0032AD75 /* ImageStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5371BBE73FF0032AD75 /* ImageStack.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5491BBE73FF0032AD75 /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5381BBE73FF0032AD75 /* StackView.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54A1BBE73FF0032AD75 /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED53A1BBE73FF0032AD75 /* CameraView.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54B1BBE73FF0032AD75 /* ConstraintsSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED53C1BBE73FF0032AD75 /* ConstraintsSetup.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54C1BBE73FF0032AD75 /* ImageGalleryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED53E1BBE73FF0032AD75 /* ImageGalleryView.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54D1BBE73FF0032AD75 /* ImageGalleryViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED53F1BBE73FF0032AD75 /* ImageGalleryViewCell.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54E1BBE73FF0032AD75 /* ImageGalleryViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5401BBE73FF0032AD75 /* ImageGalleryViewDataSource.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED54F1BBE73FF0032AD75 /* ImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5411BBE73FF0032AD75 /* ImagePickerController.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5501BBE73FF0032AD75 /* PickerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5421BBE73FF0032AD75 /* PickerConfiguration.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5511BBE73FF0032AD75 /* TopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5441BBE73FF0032AD75 /* TopView.swift */; settings = {ASSET_TAGS = (); }; }; + BD9ED5531BBE74200032AD75 /* Photos.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD9ED5521BBE74200032AD75 /* Photos.swift */; settings = {ASSET_TAGS = (); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -19,7 +33,20 @@ 14C136521AB784B200B7B07A /* CONTRIBUTING.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CONTRIBUTING.md; path = ../CONTRIBUTING.md; sourceTree = ""; }; 14C136541AB784B200B7B07A /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = LICENSE.md; path = ../LICENSE.md; sourceTree = ""; }; 14C136551AB784B200B7B07A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; - 14C1365C1AB784BC00B7B07A /* .gitkeep */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + BD9ED5331BBE73FF0032AD75 /* .gitkeep */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + BD9ED5351BBE73FF0032AD75 /* BottomContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomContainerView.swift; sourceTree = ""; }; + BD9ED5361BBE73FF0032AD75 /* ButtonPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonPicker.swift; sourceTree = ""; }; + BD9ED5371BBE73FF0032AD75 /* ImageStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageStack.swift; sourceTree = ""; }; + BD9ED5381BBE73FF0032AD75 /* StackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = ""; }; + BD9ED53A1BBE73FF0032AD75 /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = ""; }; + BD9ED53C1BBE73FF0032AD75 /* ConstraintsSetup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConstraintsSetup.swift; sourceTree = ""; }; + BD9ED53E1BBE73FF0032AD75 /* ImageGalleryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageGalleryView.swift; sourceTree = ""; }; + BD9ED53F1BBE73FF0032AD75 /* ImageGalleryViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageGalleryViewCell.swift; sourceTree = ""; }; + BD9ED5401BBE73FF0032AD75 /* ImageGalleryViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageGalleryViewDataSource.swift; sourceTree = ""; }; + BD9ED5411BBE73FF0032AD75 /* ImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerController.swift; sourceTree = ""; }; + BD9ED5421BBE73FF0032AD75 /* PickerConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickerConfiguration.swift; sourceTree = ""; }; + BD9ED5441BBE73FF0032AD75 /* TopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopView.swift; sourceTree = ""; }; + BD9ED5521BBE74200032AD75 /* Photos.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Photos.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,7 +63,7 @@ 146D728A1AB782920058798C = { isa = PBXGroup; children = ( - 14C1365B1AB784BC00B7B07A /* Source */, + BD9ED5321BBE73FF0032AD75 /* Source */, 14C136501AB7849300B7B07A /* Metadata */, 146D72AF1AB782920058798C /* Tests */, 146D72941AB782920058798C /* Products */, @@ -82,15 +109,68 @@ name = Metadata; sourceTree = ""; }; - 14C1365B1AB784BC00B7B07A /* Source */ = { + BD9ED5321BBE73FF0032AD75 /* Source */ = { isa = PBXGroup; children = ( - 14C1365C1AB784BC00B7B07A /* .gitkeep */, + BD9ED5331BBE73FF0032AD75 /* .gitkeep */, + BD9ED5341BBE73FF0032AD75 /* BottomView */, + BD9ED5391BBE73FF0032AD75 /* CameraView */, + BD9ED53B1BBE73FF0032AD75 /* Extensions */, + BD9ED53D1BBE73FF0032AD75 /* ImageGallery */, + BD9ED5411BBE73FF0032AD75 /* ImagePickerController.swift */, + BD9ED5421BBE73FF0032AD75 /* PickerConfiguration.swift */, + BD9ED5431BBE73FF0032AD75 /* TopView */, + BD9ED5521BBE74200032AD75 /* Photos.swift */, ); name = Source; path = ../Source; sourceTree = ""; }; + BD9ED5341BBE73FF0032AD75 /* BottomView */ = { + isa = PBXGroup; + children = ( + BD9ED5351BBE73FF0032AD75 /* BottomContainerView.swift */, + BD9ED5361BBE73FF0032AD75 /* ButtonPicker.swift */, + BD9ED5371BBE73FF0032AD75 /* ImageStack.swift */, + BD9ED5381BBE73FF0032AD75 /* StackView.swift */, + ); + path = BottomView; + sourceTree = ""; + }; + BD9ED5391BBE73FF0032AD75 /* CameraView */ = { + isa = PBXGroup; + children = ( + BD9ED53A1BBE73FF0032AD75 /* CameraView.swift */, + ); + path = CameraView; + sourceTree = ""; + }; + BD9ED53B1BBE73FF0032AD75 /* Extensions */ = { + isa = PBXGroup; + children = ( + BD9ED53C1BBE73FF0032AD75 /* ConstraintsSetup.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + BD9ED53D1BBE73FF0032AD75 /* ImageGallery */ = { + isa = PBXGroup; + children = ( + BD9ED53E1BBE73FF0032AD75 /* ImageGalleryView.swift */, + BD9ED53F1BBE73FF0032AD75 /* ImageGalleryViewCell.swift */, + BD9ED5401BBE73FF0032AD75 /* ImageGalleryViewDataSource.swift */, + ); + path = ImageGallery; + sourceTree = ""; + }; + BD9ED5431BBE73FF0032AD75 /* TopView */ = { + isa = PBXGroup; + children = ( + BD9ED5441BBE73FF0032AD75 /* TopView.swift */, + ); + path = TopView; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -149,6 +229,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BD9ED5451BBE73FF0032AD75 /* .gitkeep in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -159,7 +240,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BD9ED5511BBE73FF0032AD75 /* TopView.swift in Sources */, + BD9ED5481BBE73FF0032AD75 /* ImageStack.swift in Sources */, 14A139B41AEFC72B00AD732F /* Tests.swift in Sources */, + BD9ED5461BBE73FF0032AD75 /* BottomContainerView.swift in Sources */, + BD9ED54B1BBE73FF0032AD75 /* ConstraintsSetup.swift in Sources */, + BD9ED54E1BBE73FF0032AD75 /* ImageGalleryViewDataSource.swift in Sources */, + BD9ED5531BBE74200032AD75 /* Photos.swift in Sources */, + BD9ED54D1BBE73FF0032AD75 /* ImageGalleryViewCell.swift in Sources */, + BD9ED5501BBE73FF0032AD75 /* PickerConfiguration.swift in Sources */, + BD9ED54F1BBE73FF0032AD75 /* ImagePickerController.swift in Sources */, + BD9ED54A1BBE73FF0032AD75 /* CameraView.swift in Sources */, + BD9ED5471BBE73FF0032AD75 /* ButtonPicker.swift in Sources */, + BD9ED5491BBE73FF0032AD75 /* StackView.swift in Sources */, + BD9ED54C1BBE73FF0032AD75 /* ImageGalleryView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/BottomView/ButtonPicker.swift b/Source/BottomView/ButtonPicker.swift index e5b320dc..78b0c809 100644 --- a/Source/BottomView/ButtonPicker.swift +++ b/Source/BottomView/ButtonPicker.swift @@ -90,7 +90,7 @@ class ButtonPicker: UIButton { func recalculatePhotosCount(notification: NSNotification) { guard let sender = notification.object as? ImageStack else { return } - numberLabel.text = sender.images.isEmpty ? "" : String(sender.images.count) + numberLabel.text = sender.assets.isEmpty ? "" : String(sender.assets.count) } func pickerButtonDidPress(button: UIButton) { diff --git a/Source/BottomView/ImageStack.swift b/Source/BottomView/ImageStack.swift index e715b36d..ea237379 100644 --- a/Source/BottomView/ImageStack.swift +++ b/Source/BottomView/ImageStack.swift @@ -1,4 +1,5 @@ import UIKit +import Photos public class ImageStack { @@ -9,24 +10,24 @@ public class ImageStack { public static let imageKey = "image" } - public var images = [UIImage]() + public var assets = [PHAsset]() - public func pushImage(image: UIImage) { - images.append(image) - NSNotificationCenter.defaultCenter().postNotificationName(Notifications.imageDidPush, object: self, userInfo: ["image" : image]) + public func pushAsset(asset: PHAsset) { + assets.append(asset) + NSNotificationCenter.defaultCenter().postNotificationName(Notifications.imageDidPush, object: self, userInfo: ["image" : asset]) } - public func dropImage(image: UIImage) { - images = images.filter() {$0 != image} - NSNotificationCenter.defaultCenter().postNotificationName(Notifications.imageDidDrop, object: self, userInfo: ["image" : image]) + public func dropAsset(asset: PHAsset) { + assets = assets.filter() {$0 != asset} + NSNotificationCenter.defaultCenter().postNotificationName(Notifications.imageDidDrop, object: self, userInfo: ["image" : asset]) } - public func resetImages(newImages: [UIImage]) { - images = newImages + public func resetAssets(assets: [PHAsset]) { + self.assets = assets NSNotificationCenter.defaultCenter().postNotificationName(Notifications.stackDidReload, object: self, userInfo: nil) } - public func containsImage(image: UIImage) -> Bool { - return images.contains(image) + public func containsAsset(asset: PHAsset) -> Bool { + return assets.contains(asset) } } diff --git a/Source/BottomView/StackView.swift b/Source/BottomView/StackView.swift index 1ed3da74..619e7798 100644 --- a/Source/BottomView/StackView.swift +++ b/Source/BottomView/StackView.swift @@ -1,4 +1,5 @@ import UIKit +import Photos protocol ImageStackViewDelegate: class { func imageStackViewDidPress() @@ -98,18 +99,18 @@ extension ImageStackView { } if let sender = notification.object as? ImageStack { - renderViews(sender.images) + renderViews(sender.assets) } } func imageStackDidChangeContent(notification: NSNotification) { if let sender = notification.object as? ImageStack { - renderViews(sender.images) + renderViews(sender.assets) } } - func renderViews(images: [UIImage]) { - if let firstView = views.first where images.isEmpty { + func renderViews(assets: [PHAsset]) { + if let firstView = views.first where assets.isEmpty { for imageView in views { imageView.image = nil imageView.alpha = 0 @@ -119,11 +120,13 @@ extension ImageStackView { return } - let photos = Array(images.suffix(4)) + let photos = Array(assets.suffix(4)) for (index, view) in views.enumerate() { if index <= photos.count - 1 { - view.image = photos[index] + Photos.resolveAsset(photos[index], size: CGSize(width: Dimensions.imageSize, height: Dimensions.imageSize)) { image in + view.image = image + } view.alpha = 1 } else { view.image = nil diff --git a/Source/CameraView/CameraView.swift b/Source/CameraView/CameraView.swift index ad9192d7..2bff0b60 100644 --- a/Source/CameraView/CameraView.swift +++ b/Source/CameraView/CameraView.swift @@ -5,7 +5,7 @@ import AssetsLibrary protocol CameraViewDelegate: class { func handleFlashButton(hide: Bool) - func imageToLibrary(image: UIImage) + func imageToLibrary() } class CameraView: UIViewController { @@ -191,13 +191,9 @@ class CameraView: UIViewController { let image = self.cropImage(imageFromData) let orientation = self.pictureOrientation() let assetsLibrary = ALAssetsLibrary() - assetsLibrary.writeImageToSavedPhotosAlbum(image.CGImage, orientation: orientation, completionBlock: nil) - - guard let imageCG = image.CGImage, realOrientation = UIImageOrientation(rawValue: orientation.rawValue) else { return } - let rotatedImage = UIImage(CGImage: imageCG, - scale: 1.0, - orientation: realOrientation) - self.delegate?.imageToLibrary(rotatedImage) + assetsLibrary.writeImageToSavedPhotosAlbum(image.CGImage, orientation: orientation) { url, error in + self.delegate?.imageToLibrary() + } }) }) } diff --git a/Source/ImageGallery/ImageGalleryView.swift b/Source/ImageGallery/ImageGalleryView.swift index 3e05d425..7436f803 100644 --- a/Source/ImageGallery/ImageGalleryView.swift +++ b/Source/ImageGallery/ImageGalleryView.swift @@ -1,6 +1,5 @@ import UIKit import Photos -import AssetsLibrary protocol ImageGalleryPanGestureDelegate: class { @@ -70,10 +69,7 @@ public class ImageGalleryView: UIView { lazy var selectedStack = ImageStack() - lazy var images: NSMutableArray = { - let images = NSMutableArray() - return images - }() + lazy var assets = [PHAsset]() lazy var configuration: PickerConfiguration = { let configuration = PickerConfiguration() @@ -113,7 +109,7 @@ public class ImageGalleryView: UIView { topSeparator.addSubview(indicator) imagesBeforeLoading = 0 - fetchPhotos(0) + fetchPhotos() } required public init?(coder aDecoder: NSCoder) { @@ -139,46 +135,13 @@ public class ImageGalleryView: UIView { // MARK: - Photos handler - func fetchPhotos(index: Int) { - let imageManager = PHImageManager.defaultManager() - let requestOptions = PHImageRequestOptions() - let fetchOptions = PHFetchOptions() - let authorizationStatus = ALAssetsLibrary.authorizationStatus() - let size = CGSizeMake(720, 1280) - - canFetchImages = false - requestOptions.synchronous = true - fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)] + func fetchPhotos(completion: (() -> Void)? = nil) { + Photos.fetch { assets in + self.assets.removeAll() + self.assets.appendContentsOf(assets) + self.collectionView.reloadData() - guard authorizationStatus == .Authorized else { return } - - if fetchResult == nil { - fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) - } - - guard let fetchResult = fetchResult else { return } - - if fetchResult.count != 0 && index < fetchResult.count { - guard let asset = fetchResult.objectAtIndex(fetchResult.count - 1 - index) as? PHAsset else { return } - - imageManager.requestImageForAsset(asset, targetSize: size, contentMode: PHImageContentMode.AspectFill, options: requestOptions, resultHandler: { (image, _) in - dispatch_async(dispatch_get_main_queue(), { - if let image = image { - self.images.addObject(image) - if index > self.imagesBeforeLoading + 10 { - self.canFetchImages = true - self.collectionView.reloadData() - } else { - self.fetchPhotos(index + 1) - } - } - }) - }) - } else { - dispatch_async(dispatch_get_main_queue(), { - self.canFetchImages = true - self.collectionView.reloadData() - }) + completion?() } } @@ -267,32 +230,35 @@ extension ImageGalleryView: UICollectionViewDelegate { public func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ImageGalleryViewCell - let image = images[indexPath.row] as! UIImage + let asset = assets[indexPath.row] - if cell.selectedImageView.image != nil { - UIView.animateWithDuration(0.2, animations: { - cell.selectedImageView.transform = CGAffineTransformMakeScale(0.1, 0.1) - }) { _ in - cell.selectedImageView.image = nil - } - selectedStack.dropImage(image) - } else { - cell.selectedImageView.image = getImage("selectedImageGallery") - cell.selectedImageView.transform = CGAffineTransformMakeScale(0, 0) - UIView.animateWithDuration(0.2) { _ in - cell.selectedImageView.transform = CGAffineTransformIdentity + Photos.resolveAsset(asset) { image in + guard let _ = image else { return } + + if cell.selectedImageView.image != nil { + UIView.animateWithDuration(0.2, animations: { + cell.selectedImageView.transform = CGAffineTransformMakeScale(0.1, 0.1) + }) { _ in + cell.selectedImageView.image = nil + } + self.selectedStack.dropAsset(asset) + } else { + cell.selectedImageView.image = self.getImage("selectedImageGallery") + cell.selectedImageView.transform = CGAffineTransformMakeScale(0, 0) + UIView.animateWithDuration(0.2) { _ in + cell.selectedImageView.transform = CGAffineTransformIdentity + } + self.selectedStack.pushAsset(asset) } - selectedStack.pushImage(image) } } public func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { - guard indexPath.row + 10 >= images.count + guard indexPath.row + 10 >= assets.count && indexPath.row < fetchResult?.count && canFetchImages else { return } - imagesBeforeLoading = images.count - fetchPhotos(self.images.count) + fetchPhotos() canFetchImages = false } } diff --git a/Source/ImageGallery/ImageGalleryViewDataSource.swift b/Source/ImageGallery/ImageGalleryViewDataSource.swift index 55401ef0..09722e17 100644 --- a/Source/ImageGallery/ImageGalleryViewDataSource.swift +++ b/Source/ImageGallery/ImageGalleryViewDataSource.swift @@ -7,34 +7,42 @@ extension ImageGalleryView: UICollectionViewDataSource { } public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - displayNoImagesMessage(images.count == 0) - return images.count + displayNoImagesMessage(assets.count == 0) + return assets.count } public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier(CollectionView.reusableIdentifier, - forIndexPath: indexPath) as? ImageGalleryViewCell, image = images[indexPath.row] as? UIImage else { return UICollectionViewCell() } - - cell.configureCell(image) + forIndexPath: indexPath) as? ImageGalleryViewCell else { return UICollectionViewCell() } - if indexPath.row == 0 && shouldTransform { - cell.transform = CGAffineTransformMakeScale(0, 0) + let asset = assets[indexPath.row] - UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .CurveEaseInOut, animations: { - cell.transform = CGAffineTransformIdentity - }) { _ in } + Photos.resolveAsset(asset, size: CGSize(width: 160, height: 240)) { image in + if let image = image { + cell.configureCell(image) - shouldTransform = false - } + if indexPath.row == 0 && self.shouldTransform { + cell.transform = CGAffineTransformMakeScale(0, 0) + + UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .CurveEaseInOut, animations: { + cell.transform = CGAffineTransformIdentity + }) { _ in } + + self.shouldTransform = false + } - if selectedStack.containsImage(image) { - cell.selectedImageView.image = getImage("selectedImageGallery") - cell.selectedImageView.alpha = 1 - cell.selectedImageView.transform = CGAffineTransformIdentity - } else { - cell.selectedImageView.image = nil + if self.selectedStack.containsAsset(asset) { + cell.selectedImageView.image = self.getImage("selectedImageGallery") + cell.selectedImageView.alpha = 1 + cell.selectedImageView.transform = CGAffineTransformIdentity + } else { + cell.selectedImageView.image = nil + } + } } + + return cell } } diff --git a/Source/ImagePickerController.swift b/Source/ImagePickerController.swift index ddd7fbfa..a1449e4e 100644 --- a/Source/ImagePickerController.swift +++ b/Source/ImagePickerController.swift @@ -140,7 +140,7 @@ public class ImagePickerController: UIViewController { func adjustButtonTitle(notification: NSNotification) { guard let sender = notification.object as? ImageStack else { return } - let title = !sender.images.isEmpty ? + let title = !sender.assets.isEmpty ? configuration.doneButtonTitle : configuration.cancelButtonTitle bottomContainer.doneButton.setTitle(title, forState: .Normal) } @@ -207,7 +207,8 @@ extension ImagePickerController: BottomContainerViewDelegate { } func doneButtonDidPress() { - delegate?.doneButtonDidPress(stack.images) + let images = Photos.resolveAssets(stack.assets) + delegate?.doneButtonDidPress(images) } func cancelButtonDidPress() { @@ -216,7 +217,8 @@ extension ImagePickerController: BottomContainerViewDelegate { } func imageStackViewDidPress() { - delegate?.wrapperDidPress(stack.images) + let images = Photos.resolveAssets(stack.assets) + delegate?.wrapperDidPress(images) } } @@ -229,16 +231,17 @@ extension ImagePickerController: CameraViewDelegate { } } - func imageToLibrary(image: UIImage) { - galleryView.images.insertObject(image, atIndex: 0) - stack.pushImage(image) + func imageToLibrary() { + galleryView.fetchPhotos() { + guard let asset = self.galleryView.assets.first else { return } + self.stack.pushAsset(asset) + } galleryView.shouldTransform = true UIView.animateWithDuration(0.3, animations: { self.galleryView.collectionView.transform = CGAffineTransformMakeTranslation(self.galleryView.collectionSize.width, 0) }) { _ in self.galleryView.collectionView.transform = CGAffineTransformIdentity - self.galleryView.collectionView.reloadData() } } } @@ -265,7 +268,7 @@ extension ImagePickerController: ImageGalleryPanGestureDelegate { } func permissionGranted() { - galleryView.fetchPhotos(0) + galleryView.fetchPhotos() galleryView.canFetchImages = false cameraController.initializeCamera() enableGestures(true) diff --git a/Source/Photos.swift b/Source/Photos.swift new file mode 100644 index 00000000..5eafc7e2 --- /dev/null +++ b/Source/Photos.swift @@ -0,0 +1,62 @@ +import Photos +import AssetsLibrary + +struct Photos { + + static func fetch(completion: (assets: [PHAsset]) -> Void) { + let fetchOptions = PHFetchOptions() + let authorizationStatus = ALAssetsLibrary.authorizationStatus() + var fetchResult: PHFetchResult? + + guard authorizationStatus == .Authorized else { return } + + if fetchResult == nil { + fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions) + } + + if fetchResult?.count > 0 { + var assets = [PHAsset]() + fetchResult?.enumerateObjectsUsingBlock { object, index, stop in + if let asset = object as? PHAsset { + assets.insert(asset, atIndex: 0) + } + } + + dispatch_async(dispatch_get_main_queue(), { + completion(assets: assets) + }) + } + } + + static func resolveAsset(asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280) ,completion: (image: UIImage?) -> Void) { + let imageManager = PHImageManager.defaultManager() + let requestOptions = PHImageRequestOptions() + + imageManager.requestImageForAsset(asset, targetSize: size, contentMode: PHImageContentMode.AspectFill, options: requestOptions) { image, info in + if let info = info where info["PHImageFileUTIKey"] == nil { + dispatch_async(dispatch_get_main_queue(), { + completion(image: image) + }) + } + } + } + + static func resolveAssets(assets: [PHAsset], size: CGSize = CGSize(width: 720, height: 1280)) -> [UIImage] { + let imageManager = PHImageManager.defaultManager() + let requestOptions = PHImageRequestOptions() + + var images = [UIImage]() + + requestOptions.synchronous = true + + for asset in assets { + imageManager.requestImageForAsset(asset, targetSize: size, contentMode: PHImageContentMode.AspectFill, options: requestOptions) { image, info in + if let image = image { + images.append(image) + } + } + } + + return images + } +}