forked from shadowfacts/Tusker
389 lines
16 KiB
Mathematica
389 lines
16 KiB
Mathematica
|
//
|
||
|
// GMImagePickerController.m
|
||
|
// GMPhotoPicker
|
||
|
//
|
||
|
// Created by Guillermo Muntaner Perelló on 19/09/14.
|
||
|
// Copyright (c) 2014 Guillermo Muntaner Perelló. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||
|
#import "GMImagePickerController.h"
|
||
|
#import "GMAlbumsViewController.h"
|
||
|
#import <Photos/Photos.h>
|
||
|
|
||
|
@interface GMImagePickerController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIAlertViewDelegate>
|
||
|
|
||
|
@end
|
||
|
|
||
|
@implementation GMImagePickerController
|
||
|
|
||
|
- (id)init
|
||
|
{
|
||
|
if (self = [super init]) {
|
||
|
_selectedAssets = [[NSMutableArray alloc] init];
|
||
|
|
||
|
// Default values:
|
||
|
_displaySelectionInfoToolbar = YES;
|
||
|
_displayAlbumsNumberOfAssets = YES;
|
||
|
_autoDisableDoneButton = YES;
|
||
|
_allowsMultipleSelection = YES;
|
||
|
_confirmSingleSelection = NO;
|
||
|
_showCameraButton = NO;
|
||
|
|
||
|
// Grid configuration:
|
||
|
_colsInPortrait = 3;
|
||
|
_colsInLandscape = 5;
|
||
|
_minimumInteritemSpacing = 2.0;
|
||
|
|
||
|
// Sample of how to select the collections you want to display:
|
||
|
_customSmartCollections = @[@(PHAssetCollectionSubtypeSmartAlbumFavorites),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumRecentlyAdded),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumVideos),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumSlomoVideos),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumTimelapses),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumBursts),
|
||
|
@(PHAssetCollectionSubtypeSmartAlbumPanoramas)];
|
||
|
// If you don't want to show smart collections, just put _customSmartCollections to nil;
|
||
|
//_customSmartCollections=nil;
|
||
|
|
||
|
// Which media types will display
|
||
|
_mediaTypes = @[@(PHAssetMediaTypeAudio),
|
||
|
@(PHAssetMediaTypeVideo),
|
||
|
@(PHAssetMediaTypeImage)];
|
||
|
|
||
|
self.preferredContentSize = kPopoverContentSize;
|
||
|
|
||
|
// UI Customisation
|
||
|
_pickerBackgroundColor = [UIColor whiteColor];
|
||
|
_pickerTextColor = [UIColor darkTextColor];
|
||
|
_pickerFontName = @"HelveticaNeue";
|
||
|
_pickerBoldFontName = @"HelveticaNeue-Bold";
|
||
|
_pickerFontNormalSize = 14.0f;
|
||
|
_pickerFontHeaderSize = 17.0f;
|
||
|
|
||
|
_navigationBarBackgroundColor = [UIColor whiteColor];
|
||
|
_navigationBarTextColor = [UIColor darkTextColor];
|
||
|
_navigationBarTintColor = [UIColor darkTextColor];
|
||
|
|
||
|
_toolbarBarTintColor = [UIColor whiteColor];
|
||
|
_toolbarTextColor = [UIColor darkTextColor];
|
||
|
_toolbarTintColor = [UIColor darkTextColor];
|
||
|
|
||
|
_pickerStatusBarStyle = UIStatusBarStyleDefault;
|
||
|
|
||
|
[self setupNavigationController];
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
- (void)viewWillAppear:(BOOL)animated
|
||
|
{
|
||
|
[super viewWillAppear:animated];
|
||
|
|
||
|
// Ensure nav and toolbar customisations are set. Defaults are in place, but the user may have changed them
|
||
|
self.view.backgroundColor = _pickerBackgroundColor;
|
||
|
|
||
|
_navigationController.toolbar.translucent = YES;
|
||
|
_navigationController.toolbar.barTintColor = _toolbarBarTintColor;
|
||
|
_navigationController.toolbar.tintColor = _toolbarTintColor;
|
||
|
|
||
|
_navigationController.navigationBar.backgroundColor = _navigationBarBackgroundColor;
|
||
|
_navigationController.navigationBar.tintColor = _navigationBarTintColor;
|
||
|
NSDictionary *attributes;
|
||
|
if (_useCustomFontForNavigationBar) {
|
||
|
attributes = @{NSForegroundColorAttributeName : _navigationBarTextColor,
|
||
|
NSFontAttributeName : [UIFont fontWithName:_pickerBoldFontName size:_pickerFontHeaderSize]};
|
||
|
} else {
|
||
|
attributes = @{NSForegroundColorAttributeName : _navigationBarTextColor};
|
||
|
}
|
||
|
_navigationController.navigationBar.titleTextAttributes = attributes;
|
||
|
|
||
|
[self updateToolbar];
|
||
|
}
|
||
|
|
||
|
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||
|
return _pickerStatusBarStyle;
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Setup Navigation Controller
|
||
|
|
||
|
- (void)setupNavigationController
|
||
|
{
|
||
|
GMAlbumsViewController *albumsViewController = [[GMAlbumsViewController alloc] init];
|
||
|
_navigationController = [[UINavigationController alloc] initWithRootViewController:albumsViewController];
|
||
|
_navigationController.delegate = self;
|
||
|
[_navigationController.navigationBar setTranslucent:NO];
|
||
|
[_navigationController willMoveToParentViewController:self];
|
||
|
[_navigationController.view setFrame:self.view.frame];
|
||
|
[self.view addSubview:_navigationController.view];
|
||
|
[self addConstraintsToChildViewControllersView:_navigationController.view];
|
||
|
[self addChildViewController:_navigationController];
|
||
|
[_navigationController didMoveToParentViewController:self];
|
||
|
}
|
||
|
|
||
|
- (void)addConstraintsToChildViewControllersView:(UIView *)view {
|
||
|
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||
|
NSArray * hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view]-0-|" options:0 metrics:0 views:NSDictionaryOfVariableBindings(view)];
|
||
|
NSLayoutConstraint * topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
|
||
|
NSLayoutConstraint * bottomConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:view.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
|
||
|
[view.superview addConstraints:@[topConstraint,bottomConstraint]];
|
||
|
[view.superview addConstraints:hConstraints];
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - UIAlertViewDelegate
|
||
|
|
||
|
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||
|
{
|
||
|
if (buttonIndex == 1) {
|
||
|
// Only if OK was pressed do we want to completge the selection
|
||
|
[self finishPickingAssets:self];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Select / Deselect Asset
|
||
|
|
||
|
- (void)selectAsset:(PHAsset *)asset
|
||
|
{
|
||
|
[self.selectedAssets insertObject:asset atIndex:self.selectedAssets.count];
|
||
|
[self updateDoneButton];
|
||
|
|
||
|
if (!self.allowsMultipleSelection) {
|
||
|
if (self.confirmSingleSelection) {
|
||
|
NSString *message = self.confirmSingleSelectionPrompt ? self.confirmSingleSelectionPrompt : [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.confirm.message", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"Do you want to select the image you tapped on?")];
|
||
|
|
||
|
[[[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.confirm.title", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"Are You Sure?")]
|
||
|
message:message
|
||
|
delegate:self
|
||
|
cancelButtonTitle:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.action.no", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"No")]
|
||
|
otherButtonTitles:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.action.yes", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"Yes")], nil] show];
|
||
|
} else {
|
||
|
[self finishPickingAssets:self];
|
||
|
}
|
||
|
} else if (self.displaySelectionInfoToolbar || self.showCameraButton) {
|
||
|
[self updateToolbar];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)deselectAsset:(PHAsset *)asset
|
||
|
{
|
||
|
[self.selectedAssets removeObjectAtIndex:[self.selectedAssets indexOfObject:asset]];
|
||
|
if (self.selectedAssets.count == 0) {
|
||
|
[self updateDoneButton];
|
||
|
}
|
||
|
|
||
|
if (self.displaySelectionInfoToolbar || self.showCameraButton) {
|
||
|
[self updateToolbar];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)updateDoneButton
|
||
|
{
|
||
|
if (!self.allowsMultipleSelection) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UINavigationController *nav = (UINavigationController *)self.childViewControllers[0];
|
||
|
for (UIViewController *viewController in nav.viewControllers) {
|
||
|
viewController.navigationItem.rightBarButtonItem.enabled = (self.autoDisableDoneButton ? self.selectedAssets.count > 0 : TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)updateToolbar
|
||
|
{
|
||
|
if (!self.allowsMultipleSelection && !self.showCameraButton) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UINavigationController *nav = (UINavigationController *)self.childViewControllers[0];
|
||
|
for (UIViewController *viewController in nav.viewControllers) {
|
||
|
NSUInteger index = 1;
|
||
|
if (_showCameraButton) {
|
||
|
index++;
|
||
|
}
|
||
|
[[viewController.toolbarItems objectAtIndex:index] setTitleTextAttributes:[self toolbarTitleTextAttributes] forState:UIControlStateNormal];
|
||
|
[[viewController.toolbarItems objectAtIndex:index] setTitleTextAttributes:[self toolbarTitleTextAttributes] forState:UIControlStateDisabled];
|
||
|
[[viewController.toolbarItems objectAtIndex:index] setTitle:[self toolbarTitle]];
|
||
|
[viewController.navigationController setToolbarHidden:(self.selectedAssets.count == 0 && !self.showCameraButton) animated:YES];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - User finish Actions
|
||
|
|
||
|
- (void)dismiss:(id)sender
|
||
|
{
|
||
|
if ([self.delegate respondsToSelector:@selector(assetsPickerControllerDidCancel:)]) {
|
||
|
[self.delegate assetsPickerControllerDidCancel:self];
|
||
|
}
|
||
|
|
||
|
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
||
|
}
|
||
|
|
||
|
|
||
|
- (void)finishPickingAssets:(id)sender
|
||
|
{
|
||
|
if ([self.delegate respondsToSelector:@selector(assetsPickerController:didFinishPickingAssets:)]) {
|
||
|
[self.delegate assetsPickerController:self didFinishPickingAssets:self.selectedAssets];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Toolbar Title
|
||
|
|
||
|
- (NSPredicate *)predicateOfAssetType:(PHAssetMediaType)type
|
||
|
{
|
||
|
return [NSPredicate predicateWithBlock:^BOOL(PHAsset *asset, NSDictionary *bindings) {
|
||
|
return (asset.mediaType == type);
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
- (NSString *)toolbarTitle
|
||
|
{
|
||
|
if (self.selectedAssets.count == 0) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
NSPredicate *photoPredicate = [self predicateOfAssetType:PHAssetMediaTypeImage];
|
||
|
NSPredicate *videoPredicate = [self predicateOfAssetType:PHAssetMediaTypeVideo];
|
||
|
|
||
|
NSInteger nImages = [self.selectedAssets filteredArrayUsingPredicate:photoPredicate].count;
|
||
|
NSInteger nVideos = [self.selectedAssets filteredArrayUsingPredicate:videoPredicate].count;
|
||
|
|
||
|
if (nImages > 0 && nVideos > 0) {
|
||
|
return [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.selection.multiple-items", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"%@ Items Selected" ), @(nImages + nVideos)];
|
||
|
} else if (nImages > 1) {
|
||
|
return [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.selection.multiple-photos", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"%@ Photos Selected"), @(nImages)];
|
||
|
} else if (nImages == 1) {
|
||
|
return NSLocalizedStringFromTableInBundle(@"picker.selection.single-photo", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"1 Photo Selected" );
|
||
|
} else if (nVideos > 1) {
|
||
|
return [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"picker.selection.multiple-videos", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"%@ Videos Selected"), @(nVideos)];
|
||
|
} else if (nVideos == 1) {
|
||
|
return NSLocalizedStringFromTableInBundle(@"picker.selection.single-video", @"GMImagePicker", [NSBundle bundleForClass:GMImagePickerController.class], @"1 Video Selected");
|
||
|
} else {
|
||
|
return nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Toolbar Items
|
||
|
|
||
|
- (void)cameraButtonPressed:(UIBarButtonItem *)button
|
||
|
{
|
||
|
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||
|
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No Camera!"
|
||
|
message:@"Sorry, this device does not have a camera."
|
||
|
delegate:nil
|
||
|
cancelButtonTitle:@"OK"
|
||
|
otherButtonTitles:nil];
|
||
|
[alert show];
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// This allows the selection of the image taken to be better seen if the user is not already in that VC
|
||
|
if (self.autoSelectCameraImages && [self.navigationController.topViewController isKindOfClass:[GMAlbumsViewController class]]) {
|
||
|
[((GMAlbumsViewController *)self.navigationController.topViewController) selectAllAlbumsCell];
|
||
|
}
|
||
|
|
||
|
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
|
||
|
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
|
||
|
picker.mediaTypes = @[(NSString *)kUTTypeImage];
|
||
|
picker.allowsEditing = self.allowsEditingCameraImages;
|
||
|
picker.delegate = self;
|
||
|
picker.modalPresentationStyle = UIModalPresentationPopover;
|
||
|
|
||
|
UIPopoverPresentationController *popPC = picker.popoverPresentationController;
|
||
|
popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
|
||
|
popPC.barButtonItem = button;
|
||
|
|
||
|
[self showViewController:picker sender:button];
|
||
|
}
|
||
|
|
||
|
- (NSDictionary *)toolbarTitleTextAttributes {
|
||
|
return @{NSForegroundColorAttributeName : _toolbarTextColor,
|
||
|
NSFontAttributeName : [UIFont fontWithName:_pickerFontName size:_pickerFontHeaderSize]};
|
||
|
}
|
||
|
|
||
|
- (UIBarButtonItem *)titleButtonItem
|
||
|
{
|
||
|
UIBarButtonItem *title = [[UIBarButtonItem alloc] initWithTitle:self.toolbarTitle
|
||
|
style:UIBarButtonItemStylePlain
|
||
|
target:nil
|
||
|
action:nil];
|
||
|
|
||
|
NSDictionary *attributes = [self toolbarTitleTextAttributes];
|
||
|
[title setTitleTextAttributes:attributes forState:UIControlStateNormal];
|
||
|
[title setTitleTextAttributes:attributes forState:UIControlStateDisabled];
|
||
|
[title setEnabled:NO];
|
||
|
|
||
|
return title;
|
||
|
}
|
||
|
|
||
|
- (UIBarButtonItem *)spaceButtonItem
|
||
|
{
|
||
|
return [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
|
||
|
}
|
||
|
|
||
|
- (UIBarButtonItem *)cameraButtonItem
|
||
|
{
|
||
|
return [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(cameraButtonPressed:)];
|
||
|
}
|
||
|
|
||
|
- (NSArray *)toolbarItems
|
||
|
{
|
||
|
UIBarButtonItem *camera = [self cameraButtonItem];
|
||
|
UIBarButtonItem *title = [self titleButtonItem];
|
||
|
UIBarButtonItem *space = [self spaceButtonItem];
|
||
|
|
||
|
NSMutableArray *items = [[NSMutableArray alloc] init];
|
||
|
if (_showCameraButton) {
|
||
|
[items addObject:camera];
|
||
|
}
|
||
|
[items addObject:space];
|
||
|
[items addObject:title];
|
||
|
[items addObject:space];
|
||
|
|
||
|
return [NSArray arrayWithArray:items];
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark - Camera Delegate
|
||
|
|
||
|
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
|
||
|
{
|
||
|
[picker.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
||
|
|
||
|
NSString *mediaType = info[UIImagePickerControllerMediaType];
|
||
|
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
|
||
|
UIImage *image = info[UIImagePickerControllerEditedImage] ? : info[UIImagePickerControllerOriginalImage];
|
||
|
UIImageWriteToSavedPhotosAlbum(image,
|
||
|
self,
|
||
|
@selector(image:finishedSavingWithError:contextInfo:),
|
||
|
nil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
|
||
|
{
|
||
|
[picker.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
||
|
}
|
||
|
|
||
|
-(void)image:(UIImage *)image finishedSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
|
||
|
{
|
||
|
if (error) {
|
||
|
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Image Not Saved"
|
||
|
message:@"Sorry, unable to save the new image!"
|
||
|
delegate:nil
|
||
|
cancelButtonTitle:@"OK"
|
||
|
otherButtonTitles:nil];
|
||
|
[alert show];
|
||
|
}
|
||
|
|
||
|
// Note: The image view will auto refresh as the photo's are being observed in the other VCs
|
||
|
}
|
||
|
|
||
|
@end
|