| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- //Copyright (c) 2015 Katsuma Tanaka
- //Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to
- //deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- //sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- //The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
- //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- //IN THE SOFTWARE.
- #import "UGCKitAssetsViewController.h"
- #import <Photos/Photos.h>
- #import "UGCKitAssetLoader.h"
- #import "UGCKitAlbumsViewController.h"
- #import "UGCKitImageScrollerViewController.h"
- // Views
- #import "UGCKitMediaPickerViewControllerPrivate.h"
- #import "UGCKitAssetCell.h"
- #import "UGCKitVideoIndicatorView.h"
- #import "UGCKitAssetLoadingController.h"
- #import "UGCKitMem.h"
- static const CGFloat DefaultSelectionHeight = 110;
- static CGSize CGSizeScale(CGSize size, CGFloat scale) {
- return CGSizeMake(size.width * scale, size.height * scale);
- }
- @interface UGCKitMediaPickerViewController (Private)
- @property (nonatomic, strong) NSBundle *assetBundle;
- @property (nonatomic, weak) UICollectionViewLayout *collectionViewLayout;
- @end
- @implementation NSIndexSet (Convenience)
- - (NSArray *)qb_indexPathsFromIndexesWithSection:(NSUInteger)section
- {
- NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:self.count];
- [self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
- [indexPaths addObject:[NSIndexPath indexPathForItem:idx inSection:section]];
- }];
- return indexPaths;
- }
- @end
- @implementation UICollectionView (Convenience)
- - (NSArray *)qb_indexPathsForElementsInRect:(CGRect)rect
- {
- NSArray *allLayoutAttributes = [self.collectionViewLayout layoutAttributesForElementsInRect:rect];
- if (allLayoutAttributes.count == 0) { return nil; }
-
- NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];
- for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {
- NSIndexPath *indexPath = layoutAttributes.indexPath;
- [indexPaths addObject:indexPath];
- }
- return indexPaths;
- }
- @end
- @interface UGCKitAssetsViewController () <PHPhotoLibraryChangeObserver, UICollectionViewDelegateFlowLayout>
- @property (nonatomic, strong) UGCKitAssetLoader *loader;
- @property (nonatomic, copy) NSArray<AVAsset *> *exportedAssets;
- @property (nonatomic, strong) PHFetchResult *fetchResult;
- @property (nonatomic, strong) NSArray<PHAssetCollection*> *assetCollections;
- @property (nonatomic, strong) PHCachingImageManager *imageManager;
- @property (nonatomic, assign) CGRect previousPreheatRect;
- @property (nonatomic, assign) BOOL disableScrollToBottom;
- @property (nonatomic, strong) NSIndexPath *lastSelectedItemIndexPath;
- @property (nonatomic, strong) UGCKitImageScrollerViewController *imagesController;
- @end
- @implementation UGCKitAssetsViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- _loader = [[UGCKitAssetLoader alloc] init];
- __weak __typeof(self) wself = self;
- _descriptionLabel.textColor = _theme.titleColor;
- [_loader load:^{
- __strong __typeof(wself) self = wself;
- if (nil == self) return;
- self->_assetCollections = self->_loader.assetCollections;
- [self _updateWithAssetCollection:self->_assetCollections.firstObject];
- }];
- [self.doneButton setBackgroundImage:_theme.nextIcon forState:UIControlStateNormal];
- [self.doneButton setTitle:[_theme localizedString:@"UGCKit.Common.Next"] forState:UIControlStateNormal];
- [self.doneButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
- UIButton *button = (UIButton *)self.navigationItem.titleView;
- [button setTitleColor:_theme.titleColor forState:UIControlStateNormal];
- self.view.backgroundColor = _theme.backgroundColor;
- self.collectionView.backgroundColor = _theme.backgroundColor;
- [self setUpBottomView];
- [self resetCachedAssets];
-
- // Register observer
- [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
- }
- - (void)setTheme:(UGCKitTheme *)theme {
- _theme = theme;
- _descriptionLabel.textColor = _theme.titleColor;
- _timeLabel.textColor = _theme.titleColor;
- }
- - (UICollectionViewLayout *)collectionViewLayout
- {
- return self.collectionView.collectionViewLayout;
- }
- - (void)_updateWithAssetCollection:(PHAssetCollection *)assetCollection
- {
- self.assetCollection = assetCollection;
- UIButton *button = (UIButton *)self.navigationItem.titleView;
- [button setTitle:assetCollection.localizedTitle
- forState:UIControlStateNormal];
- button.titleLabel.font = [UIFont systemFontOfSize:17];
- [button sizeToFit];
- self.navigationItem.titleView = button;
- [self.navigationItem.titleView layoutIfNeeded];
- [self.collectionView reloadData];
- }
- - (void)viewWillAppear:(BOOL)animated
- {
- [super viewWillAppear:animated];
-
- // Configure navigation item
- self.navigationItem.title = self.assetCollection.localizedTitle;
- self.navigationItem.prompt = self.imagePickerController .config.prompt;
- self.navigationController.navigationBar.hidden = NO;
- // Configure collection view
- self.collectionView.allowsMultipleSelection = self.imagePickerController.allowsMultipleSelection;
-
- // Show/hide 'Done' button
- self.doneButton.hidden = !self.imagePickerController.allowsMultipleSelection;
- [self updateDoneButtonState];
- [self updateSelectionInfo];
- [self.collectionView reloadData];
-
- // Scroll to bottom
- if (self.fetchResult.count > 0 && self.isMovingToParentViewController && !self.disableScrollToBottom) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForItem:(self.fetchResult.count - 1) inSection:0];
- [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
- }
- }
- - (void)viewWillDisappear:(BOOL)animated
- {
- [super viewWillDisappear:animated];
-
- self.disableScrollToBottom = YES;
- }
- - (void)viewDidAppear:(BOOL)animated
- {
- [super viewDidAppear:animated];
-
- self.disableScrollToBottom = NO;
-
- [self updateCachedAssets];
- _timeLabel.textColor = _theme.titleColor;
- _descriptionLabel.textColor = _theme.titleColor;
- }
- - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
- {
- // Save indexPath for the last item
- NSIndexPath *indexPath = [[self.collectionView indexPathsForVisibleItems] lastObject];
-
- // Update layout
- [self.collectionViewLayout invalidateLayout];
-
- // Restore scroll position
- [coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
- [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
- }];
- }
- - (void)dealloc
- {
- // Deregister observer
- [[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
- }
- #pragma mark - Accessors
- - (void)setAssetCollection:(PHAssetCollection *)assetCollection
- {
- _assetCollection = assetCollection;
-
- [self updateFetchRequest];
- [self.collectionView reloadData];
- }
- - (PHCachingImageManager *)imageManager
- {
- if (_imageManager == nil) {
- _imageManager = [PHCachingImageManager new];
- }
-
- return _imageManager;
- }
- - (BOOL)isAutoDeselectEnabled
- {
- return (self.imagePickerController.maximumNumberOfSelection == 1
- && self.imagePickerController.maximumNumberOfSelection >= self.imagePickerController.minimumNumberOfSelection);
- }
- #pragma mark - Delegate Methods
- - (void)tellDelegateWithAssets:(NSArray<PHAsset *> *)assets {
- UGCKitAssetLoadingController *loadvc = [[UGCKitAssetLoadingController alloc] initWithTheme:_theme];
- WEAKIFY(self);
- WEAKIFY(loadvc);
- loadvc.completion = ^(UGCKitResult *result) {
- STRONGIFY(self);
- self.exportedAssets = weak_loadvc.avAssets;
- if (self.imagePickerController.completion) {
- self.imagePickerController.completion(result);
- }
- };
- loadvc.combineVideos = self.imagePickerController.config.combineVideos;
- UGCKitMediaType mediaType = self.imagePickerController.mediaType;
- if (mediaType == UGCKitMediaTypeVideo) {
- [loadvc exportAssetList:assets assetType:AssetType_Video];
- }else{
- [loadvc exportAssetList:assets assetType:AssetType_Image];
- }
- [self.navigationController pushViewController:loadvc animated:YES];
- }
- #pragma mark - Actions
- - (IBAction)done:(id)sender
- {
- [self tellDelegateWithAssets:self.imagePickerController.selectedAssets.array];
- // if ([self.imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didFinishPickingAssets:)]) {
- // [self.imagePickerController.delegate qb_imagePickerController:self.imagePickerController
- // didFinishPickingAssets:self.imagePickerController.selectedAssets.array];
- // }
- }
- - (IBAction)cancel:(id)sender
- {
- if (self.imagePickerController.completion) {
- self.imagePickerController.completion([UGCKitResult cancelledResult]);
- }
- }
- #pragma mark - Toolbar
- - (void)setUpBottomView
- {
- self.imagesController = [[UGCKitImageScrollerViewController alloc] initWithImageManage:self.imageManager];
- self.imagesController.closeIcon = _theme.closeIcon;
- __weak __typeof(self) wself = self;
- self.imagesController.onRemoveHandler = ^(NSUInteger index) {
- PHAsset *removedAsset = wself.imagePickerController.selectedAssets[index];
- NSUInteger indexOfCollection = [wself.fetchResult indexOfObject:removedAsset];
- NSMutableOrderedSet *selectedAssets = wself.imagePickerController.selectedAssets;
- [selectedAssets removeObjectAtIndex:index];
- [wself updateSelectionInfo];
- [wself.collectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:indexOfCollection inSection:0] animated:YES];
- };
- self.imagesController.collectionView.backgroundColor = self.view.backgroundColor;
- [self.view insertSubview:self.imagesController.view atIndex:0];
- CGFloat offset = 0;
- if (@available(iOS 11.0, *)) {
- offset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
- }
- self.imagesController.view.frame = CGRectMake(0, CGRectGetMaxY(self.view.bounds) - DefaultSelectionHeight - offset,
- CGRectGetWidth(self.view.bounds), DefaultSelectionHeight);
- self.imagesController.view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
- }
- - (void)updateSelectionInfo
- {
- NSMutableOrderedSet *selectedAssets = self.imagePickerController.selectedAssets;
- long duration = 0;
- for (PHAsset *asset in selectedAssets) {
- duration += asset.duration;
- }
- long minutes = (long)(duration / 60.0);
- int seconds = (int)ceil(duration - 60.0 * (double)minutes);
- self.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02d", minutes, seconds];
- }
- #pragma mark - Fetching Assets
- - (void)updateFetchRequest
- {
- if (self.assetCollection) {
- PHFetchOptions *options = [PHFetchOptions new];
- switch (self.imagePickerController.mediaType) {
- case UGCKitMediaTypePhoto:
- options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
- break;
- case UGCKitMediaTypeVideo:
- options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeVideo];
- break;
- default:
- break;
- }
- self.fetchResult = [PHAsset fetchAssetsInAssetCollection:self.assetCollection options:options];
-
- if ([self isAutoDeselectEnabled] && self.imagePickerController.selectedAssets.count > 0) {
- // Get index of previous selected asset
- PHAsset *asset = [self.imagePickerController.selectedAssets firstObject];
- NSInteger assetIndex = [self.fetchResult indexOfObject:asset];
- self.lastSelectedItemIndexPath = [NSIndexPath indexPathForItem:assetIndex inSection:0];
- }
- } else {
- self.fetchResult = nil;
- }
- }
- #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)updateDoneButtonState
- {
- self.doneButton.enabled = [self isMinimumSelectionLimitFulfilled];
- }
- #pragma mark - Segue
- - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
- {
- UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
- UGCKitAlbumsViewController *controller = (UGCKitAlbumsViewController *)navigationController.viewControllers.firstObject;
- controller.imagePickerController = self.imagePickerController;
- controller.assetCollections = self.assetCollections;
- __weak __typeof(self) wself = self;
- controller.onPickAssetCollection = ^(PHAssetCollection *collection) {
- [self _updateWithAssetCollection:collection];
- [wself dismissViewControllerAnimated:YES completion:nil];
- };
- }
- #pragma mark - Asset Caching
- - (void)resetCachedAssets
- {
- [self.imageManager stopCachingImagesForAllAssets];
- self.previousPreheatRect = CGRectZero;
- }
- - (void)updateCachedAssets
- {
- BOOL isViewVisible = [self isViewLoaded] && self.view.window != nil;
- if (!isViewVisible) { return; }
-
- // The preheat window is twice the height of the visible rect
- CGRect preheatRect = self.collectionView.bounds;
- preheatRect = CGRectInset(preheatRect, 0.0, -0.5 * CGRectGetHeight(preheatRect));
-
- // If scrolled by a "reasonable" amount...
- CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
-
- if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0) {
- // Compute the assets to start caching and to stop caching
- NSMutableArray *addedIndexPaths = [NSMutableArray array];
- NSMutableArray *removedIndexPaths = [NSMutableArray array];
-
- [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect addedHandler:^(CGRect addedRect) {
- NSArray *indexPaths = [self.collectionView qb_indexPathsForElementsInRect:addedRect];
- [addedIndexPaths addObjectsFromArray:indexPaths];
- } removedHandler:^(CGRect removedRect) {
- NSArray *indexPaths = [self.collectionView qb_indexPathsForElementsInRect:removedRect];
- [removedIndexPaths addObjectsFromArray:indexPaths];
- }];
-
- NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
- NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];
-
- CGSize itemSize = [(UICollectionViewFlowLayout *)self.collectionViewLayout itemSize];
- CGSize targetSize = CGSizeScale(itemSize, self.traitCollection.displayScale);
-
- [self.imageManager startCachingImagesForAssets:assetsToStartCaching
- targetSize:targetSize
- contentMode:PHImageContentModeAspectFill
- options:nil];
- [self.imageManager stopCachingImagesForAssets:assetsToStopCaching
- targetSize:targetSize
- contentMode:PHImageContentModeAspectFill
- options:nil];
-
- self.previousPreheatRect = preheatRect;
- }
- }
- - (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect addedHandler:(void (^)(CGRect addedRect))addedHandler removedHandler:(void (^)(CGRect removedRect))removedHandler
- {
- if (CGRectIntersectsRect(newRect, oldRect)) {
- CGFloat oldMaxY = CGRectGetMaxY(oldRect);
- CGFloat oldMinY = CGRectGetMinY(oldRect);
- CGFloat newMaxY = CGRectGetMaxY(newRect);
- CGFloat newMinY = CGRectGetMinY(newRect);
-
- if (newMaxY > oldMaxY) {
- CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
- addedHandler(rectToAdd);
- }
- if (oldMinY > newMinY) {
- CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
- addedHandler(rectToAdd);
- }
- if (newMaxY < oldMaxY) {
- CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
- removedHandler(rectToRemove);
- }
- if (oldMinY < newMinY) {
- CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
- removedHandler(rectToRemove);
- }
- } else {
- addedHandler(newRect);
- removedHandler(oldRect);
- }
- }
- - (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths
- {
- if (indexPaths.count == 0) { return nil; }
-
- NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
- for (NSIndexPath *indexPath in indexPaths) {
- if (indexPath.item < self.fetchResult.count) {
- PHAsset *asset = self.fetchResult[indexPath.item];
- [assets addObject:asset];
- }
- }
- return assets;
- }
- #pragma mark - PHPhotoLibraryChangeObserver
- - (void)photoLibraryDidChange:(PHChange *)changeInstance
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.fetchResult];
-
- if (collectionChanges) {
- // Get the new fetch result
- self.fetchResult = [collectionChanges fetchResultAfterChanges];
-
- if ([collectionChanges hasMoves]
- || [collectionChanges changedIndexes].count
- || ![collectionChanges hasIncrementalChanges]) {
- // We need to reload all if the incremental diffs are not available
- [self.collectionView reloadData];
- } else {
- // If we have incremental diffs, tell the collection view to animate insertions and deletions
- [self.collectionView performBatchUpdates:^{
- NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
- if ([removedIndexes count]) {
- [self.collectionView deleteItemsAtIndexPaths:[removedIndexes qb_indexPathsFromIndexesWithSection:0]];
- }
-
- NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
- if ([insertedIndexes count]) {
- [self.collectionView insertItemsAtIndexPaths:[insertedIndexes qb_indexPathsFromIndexesWithSection:0]];
- }
- } completion:NULL];
- }
-
- [self resetCachedAssets];
- }
- });
- }
- #pragma mark - UIScrollViewDelegate
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView
- {
- [self updateCachedAssets];
- }
- #pragma mark - UICollectionViewDataSource
- - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
- {
- return 1;
- }
- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
- {
- return self.fetchResult.count;
- }
- - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
- {
- UGCKitAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AssetCell" forIndexPath:indexPath];
- cell.tag = indexPath.item;
- cell.selectionColor = self.theme.pickerSelectionBorderColor;
- cell.showsOverlayViewWhenSelected = self.imagePickerController.allowsMultipleSelection;
-
- // Image
- PHAsset *asset = self.fetchResult[indexPath.item];
- CGSize itemSize = [(UICollectionViewFlowLayout *)collectionView.collectionViewLayout itemSize];
- CGSize targetSize = CGSizeScale(itemSize, self.traitCollection.displayScale);
-
- [self.imageManager requestImageForAsset:asset
- targetSize:targetSize
- contentMode:PHImageContentModeAspectFill
- options:nil
- resultHandler:^(UIImage *result, NSDictionary *info) {
- if (cell.tag == indexPath.item) {
- cell.imageView.image = result;
- }
- }];
-
- // Video indicator
- if (asset.mediaType == PHAssetMediaTypeVideo) {
- cell.videoIndicatorView.hidden = NO;
-
- NSInteger minutes = (NSInteger)(asset.duration / 60.0);
- NSInteger seconds = (NSInteger)ceil(asset.duration - 60.0 * (double)minutes);
- cell.videoIndicatorView.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds];
-
- if (asset.mediaSubtypes & PHAssetMediaSubtypeVideoHighFrameRate) {
- cell.videoIndicatorView.videoIcon.hidden = YES;
- cell.videoIndicatorView.slomoIcon.hidden = NO;
- }
- else {
- cell.videoIndicatorView.videoIcon.hidden = NO;
- cell.videoIndicatorView.slomoIcon.hidden = YES;
- }
- } else {
- cell.videoIndicatorView.hidden = YES;
- }
-
- // Selection state
- if ([self.imagePickerController.selectedAssets containsObject:asset]) {
- [cell setSelected:YES];
- [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
- }
-
- return cell;
- }
- - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
- {
- if (kind == UICollectionElementKindSectionFooter) {
- UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
- withReuseIdentifier:@"FooterView"
- forIndexPath:indexPath];
-
- // Number of assets
- UILabel *label = (UILabel *)[footerView viewWithTag:1];
- label.textColor = _theme.titleColor;
- NSUInteger numberOfPhotos = [self.fetchResult countOfAssetsWithMediaType:PHAssetMediaTypeImage];
- NSUInteger numberOfVideos = [self.fetchResult countOfAssetsWithMediaType:PHAssetMediaTypeVideo];
-
- switch (self.imagePickerController.mediaType) {
- case UGCKitMediaTypeAny:
- {
- NSString *format;
- if (numberOfPhotos == 1) {
- if (numberOfVideos == 1) {
- format = [_theme localizedString:@"UGCKit.MediaPicker.Footer.PhotoAndVideo"];
- } else {
- format = [_theme localizedString:@"UGCKit.MediaPicker.Footer.PhotoAndVideos"];
- }
- } else if (numberOfVideos == 1) {
- format = [_theme localizedString:@"UGCKit.MediaPicker.Footer.PhotosAndVideo"];
- } else {
- format = [_theme localizedString:@"UGCKit.MediaPicker.Footer.PhotosAndVideos"];
- }
-
- label.text = [NSString stringWithFormat:format, numberOfPhotos, numberOfVideos];
- }
- break;
-
- case UGCKitMediaTypePhoto:
- {
- NSString *key = (numberOfPhotos == 1) ? @"UGCKit.MediaPicker.Footer.Photo" : @"UGCKit.MediaPicker.Footer.Photos";
- NSString *format = [_theme localizedString:key];
-
- label.text = [NSString stringWithFormat:format, numberOfPhotos];
- }
- break;
-
- case UGCKitMediaTypeVideo:
- {
- NSString *key = (numberOfVideos == 1) ? @"UGCKit.MediaPicker.Footer.Video" : @"UGCKit.MediaPicker.Footer.Videos";
- NSString *format = [_theme localizedString:key];
-
- label.text = [NSString stringWithFormat:format, numberOfVideos];
- }
- break;
- }
-
- return footerView;
- }
-
- return [[UICollectionReusableView alloc] init];
- }
- #pragma mark - UICollectionViewDelegate
- - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
- {
- if ([self.imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:shouldSelectAsset:)]) {
- PHAsset *asset = self.fetchResult[indexPath.item];
- return [self.imagePickerController.delegate qb_imagePickerController:self.imagePickerController shouldSelectAsset:asset];
- }
-
- if ([self isAutoDeselectEnabled]) {
- return YES;
- }
-
- return ![self isMaximumSelectionLimitReached];
- }
- - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
- {
- UGCKitMediaPickerViewController *imagePickerController = self.imagePickerController;
- NSMutableOrderedSet *selectedAssets = imagePickerController.selectedAssets;
-
- PHAsset *asset = self.fetchResult[indexPath.item];
-
- if (imagePickerController.allowsMultipleSelection) {
- if ([self isAutoDeselectEnabled] && selectedAssets.count > 0) {
- // Remove previous selected asset from set
- [selectedAssets removeObjectAtIndex:0];
-
- // Deselect previous selected asset
- if (self.lastSelectedItemIndexPath) {
- [collectionView deselectItemAtIndexPath:self.lastSelectedItemIndexPath animated:NO];
- }
- }
-
- // Add asset to set
- [selectedAssets addObject:asset];
- [self.imagesController addAsset:asset];
- self.lastSelectedItemIndexPath = indexPath;
-
- [self updateDoneButtonState];
-
- if (imagePickerController.showsNumberOfSelectedAssets) {
- [self updateSelectionInfo];
- }
- } else {
- [self tellDelegateWithAssets:@[asset]];
- // if ([imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didFinishPickingAssets:)]) {
- // [imagePickerController.delegate qb_imagePickerController:imagePickerController didFinishPickingAssets:@[asset]];
- // }
- }
-
- if ([imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAsset:)]) {
- [imagePickerController.delegate qb_imagePickerController:imagePickerController didSelectAsset:asset];
- }
- }
- - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
- {
- if (!self.imagePickerController.allowsMultipleSelection) {
- return;
- }
-
- UGCKitMediaPickerViewController *imagePickerController = self.imagePickerController;
- NSMutableOrderedSet *selectedAssets = imagePickerController.selectedAssets;
-
- PHAsset *asset = self.fetchResult[indexPath.item];
-
- // Remove asset from set
- NSUInteger index = [selectedAssets indexOfObject:asset];
- [selectedAssets removeObject:asset];
- if (index != NSNotFound) {
- [self.imagesController removeAssetAtIndex:index];
- }
- self.lastSelectedItemIndexPath = nil;
-
- [self updateDoneButtonState];
-
- if (imagePickerController.showsNumberOfSelectedAssets) {
- [self updateSelectionInfo];
- }
-
- if ([imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didDeselectAsset:)]) {
- [imagePickerController.delegate qb_imagePickerController:imagePickerController didDeselectAsset:asset];
- }
- }
- #pragma mark - UICollectionViewDelegateFlowLayout
- - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
- {
- NSUInteger numberOfColumns;
- if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])) {
- numberOfColumns = self.imagePickerController.config.numberOfColumnsInPortrait;
- } else {
- numberOfColumns = self.imagePickerController.config.numberOfColumnsInLandscape;
- }
-
- CGFloat width = (CGRectGetWidth(self.view.frame) - 2.0 * (numberOfColumns - 1)) / numberOfColumns;
-
- return CGSizeMake(width, width);
- }
- @end
|