Rocket.Chat.ReactNative/ios/Pods/QBImagePickerController/QBImagePicker/QBAlbumsViewController.m

394 lines
14 KiB
Objective-C

//
// QBAlbumsViewController.m
// QBImagePicker
//
// Created by Katsuma Tanaka on 2015/04/03.
// Copyright (c) 2015 Katsuma Tanaka. All rights reserved.
//
#import "QBAlbumsViewController.h"
#import <Photos/Photos.h>
// Views
#import "QBAlbumCell.h"
// ViewControllers
#import "QBImagePickerController.h"
#import "QBAssetsViewController.h"
static CGSize CGSizeScale(CGSize size, CGFloat scale) {
return CGSizeMake(size.width * scale, size.height * scale);
}
@interface QBImagePickerController (Private)
@property (nonatomic, strong) NSBundle *assetBundle;
@end
@interface QBAlbumsViewController () <PHPhotoLibraryChangeObserver>
@property (nonatomic, strong) IBOutlet UIBarButtonItem *doneButton;
@property (nonatomic, copy) NSArray *fetchResults;
@property (nonatomic, copy) NSArray *assetCollections;
@end
@implementation QBAlbumsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self setUpToolbarItems];
// Fetch user albums and smart albums
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
PHFetchResult *userAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
self.fetchResults = @[smartAlbums, userAlbums];
[self updateAssetCollections];
// Register observer
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Configure navigation item
self.navigationItem.title = NSLocalizedStringFromTableInBundle(@"albums.title", @"QBImagePicker", self.imagePickerController.assetBundle, nil);
self.navigationItem.prompt = self.imagePickerController.prompt;
// Show/hide 'Done' button
if (self.imagePickerController.allowsMultipleSelection) {
[self.navigationItem setRightBarButtonItem:self.doneButton animated:NO];
} else {
[self.navigationItem setRightBarButtonItem:nil animated:NO];
}
[self updateControlState];
[self updateSelectionInfo];
}
- (void)dealloc
{
// Deregister observer
[[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
}
#pragma mark - Storyboard
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
QBAssetsViewController *assetsViewController = segue.destinationViewController;
assetsViewController.imagePickerController = self.imagePickerController;
assetsViewController.assetCollection = self.assetCollections[self.tableView.indexPathForSelectedRow.row];
}
#pragma mark - Actions
- (IBAction)cancel:(id)sender
{
if ([self.imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerControllerDidCancel:)]) {
[self.imagePickerController.delegate qb_imagePickerControllerDidCancel:self.imagePickerController];
}
}
- (IBAction)done:(id)sender
{
if ([self.imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didFinishPickingAssets:)]) {
[self.imagePickerController.delegate qb_imagePickerController:self.imagePickerController
didFinishPickingAssets:self.imagePickerController.selectedAssets.array];
}
}
#pragma mark - Toolbar
- (void)setUpToolbarItems
{
// Space
UIBarButtonItem *leftSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
UIBarButtonItem *rightSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
// Info label
NSDictionary *attributes = @{ NSForegroundColorAttributeName: [UIColor blackColor] };
UIBarButtonItem *infoButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:NULL];
infoButtonItem.enabled = NO;
[infoButtonItem setTitleTextAttributes:attributes forState:UIControlStateNormal];
[infoButtonItem setTitleTextAttributes:attributes forState:UIControlStateDisabled];
self.toolbarItems = @[leftSpace, infoButtonItem, rightSpace];
}
- (void)updateSelectionInfo
{
NSMutableOrderedSet *selectedAssets = self.imagePickerController.selectedAssets;
if (selectedAssets.count > 0) {
NSBundle *bundle = self.imagePickerController.assetBundle;
NSString *format;
if (selectedAssets.count > 1) {
format = NSLocalizedStringFromTableInBundle(@"assets.toolbar.items-selected", @"QBImagePicker", bundle, nil);
} else {
format = NSLocalizedStringFromTableInBundle(@"assets.toolbar.item-selected", @"QBImagePicker", bundle, nil);
}
NSString *title = [NSString stringWithFormat:format, selectedAssets.count];
[(UIBarButtonItem *)self.toolbarItems[1] setTitle:title];
} else {
[(UIBarButtonItem *)self.toolbarItems[1] setTitle:@""];
}
}
#pragma mark - Fetching Asset Collections
- (void)updateAssetCollections
{
// Filter albums
NSArray *assetCollectionSubtypes = self.imagePickerController.assetCollectionSubtypes;
NSMutableDictionary *smartAlbums = [NSMutableDictionary dictionaryWithCapacity:assetCollectionSubtypes.count];
NSMutableArray *userAlbums = [NSMutableArray array];
for (PHFetchResult *fetchResult in self.fetchResults) {
[fetchResult enumerateObjectsUsingBlock:^(PHAssetCollection *assetCollection, NSUInteger index, BOOL *stop) {
PHAssetCollectionSubtype subtype = assetCollection.assetCollectionSubtype;
if (subtype == PHAssetCollectionSubtypeAlbumRegular) {
[userAlbums addObject:assetCollection];
} else if ([assetCollectionSubtypes containsObject:@(subtype)]) {
if (!smartAlbums[@(subtype)]) {
smartAlbums[@(subtype)] = [NSMutableArray array];
}
[smartAlbums[@(subtype)] addObject:assetCollection];
}
}];
}
NSMutableArray *assetCollections = [NSMutableArray array];
// Fetch smart albums
for (NSNumber *assetCollectionSubtype in assetCollectionSubtypes) {
NSArray *collections = smartAlbums[assetCollectionSubtype];
if (collections) {
[assetCollections addObjectsFromArray:collections];
}
}
// Fetch user albums
[userAlbums enumerateObjectsUsingBlock:^(PHAssetCollection *assetCollection, NSUInteger index, BOOL *stop) {
[assetCollections addObject:assetCollection];
}];
self.assetCollections = assetCollections;
}
- (UIImage *)placeholderImageWithSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor *backgroundColor = [UIColor colorWithRed:(239.0 / 255.0) green:(239.0 / 255.0) blue:(244.0 / 255.0) alpha:1.0];
UIColor *iconColor = [UIColor colorWithRed:(179.0 / 255.0) green:(179.0 / 255.0) blue:(182.0 / 255.0) alpha:1.0];
// Background
CGContextSetFillColorWithColor(context, [backgroundColor CGColor]);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
// Icon (back)
CGRect backIconRect = CGRectMake(size.width * (16.0 / 68.0),
size.height * (20.0 / 68.0),
size.width * (32.0 / 68.0),
size.height * (24.0 / 68.0));
CGContextSetFillColorWithColor(context, [iconColor CGColor]);
CGContextFillRect(context, backIconRect);
CGContextSetFillColorWithColor(context, [backgroundColor CGColor]);
CGContextFillRect(context, CGRectInset(backIconRect, 1.0, 1.0));
// Icon (front)
CGRect frontIconRect = CGRectMake(size.width * (20.0 / 68.0),
size.height * (24.0 / 68.0),
size.width * (32.0 / 68.0),
size.height * (24.0 / 68.0));
CGContextSetFillColorWithColor(context, [backgroundColor CGColor]);
CGContextFillRect(context, CGRectInset(frontIconRect, -1.0, -1.0));
CGContextSetFillColorWithColor(context, [iconColor CGColor]);
CGContextFillRect(context, frontIconRect);
CGContextSetFillColorWithColor(context, [backgroundColor CGColor]);
CGContextFillRect(context, CGRectInset(frontIconRect, 1.0, 1.0));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark - Checking for Selection Limit
- (BOOL)isMinimumSelectionLimitFulfilled
{
return (self.imagePickerController.minimumNumberOfSelection <= self.imagePickerController.selectedAssets.count);
}
- (BOOL)isMaximumSelectionLimitReached
{
NSUInteger minimumNumberOfSelection = MAX(1, self.imagePickerController.minimumNumberOfSelection);
if (minimumNumberOfSelection <= self.imagePickerController.maximumNumberOfSelection) {
return (self.imagePickerController.maximumNumberOfSelection <= self.imagePickerController.selectedAssets.count);
}
return NO;
}
- (void)updateControlState
{
self.doneButton.enabled = [self isMinimumSelectionLimitFulfilled];
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.assetCollections.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
QBAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AlbumCell" forIndexPath:indexPath];
cell.tag = indexPath.row;
cell.borderWidth = 1.0 / self.traitCollection.displayScale;
// Thumbnail
PHAssetCollection *assetCollection = self.assetCollections[indexPath.row];
PHFetchOptions *options = [PHFetchOptions new];
switch (self.imagePickerController.mediaType) {
case QBImagePickerMediaTypeImage:
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
break;
case QBImagePickerMediaTypeVideo:
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeVideo];
break;
default:
break;
}
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:options];
PHImageManager *imageManager = [PHImageManager defaultManager];
if (fetchResult.count >= 3) {
cell.imageView3.hidden = NO;
[imageManager requestImageForAsset:fetchResult[fetchResult.count - 3]
targetSize:CGSizeScale(cell.imageView3.frame.size, self.traitCollection.displayScale)
contentMode:PHImageContentModeAspectFill
options:nil
resultHandler:^(UIImage *result, NSDictionary *info) {
if (cell.tag == indexPath.row) {
cell.imageView3.image = result;
}
}];
} else {
cell.imageView3.hidden = YES;
}
if (fetchResult.count >= 2) {
cell.imageView2.hidden = NO;
[imageManager requestImageForAsset:fetchResult[fetchResult.count - 2]
targetSize:CGSizeScale(cell.imageView2.frame.size, self.traitCollection.displayScale)
contentMode:PHImageContentModeAspectFill
options:nil
resultHandler:^(UIImage *result, NSDictionary *info) {
if (cell.tag == indexPath.row) {
cell.imageView2.image = result;
}
}];
} else {
cell.imageView2.hidden = YES;
}
if (fetchResult.count >= 1) {
[imageManager requestImageForAsset:fetchResult[fetchResult.count - 1]
targetSize:CGSizeScale(cell.imageView1.frame.size, self.traitCollection.displayScale)
contentMode:PHImageContentModeAspectFill
options:nil
resultHandler:^(UIImage *result, NSDictionary *info) {
if (cell.tag == indexPath.row) {
cell.imageView1.image = result;
}
}];
}
if (fetchResult.count == 0) {
cell.imageView3.hidden = NO;
cell.imageView2.hidden = NO;
// Set placeholder image
UIImage *placeholderImage = [self placeholderImageWithSize:cell.imageView1.frame.size];
cell.imageView1.image = placeholderImage;
cell.imageView2.image = placeholderImage;
cell.imageView3.image = placeholderImage;
}
// Album title
cell.titleLabel.text = assetCollection.localizedTitle;
// Number of photos
cell.countLabel.text = [NSString stringWithFormat:@"%lu", (long)fetchResult.count];
return cell;
}
#pragma mark - PHPhotoLibraryChangeObserver
- (void)photoLibraryDidChange:(PHChange *)changeInstance
{
dispatch_async(dispatch_get_main_queue(), ^{
// Update fetch results
NSMutableArray *fetchResults = [self.fetchResults mutableCopy];
[self.fetchResults enumerateObjectsUsingBlock:^(PHFetchResult *fetchResult, NSUInteger index, BOOL *stop) {
PHFetchResultChangeDetails *changeDetails = [changeInstance changeDetailsForFetchResult:fetchResult];
if (changeDetails) {
[fetchResults replaceObjectAtIndex:index withObject:changeDetails.fetchResultAfterChanges];
}
}];
if (![self.fetchResults isEqualToArray:fetchResults]) {
self.fetchResults = fetchResults;
// Reload albums
[self updateAssetCollections];
[self.tableView reloadData];
}
});
}
@end