Skip to content
This repository was archived by the owner on Jun 19, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Example/WPMediaPicker/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
UIColor *cellBackgroundColor = [UIColor colorWithRed:243/255.0f green:246/255.0f blue:248/255.0f alpha:1.0f];
[[WPMediaCollectionViewCell appearanceWhenContainedIn:[WPMediaPickerViewController class],nil] setBackgroundColor:cellBackgroundColor];
[[WPMediaCollectionViewCell appearanceWhenContainedIn:[WPInputMediaPickerViewController class],nil] setBackgroundColor:cellBackgroundColor];
[[UIImageView appearanceWhenContainedIn:[WPMediaGroupTableViewCell class],nil] setBackgroundColor:cellBackgroundColor];

//Configure color for activity indicator while loading media collection
[[UIActivityIndicatorView appearanceWhenContainedIn:[WPMediaPickerViewController class],nil] setColor:[UIColor grayColor]];
Expand Down
26 changes: 17 additions & 9 deletions Pod/Classes/WPMediaCollectionDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@ typedef NS_ENUM(NSInteger, WPMediaPickerErrorCode){
- (NSUInteger)to;
@end

typedef NS_ENUM(NSInteger, WPMediaLoadOptions){
WPMediaLoadOptionsGroups,
WPMediaLoadOptionsAssets,
WPMediaLoadOptionsGroupsAndAssets
};


@protocol WPMediaAsset;

typedef void (^WPMediaChangesBlock)(BOOL incrementalChanges, NSIndexSet *removed, NSIndexSet *inserted, NSIndexSet *changed, NSArray<id<WPMediaMove>> *moves);
typedef void (^WPMediaSuccessBlock)();
typedef void (^WPMediaFailureBlock)(NSError *error);
typedef void (^WPMediaAddedBlock)(id<WPMediaAsset> media, NSError *error);
typedef void (^WPMediaImageBlock)(UIImage *result, NSError *error);
typedef void (^WPMediaCountBlock)(NSInteger result, NSError *error);
typedef void (^WPMediaAssetBlock)(AVAsset *asset, NSError *error);
typedef int32_t WPMediaRequestID;

Expand Down Expand Up @@ -68,11 +76,13 @@ typedef int32_t WPMediaRequestID;
- (NSString *)identifier;

/**
* The numbers of assets that exist in the group
*
* @return The numbers of assets that exist in the group
The numbers of assets that exist in the group of a certain mediaType

@param mediaType the asset type to count
@param completionHandler a block that is executed when the real number of assets is know.
@return return an estimation of the current number of assets, if no estimate is known return NSNotFound
*/
- (NSInteger)numberOfAssetsOfType:(WPMediaType)mediaType;
- (NSInteger)numberOfAssetsOfType:(WPMediaType)mediaType completionHandler:(WPMediaCountBlock)completionHandler;

@end

Expand Down Expand Up @@ -250,16 +260,14 @@ typedef int32_t WPMediaRequestID;
* Asks the data source to reload the data available of the media library. This should be invoked after changing the
* current active group or if a change is detected.
*
* @param options specifiy what type of data to load
* @param successBlock a block that is invoked when the data is loaded with success.
* @param failureBlock a block that is invoked when the are is any kind of error when loading the data.
*/
- (void)loadDataWithSuccess:(WPMediaSuccessBlock)successBlock
- (void)loadDataWithOptions:(WPMediaLoadOptions)options
success:(WPMediaSuccessBlock)successBlock
failure:(WPMediaFailureBlock)failureBlock;

- (void)loadGroupDataWithSuccess:(WPMediaSuccessBlock)successBlock
failure:(WPMediaFailureBlock)failureBlock;


/**
* Requests to the data source to add an image to the library.
*
Expand Down
12 changes: 7 additions & 5 deletions Pod/Classes/WPMediaGroupPickerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@ - (void)viewDidLoad
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelPicker:)];
__weak __typeof__(self) weakSelf = self;
self.changesObserver = [self.dataSource registerChangeObserverBlock:^(BOOL incrementalChanges, NSIndexSet *deleted, NSIndexSet *inserted, NSIndexSet *reload, NSArray *moves) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadData];
});
[weakSelf loadData];
}];
[self loadData];
}

- (void)loadData
{
[self.dataSource loadGroupDataWithSuccess:^{
[self.dataSource loadDataWithOptions:WPMediaLoadOptionsGroups success:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
Expand Down Expand Up @@ -135,7 +133,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}];
cell.tag = requestKey;
cell.titleLabel.text = [group name];
NSInteger numberOfAssets = [group numberOfAssetsOfType:[self.dataSource mediaTypeFilter]];
NSInteger numberOfAssets = [group numberOfAssetsOfType:[self.dataSource mediaTypeFilter] completionHandler:^(NSInteger result, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
cell.countLabel.text = [NSString stringWithFormat:@"%ld", (long)result];
});
}];
if (numberOfAssets != NSNotFound) {
cell.countLabel.text = [NSString stringWithFormat:@"%ld", (long)numberOfAssets];
} else {
Expand Down
2 changes: 1 addition & 1 deletion Pod/Classes/WPMediaPickerViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ - (void)refreshDataAnimated:(BOOL)animated

__weak __typeof__(self) weakSelf = self;

[self.dataSource loadDataWithSuccess:^{
[self.dataSource loadDataWithOptions:WPMediaLoadOptionsAssets success:^{
__typeof__(self) strongSelf = weakSelf;
BOOL refreshGroupFirstTime = strongSelf.refreshGroupFirstTime;
strongSelf.refreshGroupFirstTime = NO;
Expand Down
106 changes: 47 additions & 59 deletions Pod/Classes/WPPHAssetDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ - (void)photoLibraryDidChange:(PHChange *)changeInstance
});
}

- (void)loadDataWithSuccess:(WPMediaSuccessBlock)successBlock
- (void)loadDataWithOptions:(WPMediaLoadOptions)options
success:(WPMediaSuccessBlock)successBlock
failure:(WPMediaFailureBlock)failureBlock
{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
Expand All @@ -118,51 +119,31 @@ - (void)loadDataWithSuccess:(WPMediaSuccessBlock)successBlock
case PHAuthorizationStatusNotDetermined:
{
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
[self loadDataWithSuccess:successBlock failure:failureBlock];
[self loadDataWithOptions:options success:successBlock failure:failureBlock];
}];
}
case PHAuthorizationStatusAuthorized: {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
if (self.activeAssetsCollection == nil) {
self.activeAssetsCollection = [[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary
options:nil] firstObject];
}
if (self.refreshGroups) {
[[[self class] sharedImageManager] stopCachingImagesForAllAssets];
[self loadGroupsWithSuccess:^{
self.refreshGroups = NO;
} failure:nil];
switch (options) {
case (WPMediaLoadOptionsGroups): {
[self loadGroupsWithSuccess:successBlock failure:failureBlock];
return;
}
case (WPMediaLoadOptionsAssets): {
[self loadAssetsWithSuccess:successBlock failure:failureBlock];
return;
}
case (WPMediaLoadOptionsGroupsAndAssets): {
[self loadGroupsWithSuccess:^{
[self loadAssetsWithSuccess:successBlock failure:failureBlock];
} failure:failureBlock];
}
}
[self loadAssetsWithSuccess:successBlock failure:failureBlock];
});
}
}
}

- (void)loadGroupDataWithSuccess:(WPMediaSuccessBlock)successBlock
failure:(WPMediaFailureBlock)failureBlock
{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
switch (status) {
case PHAuthorizationStatusRestricted:
case PHAuthorizationStatusDenied:
{
if (failureBlock) {
NSError *error = [NSError errorWithDomain:WPMediaPickerErrorDomain code:WPMediaErrorCodePermissionsFailed userInfo:nil];
failureBlock(error);
}
return;
}
case PHAuthorizationStatusNotDetermined:
{
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
[self loadGroupDataWithSuccess:successBlock failure:failureBlock];
}];
}
case PHAuthorizationStatusAuthorized: {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
[self loadGroupsWithSuccess:successBlock failure:failureBlock];
});
}
}
Expand Down Expand Up @@ -190,28 +171,21 @@ - (NSArray *)smartAlbumsToShow {
- (void)loadGroupsWithSuccess:(WPMediaSuccessBlock)successBlock
failure:(WPMediaFailureBlock)failureBlock
{
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.predicate = [[self class] predicateForFilterMediaType:self.mediaTypeFilter];
NSMutableArray *collectionsArray=[NSMutableArray array];
for (NSNumber *subType in [self smartAlbumsToShow]) {
PHFetchResult * smartAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
subtype:[subType intValue]
options:nil];
PHAssetCollection *collection = (PHAssetCollection *)smartAlbum.firstObject;
if ([PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions].count > 0 || [subType intValue] == PHAssetCollectionSubtypeSmartAlbumUserLibrary){
[collectionsArray addObjectsFromArray:[smartAlbum objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, smartAlbum.count)]]];
}
[collectionsArray addObject:collection];
}

self.albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
subtype:PHAssetCollectionSubtypeAny
options:nil];

[self.albums enumerateObjectsUsingBlock:^(PHAssetCollection *collection, NSUInteger index, BOOL *stop){
if ([PHAsset fetchAssetsInAssetCollection:collection options:fetchOptions].count > 0) {
[collectionsArray addObject:collection];
}
}];
[collectionsArray addObjectsFromArray:[self.albums objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.albums.count)]]];


PHCollectionList *allAlbums = [PHCollectionList transientCollectionListWithCollections:collectionsArray title:@"Root"];
self.assetsCollections = [PHAssetCollection fetchCollectionsInCollectionList:allAlbums options:nil];
Expand All @@ -232,6 +206,10 @@ - (void)loadGroupsWithSuccess:(WPMediaSuccessBlock)successBlock
}

}

self.albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
subtype:PHAssetCollectionSubtypeAny
options:nil];
}

+ (NSPredicate *)predicateForFilterMediaType:(WPMediaType)mediaType
Expand Down Expand Up @@ -558,6 +536,7 @@ @interface PHAssetCollectionForWPMediaGroup()
@property(nonatomic, strong) PHAsset *posterAsset;
@property(nonatomic, assign) WPMediaType mediaType;
@property(nonatomic, strong) PHFetchResult *fetchResult;
@property(nonatomic, strong) PHFetchResult *posterAssetFetchResult;

@end

Expand All @@ -584,7 +563,10 @@ - (NSString *)name

- (WPMediaRequestID)imageWithSize:(CGSize)size completionHandler:(WPMediaImageBlock)completionHandler
{
return [self.posterAsset imageWithSize:size completionHandler:completionHandler];
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
[self.posterAsset imageWithSize:size completionHandler:completionHandler];
});
return 0;
}

- (void)cancelImageRequest:(WPMediaRequestID)requestID
Expand All @@ -602,18 +584,13 @@ - (NSString *)identifier
return [self.collection localIdentifier];
}

- (NSInteger)numberOfAssetsOfType:(WPMediaType)mediaType
- (NSInteger)numberOfAssetsOfType:(WPMediaType)mediaType completionHandler:(WPMediaCountBlock)completionHandler
{
NSInteger count = self.collection.estimatedAssetCount;
if (count != NSNotFound) {
return count;
}

if (self.assetCount == NSNotFound) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
self.assetCount = [self.fetchResult count];
}

return self.assetCount;
completionHandler(self.assetCount, nil);
});
return self.collection.estimatedAssetCount;
}

- (PHFetchResult *)fetchResult {
Expand All @@ -626,9 +603,20 @@ - (PHFetchResult *)fetchResult {
return _fetchResult;
}

- (PHFetchResult *)posterAssetFetchResult {
if (!_posterAssetFetchResult) {
PHFetchOptions *fetchOptions = [PHFetchOptions new];
fetchOptions.fetchLimit = 1;
fetchOptions.predicate = [WPPHAssetDataSource predicateForFilterMediaType:_mediaType];
_posterAssetFetchResult = [PHAsset fetchKeyAssetsInAssetCollection:self.collection options:fetchOptions];
}

return _posterAssetFetchResult;
}

- (PHAsset *)posterAsset {
if (!_posterAsset) {
_posterAsset = [[self fetchResult] lastObject];
_posterAsset = [[self posterAssetFetchResult] firstObject];
}

return _posterAsset;
Expand Down