From aa041fa038e9a13aff832b0cf3c301b4889de7a9 Mon Sep 17 00:00:00 2001 From: Andrew Shini Date: Tue, 30 Aug 2016 14:24:09 +1000 Subject: [PATCH] Show loader in QBImagePicker --- .../QBImagePicker/QBAssetsViewController.m | 168 ++++++++++-------- 1 file changed, 89 insertions(+), 79 deletions(-) diff --git a/ios/QBImagePicker/QBImagePicker/QBAssetsViewController.m b/ios/QBImagePicker/QBImagePicker/QBAssetsViewController.m index 3738171..638dea7 100644 --- a/ios/QBImagePicker/QBImagePicker/QBAssetsViewController.m +++ b/ios/QBImagePicker/QBImagePicker/QBAssetsViewController.m @@ -43,7 +43,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { 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; @@ -73,10 +73,10 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (void)viewDidLoad { [super viewDidLoad]; - + [self setUpToolbarItems]; [self resetCachedAssets]; - + // Register observer [[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self]; } @@ -84,25 +84,25 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - + // Configure navigation item self.navigationItem.title = self.assetCollection.localizedTitle; self.navigationItem.prompt = self.imagePickerController.prompt; - + // Configure collection view self.collectionView.allowsMultipleSelection = self.imagePickerController.allowsMultipleSelection; - + // Show/hide 'Done' button if (self.imagePickerController.allowsMultipleSelection) { [self.navigationItem setRightBarButtonItem:self.doneButton animated:NO]; } else { [self.navigationItem setRightBarButtonItem:nil animated:NO]; } - + [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]; @@ -113,16 +113,16 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - + self.disableScrollToBottom = YES; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - + self.disableScrollToBottom = NO; - + [self updateCachedAssets]; } @@ -130,10 +130,10 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { // 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 context) { [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; @@ -152,7 +152,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (void)setAssetCollection:(PHAssetCollection *)assetCollection { _assetCollection = assetCollection; - + [self updateFetchRequest]; [self.collectionView reloadData]; } @@ -162,7 +162,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { if (_imageManager == nil) { _imageManager = [PHCachingImageManager new]; } - + return _imageManager; } @@ -177,12 +177,22 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (IBAction)done:(id)sender { + [NSThread detachNewThreadSelector:@selector(showLoader) toTarget:self withObject:nil]; + if ([self.imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didFinishPickingAssets:)]) { [self.imagePickerController.delegate qb_imagePickerController:self.imagePickerController didFinishPickingAssets:self.imagePickerController.selectedAssets.array]; } } +- (void) showLoader { + UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; + UIBarButtonItem * loadingView = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator]; + activityIndicator.color = [UIColor blackColor]; + [self.navigationItem setRightBarButtonItem:loadingView animated:NO]; + [activityIndicator startAnimating]; +} + #pragma mark - Toolbar @@ -191,21 +201,21 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { // 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; @@ -214,7 +224,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { } else { format = NSLocalizedStringFromTableInBundle(@"assets.toolbar.item-selected", @"QBImagePicker", bundle, nil); } - + NSString *title = [NSString stringWithFormat:format, selectedAssets.count]; [(UIBarButtonItem *)self.toolbarItems[1] setTitle:title]; } else { @@ -229,22 +239,22 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { if (self.assetCollection) { 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; } - + 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]; @@ -267,11 +277,11 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (BOOL)isMaximumSelectionLimitReached { NSUInteger minimumNumberOfSelection = MAX(1, self.imagePickerController.minimumNumberOfSelection); - + if (minimumNumberOfSelection <= self.imagePickerController.maximumNumberOfSelection) { return (self.imagePickerController.maximumNumberOfSelection <= self.imagePickerController.selectedAssets.count); } - + return NO; } @@ -293,19 +303,19 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { 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]; @@ -313,13 +323,13 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { 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, [[UIScreen mainScreen] scale]); - + [self.imageManager startCachingImagesForAssets:assetsToStartCaching targetSize:targetSize contentMode:PHImageContentModeAspectFill @@ -328,7 +338,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { targetSize:targetSize contentMode:PHImageContentModeAspectFill options:nil]; - + self.previousPreheatRect = preheatRect; } } @@ -340,7 +350,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { 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); @@ -366,7 +376,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { - (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) { @@ -384,11 +394,11 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { 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 hasIncrementalChanges] || [collectionChanges hasMoves]) { // We need to reload all if the incremental diffs are not available [self.collectionView reloadData]; @@ -399,19 +409,19 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { if ([removedIndexes count]) { [self.collectionView deleteItemsAtIndexPaths:[removedIndexes qb_indexPathsFromIndexesWithSection:0]]; } - + NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes]; if ([insertedIndexes count]) { [self.collectionView insertItemsAtIndexPaths:[insertedIndexes qb_indexPathsFromIndexesWithSection:0]]; } - + NSIndexSet *changedIndexes = [collectionChanges changedIndexes]; if ([changedIndexes count]) { [self.collectionView reloadItemsAtIndexPaths:[changedIndexes qb_indexPathsFromIndexesWithSection:0]]; } } completion:NULL]; } - + [self resetCachedAssets]; } }); @@ -443,12 +453,12 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { QBAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AssetCell" forIndexPath:indexPath]; cell.tag = indexPath.item; cell.showsOverlayViewWhenSelected = self.imagePickerController.allowsMultipleSelection; - + // Image PHAsset *asset = self.fetchResult[indexPath.item]; CGSize itemSize = [(UICollectionViewFlowLayout *)collectionView.collectionViewLayout itemSize]; CGSize targetSize = CGSizeScale(itemSize, [[UIScreen mainScreen] scale]); - + [self.imageManager requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill @@ -458,15 +468,15 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { 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; @@ -478,13 +488,13 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { } 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; } @@ -494,14 +504,14 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"FooterView" forIndexPath:indexPath]; - + // Number of assets UILabel *label = (UILabel *)[footerView viewWithTag:1]; - + NSBundle *bundle = self.imagePickerController.assetBundle; NSUInteger numberOfPhotos = [self.fetchResult countOfAssetsWithMediaType:PHAssetMediaTypeImage]; NSUInteger numberOfVideos = [self.fetchResult countOfAssetsWithMediaType:PHAssetMediaTypeVideo]; - + switch (self.imagePickerController.mediaType) { case QBImagePickerMediaTypeAny: { @@ -517,33 +527,33 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { } else { format = NSLocalizedStringFromTableInBundle(@"assets.footer.photos-and-videos", @"QBImagePicker", bundle, nil); } - + label.text = [NSString stringWithFormat:format, numberOfPhotos, numberOfVideos]; } break; - + case QBImagePickerMediaTypeImage: { NSString *key = (numberOfPhotos == 1) ? @"assets.footer.photo" : @"assets.footer.photos"; NSString *format = NSLocalizedStringFromTableInBundle(key, @"QBImagePicker", bundle, nil); - + label.text = [NSString stringWithFormat:format, numberOfPhotos]; } break; - + case QBImagePickerMediaTypeVideo: { NSString *key = (numberOfVideos == 1) ? @"assets.footer.video" : @"assets.footer.videos"; NSString *format = NSLocalizedStringFromTableInBundle(key, @"QBImagePicker", bundle, nil); - + label.text = [NSString stringWithFormat:format, numberOfVideos]; } break; } - + return footerView; } - + return nil; } @@ -556,11 +566,11 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { PHAsset *asset = self.fetchResult[indexPath.item]; return [self.imagePickerController.delegate qb_imagePickerController:self.imagePickerController shouldSelectAsset:asset]; } - + if ([self isAutoDeselectEnabled]) { return YES; } - + return ![self isMaximumSelectionLimitReached]; } @@ -568,30 +578,30 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { { QBImagePickerController *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.lastSelectedItemIndexPath = indexPath; - + [self updateDoneButtonState]; - + if (imagePickerController.showsNumberOfSelectedAssets) { [self updateSelectionInfo]; - + if (selectedAssets.count == 1) { // Show toolbar [self.navigationController setToolbarHidden:NO animated:YES]; @@ -602,7 +612,7 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { [imagePickerController.delegate qb_imagePickerController:imagePickerController didFinishPickingAssets:@[asset]]; } } - + if ([imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAsset:)]) { [imagePickerController.delegate qb_imagePickerController:imagePickerController didSelectAsset:asset]; } @@ -613,28 +623,28 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { if (!self.imagePickerController.allowsMultipleSelection) { return; } - + QBImagePickerController *imagePickerController = self.imagePickerController; NSMutableOrderedSet *selectedAssets = imagePickerController.selectedAssets; - + PHAsset *asset = self.fetchResult[indexPath.item]; - + // Remove asset from set [selectedAssets removeObject:asset]; - + self.lastSelectedItemIndexPath = nil; - + [self updateDoneButtonState]; - + if (imagePickerController.showsNumberOfSelectedAssets) { [self updateSelectionInfo]; - + if (selectedAssets.count == 0) { // Hide toolbar [self.navigationController setToolbarHidden:YES animated:YES]; } } - + if ([imagePickerController.delegate respondsToSelector:@selector(qb_imagePickerController:didDeselectAsset:)]) { [imagePickerController.delegate qb_imagePickerController:imagePickerController didDeselectAsset:asset]; } @@ -651,9 +661,9 @@ static CGSize CGSizeScale(CGSize size, CGFloat scale) { } else { numberOfColumns = self.imagePickerController.numberOfColumnsInLandscape; } - + CGFloat width = (CGRectGetWidth(self.view.frame) - 2.0 * (numberOfColumns - 1)) / numberOfColumns; - + return CGSizeMake(width, width); }