diff --git a/DZNPhotoPickerController.podspec b/DZNPhotoPickerController.podspec index 707bdbde..6b901a53 100644 --- a/DZNPhotoPickerController.podspec +++ b/DZNPhotoPickerController.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| ss.source_files = 'Source/Classes/Core/*.{h,m}' ss.dependency 'DZNPhotoPickerController/Services' ss.dependency 'DZNPhotoPickerController/Editor' - ss.dependency 'SDWebImage', '~> 3.7' + ss.dependency 'SDWebImage', '~> 4.0' ss.dependency 'DZNEmptyDataSet', '~> 1.7' end diff --git a/Source/Classes/Core/DZNPhotoDisplayViewCell.m b/Source/Classes/Core/DZNPhotoDisplayViewCell.m index 2498dc12..ee0fc0bd 100644 --- a/Source/Classes/Core/DZNPhotoDisplayViewCell.m +++ b/Source/Classes/Core/DZNPhotoDisplayViewCell.m @@ -10,6 +10,7 @@ #import "DZNPhotoDisplayViewCell.h" #import "UIImageView+WebCache.h" +#import "UIView+WebCache.h" @implementation DZNPhotoDisplayViewCell @synthesize imageView = _imageView; diff --git a/Source/Classes/Core/DZNPhotoDisplayViewController.h b/Source/Classes/Core/DZNPhotoDisplayViewController.h index 8c7ba0dd..79832ef0 100644 --- a/Source/Classes/Core/DZNPhotoDisplayViewController.h +++ b/Source/Classes/Core/DZNPhotoDisplayViewController.h @@ -17,7 +17,7 @@ @interface DZNPhotoDisplayViewController : UICollectionViewController /** The nearest ancestor in the view controller hierarchy that is a photo picker controller. */ -@property (nonatomic, readonly) DZNPhotoPickerController *navigationController; +@property (nonatomic, readonly) DZNPhotoPickerController *pickerController; /** The view controller's search controller. */ @property (nonatomic, readonly) UISearchController *searchController; /** The count number of rows of thumbs to be diplayed. */ diff --git a/Source/Classes/Core/DZNPhotoDisplayViewController.m b/Source/Classes/Core/DZNPhotoDisplayViewController.m index 3b7ebdf7..ea54223c 100644 --- a/Source/Classes/Core/DZNPhotoDisplayViewController.m +++ b/Source/Classes/Core/DZNPhotoDisplayViewController.m @@ -92,10 +92,10 @@ - (void)loadView { [super loadView]; - _segmentedControlTitles = NSArrayFromServices(self.navigationController.supportedServices); + _segmentedControlTitles = NSArrayFromServices(self.pickerController.supportedServices); NSAssert((_segmentedControlTitles.count <= 4), @"DZNPhotoPickerController doesn't support more than 4 photo service providers"); - _selectedService = DZNFirstPhotoServiceFromPhotoServices(self.navigationController.supportedServices); + _selectedService = DZNFirstPhotoServiceFromPhotoServices(self.pickerController.supportedServices); NSAssert((_selectedService > 0), @"DZNPhotoPickerController requieres at least 1 supported photo service provider"); self.extendedLayoutIncludesOpaqueBars = YES; @@ -128,6 +128,17 @@ - (void)viewWillAppear:(BOOL)animated } } +- (void) viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + if (([self.searchController.searchBar.text length] == 0) && (self.metadataList.count == 0)) { + // Calling becomeFirstResponder directly doesn't open the keybord for some reason + dispatch_async(dispatch_get_main_queue(), ^{ + [self.searchController.searchBar becomeFirstResponder]; + }); + } +} #pragma mark - Getter methods @@ -159,10 +170,10 @@ + (UICollectionViewFlowLayout *)layoutFittingSize:(CGSize)size return [[DZNPhotoServiceFactory defaultFactory] clientForService:self.selectedService]; } -/* Returns the navigation controller casted to DZNPhotoPickerController. */ -- (DZNPhotoPickerController *)navigationController +///* Returns the navigation controller casted to DZNPhotoPickerController. */ +- (DZNPhotoPickerController *)pickerController { - return (DZNPhotoPickerController *)[super navigationController]; + return (DZNPhotoPickerController *) self.parentViewController; } /* Returns the custom search display controller. */ @@ -176,12 +187,13 @@ - (UISearchController *)searchController _searchController.searchResultsUpdater = self; _searchController.delegate = self; _searchController.dimsBackgroundDuringPresentation = YES; - _searchController.hidesNavigationBarDuringPresentation = YES; + _searchController.hidesNavigationBarDuringPresentation = NO; UISearchBar *searchBar = _searchController.searchBar; + [searchBar sizeToFit]; searchBar.placeholder = NSLocalizedString(@"Search", nil); - searchBar.text = self.navigationController.initialSearchTerm; - searchBar.scopeButtonTitles = self.segmentedControlTitles; + searchBar.text = self.pickerController.initialSearchTerm; + searchBar.scopeButtonTitles = [self segmentedControlTitles]; searchBar.searchBarStyle = UISearchBarStyleProminent; searchBar.barStyle = UIBarStyleDefault; searchBar.selectedScopeButtonIndex = 0; @@ -418,16 +430,16 @@ - (void)resetPhotos */ - (void)selectedMetadata:(DZNPhotoMetadata *)metadata { - if (!self.navigationController.enablePhotoDownload) { + if (!self.pickerController.enablePhotoDownload) { [metadata postMetadataUpdate:nil]; } - else if (self.navigationController.allowsEditing) { + else if (self.pickerController.allowsEditing) { UIImage *image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:metadata.sourceURL.absoluteString]; DZNPhotoEditorViewController *controller = [[DZNPhotoEditorViewController alloc] initWithImage:image]; - controller.cropMode = self.navigationController.cropMode; - controller.cropSize = self.navigationController.cropSize; + controller.cropMode = self.pickerController.cropMode; + controller.cropSize = self.pickerController.cropSize; [self.navigationController pushViewController:controller animated:YES]; @@ -464,28 +476,29 @@ - (void)selectedMetadata:(DZNPhotoMetadata *)metadata } } else { - [self setActivityIndicatorsVisible:YES]; - + self.pickerController.activityBlock(self.pickerController, YES); [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:metadata.sourceURL options:SDWebImageCacheMemoryOnly|SDWebImageRetryFailed progress:NULL - completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished){ - if (image) { - NSDictionary *userInfo = @{UIImagePickerControllerOriginalImage: image}; - [metadata postMetadataUpdate:userInfo]; - } - else { - [self setLoadingError:error]; - } - - [self setActivityIndicatorsVisible:NO]; + completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (image) { + NSDictionary *userInfo = @{UIImagePickerControllerOriginalImage: image}; + [metadata postMetadataUpdate:userInfo]; + } + else { + [self setLoadingError:error]; + } + + self.pickerController.activityBlock(self.pickerController, NO); + }); }]; } } - (BOOL)canSearchTags { - if (!self.navigationController.allowAutoCompletedSearch) { + if (!self.pickerController.allowAutoCompletedSearch) { return NO; } @@ -643,7 +656,7 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView UIView *subview = nil; if ([self canDisplayFooterView]) { - if (self.isLoading || self.navigationController.infiniteScrollingEnabled) { + if (self.isLoading || self.pickerController.infiniteScrollingEnabled) { subview = self.activityIndicator; } else { @@ -685,7 +698,7 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath { if ([elementKind isEqualToString:UICollectionElementKindSectionFooter]) { - if (self.navigationController.infiniteScrollingEnabled && [self canDisplayFooterView] && !self.isLoading) { + if (self.pickerController.infiniteScrollingEnabled && [self canDisplayFooterView] && !self.isLoading) { // It is important to schedule this call on the next run loop so it doesn't // interfere with the current scroll's run loop. @@ -900,7 +913,10 @@ - (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView text = localizedDescription; } else if (!self.loading) { - text = NSLocalizedString(@"Make sure that all words are\nspelled correctly.", nil); + if (self.pickerController.initialSearchTerm) + text = NSLocalizedString(@"Make sure that all words are\nspelled correctly.", nil); + else + text = nil; } if (text) { diff --git a/Source/Classes/Core/DZNPhotoPickerController.h b/Source/Classes/Core/DZNPhotoPickerController.h index 39c5232a..4b9878f9 100644 --- a/Source/Classes/Core/DZNPhotoPickerController.h +++ b/Source/Classes/Core/DZNPhotoPickerController.h @@ -19,8 +19,9 @@ @discussion Due to Terms of Use of some photo services, the images can only be cached in memory, but not the device's hard drive. */ -@interface DZNPhotoPickerController : UINavigationController +@interface DZNPhotoPickerController : UIViewController +typedef void (^DZNPhotoPickerControllerActivityBlock)(DZNPhotoPickerController *picker, BOOL show); typedef void (^DZNPhotoPickerControllerFinalizationBlock)(DZNPhotoPickerController *picker, NSDictionary *info); typedef void (^DZNPhotoPickerControllerFailureBlock)(DZNPhotoPickerController *picker, NSError *error); typedef void (^DZNPhotoPickerControllerCancellationBlock)(DZNPhotoPickerController *picker); @@ -41,6 +42,9 @@ typedef void (^DZNPhotoPickerControllerCancellationBlock)(DZNPhotoPickerControll @property (nonatomic) DZNPhotoPickerControllerCCLicenses supportedLicenses; /** YES if the picker should download the full size photo after selecting its thumbnail, when allowsEditing is NO. Default is YES. */ @property (nonatomic) BOOL enablePhotoDownload; + +@property (nonatomic, strong) DZNPhotoPickerControllerActivityBlock activityBlock; + /** A block to be executed whenever the user pickes a new photo. Use this block to replace delegate method photoPickerController:didFinishPickingPhotoWithInfo: */ @property (nonatomic, strong) DZNPhotoPickerControllerFinalizationBlock finalizationBlock; /** A block to be executed whenever an error occurs while picking a photo. Use this block to replace delegate method photoPickerController:didFailedPickingPhotoWithError: */ diff --git a/Source/Classes/Core/DZNPhotoPickerController.m b/Source/Classes/Core/DZNPhotoPickerController.m index 8891930b..e01f9385 100644 --- a/Source/Classes/Core/DZNPhotoPickerController.m +++ b/Source/Classes/Core/DZNPhotoPickerController.m @@ -21,6 +21,7 @@ @interface DZNPhotoPickerController () @property (nonatomic, getter=isEditModeEnabled) BOOL editModeEnabled; +@property (nonatomic, assign) BOOL firstAppear; @end @implementation DZNPhotoPickerController @@ -33,8 +34,9 @@ - (id)init self.allowsEditing = NO; self.enablePhotoDownload = YES; self.allowAutoCompletedSearch = YES; + self.firstAppear = YES; - self.supportedServices = DZNPhotoPickerControllerService500px | DZNPhotoPickerControllerServiceFlickr; + self.supportedServices = DZNPhotoPickerControllerServiceGoogleImages | DZNPhotoPickerControllerServiceFlickr | DZNPhotoPickerControllerServiceBingImages; self.supportedLicenses = DZNPhotoPickerControllerCCLicenseBY_ALL; self.cropMode = DZNPhotoEditorViewControllerCropModeSquare; } @@ -58,7 +60,8 @@ - (void)viewWillAppear:(BOOL)animated [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishPickingPhoto:) name:DZNPhotoPickerDidFinishPickingNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFailPickingPhoto:) name:DZNPhotoPickerDidFailPickingNotification object:nil]; - if (!self.isEditModeEnabled) { + if (!self.isEditModeEnabled && self.firstAppear) { + self.firstAppear = NO; [self showPhotoDisplayController]; } } @@ -120,7 +123,6 @@ + (void)registerService:(DZNPhotoPickerControllerServices)service consumerKey:(N /* Shows the photo display controller. */ - (void)showPhotoDisplayController { - [self setViewControllers:@[]]; DZNPhotoDisplayViewController *controller = [[DZNPhotoDisplayViewController alloc] initWithPreferredContentSize:self.view.frame.size]; if (self.title) controller.title = self.title; @@ -130,7 +132,16 @@ - (void)showPhotoDisplayController [controller.navigationItem setRightBarButtonItem:cancel]; } - [self setViewControllers:@[controller]]; + [self addChildViewController:controller]; + [self.view addSubview:controller.view]; + + controller.view.translatesAutoresizingMaskIntoConstraints = false; + [NSLayoutConstraint activateConstraints:@[[controller.view.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [controller.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [controller.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [controller.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]]]; + + [controller didMoveToParentViewController:self]; } /* Called by a notification whenever the user picks a photo. */ @@ -158,7 +169,7 @@ - (void)didFailPickingPhoto:(NSNotification *)notification /* Called whenever the user cancels the picker. */ - (void)cancelPicker:(id)sender { - DZNPhotoDisplayViewController *controller = (DZNPhotoDisplayViewController *)[self.viewControllers firstObject]; + DZNPhotoDisplayViewController *controller = (DZNPhotoDisplayViewController *)[self.childViewControllers firstObject]; if ([controller respondsToSelector:@selector(stopLoadingRequest)]) { [controller stopLoadingRequest]; } diff --git a/Source/Classes/Services/DZNPhotoServiceClient.m b/Source/Classes/Services/DZNPhotoServiceClient.m index 87bb6433..c7f2bf3e 100644 --- a/Source/Classes/Services/DZNPhotoServiceClient.m +++ b/Source/Classes/Services/DZNPhotoServiceClient.m @@ -150,10 +150,8 @@ - (NSDictionary *)photosParamsWithKeyword:(NSString *)keyword page:(NSInteger)pa [params setObject:[self consumerSecret] forKey:keyForAPIConsumerSecret(self.service)]; [params setObject:@"image" forKey:@"searchType"]; [params setObject:@"medium" forKey:@"safe"]; - - if (page > 1) { - [params setObject:@((page - 1) * resultPerPage + 1) forKey:@"start"]; - } + [params setObject:@(10) forKey:@"num"]; + [params setObject:@(page ? page * resultPerPage + 1 : 1) forKey:@"start"]; } else if (self.service == DZNPhotoPickerControllerServiceBingImages) { @@ -161,6 +159,7 @@ - (NSDictionary *)photosParamsWithKeyword:(NSString *)keyword page:(NSInteger)pa // Default to size medium. Size Large causes some buggy behavior with download times. [params setObject:@"'Size:Medium'" forKey:@"ImageFilters"]; + [params setObject:@"Image" forKey:@"Source"]; // Top and skip are like limit and offset [params setObject:@(resultPerPage) forKey:@"$top"]; @@ -244,7 +243,29 @@ - (void)searchPhotosWithKeyword:(NSString *)keyword page:(NSInteger)page resultP NSString *path = photoSearchUrlPathForService(self.service); NSDictionary *params = [self photosParamsWithKeyword:keyword page:page resultPerPage:resultPerPage]; - [self getObject:[DZNPhotoMetadata class] path:path params:params completion:completion]; + __block NSMutableArray * aggregate = [NSMutableArray arrayWithCapacity:resultPerPage]; + __block NSInteger currentPage = [[params objectForKey:keyForSearchPage(self.service)] integerValue]; + NSLog(@"starting with currentPage %ul", currentPage); + __block DZNHTTPRequestCompletion recursive = ^(NSArray *list, NSError *error) { + if (error) + completion(nil, error); + + [aggregate addObjectsFromArray:list]; + currentPage = currentPage + list.count; + if ((aggregate.count < resultPerPage) && list.count) { + NSLog(@"asking for more at %ul after receiving %ul", currentPage, list.count); + [params setValue:@(currentPage) forKey:keyForSearchPage(self.service)]; + [params setValue:MIN(@(resultPerPage - aggregate.count),[params objectForKey:keyForSearchResultPerPage(self.service)]) forKey:keyForSearchResultPerPage(self.service)]; + [self getObject:[DZNPhotoMetadata class] path:path params:params completion:recursive]; + } else { + NSLog(@"received all items %ul",aggregate.count); + completion(aggregate, nil); + } + }; + + [self getObject:[DZNPhotoMetadata class] path:path params:params completion:recursive]; + + } - (void)getObject:(Class)class path:(NSString *)path params:(NSDictionary *)params completion:(DZNHTTPRequestCompletion)completion diff --git a/Source/Classes/Services/DZNPhotoServiceConstants.m b/Source/Classes/Services/DZNPhotoServiceConstants.m index c0acb011..56e4950f 100644 --- a/Source/Classes/Services/DZNPhotoServiceConstants.m +++ b/Source/Classes/Services/DZNPhotoServiceConstants.m @@ -143,6 +143,7 @@ NSString *keyForSearchPage(DZNPhotoPickerControllerServices service) { switch (service) { + case DZNPhotoPickerControllerServiceGoogleImages: return @"start"; case DZNPhotoPickerControllerServiceBingImages: return nil; default: return @"page"; } diff --git a/Source/Classes/UIImagePickerController/UIImagePickerController+Block.h b/Source/Classes/UIImagePickerController/UIImagePickerController+Block.h deleted file mode 100644 index 8554518e..00000000 --- a/Source/Classes/UIImagePickerController/UIImagePickerController+Block.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// UIImagePickerController+Block.h -// DZNPhotoPickerController -// https://github.com/dzenbot/DZNPhotoPickerController -// -// Created by Ignacio Romero Zurbuchen on 3/25/14. -// Copyright (c) 2014 DZN Labs. All rights reserved. -// Licence: MIT-Licence -// - -#import - -typedef void (^UIImagePickerControllerFinalizationBlock)(UIImagePickerController *picker, NSDictionary *info); -typedef void (^UIImagePickerControllerCancellationBlock)(UIImagePickerController *picker); - -/** - A category class adding block support to UIImagePickerController, replacing delegation implementation. - */ -@interface UIImagePickerController (Block) - -/** A block to be executed whenever the user picks a new photo. Use this block to replace delegate method imagePickerController:didFinishPickingPhotoWithInfo: */ -@property (nonatomic, strong) UIImagePickerControllerFinalizationBlock finalizationBlock; -/** A block to be executed whenever the user cancels the pick operation. Use this block to replace delegate method imagePickerControllerDidCancel: */ -@property (nonatomic, strong) UIImagePickerControllerCancellationBlock cancellationBlock; - -@end \ No newline at end of file diff --git a/Source/Classes/UIImagePickerController/UIImagePickerController+Block.m b/Source/Classes/UIImagePickerController/UIImagePickerController+Block.m deleted file mode 100644 index 68a25ffd..00000000 --- a/Source/Classes/UIImagePickerController/UIImagePickerController+Block.m +++ /dev/null @@ -1,74 +0,0 @@ -// -// UIImagePickerController+Block.h -// DZNPhotoPickerController -// https://github.com/dzenbot/DZNPhotoPickerController -// -// Created by Ignacio Romero Zurbuchen on 3/25/14. -// Copyright (c) 2014 DZN Labs. All rights reserved. -// Licence: MIT-Licence -// - -#import "UIImagePickerController+Block.h" -#import - -static char finalizationBlockKey; -static char cancelationBlockKey; - -@interface UIImagePickerController () -@end - -@implementation UIImagePickerController (Block) - -#pragma mark - Getter methods - -- (UIImagePickerControllerFinalizationBlock)finalizationBlock -{ - return objc_getAssociatedObject(self, &finalizationBlockKey); -} - -- (UIImagePickerControllerCancellationBlock)cancellationBlock -{ - return objc_getAssociatedObject(self, &cancelationBlockKey); -} - - -#pragma mark - Setter methods - -- (void)setFinalizationBlock:(UIImagePickerControllerFinalizationBlock)block -{ - if (!block) { - return; - } - - self.delegate = self; - objc_setAssociatedObject(self, &finalizationBlockKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (void)setCancellationBlock:(UIImagePickerControllerCancellationBlock)block -{ - if (!block) { - return; - } - - self.delegate = self; - objc_setAssociatedObject(self, &cancelationBlockKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - - -#pragma mark - UIImagePickerControllerDelegate methods - -- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info -{ - if (self.finalizationBlock) { - self.finalizationBlock(self, info); - } -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker -{ - if (self.cancellationBlock) { - self.cancellationBlock(self); - } -} - -@end \ No newline at end of file