commit 89d39106a2481dbe8ea37c4a1b1a1ee19ebc274c Author: wu736139669 Date: Mon Jun 29 11:51:01 2015 +0800 first commit diff --git a/AssetHelper.h b/AssetHelper.h new file mode 100644 index 0000000..17eac0b --- /dev/null +++ b/AssetHelper.h @@ -0,0 +1,52 @@ +// +// AssetHelper.m +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import +#import +//@class ALAssetsLibrary; + +#define ASSETHELPER [AssetHelper sharedAssetHelper] + +#define ASSET_PHOTO_THUMBNAIL 0 +#define ASSET_PHOTO_SCREEN_SIZE 1 +#define ASSET_PHOTO_FULL_RESOLUTION 2 + +@interface AssetHelper : NSObject + +- (void)initAsset; + +@property (nonatomic, strong) ALAssetsLibrary *assetsLibrary; +@property (nonatomic, strong) NSMutableArray *assetPhotos; +@property (nonatomic, strong) NSMutableArray *assetGroups; + +@property (readwrite) BOOL bReverse; + ++ (AssetHelper *)sharedAssetHelper; + +// get album list from asset +- (void)getGroupList:(void (^)(NSArray *))result; +// get photos from specific album with ALAssetsGroup object +- (void)getPhotoListOfGroup:(ALAssetsGroup *)alGroup result:(void (^)(NSArray *))result; +// get photos from specific album with index of album array +- (void)getPhotoListOfGroupByIndex:(NSInteger)nGroupIndex result:(void (^)(NSArray *))result; +// get photos from camera roll +- (void)getSavedPhotoList:(void (^)(NSArray *))result error:(void (^)(NSError *))error; + +- (NSInteger)getGroupCount; +- (NSInteger)getPhotoCountOfCurrentGroup; +- (NSDictionary *)getGroupInfo:(NSInteger)nIndex; + +- (void)clearData; + +// utils +- (UIImage *)getCroppedImage:(NSURL *)urlImage; +- (UIImage *)getImageFromAsset:(ALAsset *)asset type:(NSInteger)nType; +- (UIImage *)getImageAtIndex:(NSInteger)nIndex type:(NSInteger)nType; +- (ALAsset *)getAssetAtIndex:(NSInteger)nIndex; + +@end + diff --git a/AssetHelper.m b/AssetHelper.m new file mode 100644 index 0000000..9be35bc --- /dev/null +++ b/AssetHelper.m @@ -0,0 +1,296 @@ +// +// AssetHelper.m +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import "AssetHelper.h" + +@implementation AssetHelper + + ++ (AssetHelper *)sharedAssetHelper +{ + static AssetHelper *_sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[AssetHelper alloc] init]; + [_sharedInstance initAsset]; + }); + + return _sharedInstance; +} + +- (void)initAsset +{ + if (self.assetsLibrary == nil) + { + _assetsLibrary = [[ALAssetsLibrary alloc] init]; + [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; + [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]; + [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]; + NSString *strVersion = [[UIDevice alloc] systemVersion]; + if ([strVersion compare:@"5"] >= 0) + [_assetsLibrary writeImageToSavedPhotosAlbum:nil metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) { + }]; + } +} + +- (void)getGroupList:(void (^)(NSArray *))result +{ + [self initAsset]; + void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) + { + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + + if (group == nil) + { + if (_bReverse) + _assetGroups = [[NSMutableArray alloc] initWithArray:[[_assetGroups reverseObjectEnumerator] allObjects]]; + + + for (ALAssetsGroup* group in _assetGroups) { + if ([[group valueForProperty:ALAssetsGroupPropertyType] integerValue] == 16) { + [_assetGroups exchangeObjectAtIndex:0 withObjectAtIndex:[_assetGroups indexOfObject:group]]; + break; + } + } + for (ALAssetsGroup* group in _assetGroups) { + if ([[group valueForProperty:ALAssetsGroupPropertyType] integerValue] == 32) { + [_assetGroups exchangeObjectAtIndex:1 withObjectAtIndex:[_assetGroups indexOfObject:group]]; + break; + } + } + // end of enumeration + result(_assetGroups); + return; + } +// //查看相册的名字 +// NSLog(@"ALAssetsGroupPropertyName:%@",[group valueForProperty:ALAssetsGroupPropertyName]); +// //查看相册的类型 +// NSLog(@"ALAssetsGroupPropertyType:%@",[group valueForProperty:ALAssetsGroupPropertyType]); +// //查看相册的存储id +// NSLog(@"ALAssetsGroupPropertyPersistentID:%@",[group valueForProperty:ALAssetsGroupPropertyPersistentID]); + [_assetGroups addObject:group]; + }; + + void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *error) + { + DLog(@"Error : %@", [error description]); + }; + + _assetGroups = [[NSMutableArray alloc] init]; + [_assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll + usingBlock:assetGroupEnumerator + failureBlock:assetGroupEnumberatorFailure]; +} + +- (void)getPhotoListOfGroup:(ALAssetsGroup *)alGroup result:(void (^)(NSArray *))result +{ + [self initAsset]; + + _assetPhotos = [[NSMutableArray alloc] init]; + [alGroup setAssetsFilter:[ALAssetsFilter allPhotos]]; + [alGroup enumerateAssetsUsingBlock:^(ALAsset *alPhoto, NSUInteger index, BOOL *stop) { + + if(alPhoto == nil) + { + if (_bReverse) + _assetPhotos = [[NSMutableArray alloc] initWithArray:[[_assetPhotos reverseObjectEnumerator] allObjects]]; + + result(_assetPhotos); + return; + } + + [_assetPhotos addObject:alPhoto]; + }]; +} + +- (void)getPhotoListOfGroupByIndex:(NSInteger)nGroupIndex result:(void (^)(NSArray *))result +{ + [self getPhotoListOfGroup:_assetGroups[nGroupIndex] result:^(NSArray *aResult) { + + result(_assetPhotos); + + }]; +} + +- (void)getSavedPhotoList:(void (^)(NSArray *))result error:(void (^)(NSError *))error +{ + [self initAsset]; + + dispatch_async(dispatch_get_main_queue(), ^{ + + void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) + { + if ([[group valueForProperty:@"ALAssetsGroupPropertyType"] intValue] == ALAssetsGroupSavedPhotos) + { + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + + [group enumerateAssetsUsingBlock:^(ALAsset *alPhoto, NSUInteger index, BOOL *stop) { + + if(alPhoto == nil) + { + if (_bReverse) + _assetPhotos = [[NSMutableArray alloc] initWithArray:[[_assetPhotos reverseObjectEnumerator] allObjects]]; + + result(_assetPhotos); + return; + } + + [_assetPhotos addObject:alPhoto]; + }]; + } + }; + + void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *err) + { + DLog(@"Error : %@", [err description]); + error(err); + }; + + _assetPhotos = [[NSMutableArray alloc] init]; + [_assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos + usingBlock:assetGroupEnumerator + failureBlock:assetGroupEnumberatorFailure]; + }); +} + +- (NSInteger)getGroupCount +{ + return _assetGroups.count; +} + +- (NSInteger)getPhotoCountOfCurrentGroup +{ + return _assetPhotos.count; +} + +- (NSDictionary *)getGroupInfo:(NSInteger)nIndex +{ + if ([_assetGroups[nIndex] valueForProperty:ALAssetsGroupPropertyName] && @([_assetGroups[nIndex] numberOfAssets]) && [UIImage imageWithCGImage:[_assetGroups[nIndex] posterImage]]) { + return @{@"name" : [_assetGroups[nIndex] valueForProperty:ALAssetsGroupPropertyName], + @"count" : @([_assetGroups[nIndex] numberOfAssets]), + @"thumbnail" : [UIImage imageWithCGImage:[_assetGroups[nIndex] posterImage]]}; + }else{ + return nil; + } + +} + +- (void)clearData +{ + _assetGroups = nil; + _assetPhotos = nil; +} + +#pragma mark - utils +- (UIImage *)getCroppedImage:(NSURL *)urlImage +{ + __block UIImage *iImage = nil; + __block BOOL bBusy = YES; + + ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) + { + ALAssetRepresentation *rep = [myasset defaultRepresentation]; + NSString *strXMP = rep.metadata[@"AdjustmentXMP"]; + if (strXMP == nil || [strXMP isKindOfClass:[NSNull class]]) + { + CGImageRef iref = [rep fullResolutionImage]; + if (iref) + iImage = [UIImage imageWithCGImage:iref scale:1.0 orientation:(UIImageOrientation)rep.orientation]; + else + iImage = nil; + } + else + { + // to get edited photo by photo app + NSData *dXMP = [strXMP dataUsingEncoding:NSUTF8StringEncoding]; + + CIImage *image = [CIImage imageWithCGImage:rep.fullResolutionImage]; + + NSError *error = nil; + NSArray *filterArray = [CIFilter filterArrayFromSerializedXMP:dXMP + inputImageExtent:image.extent + error:&error]; + if (error) { + DLog(@"Error during CIFilter creation: %@", [error localizedDescription]); + } + + for (CIFilter *filter in filterArray) { + [filter setValue:image forKey:kCIInputImageKey]; + image = [filter outputImage]; + } + + iImage = [UIImage imageWithCIImage:image scale:1.0 orientation:(UIImageOrientation)rep.orientation]; + } + + bBusy = NO; + }; + + ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) + { + DLog(@"booya, cant get image - %@",[myerror localizedDescription]); + }; + + [_assetsLibrary assetForURL:urlImage + resultBlock:resultblock + failureBlock:failureblock]; + + while (bBusy) + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + + return iImage; +} + +- (UIImage *)getImageFromAsset:(ALAsset *)asset type:(NSInteger)nType +{ + CGImageRef iRef = nil; +// NSLog(@"%@",[asset valueForProperty:ALAssetPropertyAssetURL]); + if (nType == ASSET_PHOTO_THUMBNAIL) + iRef = [asset thumbnail]; + else if (nType == ASSET_PHOTO_SCREEN_SIZE) + iRef = [asset.defaultRepresentation fullScreenImage]; + else if (nType == ASSET_PHOTO_FULL_RESOLUTION) + { +// NSString *strXMP = asset.defaultRepresentation.metadata[@"AdjustmentXMP"]; +// NSData *dXMP = [strXMP dataUsingEncoding:NSUTF8StringEncoding]; +// +// CIImage *image = [CIImage imageWithCGImage:asset.defaultRepresentation.fullResolutionImage]; +// +// NSError *error = nil; +// NSArray *filterArray = [CIFilter filterArrayFromSerializedXMP:dXMP +// inputImageExtent:image.extent +// error:&error]; +// if (error) { +// NSLog(@"Error during CIFilter creation: %@", [error localizedDescription]); +// } +// +// for (CIFilter *filter in filterArray) { +// [filter setValue:image forKey:kCIInputImageKey]; +// image = [filter outputImage]; +// } +// +// UIImage *iImage = [UIImage imageWithCIImage:image scale:1.0 orientation:(UIImageOrientation)asset.defaultRepresentation.orientation]; +// return iImage; + iRef = [asset.defaultRepresentation fullResolutionImage]; + } + + return [UIImage imageWithCGImage:iRef]; +} + +- (UIImage *)getImageAtIndex:(NSInteger)nIndex type:(NSInteger)nType +{ + if (_assetPhotos.count > nIndex) { + return [self getImageFromAsset:(ALAsset *)_assetPhotos[nIndex] type:nType]; + } + return nil; +} + +- (ALAsset *)getAssetAtIndex:(NSInteger)nIndex +{ + return _assetPhotos[nIndex]; +} + +@end diff --git a/DoAlbumCell.h b/DoAlbumCell.h new file mode 100644 index 0000000..26493a2 --- /dev/null +++ b/DoAlbumCell.h @@ -0,0 +1,15 @@ +// +// DoAlbumCell.h +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import + +@interface DoAlbumCell : UITableViewCell + +@property (weak, nonatomic) IBOutlet UILabel *lbAlbumName; +@property (weak, nonatomic) IBOutlet UILabel *lbCount; + +@end diff --git a/DoAlbumCell.m b/DoAlbumCell.m new file mode 100644 index 0000000..5474ac7 --- /dev/null +++ b/DoAlbumCell.m @@ -0,0 +1,42 @@ +// +// DoAlbumCell.m +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import "DoAlbumCell.h" +#import "DoImagePickerController.h" + +@implementation DoAlbumCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + if (selected) + { + _lbAlbumName.textColor = [UIColor whiteColor]; + _lbCount.textColor = [UIColor whiteColor]; + + self.contentView.backgroundColor = DO_ALBUM_NAME_TEXT_COLOR; + } + else + { + _lbAlbumName.textColor = DO_ALBUM_NAME_TEXT_COLOR; + _lbCount.textColor = DO_ALBUM_COUNT_TEXT_COLOR; + + self.contentView.backgroundColor = [UIColor whiteColor]; + } +} + +@end diff --git a/DoAlbumCell.xib b/DoAlbumCell.xib new file mode 100644 index 0000000..a613b07 --- /dev/null +++ b/DoAlbumCell.xib @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoImagePickerController.h b/DoImagePickerController.h new file mode 100644 index 0000000..99e6cfd --- /dev/null +++ b/DoImagePickerController.h @@ -0,0 +1,96 @@ +// +// DoImagePickerController.h +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import +#import "DoPhotoCell.h" +#import "MWPhoto.h" +#import "DoPhotoBrowser.h" +#define DO_RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1] +#define DO_RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a] + +#define DO_MENU_BACK_COLOR DO_RGBA(57, 185, 238, 0.98) +#define DO_SIDE_BUTTON_COLOR DO_RGBA(57, 185, 238, 0.9) + +#define DO_ALBUM_NAME_TEXT_COLOR DO_RGB(57, 185, 238) +#define DO_ALBUM_COUNT_TEXT_COLOR DO_RGB(247, 200, 142) +#define DO_BOTTOM_TEXT_COLOR DO_RGB(255, 255, 255) + +#define DO_PICKER_RESULT_UIIMAGE 0 +#define DO_PICKER_RESULT_ASSET 1 + +#define DO_NO_LIMIT_SELECT -1 + +@interface DoImagePickerController : UIViewController +{ + NSInteger _imgType; //图片类型选项. + NSInteger _isResolutionImg; //是否原图 +} + +@property (assign, nonatomic) id delegate; +@property (assign, nonatomic) NSInteger selectIndex; +@property (readwrite) NSInteger nMaxCount; // -1 : no limit +@property (readwrite) NSInteger nColumnCount; // 2, 3, or 4 +@property (readwrite) NSInteger nResultType; // default :DO_PICKER_RESULT_UIIMAGE +@property (strong, nonatomic) UIImage* tempImage; //点击的图片 + +@property (weak, nonatomic) IBOutlet UICollectionView *cvPhotoList; +@property (weak, nonatomic) IBOutlet UIView *vDimmed; + +@property (assign, nonatomic)NSInteger isResolutionImg; + +// init +- (void)initControls; +- (void)readAlbumList; + + +// bottom menu +@property (weak, nonatomic) IBOutlet UIView *vBottomMenu; +@property (weak, nonatomic) IBOutlet UIButton *btSelectAlbum; +@property (strong, nonatomic) IBOutlet UIButton *btOK; +@property (weak, nonatomic) IBOutlet UIImageView *ivLine1; +@property (weak, nonatomic) IBOutlet UIImageView *ivLine2; +@property (weak, nonatomic) IBOutlet UILabel *lbSelectCount; +@property (weak, nonatomic) IBOutlet UIImageView *ivShowMark; +@property (weak, nonatomic) IBOutlet UIButton *selectQualty; + +- (IBAction)imgModeSelectBtnClick:(id)sender; +- (void)initBottomMenu; +- (IBAction)onSelectPhoto:(id)sender; +- (IBAction)onCancel:(id)sender; +- (IBAction)onSelectAlbum:(id)sender; +- (void)hideBottomMenu; +-(void)didSelectAtIndex:(NSInteger)index; + +// side buttons +@property (weak, nonatomic) IBOutlet UIButton *btUp; +@property (weak, nonatomic) IBOutlet UIButton *btDown; + +- (IBAction)onUp:(id)sender; +- (IBAction)onDown:(id)sender; + + +// photos +@property (strong, nonatomic) UIImageView *ivPreview; + +- (void)showPhotosInGroup:(NSInteger)nIndex; // nIndex : index in album array +- (void)showPreview:(NSInteger)nIndex; // nIndex : index in photo array +- (void)hidePreview; + + +// select photos +@property (strong, nonatomic) NSMutableArray *dSelected; +@property (strong, nonatomic) NSIndexPath *lastAccessed; +@property (strong, nonatomic) NSMutableArray *noSelect; + +@end + +@protocol DoImagePickerControllerDelegate + +- (void)didCancelDoImagePickerController; +- (void)didSelectPhotosFromDoImagePickerController:(DoImagePickerController *)picker result:(NSArray *)aSelected; + +@end diff --git a/DoImagePickerController.m b/DoImagePickerController.m new file mode 100644 index 0000000..9547692 --- /dev/null +++ b/DoImagePickerController.m @@ -0,0 +1,674 @@ +// +// DoImagePickerController.m +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import "DoImagePickerController.h" +#import "AssetHelper.h" +#import "DoAlbumCell.h" +#import "DoPhotoCell.h" +#import "DoImagePickerGroupViewController.h" +#import "DoPhotoBrowser.h" + +@implementation DoImagePickerController +{ +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + _noSelect = nil; + _isResolutionImg = NO; + _nMaxCount = 8; + _nColumnCount = 4; + _nResultType = DO_PICKER_RESULT_UIIMAGE; + } + return self; +} + +- (void)viewWillAppear:(BOOL)animated +{ + + + if ([ASSETHELPER getPhotoCountOfCurrentGroup] > 0) { + NSLog(@"%ld",[ASSETHELPER getPhotoCountOfCurrentGroup]); + [_cvPhotoList scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:[ASSETHELPER getPhotoCountOfCurrentGroup]-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; + } + [super viewWillAppear:animated]; + [_cvPhotoList reloadData]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + if (iOSVersion>=7.0) { + self.edgesForExtendedLayout = UIRectEdgeNone; + } +// [self.navigationItem setTitle:@"图片"]; + [self initBottomMenu]; + [self initControls]; + _imgType = ASSET_PHOTO_SCREEN_SIZE; + _selectQualty.hidden = YES; + if (_isResolutionImg) { + [_selectQualty setSelected:YES]; + _imgType = ASSET_PHOTO_FULL_RESOLUTION; + }else{ + [_selectQualty setSelected:NO]; + _imgType = ASSET_PHOTO_SCREEN_SIZE; + } + +// [_selectQualty setTitleColor:[UIColor colorWithHexString:@"#0099e6" alpha:1]forState:UIControlStateNormal]; + + //取消按钮 + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStyleBordered target:self action:@selector(onCancel:)]; +// self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"相册" style:UIBarButtonItemStyleBordered target:self action:@selector(onSelectAlbum:)]; + + UINib *nib = [UINib nibWithNibName:@"DoPhotoCell" bundle:nil]; + [_cvPhotoList registerNib:nib forCellWithReuseIdentifier:@"DoPhotoCell"]; + + [_btOK setImageWithColor:[UIColor buttonMainColor]]; + _btOK.enabled = NO; + // new photo is located at the first of array + ASSETHELPER.bReverse = YES; + if (_nMaxCount >= 1) + { + // init gesture for multiple selection with panning + UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPanForSelection:)]; + [self.view addGestureRecognizer:pan]; + } + + // init gesture for preview + + // add observer for refresh asset data + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(handleEnterForeground:) + name: UIApplicationWillEnterForegroundNotification + object: nil]; +} + + +- (void)viewDidAppear:(BOOL)animated +{ +// [_cvPhotoList scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:[ASSETHELPER getPhotoCountOfCurrentGroup]-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; + [super viewDidAppear:animated]; + if (_dSelected.count > 0) { + _btOK.enabled = YES; + }else{ + _btOK.enabled = NO; + } + + [_btOK setTitle:[NSString stringWithFormat:@"完成(%d/%d)", (int)_dSelected.count, (int)_nMaxCount] forState:UIControlStateNormal]; + [_btOK setTitle:[NSString stringWithFormat:@"完成(%d/%d)", (int)_dSelected.count, (int)_nMaxCount] forState:UIControlStateDisabled]; + [_cvPhotoList reloadData]; + +} +-(void)dealloc{ + if (_nResultType == DO_PICKER_RESULT_UIIMAGE) + [ASSETHELPER clearData]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil]; + _noSelect = nil; +} +- (void)handleEnterForeground:(NSNotification*)notification +{ +// [self readAlbumList]; +} + +#pragma mark - for init +- (void)initControls +{ + // side buttons + _btUp.backgroundColor = DO_SIDE_BUTTON_COLOR; + _btDown.backgroundColor = DO_SIDE_BUTTON_COLOR; + + CALayer *layer1 = [_btDown layer]; + [layer1 setMasksToBounds:YES]; + [layer1 setCornerRadius:_btDown.frame.size.height / 2.0 - 1]; + + CALayer *layer2 = [_btUp layer]; + [layer2 setMasksToBounds:YES]; + [layer2 setCornerRadius:_btUp.frame.size.height / 2.0 - 1]; + + + // dimmed view + _vDimmed.alpha = 0.0; + _vDimmed.frame = self.view.frame; +// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapOnDimmedView:)]; +// [_vDimmed addGestureRecognizer:tap]; +} + +- (void)readAlbumList +{ + [ASSETHELPER getGroupList:^(NSArray *aGroups) { + + +// self.navigationItem.leftBarButtonItem.title = [ASSETHELPER getGroupInfo:0][@"name"]; + [self.navigationItem setTitle:[ASSETHELPER getGroupInfo:0][@"name"]]; + [self showPhotosInGroup:0]; + + if (aGroups.count == 1) + _btSelectAlbum.enabled = NO; + + // calculate tableview's height + }]; +} + +#pragma mark - for bottom menu +- (IBAction)imgModeSelectBtnClick:(id)sender { + UIButton* button = (UIButton*)sender; + if ( button.isSelected ) { + button.selected = NO; + _isResolutionImg = NO; + _imgType = ASSET_PHOTO_SCREEN_SIZE; + }else{ + button.selected = YES; + _isResolutionImg = YES; + _imgType = ASSET_PHOTO_FULL_RESOLUTION; + } +} + +- (void)initBottomMenu +{ +// _vBottomMenu.backgroundColor = DO_MENU_BACK_COLOR; +// [_btSelectAlbum setTitleColor:DO_BOTTOM_TEXT_COLOR forState:UIControlStateNormal]; +// [_btSelectAlbum setTitleColor:DO_BOTTOM_TEXT_COLOR forState:UIControlStateDisabled]; + + _ivLine1.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"line.png"]]; + _ivLine2.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"line.png"]]; + + if (_nMaxCount == DO_NO_LIMIT_SELECT) + { + _lbSelectCount.text = @"(0)"; + _lbSelectCount.textColor = DO_BOTTOM_TEXT_COLOR; + } + else if (_nMaxCount < 1) + { + // hide ok button + _btOK.hidden = YES; + _ivLine1.hidden = YES; + + CGRect rect = _btSelectAlbum.frame; + rect.size.width = rect.size.width + 60; + _btSelectAlbum.frame = rect; + + _lbSelectCount.hidden = YES; + } + else + { + _btOK.titleLabel.text = [NSString stringWithFormat:@"完成(%d/%d)",(int)_dSelected.count, (int)_nMaxCount]; + _lbSelectCount.textColor = DO_BOTTOM_TEXT_COLOR; + } +} + +- (IBAction)onSelectPhoto:(id)sender +{ + NSMutableArray *aResult = [[NSMutableArray alloc] initWithCapacity:_dSelected.count]; + + if (_nResultType == DO_PICKER_RESULT_UIIMAGE) + { + for (int i = 0; i < _dSelected.count; i++) + if ([ASSETHELPER getImageAtIndex:[_dSelected[i] integerValue] type:_imgType]) { + [aResult addObject:[ASSETHELPER getImageAtIndex:[_dSelected[i] integerValue] type:_imgType]]; + } + + } + else + { + for (int i = 0; i < _dSelected.count; i++) + if ([ASSETHELPER getAssetAtIndex:[_dSelected[i] integerValue]] != nil) { + [aResult addObject:[ASSETHELPER getAssetAtIndex:[_dSelected[i] integerValue]]]; + } + + } + + [_delegate didSelectPhotosFromDoImagePickerController:self result:aResult]; +} + +- (IBAction)onCancel:(id)sender +{ + + + [_delegate didCancelDoImagePickerController]; +} + +- (IBAction)onSelectAlbum:(id)sender +{ +// BOOL isAnimated = YES; +// if ([sender isKindOfClass:[NSNumber class]]) { +// isAnimated = NO; +// } +// DoImagePickerGroupViewController* doImagePickerGroupViewController = [[DoImagePickerGroupViewController alloc] initWithNibName:@"DoImagePickerGroupViewController" bundle:nil]; +// doImagePickerGroupViewController.delegate = self; +// [self.navigationController pushViewController:doImagePickerGroupViewController animated:isAnimated]; + +} +#pragma mark - for DoImagePickerGroupViewControllerDelegate +-(void)didSelectAtIndex:(NSInteger)index +{ + _dSelected = nil; + _dSelected = [[NSMutableArray alloc] initWithCapacity:_nMaxCount]; + _noSelect = nil; + [self showPhotosInGroup:index]; + [self.navigationItem setTitle:[ASSETHELPER getGroupInfo:index][@"name"]]; +} +#pragma mark - for side buttons +- (void)onTapOnDimmedView:(UITapGestureRecognizer *)tap +{ + if (tap.state == UIGestureRecognizerStateEnded) + { + [self hideBottomMenu]; + + if (_ivPreview != nil) + [self hidePreview]; + } +} + +- (IBAction)onUp:(id)sender +{ + [_cvPhotoList scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; +} + +- (IBAction)onDown:(id)sender +{ + [_cvPhotoList scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:[ASSETHELPER getPhotoCountOfCurrentGroup] - 1 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; +} + +#pragma mark - UITableViewDelegate for selecting album +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [ASSETHELPER getGroupCount]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + DoAlbumCell *cell = (DoAlbumCell*)[tableView dequeueReusableCellWithIdentifier:@"DoAlbumCell"]; + + if (cell == nil) + { + cell = [[[NSBundle mainBundle] loadNibNamed:@"DoAlbumCell" owner:nil options:nil] lastObject]; + } + + NSDictionary *d = [ASSETHELPER getGroupInfo:indexPath.row]; + cell.lbAlbumName.text = d[@"name"]; + cell.lbCount.text = [NSString stringWithFormat:@"%@", d[@"count"]]; + + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [self showPhotosInGroup:indexPath.row]; + [_btSelectAlbum setTitle:[ASSETHELPER getGroupInfo:indexPath.row][@"name"] forState:UIControlStateNormal]; + [self hideBottomMenu]; +} + +- (void)hideBottomMenu +{ + [UIView animateWithDuration:0.2 animations:^(void) { + + _vDimmed.alpha = 0.0; + + _ivShowMark.transform = CGAffineTransformMakeRotation(0); + + [UIView setAnimationDelay:0.1]; + + }]; +} + +#pragma mark - UICollectionViewDelegate for photos +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + + return [ASSETHELPER getPhotoCountOfCurrentGroup]; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + DoPhotoCell *cell = (DoPhotoCell *)[_cvPhotoList dequeueReusableCellWithReuseIdentifier:@"DoPhotoCell" forIndexPath:indexPath]; + + cell.tag = indexPath.row; + cell.delegate = self; + cell.ivPhoto.image = [ASSETHELPER getImageAtIndex:indexPath.row type:ASSET_PHOTO_THUMBNAIL]; + + + if (![self isInNumArray:_dSelected withIndex:indexPath.row]) + [cell setSelectMode:NO]; + else{ + + [cell setSelectIndex:[_dSelected indexOfObject:[self isInNumArray:_dSelected withIndex:indexPath.row]]+1]; + + } + return cell; +} +-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section +{ + return UIEdgeInsetsMake(5, 5, 5, 5); +// return UIEdgeInsetsZero; +} +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + DoPhotoBrowser *photoBrowser = nil; + + photoBrowser = [[DoPhotoBrowser alloc] initWithDelegate:self]; + + // Decide if you want the photo browser full screen, i.e. whether the status bar is affected (defaults to YES) + photoBrowser.wantsFullScreenLayout = YES; + // Show action button to save, copy or email photos (defaults to NO) + photoBrowser.displayActionButton = YES; + photoBrowser.maxNum = _nMaxCount; + photoBrowser.selectImgArray = _dSelected; + photoBrowser.displayNavArrows = YES; + // Example: allows second image to be presented first + [photoBrowser setCurrentPhotoIndex:indexPath.row]; + [self.navigationController pushViewController:photoBrowser animated:YES]; +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + CGFloat currentScreenSizeRate = ([[UIScreen mainScreen] bounds].size.width)/320.0; + if (_nColumnCount == 2) + return CGSizeMake(158*currentScreenSizeRate, 158*currentScreenSizeRate); + else if (_nColumnCount == 3) + return CGSizeMake(104*currentScreenSizeRate, 104*currentScreenSizeRate); + else if (_nColumnCount == 4) + return CGSizeMake(70*currentScreenSizeRate, 70*currentScreenSizeRate); + + return CGSizeZero; +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + if (scrollView == _cvPhotoList) + { + [UIView animateWithDuration:0.2 animations:^(void) { + if (scrollView.contentOffset.y <= 50) + _btUp.alpha = 0.0; + else +// _btUp.alpha = 1.0; + _btUp.alpha = 0.0; + + if (scrollView.contentOffset.y + scrollView.frame.size.height >= scrollView.contentSize.height) + _btDown.alpha = 0.0; + else +// _btDown.alpha = 1.0; + _btUp.alpha = 0.0; + }]; + } +} + +// for multiple selection with panning +- (void)onPanForSelection:(UIPanGestureRecognizer *)gestureRecognizer +{ + if (_ivPreview != nil) + return; + + double fX = [gestureRecognizer locationInView:_cvPhotoList].x; + double fY = [gestureRecognizer locationInView:_cvPhotoList].y; + + for (UICollectionViewCell *cell in _cvPhotoList.visibleCells) + { + float fSX = cell.frame.origin.x; + float fEX = cell.frame.origin.x + cell.frame.size.width; + float fSY = cell.frame.origin.y; + float fEY = cell.frame.origin.y + cell.frame.size.height; + + if (fX >= fSX && fX <= fEX && fY >= fSY && fY <= fEY) + { + NSIndexPath *indexPath = [_cvPhotoList indexPathForCell:cell]; + + if (_lastAccessed != indexPath) + { + [self collectionView:_cvPhotoList didSelectItemAtIndexPath:indexPath]; + } + + _lastAccessed = indexPath; + } + } + + if (gestureRecognizer.state == UIGestureRecognizerStateEnded) + { + _lastAccessed = nil; + _cvPhotoList.scrollEnabled = YES; + } +} + +// for preview +- (void)onLongTapForPreview:(UILongPressGestureRecognizer *)gestureRecognizer +{ + if (_ivPreview != nil) + return; + + if (gestureRecognizer.state == UIGestureRecognizerStateBegan) + { + double fX = [gestureRecognizer locationInView:_cvPhotoList].x; + double fY = [gestureRecognizer locationInView:_cvPhotoList].y; + + NSIndexPath *indexPath = nil; + for (UICollectionViewCell *cell in _cvPhotoList.visibleCells) + { + float fSX = cell.frame.origin.x; + float fEX = cell.frame.origin.x + cell.frame.size.width; + float fSY = cell.frame.origin.y; + float fEY = cell.frame.origin.y + cell.frame.size.height; + + if (fX >= fSX && fX <= fEX && fY >= fSY && fY <= fEY) + { + indexPath = [_cvPhotoList indexPathForCell:cell]; + break; + } + } + + if (indexPath != nil) + [self showPreview:indexPath.row]; + } +} +#pragma mark - for DoPhoteCellDelegate +-(void)selectAtIndex:(NSInteger)index +{ + NSIndexPath* indexPath =[NSIndexPath indexPathForRow:index inSection:0]; + + if (_nMaxCount >= 1 || _nMaxCount == DO_NO_LIMIT_SELECT) + { + + DoPhotoCell *cell = (DoPhotoCell *)[_cvPhotoList cellForItemAtIndexPath:indexPath]; + + if ((![self isInNumArray:_dSelected withIndex:indexPath.row]) && (_nMaxCount > _dSelected.count)) + { + + // select + [_dSelected addObject:[NSNumber numberWithInt:indexPath.row]]; + + [cell setSelectIndex:_dSelected.count]; + } + else if(([self isInNumArray:_dSelected withIndex:indexPath.row])) + { + // unselect + [_dSelected removeObject:[self isInNumArray:_dSelected withIndex:indexPath.row]]; + // [cell setSelectMode:NO]; + [_cvPhotoList reloadData]; + + }else if (_nMaxCount <= _dSelected.count){ +// [RTUtil showStatusBarWarning:[NSString stringWithFormat:@"最多只能选择%d张",_nMaxCount]]; + } + + if (_nMaxCount == DO_NO_LIMIT_SELECT) + _btOK.titleLabel.text = [NSString stringWithFormat:@"完成(%d)", (int)_dSelected.count]; + + else{ + [_btOK setTitle:[NSString stringWithFormat:@"完成(%d/%d)", (int)_dSelected.count, (int)_nMaxCount] forState:UIControlStateNormal]; + [_btOK setTitle:[NSString stringWithFormat:@"完成(%d/%d)", (int)_dSelected.count, (int)_nMaxCount] forState:UIControlStateDisabled]; + if (_dSelected.count <= 0 ) { + [_btOK setEnabled:NO]; + }else{ + [_btOK setEnabled:YES]; + } + } + + + } + else + { + if (_nResultType == DO_PICKER_RESULT_UIIMAGE) + [_delegate didSelectPhotosFromDoImagePickerController:self result:@[[ASSETHELPER getImageAtIndex:indexPath.row type:ASSET_PHOTO_SCREEN_SIZE]]]; + else + [_delegate didSelectPhotosFromDoImagePickerController:self result:@[[ASSETHELPER getAssetAtIndex:indexPath.row]]]; + } + +} +#pragma mark - MWPhotoBrowserDelegate +- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser { + return [ASSETHELPER getPhotoCountOfCurrentGroup]; +} + +- (MWPhoto *)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index { + return [MWPhoto photoWithImage:[ASSETHELPER getImageAtIndex:index type:ASSET_PHOTO_SCREEN_SIZE]]; +} +-(void)selectImageIndexArray:(NSArray*)imgArray +{ + [self onSelectPhoto:nil]; +} +#pragma mark - for photos +- (void)showPhotosInGroup:(NSInteger)nIndex +{ + + + if (_nMaxCount == DO_NO_LIMIT_SELECT) + { + _dSelected = [[NSMutableArray alloc] init]; + _lbSelectCount.text = @"(0)"; + + } + else if (_nMaxCount >= 1) + { + _dSelected = [[NSMutableArray alloc] initWithCapacity:_nMaxCount]; + if (_noSelect.count != 0) { + // _dSelected = _noSelect; + _dSelected = [[NSMutableArray alloc] initWithArray:_noSelect]; + } + _btOK.titleLabel.text = [NSString stringWithFormat:@"完成(%d/%d)", (int)_dSelected.count, (int)_nMaxCount]; + } + + [ASSETHELPER setBReverse:NO]; + [ASSETHELPER getPhotoListOfGroupByIndex:nIndex result:^(NSArray *aPhotos) { + [_cvPhotoList reloadData]; + _cvPhotoList.alpha = 0.3; + [UIView animateWithDuration:0.2 animations:^(void) { + [UIView setAnimationDelay:0.1]; + _cvPhotoList.alpha = 1.0; + }]; + + if (aPhotos.count > 0) + { + [_cvPhotoList scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:aPhotos.count-1 inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; + } + + _btUp.alpha = 0.0; + + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (_cvPhotoList.contentSize.height < _cvPhotoList.frame.size.height) + _btDown.alpha = 0.0; + else + _btDown.alpha = 0.0; + }); + }]; +} + +- (void)showPreview:(NSInteger)nIndex +{ + [self.view bringSubviewToFront:_vDimmed]; + + _ivPreview = [[UIImageView alloc] initWithFrame:_vDimmed.frame]; + _ivPreview.contentMode = UIViewContentModeScaleAspectFit; + _ivPreview.autoresizingMask = _vDimmed.autoresizingMask; + [_vDimmed addSubview:_ivPreview]; + + _ivPreview.image = [ASSETHELPER getImageAtIndex:nIndex type:ASSET_PHOTO_SCREEN_SIZE]; + + // add gesture for close preview + UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPanToClosePreview:)]; + [_vDimmed addGestureRecognizer:pan]; + + [UIView animateWithDuration:0.2 animations:^(void) { + _vDimmed.alpha = 1.0; + }]; +} + +- (void)hidePreview +{ + [self.view bringSubviewToFront:_vBottomMenu]; + + [_ivPreview removeFromSuperview]; + _ivPreview = nil; + + _vDimmed.alpha = 0.0; + [_vDimmed removeGestureRecognizer:[_vDimmed.gestureRecognizers lastObject]]; +} + +- (void)onPanToClosePreview:(UIPanGestureRecognizer *)gestureRecognizer +{ + CGPoint translation = [gestureRecognizer translationInView:self.view]; + + if (gestureRecognizer.state == UIGestureRecognizerStateEnded) + { + [UIView animateWithDuration:0.2 animations:^(void) { + + if (_vDimmed.alpha < 0.7) // close preview + { + CGPoint pt = _ivPreview.center; + if (_ivPreview.center.y > _vDimmed.center.y) + pt.y = self.view.frame.size.height * 1.5; + else if (_ivPreview.center.y < _vDimmed.center.y) + pt.y = -self.view.frame.size.height * 1.5; + + _ivPreview.center = pt; + + [self hidePreview]; + } + else + { + _vDimmed.alpha = 1.0; + _ivPreview.center = _vDimmed.center; + } + + }]; + } + else + { + _ivPreview.center = CGPointMake(_ivPreview.center.x, _ivPreview.center.y + translation.y); + [gestureRecognizer setTranslation:CGPointMake(0, 0) inView:self.view]; + + _vDimmed.alpha = 1 - ABS(_ivPreview.center.y - _vDimmed.center.y) / (self.view.frame.size.height / 2.0); + } +} + +#pragma mark - Others +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (BOOL)prefersStatusBarHidden +{ + return NO; +} +-(id)isInNumArray:(NSMutableArray*)numArray withIndex:(NSInteger)index{ + + for (NSNumber* num in numArray) { + if (num.integerValue == index) { + return num; + } + } + return nil; +} +@end diff --git a/DoImagePickerController.xib b/DoImagePickerController.xib new file mode 100644 index 0000000..9c9548b --- /dev/null +++ b/DoImagePickerController.xib @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoImagePickerGroupCell.h b/DoImagePickerGroupCell.h new file mode 100644 index 0000000..550e61d --- /dev/null +++ b/DoImagePickerGroupCell.h @@ -0,0 +1,18 @@ +/* + Copyright (c) 2013 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 + +@interface DoImagePickerGroupCell : UITableViewCell + +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *countLabel; + +@end diff --git a/DoImagePickerGroupCell.m b/DoImagePickerGroupCell.m new file mode 100644 index 0000000..fa531dd --- /dev/null +++ b/DoImagePickerGroupCell.m @@ -0,0 +1,84 @@ +/* + Copyright (c) 2013 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 "DoImagePickerGroupCell.h" + +@implementation DoImagePickerGroupCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if(self) { + /* Initialization */ + // Title + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; + titleLabel.font = [UIFont boldSystemFontOfSize:17]; + titleLabel.textColor = [UIColor blackColor]; + titleLabel.highlightedTextColor = [UIColor whiteColor]; + titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth; + + [self.contentView addSubview:titleLabel]; + self.titleLabel = titleLabel; + + + // Count + UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; + countLabel.font = [UIFont systemFontOfSize:17]; + countLabel.textColor = [UIColor colorWithWhite:0.498 alpha:1.0]; + countLabel.highlightedTextColor = [UIColor whiteColor]; + countLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; + + [self.contentView addSubview:countLabel]; + self.countLabel = countLabel; + } + + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + self.titleLabel.highlighted = selected; + self.countLabel.highlighted = selected; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + CGFloat height = self.contentView.bounds.size.height; + CGFloat imageViewSize = height - 1; + CGFloat width = self.contentView.bounds.size.width - 20; + + CGSize titleTextSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font forWidth:width lineBreakMode:NSLineBreakByTruncatingTail]; + CGSize countTextSize = [self.countLabel.text sizeWithFont:self.countLabel.font forWidth:width lineBreakMode:NSLineBreakByTruncatingTail]; + + CGRect titleLabelFrame; + CGRect countLabelFrame; + + if((titleTextSize.width + countTextSize.width + 10) > width) { + titleLabelFrame = CGRectMake(imageViewSize + 20, 0, width - countTextSize.width - 10, imageViewSize); + countLabelFrame = CGRectMake(titleLabelFrame.origin.x + titleLabelFrame.size.width + 10, 0, countTextSize.width, imageViewSize); + } else { + titleLabelFrame = CGRectMake(imageViewSize + 20, 0, titleTextSize.width, imageViewSize); + countLabelFrame = CGRectMake(titleLabelFrame.origin.x + titleLabelFrame.size.width + 10, 0, countTextSize.width, imageViewSize); + } + + self.titleLabel.frame = titleLabelFrame; + self.countLabel.frame = countLabelFrame; +} + +- (void)dealloc +{ +} + +@end diff --git a/DoImagePickerGroupViewController.h b/DoImagePickerGroupViewController.h new file mode 100644 index 0000000..2d48a64 --- /dev/null +++ b/DoImagePickerGroupViewController.h @@ -0,0 +1,26 @@ +// +// DoImagePickerGroupViewController.h +// XiaoYu +// +// Created by xmfish on 14-7-30. +// Copyright (c) 2014年 Benson. All rights reserved. +// + +#import +#import "DoImagePickerController.h" +@protocol DoImagePickerGroupViewControllerDelegate + +-(void)didSelectAtIndex:(NSInteger)index; + +@end +@interface DoImagePickerGroupViewController : UIViewController +{ + __weak id _delegate; + DoImagePickerController* _doImagePickerController; +} +@property (weak, nonatomic) IBOutlet UITableView *tableview; + +@property (strong, nonatomic) NSMutableArray* groupArray; +@property (weak, nonatomic)id delegate; +@property (strong, nonatomic)DoImagePickerController* doImagePickerController; +@end diff --git a/DoImagePickerGroupViewController.m b/DoImagePickerGroupViewController.m new file mode 100644 index 0000000..a0f3121 --- /dev/null +++ b/DoImagePickerGroupViewController.m @@ -0,0 +1,96 @@ +// +// DoImagePickerGroupViewController.m +// XiaoYu +// +// Created by xmfish on 14-7-30. +// Copyright (c) 2014年 Benson. All rights reserved. +// + +#import "DoImagePickerGroupViewController.h" +#import "DoImagePickerGroupCell.h" +#import "AssetHelper.h" +@interface DoImagePickerGroupViewController () + +@end + +@implementation DoImagePickerGroupViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + + _groupArray = nil; + [ASSETHELPER setBReverse:NO]; + [ASSETHELPER getGroupList:^(NSArray* groups){ + _groupArray = [[NSMutableArray alloc] initWithArray:groups]; + [self.tableview reloadData]; + }]; + self.doImagePickerController = [[DoImagePickerController alloc] initWithNibName:@"DoImagePickerController" bundle:nil]; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + [self.navigationItem setTitle:@"图片"]; + //取消按钮 + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStyleBordered target:self action:@selector(onCancel:)]; + +} +- (void)onCancel:(id)sender +{ + + + [self dismissViewControllerAnimated:YES completion:nil]; +} +#pragma mark - UITableViewDelegate +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ + return 1; +} +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + if (_groupArray) { + return _groupArray.count; + } + return 0; +} +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 60; +} +-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString* cellIdentifier = @"Cell"; + DoImagePickerGroupCell * cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + + if(cell == nil) { + cell = [[DoImagePickerGroupCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } + + ALAssetsGroup *assetsGroup = [_groupArray objectAtIndex:indexPath.row]; + + cell.imageView.image = [UIImage imageWithCGImage:assetsGroup.posterImage]; + cell.titleLabel.text = [NSString stringWithFormat:@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyName]]; + cell.countLabel.text = [NSString stringWithFormat:@"(%ld)", assetsGroup.numberOfAssets]; + + return cell; +} +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:NO]; + + [_doImagePickerController didSelectAtIndex:indexPath.row]; + [self.navigationController pushViewController:_doImagePickerController animated:YES]; +} +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/DoImagePickerGroupViewController.xib b/DoImagePickerGroupViewController.xib new file mode 100644 index 0000000..02be965 --- /dev/null +++ b/DoImagePickerGroupViewController.xib @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DoPhotoBrowser.h b/DoPhotoBrowser.h new file mode 100644 index 0000000..2d6c8c5 --- /dev/null +++ b/DoPhotoBrowser.h @@ -0,0 +1,74 @@ +// +// MWPhotoBrowser.h +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import +#import "MWPhoto.h" +#import "MWPhotoProtocol.h" +#import "MWCaptionView.h" +#import "MWPhotoBrowser.h" + +// Debug Logging +#if 0 // Set to 1 to enable debug logging +#define MWLog(x, ...) NSLog(x, ## __VA_ARGS__); +#else +#define MWLog(x, ...) +#endif + +@class DoPhotoBrowser; + +@protocol DoPhotoBrowserDelegate + +- (NSUInteger)numberOfPhotosInPhotoBrowser:(DoPhotoBrowser *)photoBrowser; +- (id )photoBrowser:(DoPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index; +-(void)selectImageIndexArray:(NSArray*)imgArray; +@optional + +- (id )photoBrowser:(DoPhotoBrowser *)photoBrowser thumbPhotoAtIndex:(NSUInteger)index; +- (MWCaptionView *)photoBrowser:(DoPhotoBrowser *)photoBrowser captionViewForPhotoAtIndex:(NSUInteger)index; +- (NSString *)photoBrowser:(DoPhotoBrowser *)photoBrowser titleForPhotoAtIndex:(NSUInteger)index; +- (void)photoBrowser:(DoPhotoBrowser *)photoBrowser didDisplayPhotoAtIndex:(NSUInteger)index; +- (void)photoBrowser:(DoPhotoBrowser *)photoBrowser actionButtonPressedForPhotoAtIndex:(NSUInteger)index; +- (BOOL)photoBrowser:(DoPhotoBrowser *)photoBrowser isPhotoSelectedAtIndex:(NSUInteger)index; +- (void)photoBrowser:(DoPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index selectedChanged:(BOOL)selected; +- (void)photoBrowserDidFinishModalPresentation:(DoPhotoBrowser *)photoBrowser; + +@end + +@interface DoPhotoBrowser : UIViewController + +@property (nonatomic)NSUInteger maxNum; +@property (nonatomic, strong)NSMutableArray* selectImgArray; +@property (nonatomic, weak) IBOutlet id delegate; +@property (nonatomic) BOOL zoomPhotosToFill; +@property (nonatomic) BOOL displayNavArrows; +@property (nonatomic) BOOL displayActionButton; +@property (nonatomic) BOOL displaySelectionButtons; +@property (nonatomic) BOOL alwaysShowControls; +@property (nonatomic) BOOL enableGrid; +@property (nonatomic) BOOL enableSwipeToDismiss; +@property (nonatomic) BOOL startOnGrid; +@property (nonatomic) NSUInteger delayToHideElements; +@property (nonatomic, readonly) NSUInteger currentIndex; + +// Init +- (id)initWithPhotos:(NSArray *)photosArray __attribute__((deprecated("Use initWithDelegate: instead"))); // Depreciated +- (id)initWithDelegate:(id )delegate; + +// Reloads the photo browser and refetches data +- (void)reloadData; + +// Set page that photo browser starts on +- (void)setCurrentPhotoIndex:(NSUInteger)index; +- (void)setInitialPageIndex:(NSUInteger)index __attribute__((deprecated("Use setCurrentPhotoIndex: instead"))); // Depreciated + +// Navigation +- (void)showNextPhotoAnimated:(BOOL)animated; +- (void)showPreviousPhotoAnimated:(BOOL)animated; + +@end diff --git a/DoPhotoBrowser.m b/DoPhotoBrowser.m new file mode 100644 index 0000000..2524f2c --- /dev/null +++ b/DoPhotoBrowser.m @@ -0,0 +1,1734 @@ +// +// MWPhotoBrowser.m +// MWPhotoBrowser +// +// Created by Michael Waterfall on 14/10/2010. +// Copyright 2010 d3i. All rights reserved. +// + +#import +#import "MWCommon.h" +#import "DoPhotoBrowser.h" +#import "DoPhotoBrowserPrivate.h" +#import "SDImageCache.h" +#import "DoSureBtn.h" +#import "DoSelectBtn.h" +#define PADDING 10 +#define ACTION_SHEET_OLD_ACTIONS 2000 + +@implementation DoPhotoBrowser +{ + DoSelectBtn* _selectBtn; + + DoSureBtn* _doSureBtn; +} +#pragma mark - Init + +- (id)init { + if ((self = [super init])) { + [self _initialisation]; + } + return self; +} + +- (id)initWithDelegate:(id )delegate { + if ((self = [self init])) { + _delegate = delegate; + } + return self; +} + +- (id)initWithPhotos:(NSArray *)photosArray { + if ((self = [self init])) { + _depreciatedPhotoData = photosArray; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)decoder { + if ((self = [super initWithCoder:decoder])) { + [self _initialisation]; + } + return self; +} + +- (void)_initialisation { + + // Defaults + NSNumber *isVCBasedStatusBarAppearanceNum = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"]; + if (isVCBasedStatusBarAppearanceNum) { + _isVCBasedStatusBarAppearance = isVCBasedStatusBarAppearanceNum.boolValue; + } else { + _isVCBasedStatusBarAppearance = YES; // default + } +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) self.wantsFullScreenLayout = YES; +#endif + _maxNum = 0; + self.hidesBottomBarWhenPushed = YES; + _hasBelongedToViewController = NO; + _photoCount = NSNotFound; + _previousLayoutBounds = CGRectZero; + _currentPageIndex = 0; + _previousPageIndex = NSUIntegerMax; + _displayActionButton = YES; + _displayNavArrows = NO; + _zoomPhotosToFill = YES; + _performingLayout = NO; // Reset on view did appear + _rotating = NO; + _viewIsActive = NO; + _enableGrid = YES; + _startOnGrid = NO; + _enableSwipeToDismiss = YES; + _delayToHideElements = 5; + _visiblePages = [[NSMutableSet alloc] init]; + _recycledPages = [[NSMutableSet alloc] init]; + _photos = [[NSMutableArray alloc] init]; + _thumbPhotos = [[NSMutableArray alloc] init]; + _currentGridContentOffset = CGPointMake(0, CGFLOAT_MAX); + _didSavePreviousStateOfNavBar = NO; + if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]){ + self.automaticallyAdjustsScrollViewInsets = NO; + } + + // Listen for MWPhoto notifications + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(handleMWPhotoLoadingDidEndNotification:) + name:MWPHOTO_LOADING_DID_END_NOTIFICATION + object:nil]; + +} + +- (void)dealloc { + _pagingScrollView.delegate = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self releaseAllUnderlyingPhotos:NO]; + [[SDImageCache sharedImageCache] clearMemory]; // clear memory +} + +- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent { + // Create a copy in case this array is modified while we are looping through + // Release photos + NSArray *copy = [_photos copy]; + for (id p in copy) { + if (p != [NSNull null]) { + if (preserveCurrent && p == [self photoAtIndex:self.currentIndex]) { + continue; // skip current + } + [p unloadUnderlyingImage]; + } + } + // Release thumbs + copy = [_thumbPhotos copy]; + for (id p in copy) { + if (p != [NSNull null]) { + [p unloadUnderlyingImage]; + } + } +} + +- (void)didReceiveMemoryWarning { + + // Release any cached data, images, etc that aren't in use. + [self releaseAllUnderlyingPhotos:YES]; + [_recycledPages removeAllObjects]; + + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + +} + +#pragma mark - View Loading + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad { + + + // Validate grid settings + if (_startOnGrid) _enableGrid = YES; + if (_enableGrid) { + _enableGrid = [_delegate respondsToSelector:@selector(photoBrowser:thumbPhotoAtIndex:)]; + } + if (!_enableGrid) _startOnGrid = NO; + + // View + self.view.backgroundColor = [UIColor blackColor]; + self.view.clipsToBounds = YES; + + // Setup paging scrolling view + CGRect pagingScrollViewFrame = [self frameForPagingScrollView]; + _pagingScrollView = [[UIScrollView alloc] initWithFrame:pagingScrollViewFrame]; + _pagingScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _pagingScrollView.pagingEnabled = YES; + _pagingScrollView.delegate = self; + _pagingScrollView.showsHorizontalScrollIndicator = NO; + _pagingScrollView.showsVerticalScrollIndicator = NO; + _pagingScrollView.backgroundColor = [UIColor blackColor]; + _pagingScrollView.contentSize = [self contentSizeForPagingScrollView]; + [self.view addSubview:_pagingScrollView]; + + // Toolbar + _toolbar = [[UIToolbar alloc] initWithFrame:[self frameForToolbarAtOrientation:self.interfaceOrientation]]; + _toolbar.tintColor = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7") ? [UIColor whiteColor] : nil; + if ([_toolbar respondsToSelector:@selector(setBarTintColor:)]) { + _toolbar.barTintColor = nil; + } + if ([[UIToolbar class] respondsToSelector:@selector(appearance)]) { + [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault]; + [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsLandscapePhone]; + } + _toolbar.barStyle = UIBarStyleBlackTranslucent; + _toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; + + // Toolbar Items + if (self.displayNavArrows) { + NSString *arrowPathFormat; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7")) { + arrowPathFormat = @"MWPhotoBrowser.bundle/images/UIBarButtonItemArrowOutline%@.png"; + } else { + arrowPathFormat = @"MWPhotoBrowser.bundle/images/UIBarButtonItemArrow%@.png"; + } + _previousButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:arrowPathFormat, @"Left"]] style:UIBarButtonItemStylePlain target:self action:@selector(gotoPreviousPage)]; + _nextButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:arrowPathFormat, @"Right"]] style:UIBarButtonItemStylePlain target:self action:@selector(gotoNextPage)]; + } + if (self.displayActionButton) { + _selectBtn = [DoSelectBtn instance]; + + [_selectBtn.selectBtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside]; +// _actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(actionButtonPressed:)]; + _actionButton = [[UIBarButtonItem alloc] initWithCustomView:_selectBtn]; + self.navigationItem.rightBarButtonItem = _actionButton; + } + + // Update + [self reloadData]; + + // Swipe to dismiss + if (_enableSwipeToDismiss) { + UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(doneButtonPressed:)]; + swipeGesture.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp; + [self.view addGestureRecognizer:swipeGesture]; + } + + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 44)]; + titleLabel.backgroundColor = [UIColor clearColor]; + titleLabel.textColor = [UIColor whiteColor]; + titleLabel.textAlignment = NSTextAlignmentCenter; +// titleLabel.font = XIAOYUFONT(16); + titleLabel.font = [UIFont systemFontOfSize:16]; + self.navigationItem.titleView = titleLabel; + + [_doSureBtn setNum:_selectImgArray.count]; + // Super + [super viewDidLoad]; + +} + +- (void)performLayout { + + // Setup + _performingLayout = YES; + NSUInteger numberOfPhotos = [self numberOfPhotos]; + + // Setup pages + [_visiblePages removeAllObjects]; + [_recycledPages removeAllObjects]; + + // Navigation buttons + if ([self.navigationController.viewControllers objectAtIndex:0] == self) { + // We're first on stack so show done button + _doneButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Done", nil) style:UIBarButtonItemStylePlain target:self action:@selector(doneButtonPressed:)]; + // Set appearance + if ([UIBarButtonItem respondsToSelector:@selector(appearance)]) { + [_doneButton setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; + [_doneButton setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone]; + [_doneButton setBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; + [_doneButton setBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsLandscapePhone]; + [_doneButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateNormal]; + [_doneButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateHighlighted]; + } + self.navigationItem.rightBarButtonItem = _doneButton; + } else { + // We're not first so show back button + UIViewController *previousViewController = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2]; + NSString *backButtonTitle = previousViewController.navigationItem.backBarButtonItem ? previousViewController.navigationItem.backBarButtonItem.title : previousViewController.title; + UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:backButtonTitle style:UIBarButtonItemStylePlain target:nil action:nil]; + // Appearance + if ([UIBarButtonItem respondsToSelector:@selector(appearance)]) { + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; + [newBackButton setBackButtonBackgroundImage:nil forState:UIControlStateHighlighted barMetrics:UIBarMetricsLandscapePhone]; + [newBackButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateNormal]; + [newBackButton setTitleTextAttributes:[NSDictionary dictionary] forState:UIControlStateHighlighted]; + } + _previousViewControllerBackButton = previousViewController.navigationItem.backBarButtonItem; // remember previous + previousViewController.navigationItem.backBarButtonItem = newBackButton; + } + + // Toolbar items + BOOL hasItems = NO; + UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:nil]; + fixedSpace.width = 32; // To balance action button + UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]; + NSMutableArray *items = [[NSMutableArray alloc] init]; + + // Left button - Grid + if (_enableGrid) { + hasItems = YES; + NSString *buttonName = @"UIBarButtonItemGrid"; + if (SYSTEM_VERSION_LESS_THAN(@"7")) buttonName = @"UIBarButtonItemGridiOS6"; + [items addObject:[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"MWPhotoBrowser.bundle/images/%@.png", buttonName]] style:UIBarButtonItemStylePlain target:self action:@selector(showGridAnimated)]]; + } else { + [items addObject:fixedSpace]; + } + + // Middle - Nav + if (_previousButton && _nextButton && numberOfPhotos > 1) { + hasItems = YES; + [items addObject:flexSpace]; + [items addObject:flexSpace]; + [items addObject:flexSpace]; + [items addObject:flexSpace]; + [items addObject:flexSpace]; + } else { + [items addObject:flexSpace]; + } + + // Right - Action + if (_actionButton && !(!hasItems && !self.navigationItem.rightBarButtonItem)) { + _doSureBtn = [DoSureBtn instance]; + _doSureBtn.maxCount = _maxNum; + [_doSureBtn.sureBtn addTarget:self action:@selector(sureBtnClick:) forControlEvents:UIControlEventTouchUpInside]; + [items addObject:[[UIBarButtonItem alloc] initWithCustomView:_doSureBtn]]; + } else { + // We're not showing the toolbar so try and show in top right + if (_actionButton) + self.navigationItem.rightBarButtonItem = _actionButton; + [items addObject:fixedSpace]; + } + + // Toolbar visibility + [_toolbar setItems:items]; + BOOL hideToolbar = YES; + for (UIBarButtonItem* item in _toolbar.items) { + if (item != fixedSpace && item != flexSpace) { + hideToolbar = NO; + break; + } + } + if (hideToolbar) { + [_toolbar removeFromSuperview]; + } else { + [self.view addSubview:_toolbar]; + } + + // Update nav + [self updateNavigation]; + + // Content offset + _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:_currentPageIndex]; + [self tilePages]; + _performingLayout = NO; + +} + +// Release any retained subviews of the main view. +- (void)viewDidUnload { + _currentPageIndex = 0; + _pagingScrollView = nil; + _visiblePages = nil; + _recycledPages = nil; + _toolbar = nil; + _previousButton = nil; + _nextButton = nil; + _progressHUD = nil; + [super viewDidUnload]; +} + +- (BOOL)presentingViewControllerPrefersStatusBarHidden { + UIViewController *presenting = self.presentingViewController; + if (presenting) { + if ([presenting isKindOfClass:[UINavigationController class]]) { + presenting = [(UINavigationController *)presenting topViewController]; + } + } else { + // We're in a navigation controller so get previous one! + if (self.navigationController && self.navigationController.viewControllers.count > 1) { + presenting = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2]; + } + } + if (presenting) { + return [presenting prefersStatusBarHidden]; + } else { + return NO; + } +} + +#pragma mark - Appearance + +- (void)viewWillAppear:(BOOL)animated { + + // Super + [super viewWillAppear:animated]; + + // Status bar + if ([UIViewController instancesRespondToSelector:@selector(prefersStatusBarHidden)]) { + _leaveStatusBarAlone = [self presentingViewControllerPrefersStatusBarHidden]; + } else { + _leaveStatusBarAlone = [UIApplication sharedApplication].statusBarHidden; + } + if (CGRectEqualToRect([[UIApplication sharedApplication] statusBarFrame], CGRectZero)) { + // If the frame is zero then definitely leave it alone + _leaveStatusBarAlone = YES; + } + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (!_leaveStatusBarAlone && fullScreen && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + _previousStatusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; + if (SYSTEM_VERSION_LESS_THAN(@"7")) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:animated]; +#pragma clang diagnostic push + } else { + [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:animated]; + } + } + + // Navigation bar appearance + if (!_viewIsActive && [self.navigationController.viewControllers objectAtIndex:0] != self) { + [self storePreviousNavBarAppearance]; + } + [self setNavBarAppearance:animated]; + + // Hide navigation controller's toolbar + _previousNavToolbarHidden = self.navigationController.toolbarHidden; + [self.navigationController setToolbarHidden:YES]; + + // Update UI + [self hideControlsAfterDelay]; + + // Initial appearance + if (!_viewHasAppearedInitially) { + if (_startOnGrid) { + [self showGrid:NO]; + } + _viewHasAppearedInitially = YES; + } + +} + +- (void)viewWillDisappear:(BOOL)animated { + + // Check that we're being popped for good + if ([self.navigationController.viewControllers objectAtIndex:0] != self && + ![self.navigationController.viewControllers containsObject:self]) { + + // State + _viewIsActive = NO; + + // Bar state / appearance + [self restorePreviousNavBarAppearance:animated]; + + } + + // Controls + [self.navigationController.navigationBar.layer removeAllAnimations]; // Stop all animations on nav bar + [NSObject cancelPreviousPerformRequestsWithTarget:self]; // Cancel any pending toggles from taps + [self setControlsHidden:NO animated:NO permanent:YES]; + + // Status bar + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (!_leaveStatusBarAlone && fullScreen && UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + [[UIApplication sharedApplication] setStatusBarStyle:_previousStatusBarStyle animated:animated]; + } + + // Show navigation controller's toolbar + [self.navigationController setToolbarHidden:_previousNavToolbarHidden]; + + // Super + [super viewWillDisappear:animated]; + +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + _viewIsActive = YES; +} + +- (void)willMoveToParentViewController:(UIViewController *)parent { + if (parent && _hasBelongedToViewController) { + [NSException raise:@"MWPhotoBrowser Instance Reuse" format:@"MWPhotoBrowser instances cannot be reused."]; + } +} + +- (void)didMoveToParentViewController:(UIViewController *)parent { + if (!parent) _hasBelongedToViewController = YES; +} + +#pragma mark - Nav Bar Appearance + +- (void)setNavBarAppearance:(BOOL)animated { + [self.navigationController setNavigationBarHidden:NO animated:animated]; + UINavigationBar *navBar = self.navigationController.navigationBar; + navBar.tintColor = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7") ? [UIColor whiteColor] : nil; + if ([navBar respondsToSelector:@selector(setBarTintColor:)]) { + navBar.barTintColor = nil; + navBar.shadowImage = nil; + } + navBar.translucent = YES; + navBar.barStyle = UIBarStyleBlackTranslucent; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; + [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsLandscapePhone]; + } +} + +- (void)storePreviousNavBarAppearance { + _didSavePreviousStateOfNavBar = YES; + if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { + _previousNavBarBarTintColor = self.navigationController.navigationBar.barTintColor; + } + _previousNavBarTranslucent = self.navigationController.navigationBar.translucent; + _previousNavBarTintColor = self.navigationController.navigationBar.tintColor; + _previousNavBarHidden = self.navigationController.navigationBarHidden; + _previousNavBarStyle = self.navigationController.navigationBar.barStyle; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + _previousNavigationBarBackgroundImageDefault = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]; + _previousNavigationBarBackgroundImageLandscapePhone = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsLandscapePhone]; + } +} + +- (void)restorePreviousNavBarAppearance:(BOOL)animated { + if (_didSavePreviousStateOfNavBar) { + [self.navigationController setNavigationBarHidden:_previousNavBarHidden animated:animated]; + UINavigationBar *navBar = self.navigationController.navigationBar; + navBar.tintColor = _previousNavBarTintColor; + navBar.translucent = _previousNavBarTranslucent; + if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { + navBar.barTintColor = _previousNavBarBarTintColor; + } + navBar.barStyle = _previousNavBarStyle; + if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { + [navBar setBackgroundImage:_previousNavigationBarBackgroundImageDefault forBarMetrics:UIBarMetricsDefault]; + [navBar setBackgroundImage:_previousNavigationBarBackgroundImageLandscapePhone forBarMetrics:UIBarMetricsLandscapePhone]; + } + // Restore back button if we need to + if (_previousViewControllerBackButton) { + UIViewController *previousViewController = [self.navigationController topViewController]; // We've disappeared so previous is now top + previousViewController.navigationItem.backBarButtonItem = _previousViewControllerBackButton; + _previousViewControllerBackButton = nil; + } + } +} + +#pragma mark - Layout + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + [self layoutVisiblePages]; +} + +- (void)layoutVisiblePages { + + // Flag + _performingLayout = YES; + + // Toolbar + _toolbar.frame = [self frameForToolbarAtOrientation:self.interfaceOrientation]; + + // Remember index + NSUInteger indexPriorToLayout = _currentPageIndex; + + // Get paging scroll view frame to determine if anything needs changing + CGRect pagingScrollViewFrame = [self frameForPagingScrollView]; + + // Frame needs changing + if (!_skipNextPagingScrollViewPositioning) { + _pagingScrollView.frame = pagingScrollViewFrame; + } + _skipNextPagingScrollViewPositioning = NO; + + // Recalculate contentSize based on current orientation + _pagingScrollView.contentSize = [self contentSizeForPagingScrollView]; + + // Adjust frames and configuration of each visible page + for (MWZoomingScrollView *page in _visiblePages) { + NSUInteger index = page.index; + page.frame = [self frameForPageAtIndex:index]; + if (page.captionView) { + page.captionView.frame = [self frameForCaptionView:page.captionView atIndex:index]; + } + if (page.selectedButton) { + page.selectedButton.frame = [self frameForSelectedButton:page.selectedButton atIndex:index]; + } + + // Adjust scales if bounds has changed since last time + if (!CGRectEqualToRect(_previousLayoutBounds, self.view.bounds)) { + // Update zooms for new bounds + [page setMaxMinZoomScalesForCurrentBounds]; + _previousLayoutBounds = self.view.bounds; + } + + } + + // Adjust contentOffset to preserve page location based on values collected prior to location + _pagingScrollView.contentOffset = [self contentOffsetForPageAtIndex:indexPriorToLayout]; + [self didStartViewingPageAtIndex:_currentPageIndex]; // initial + + // Reset + _currentPageIndex = indexPriorToLayout; + _performingLayout = NO; + +} + +#pragma mark - Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { + return YES; +} + +- (NSUInteger)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskAll; +} + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + + // Remember page index before rotation + _pageIndexBeforeRotation = _currentPageIndex; + _rotating = YES; + + // In iOS 7 the nav bar gets shown after rotation, but might as well do this for everything! + if ([self areControlsHidden]) { + // Force hidden + self.navigationController.navigationBarHidden = YES; + } + +} + +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + + // Perform layout + _currentPageIndex = _pageIndexBeforeRotation; + + // Delay control holding + [self hideControlsAfterDelay]; + + // Layout + [self layoutVisiblePages]; + +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + _rotating = NO; + // Ensure nav bar isn't re-displayed + if ([self areControlsHidden]) { + self.navigationController.navigationBarHidden = NO; + self.navigationController.navigationBar.alpha = 0; + } +} + +#pragma mark - Data + +- (NSUInteger)currentIndex { + return _currentPageIndex; +} + +- (void)reloadData { + + // Reset + _photoCount = NSNotFound; + + // Get data + NSUInteger numberOfPhotos = [self numberOfPhotos]; + [self releaseAllUnderlyingPhotos:YES]; + [_photos removeAllObjects]; + [_thumbPhotos removeAllObjects]; + for (int i = 0; i < numberOfPhotos; i++) { + [_photos addObject:[NSNull null]]; + [_thumbPhotos addObject:[NSNull null]]; + } + + // Update current page index + if (numberOfPhotos > 0) { + _currentPageIndex = MAX(0, MIN(_currentPageIndex, numberOfPhotos - 1)); + } else { + _currentPageIndex = 0; + } + + // Update layout + if ([self isViewLoaded]) { + while (_pagingScrollView.subviews.count) { + [[_pagingScrollView.subviews lastObject] removeFromSuperview]; + } + [self performLayout]; + [self.view setNeedsLayout]; + } + +} + +- (NSUInteger)numberOfPhotos { + if (_photoCount == NSNotFound) { + if ([_delegate respondsToSelector:@selector(numberOfPhotosInPhotoBrowser:)]) { + _photoCount = [_delegate numberOfPhotosInPhotoBrowser:self]; + } else if (_depreciatedPhotoData) { + _photoCount = _depreciatedPhotoData.count; + } + } + if (_photoCount == NSNotFound) _photoCount = 0; + return _photoCount; +} + +- (id)photoAtIndex:(NSUInteger)index { + id photo = nil; + + BOOL isSelect = NO; + for (int i=0; i<_selectImgArray.count; i++) { + + //设置右上角的数字 + if ([[_selectImgArray objectAtIndex:i] integerValue] == self.currentIndex) { + isSelect = YES; + for (int j=0; j<_selectImgArray.count; j++) { + if ([[_selectImgArray objectAtIndex:j] integerValue] == self.currentIndex) { + [_selectBtn setNum:[_selectImgArray indexOfObject:[_selectImgArray objectAtIndex:j]]+1]; + } + } + + } + } + if (isSelect == NO) { + [_selectBtn setSelectMode:NO]; + } + if (index < _photos.count) { + if ([_photos objectAtIndex:index] == [NSNull null]) { + if ([_delegate respondsToSelector:@selector(photoBrowser:photoAtIndex:)]) { + photo = [_delegate photoBrowser:self photoAtIndex:index]; + + } else if (_depreciatedPhotoData && index < _depreciatedPhotoData.count) { + photo = [_depreciatedPhotoData objectAtIndex:index]; + } + if (photo) [_photos replaceObjectAtIndex:index withObject:photo]; + } else { + photo = [_photos objectAtIndex:index]; + } + } + + return photo; +} + +- (id)thumbPhotoAtIndex:(NSUInteger)index { + id photo = nil; + if (index < _thumbPhotos.count) { + if ([_thumbPhotos objectAtIndex:index] == [NSNull null]) { + if ([_delegate respondsToSelector:@selector(photoBrowser:thumbPhotoAtIndex:)]) { + photo = [_delegate photoBrowser:self thumbPhotoAtIndex:index]; + } + if (photo) [_thumbPhotos replaceObjectAtIndex:index withObject:photo]; + } else { + photo = [_thumbPhotos objectAtIndex:index]; + } + } + return photo; +} + +- (MWCaptionView *)captionViewForPhotoAtIndex:(NSUInteger)index { + MWCaptionView *captionView = nil; + if ([_delegate respondsToSelector:@selector(photoBrowser:captionViewForPhotoAtIndex:)]) { + captionView = [_delegate photoBrowser:self captionViewForPhotoAtIndex:index]; + } else { + id photo = [self photoAtIndex:index]; + if ([photo respondsToSelector:@selector(caption)]) { + if ([photo caption]) captionView = [[MWCaptionView alloc] initWithPhoto:photo]; + } + } + captionView.alpha = [self areControlsHidden] ? 0 : 1; // Initial alpha + return captionView; +} + +- (BOOL)photoIsSelectedAtIndex:(NSUInteger)index { + BOOL value = NO; + if (_displaySelectionButtons) { + if ([self.delegate respondsToSelector:@selector(photoBrowser:isPhotoSelectedAtIndex:)]) { + value = [self.delegate photoBrowser:self isPhotoSelectedAtIndex:index]; + } + } + return value; +} + +- (void)setPhotoSelected:(BOOL)selected atIndex:(NSUInteger)index { + if (_displaySelectionButtons) { + if ([self.delegate respondsToSelector:@selector(photoBrowser:photoAtIndex:selectedChanged:)]) { + [self.delegate photoBrowser:self photoAtIndex:index selectedChanged:selected]; + } + } +} + +- (UIImage *)imageForPhoto:(id)photo { + if (photo) { + // Get image or obtain in background + if ([photo underlyingImage]) { + return [photo underlyingImage]; + } else { + [photo loadUnderlyingImageAndNotify]; + } + } + return nil; +} + +- (void)loadAdjacentPhotosIfNecessary:(id)photo { + MWZoomingScrollView *page = [self pageDisplayingPhoto:photo]; + if (page) { + // If page is current page then initiate loading of previous and next pages + NSUInteger pageIndex = page.index; + if (_currentPageIndex == pageIndex) { + if (pageIndex > 0) { + // Preload index - 1 + id photo = [self photoAtIndex:pageIndex-1]; + if (![photo underlyingImage]) { + [photo loadUnderlyingImageAndNotify]; + MWLog(@"Pre-loading image at index %lu", (unsigned long)pageIndex-1); + } + } + if (pageIndex < [self numberOfPhotos] - 1) { + // Preload index + 1 + id photo = [self photoAtIndex:pageIndex+1]; + if (![photo underlyingImage]) { + [photo loadUnderlyingImageAndNotify]; + MWLog(@"Pre-loading image at index %lu", (unsigned long)pageIndex+1); + } + } + } + } +} + +#pragma mark - MWPhoto Loading Notification + +- (void)handleMWPhotoLoadingDidEndNotification:(NSNotification *)notification { + id photo = [notification object]; + MWZoomingScrollView *page = [self pageDisplayingPhoto:photo]; + if (page) { + if ([photo underlyingImage]) { + // Successful load + [page displayImage]; + [self loadAdjacentPhotosIfNecessary:photo]; + } else { + // Failed to load + [page displayImageFailure]; + } + // Update nav + [self updateNavigation]; + } +} + +#pragma mark - Paging + +- (void)tilePages { + + // Calculate which pages should be visible + // Ignore padding as paging bounces encroach on that + // and lead to false page loads + CGRect visibleBounds = _pagingScrollView.bounds; + NSInteger iFirstIndex = (NSInteger)floorf((CGRectGetMinX(visibleBounds)+PADDING*2) / CGRectGetWidth(visibleBounds)); + NSInteger iLastIndex = (NSInteger)floorf((CGRectGetMaxX(visibleBounds)-PADDING*2-1) / CGRectGetWidth(visibleBounds)); + if (iFirstIndex < 0) iFirstIndex = 0; + if (iFirstIndex > [self numberOfPhotos] - 1) iFirstIndex = [self numberOfPhotos] - 1; + if (iLastIndex < 0) iLastIndex = 0; + if (iLastIndex > [self numberOfPhotos] - 1) iLastIndex = [self numberOfPhotos] - 1; + + // Recycle no longer needed pages + NSInteger pageIndex; + for (MWZoomingScrollView *page in _visiblePages) { + pageIndex = page.index; + if (pageIndex < (NSUInteger)iFirstIndex || pageIndex > (NSUInteger)iLastIndex) { + [_recycledPages addObject:page]; + [page.captionView removeFromSuperview]; + [page.selectedButton removeFromSuperview]; + [page prepareForReuse]; + [page removeFromSuperview]; + MWLog(@"Removed page at index %lu", (unsigned long)pageIndex); + } + } + [_visiblePages minusSet:_recycledPages]; + while (_recycledPages.count > 2) // Only keep 2 recycled pages + [_recycledPages removeObject:[_recycledPages anyObject]]; + + // Add missing pages + for (NSUInteger index = (NSUInteger)iFirstIndex; index <= (NSUInteger)iLastIndex; index++) { + if (![self isDisplayingPageForIndex:index]) { + + // Add new page + MWZoomingScrollView *page = [self dequeueRecycledPage]; + if (!page) { + page = [[MWZoomingScrollView alloc] initWithPhotoBrowser:self]; + } + [_visiblePages addObject:page]; + [self configurePage:page forIndex:index]; + + [_pagingScrollView addSubview:page]; + MWLog(@"Added page at index %lu", (unsigned long)index); + + // Add caption + MWCaptionView *captionView = [self captionViewForPhotoAtIndex:index]; + if (captionView) { + captionView.frame = [self frameForCaptionView:captionView atIndex:index]; + [_pagingScrollView addSubview:captionView]; + page.captionView = captionView; + } + + // Add selected button + if (self.displaySelectionButtons) { + UIButton *selectedButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedOff.png"] forState:UIControlStateNormal]; + [selectedButton setImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/ImageSelectedOn.png"] forState:UIControlStateSelected]; + [selectedButton sizeToFit]; + selectedButton.adjustsImageWhenHighlighted = NO; + [selectedButton addTarget:self action:@selector(selectedButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + selectedButton.frame = [self frameForSelectedButton:selectedButton atIndex:index]; + [_pagingScrollView addSubview:selectedButton]; + page.selectedButton = selectedButton; + selectedButton.selected = [self photoIsSelectedAtIndex:index]; + } + + } + } + +} + +- (void)updateVisiblePageStates { + NSSet *copy = [_visiblePages copy]; + for (MWZoomingScrollView *page in copy) { + + // Update selection + page.selectedButton.selected = [self photoIsSelectedAtIndex:page.index]; + + } +} + +- (BOOL)isDisplayingPageForIndex:(NSUInteger)index { + for (MWZoomingScrollView *page in _visiblePages) + if (page.index == index) return YES; + return NO; +} + +- (MWZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index { + MWZoomingScrollView *thePage = nil; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.index == index) { + thePage = page; break; + } + } + return thePage; +} + +- (MWZoomingScrollView *)pageDisplayingPhoto:(id)photo { + MWZoomingScrollView *thePage = nil; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.photo == photo) { + thePage = page; break; + } + } + return thePage; +} + +- (void)configurePage:(MWZoomingScrollView *)page forIndex:(NSUInteger)index { + page.frame = [self frameForPageAtIndex:index]; + page.index = index; + page.photo = [self photoAtIndex:index]; +} + +- (MWZoomingScrollView *)dequeueRecycledPage { + MWZoomingScrollView *page = [_recycledPages anyObject]; + if (page) { + [_recycledPages removeObject:page]; + } + return page; +} + +// Handle page changes +- (void)didStartViewingPageAtIndex:(NSUInteger)index { + + if (![self numberOfPhotos]) { + // Show controls + [self setControlsHidden:NO animated:YES permanent:YES]; + return; + } + + // Release images further away than +/-1 + NSUInteger i; + if (index > 0) { + // Release anything < index - 1 + for (i = 0; i < index-1; i++) { + id photo = [_photos objectAtIndex:i]; + if (photo != [NSNull null]) { + [photo unloadUnderlyingImage]; + [_photos replaceObjectAtIndex:i withObject:[NSNull null]]; + MWLog(@"Released underlying image at index %lu", (unsigned long)i); + } + } + } + if (index < [self numberOfPhotos] - 1) { + // Release anything > index + 1 + for (i = index + 2; i < _photos.count; i++) { + id photo = [_photos objectAtIndex:i]; + if (photo != [NSNull null]) { + [photo unloadUnderlyingImage]; + [_photos replaceObjectAtIndex:i withObject:[NSNull null]]; + MWLog(@"Released underlying image at index %lu", (unsigned long)i); + } + } + } + + // Load adjacent images if needed and the photo is already + // loaded. Also called after photo has been loaded in background + id currentPhoto = [self photoAtIndex:index]; + if ([currentPhoto underlyingImage]) { + // photo loaded so load ajacent now + [self loadAdjacentPhotosIfNecessary:currentPhoto]; + } + + // Notify delegate + if (index != _previousPageIndex) { + if ([_delegate respondsToSelector:@selector(photoBrowser:didDisplayPhotoAtIndex:)]) + [_delegate photoBrowser:self didDisplayPhotoAtIndex:index]; + _previousPageIndex = index; + } + + // Update nav + [self updateNavigation]; + +} + +#pragma mark - Frame Calculations + +- (CGRect)frameForPagingScrollView { + CGRect frame = self.view.bounds;// [[UIScreen mainScreen] bounds]; + frame.origin.x -= PADDING; + frame.size.width += (2 * PADDING); + return CGRectIntegral(frame); +} + +- (CGRect)frameForPageAtIndex:(NSUInteger)index { + // We have to use our paging scroll view's bounds, not frame, to calculate the page placement. When the device is in + // landscape orientation, the frame will still be in portrait because the pagingScrollView is the root view controller's + // view, so its frame is in window coordinate space, which is never rotated. Its bounds, however, will be in landscape + // because it has a rotation transform applied. + CGRect bounds = _pagingScrollView.bounds; + CGRect pageFrame = bounds; + pageFrame.size.width -= (2 * PADDING); + pageFrame.origin.x = (bounds.size.width * index) + PADDING; + return CGRectIntegral(pageFrame); +} + +- (CGSize)contentSizeForPagingScrollView { + // We have to use the paging scroll view's bounds to calculate the contentSize, for the same reason outlined above. + CGRect bounds = _pagingScrollView.bounds; + return CGSizeMake(bounds.size.width * [self numberOfPhotos], bounds.size.height); +} + +- (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index { + CGFloat pageWidth = _pagingScrollView.bounds.size.width; + CGFloat newOffset = index * pageWidth; + return CGPointMake(newOffset, 0); +} + +- (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation { + CGFloat height = 44; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && + UIInterfaceOrientationIsLandscape(orientation)) height = 32; + return CGRectIntegral(CGRectMake(0, self.view.bounds.size.height - height, self.view.bounds.size.width, height)); +} + +- (CGRect)frameForCaptionView:(MWCaptionView *)captionView atIndex:(NSUInteger)index { + CGRect pageFrame = [self frameForPageAtIndex:index]; + CGSize captionSize = [captionView sizeThatFits:CGSizeMake(pageFrame.size.width, 0)]; + CGRect captionFrame = CGRectMake(pageFrame.origin.x, + pageFrame.size.height - captionSize.height - (_toolbar.superview?_toolbar.frame.size.height:0), + pageFrame.size.width, + captionSize.height); + return CGRectIntegral(captionFrame); +} + +- (CGRect)frameForSelectedButton:(UIButton *)selectedButton atIndex:(NSUInteger)index { + CGRect pageFrame = [self frameForPageAtIndex:index]; + CGFloat yOffset = 0; + if (![self areControlsHidden]) { + UINavigationBar *navBar = self.navigationController.navigationBar; + yOffset = navBar.frame.origin.y + navBar.frame.size.height; + } + CGFloat statusBarOffset = [[UIApplication sharedApplication] statusBarFrame].size.height; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7") && !self.wantsFullScreenLayout) statusBarOffset = 0; +#endif + CGRect captionFrame = CGRectMake(pageFrame.origin.x + pageFrame.size.width - 20 - selectedButton.frame.size.width, + statusBarOffset + yOffset, + selectedButton.frame.size.width, + selectedButton.frame.size.height); + return CGRectIntegral(captionFrame); +} + +#pragma mark - UIScrollView Delegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + + // Checks + if (!_viewIsActive || _performingLayout || _rotating) return; + + // Tile pages + [self tilePages]; + + // Calculate current page + CGRect visibleBounds = _pagingScrollView.bounds; + NSInteger index = (NSInteger)(floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds))); + if (index < 0) index = 0; + if (index > [self numberOfPhotos] - 1) index = [self numberOfPhotos] - 1; + NSUInteger previousCurrentPage = _currentPageIndex; + _currentPageIndex = index; + if (_currentPageIndex != previousCurrentPage) { + [self didStartViewingPageAtIndex:index]; + } + +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + // Hide controls when dragging begins + [self setControlsHidden:YES animated:YES permanent:NO]; +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + // Update nav when page changes + [self updateNavigation]; +} + +#pragma mark - Navigation + +- (void)updateNavigation { + + // Title + NSUInteger numberOfPhotos = [self numberOfPhotos]; + if (_gridController) { + if (_gridController.selectionMode) { + self.title = NSLocalizedString(@"Select Photos", nil); + } else { + NSString *photosText; + if (numberOfPhotos == 1) { + photosText = NSLocalizedString(@"photo", @"Used in the context: '1 photo'"); + } else { + photosText = NSLocalizedString(@"photos", @"Used in the context: '3 photos'"); + } + self.title = [NSString stringWithFormat:@"%lu %@", (unsigned long)numberOfPhotos, photosText]; + } + } else if (numberOfPhotos > 1) { + if ([_delegate respondsToSelector:@selector(photoBrowser:titleForPhotoAtIndex:)]) { + self.title = [_delegate photoBrowser:self titleForPhotoAtIndex:_currentPageIndex]; + } else { + self.title = [NSString stringWithFormat:@"%lu%@%lu", (unsigned long)(_currentPageIndex+1), NSLocalizedString(@"/", @"Used in the context: 'Showing 1 of 3 items'"), (unsigned long)numberOfPhotos]; + } + } else { + self.title = nil; + } + ((UILabel *)self.navigationItem.titleView).text = self.title; + + // Buttons + _previousButton.enabled = (_currentPageIndex > 0); + _nextButton.enabled = (_currentPageIndex < numberOfPhotos - 1); + _actionButton.enabled = [[self photoAtIndex:_currentPageIndex] underlyingImage] != nil; + +} + +- (void)jumpToPageAtIndex:(NSUInteger)index animated:(BOOL)animated { + + // Change page + if (index < [self numberOfPhotos]) { + CGRect pageFrame = [self frameForPageAtIndex:index]; + [_pagingScrollView setContentOffset:CGPointMake(pageFrame.origin.x - PADDING, 0) animated:animated]; + [self updateNavigation]; + } + + // Update timer to give more time + [self hideControlsAfterDelay]; + +} + +- (void)gotoPreviousPage { + [self showPreviousPhotoAnimated:NO]; +} +- (void)gotoNextPage { + [self showNextPhotoAnimated:NO]; +} + +- (void)showPreviousPhotoAnimated:(BOOL)animated { + [self jumpToPageAtIndex:_currentPageIndex-1 animated:animated]; +} + +- (void)showNextPhotoAnimated:(BOOL)animated { + [self jumpToPageAtIndex:_currentPageIndex+1 animated:animated]; +} + +#pragma mark - Interactions + +- (void)selectedButtonTapped:(id)sender { + UIButton *selectedButton = (UIButton *)sender; + selectedButton.selected = !selectedButton.selected; + NSUInteger index = NSUIntegerMax; + for (MWZoomingScrollView *page in _visiblePages) { + if (page.selectedButton == selectedButton) { + index = page.index; + break; + } + } + if (index != NSUIntegerMax) { + [self setPhotoSelected:selectedButton.selected atIndex:index]; + } +} + +#pragma mark - Grid + +- (void)showGridAnimated { + [self showGrid:YES]; +} + +- (void)showGrid:(BOOL)animated { + + // if (_gridController) return; + + // Init grid controller + _gridController = [[MWGridViewController alloc] init]; + _gridController.initialContentOffset = _currentGridContentOffset; + _gridController.browser = self; + _gridController.selectionMode = _displaySelectionButtons; + _gridController.view.frame = self.view.bounds; + _gridController.view.frame = CGRectOffset(_gridController.view.frame, 0, self.view.bounds.size.height); + + // Stop specific layout being triggered + _skipNextPagingScrollViewPositioning = YES; + + // Add as a child view controller + [self addChildViewController:_gridController]; + [self.view addSubview:_gridController.view]; + + // Hide action button on nav bar if it exists + if (self.navigationItem.rightBarButtonItem == _actionButton) { + _gridPreviousRightNavItem = _actionButton; + [self.navigationItem setRightBarButtonItem:nil animated:YES]; + } else { + _gridPreviousRightNavItem = nil; + } + + // Update + [self updateNavigation]; + [self setControlsHidden:NO animated:YES permanent:YES]; + + // Animate grid in and photo scroller out + [UIView animateWithDuration:animated ? 0.3 : 0 animations:^(void) { + _gridController.view.frame = self.view.bounds; + CGRect newPagingFrame = [self frameForPagingScrollView]; + newPagingFrame = CGRectOffset(newPagingFrame, 0, -newPagingFrame.size.height); + _pagingScrollView.frame = newPagingFrame; + } completion:^(BOOL finished) { + [_gridController didMoveToParentViewController:self]; + }]; + +} + +- (void)hideGrid { + + if (!_gridController) return; + + // Remember previous content offset + _currentGridContentOffset = _gridController.collectionView.contentOffset; + + // Restore action button if it was removed + if (_gridPreviousRightNavItem == _actionButton && _actionButton) { + [self.navigationItem setRightBarButtonItem:_gridPreviousRightNavItem animated:YES]; + } + + // Position prior to hide animation + CGRect newPagingFrame = [self frameForPagingScrollView]; + newPagingFrame = CGRectOffset(newPagingFrame, 0, -newPagingFrame.size.height); + _pagingScrollView.frame = newPagingFrame; + + // Remember and remove controller now so things can detect a nil grid controller + MWGridViewController *tmpGridController = _gridController; + _gridController = nil; + + // Update + [self updateNavigation]; + [self updateVisiblePageStates]; + + // Animate, hide grid and show paging scroll view + [UIView animateWithDuration:0.3 animations:^{ + tmpGridController.view.frame = CGRectOffset(self.view.bounds, 0, self.view.bounds.size.height); + _pagingScrollView.frame = [self frameForPagingScrollView]; + } completion:^(BOOL finished) { + [tmpGridController willMoveToParentViewController:nil]; + [tmpGridController.view removeFromSuperview]; + [tmpGridController removeFromParentViewController]; + [self setControlsHidden:NO animated:YES permanent:NO]; // retrigger timer + }]; + +} + +#pragma mark - Control Hiding / Showing + +// If permanent then we don't set timers to hide again +// Fades all controls on iOS 5 & 6, and iOS 7 controls slide and fade +- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent { + + // Force visible + if (![self numberOfPhotos] || _gridController || _alwaysShowControls) + hidden = NO; + + // Cancel any timers + [self cancelControlHiding]; + + // Animations & positions + BOOL slideAndFade = SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7"); + CGFloat animatonOffset = 20; + CGFloat animationDuration = (animated ? 0.35 : 0); + + // Status bar + if (!_leaveStatusBarAlone) { + if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + + // iOS 7 + // Hide status bar + if (!_isVCBasedStatusBarAppearance) { + + // Non-view controller based + [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated ? UIStatusBarAnimationSlide : UIStatusBarAnimationNone]; + + } else { + + // View controller based so animate away + _statusBarShouldBeHidden = hidden; + [UIView animateWithDuration:animationDuration animations:^(void) { + [self setNeedsStatusBarAppearanceUpdate]; + } completion:^(BOOL finished) {}]; + + } + + } else { + + // iOS < 7 + // Status bar and nav bar positioning + BOOL fullScreen = YES; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 + if (SYSTEM_VERSION_LESS_THAN(@"7")) fullScreen = self.wantsFullScreenLayout; +#endif + if (fullScreen) { + + // Need to get heights and set nav bar position to overcome display issues + + // Get status bar height if visible + CGFloat statusBarHeight = 0; + if (![UIApplication sharedApplication].statusBarHidden) { + CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame]; + statusBarHeight = MIN(statusBarFrame.size.height, statusBarFrame.size.width); + } + + // Status Bar + [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated?UIStatusBarAnimationFade:UIStatusBarAnimationNone]; + + // Get status bar height if visible + if (![UIApplication sharedApplication].statusBarHidden) { + CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame]; + statusBarHeight = MIN(statusBarFrame.size.height, statusBarFrame.size.width); + } + + // Set navigation bar frame + CGRect navBarFrame = self.navigationController.navigationBar.frame; + navBarFrame.origin.y = statusBarHeight; + self.navigationController.navigationBar.frame = navBarFrame; + + } + + } + } + + // Toolbar, nav bar and captions + // Pre-appear animation positions for iOS 7 sliding + if (slideAndFade && [self areControlsHidden] && !hidden && animated) { + + // Toolbar + _toolbar.frame = CGRectOffset([self frameForToolbarAtOrientation:self.interfaceOrientation], 0, animatonOffset); + + // Captions + for (MWZoomingScrollView *page in _visiblePages) { + if (page.captionView) { + MWCaptionView *v = page.captionView; + // Pass any index, all we're interested in is the Y + CGRect captionFrame = [self frameForCaptionView:v atIndex:0]; + captionFrame.origin.x = v.frame.origin.x; // Reset X + v.frame = CGRectOffset(captionFrame, 0, animatonOffset); + } + } + + } + [UIView animateWithDuration:animationDuration animations:^(void) { + + CGFloat alpha = hidden ? 0 : 1; + + // Nav bar slides up on it's own on iOS 7 + [self.navigationController.navigationBar setAlpha:alpha]; + + // Toolbar + if (slideAndFade) { + _toolbar.frame = [self frameForToolbarAtOrientation:self.interfaceOrientation]; + if (hidden) _toolbar.frame = CGRectOffset(_toolbar.frame, 0, animatonOffset); + } + _toolbar.alpha = alpha; + + // Captions + for (MWZoomingScrollView *page in _visiblePages) { + if (page.captionView) { + MWCaptionView *v = page.captionView; + if (slideAndFade) { + // Pass any index, all we're interested in is the Y + CGRect captionFrame = [self frameForCaptionView:v atIndex:0]; + captionFrame.origin.x = v.frame.origin.x; // Reset X + if (hidden) captionFrame = CGRectOffset(captionFrame, 0, animatonOffset); + v.frame = captionFrame; + } + v.alpha = alpha; + } + } + + // Selected buttons + for (MWZoomingScrollView *page in _visiblePages) { + if (page.selectedButton) { + UIButton *v = page.selectedButton; + CGRect newFrame = [self frameForSelectedButton:v atIndex:0]; + newFrame.origin.x = v.frame.origin.x; + v.frame = newFrame; + } + } + + } completion:^(BOOL finished) {}]; + + // Control hiding timer + // Will cancel existing timer but only begin hiding if + // they are visible + if (!permanent) [self hideControlsAfterDelay]; + +} + +- (BOOL)prefersStatusBarHidden { + if (!_leaveStatusBarAlone) { + return _statusBarShouldBeHidden; + } else { + return [self presentingViewControllerPrefersStatusBarHidden]; + } +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return UIStatusBarAnimationSlide; +} + +- (void)cancelControlHiding { + // If a timer exists then cancel and release + if (_controlVisibilityTimer) { + [_controlVisibilityTimer invalidate]; + _controlVisibilityTimer = nil; + } +} + +// Enable/disable control visiblity timer +- (void)hideControlsAfterDelay { + if (![self areControlsHidden]) { + [self cancelControlHiding]; + _controlVisibilityTimer = [NSTimer scheduledTimerWithTimeInterval:self.delayToHideElements target:self selector:@selector(hideControls) userInfo:nil repeats:NO]; + } +} + +- (BOOL)areControlsHidden { return (_toolbar.alpha == 0); } +- (void)hideControls { [self setControlsHidden:YES animated:YES permanent:NO]; } +- (void)toggleControls { [self setControlsHidden:![self areControlsHidden] animated:YES permanent:NO]; } + +#pragma mark - Properties + +// Handle depreciated method +- (void)setInitialPageIndex:(NSUInteger)index { + [self setCurrentPhotoIndex:index]; +} + +- (void)setCurrentPhotoIndex:(NSUInteger)index { + // Validate + NSUInteger photoCount = [self numberOfPhotos]; + if (photoCount == 0) { + index = 0; + } else { + if (index >= photoCount) + index = [self numberOfPhotos]-1; + } + _currentPageIndex = index; + if ([self isViewLoaded]) { + [self jumpToPageAtIndex:index animated:NO]; + if (!_viewIsActive) + [self tilePages]; // Force tiling if view is not visible + } +} + +#pragma mark - Misc + +- (void)doneButtonPressed:(id)sender { + // Only if we're modal and there's a done button + if (_doneButton) { + if ([_delegate respondsToSelector:@selector(photoBrowserDidFinishModalPresentation:)]) { + // Call delegate method and let them dismiss us + [_delegate photoBrowserDidFinishModalPresentation:self]; + } else { + [self dismissViewControllerAnimated:YES completion:nil]; + } + } +} + +#pragma mark - Actions + +- (void)actionButtonPressed:(id)sender { + if (_actionsSheet) { + + // Dismiss + [_actionsSheet dismissWithClickedButtonIndex:_actionsSheet.cancelButtonIndex animated:YES]; + + } else { + + // Only react when image has loaded + id photo = [self photoAtIndex:_currentPageIndex]; + if ([self numberOfPhotos] > 0 && [photo underlyingImage]) { + + // If they have defined a delegate method then just message them + if ([self.delegate respondsToSelector:@selector(photoBrowser:actionButtonPressedForPhotoAtIndex:)]) { + + // Let delegate handle things + [self.delegate photoBrowser:self actionButtonPressedForPhotoAtIndex:_currentPageIndex]; + + } else { + + // Handle default actions + if (SYSTEM_VERSION_LESS_THAN(@"6")) { + + // Old handling of activities with action sheet + if ([MFMailComposeViewController canSendMail]) { + _actionsSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil + otherButtonTitles:NSLocalizedString(@"Save", nil), NSLocalizedString(@"Copy", nil), NSLocalizedString(@"Email", nil), nil]; + } else { + _actionsSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) destructiveButtonTitle:nil + otherButtonTitles:NSLocalizedString(@"Save", nil), NSLocalizedString(@"Copy", nil), nil]; + } + _actionsSheet.tag = ACTION_SHEET_OLD_ACTIONS; + _actionsSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [_actionsSheet showFromBarButtonItem:sender animated:YES]; + } else { + [_actionsSheet showInView:self.view]; + } + + } else { + + // Show activity view controller + NSMutableArray *items = [NSMutableArray arrayWithObject:[photo underlyingImage]]; + if (photo.caption) { + [items addObject:photo.caption]; + } + self.activityViewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil]; + + // Show loading spinner after a couple of seconds + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + if (self.activityViewController) { + [self showProgressHUDWithMessage:nil]; + } + }); + + // Show + typeof(self) __weak weakSelf = self; + [self.activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) { + weakSelf.activityViewController = nil; + [weakSelf hideControlsAfterDelay]; + [weakSelf hideProgressHUD:YES]; + }]; + [self presentViewController:self.activityViewController animated:YES completion:nil]; + + } + + } + + // Keep controls hidden + [self setControlsHidden:NO animated:YES permanent:YES]; + + } + } +} + +#pragma mark - Action Sheet Delegate + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { + if (actionSheet.tag == ACTION_SHEET_OLD_ACTIONS) { + // Old Actions + _actionsSheet = nil; + if (buttonIndex != actionSheet.cancelButtonIndex) { + if (buttonIndex == actionSheet.firstOtherButtonIndex) { + [self savePhoto]; return; + } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) { + [self copyPhoto]; return; + } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2) { + [self emailPhoto]; return; + } + } + } + [self hideControlsAfterDelay]; // Continue as normal... +} + +#pragma mark - Action Progress + +- (MBProgressHUD *)progressHUD { + if (!_progressHUD) { + _progressHUD = [[MBProgressHUD alloc] initWithView:self.view]; + _progressHUD.minSize = CGSizeMake(120, 120); + _progressHUD.minShowTime = 1; + // The sample image is based on the + // work by: http://www.pixelpressicons.com + // licence: http://creativecommons.org/licenses/by/2.5/ca/ + self.progressHUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MWPhotoBrowser.bundle/images/Checkmark.png"]]; + [self.view addSubview:_progressHUD]; + } + return _progressHUD; +} + +- (void)showProgressHUDWithMessage:(NSString *)message { + self.progressHUD.labelText = message; + self.progressHUD.mode = MBProgressHUDModeIndeterminate; + [self.progressHUD show:YES]; + self.navigationController.navigationBar.userInteractionEnabled = NO; +} + +- (void)hideProgressHUD:(BOOL)animated { + [self.progressHUD hide:animated]; + self.navigationController.navigationBar.userInteractionEnabled = YES; +} + +- (void)showProgressHUDCompleteMessage:(NSString *)message { + if (message) { + if (self.progressHUD.isHidden) [self.progressHUD show:YES]; + self.progressHUD.labelText = message; + self.progressHUD.mode = MBProgressHUDModeCustomView; + [self.progressHUD hide:YES afterDelay:1.5]; + } else { + [self.progressHUD hide:YES]; + } + self.navigationController.navigationBar.userInteractionEnabled = YES; +} + +#pragma mark - Actions + +- (void)savePhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Saving", @"Displayed with ellipsis as 'Saving...' when an item is in the process of being saved")]]; + [self performSelector:@selector(actuallySavePhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallySavePhoto:(id)photo { + if ([photo underlyingImage]) { + UIImageWriteToSavedPhotosAlbum([photo underlyingImage], self, + @selector(image:didFinishSavingWithError:contextInfo:), nil); + } +} + +- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { + [self showProgressHUDCompleteMessage: error ? NSLocalizedString(@"Failed", @"Informing the user a process has failed") : NSLocalizedString(@"Saved", @"Informing the user an item has been saved")]; + [self hideControlsAfterDelay]; // Continue as normal... +} + +- (void)copyPhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Copying", @"Displayed with ellipsis as 'Copying...' when an item is in the process of being copied")]]; + [self performSelector:@selector(actuallyCopyPhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallyCopyPhoto:(id)photo { + if ([photo underlyingImage]) { + [[UIPasteboard generalPasteboard] setData:UIImagePNGRepresentation([photo underlyingImage]) + forPasteboardType:@"public.png"]; + [self showProgressHUDCompleteMessage:NSLocalizedString(@"Copied", @"Informing the user an item has finished copying")]; + [self hideControlsAfterDelay]; // Continue as normal... + } +} + +- (void)emailPhoto { + id photo = [self photoAtIndex:_currentPageIndex]; + if ([photo underlyingImage]) { + [self showProgressHUDWithMessage:[NSString stringWithFormat:@"%@\u2026" , NSLocalizedString(@"Preparing", @"Displayed with ellipsis as 'Preparing...' when an item is in the process of being prepared")]]; + [self performSelector:@selector(actuallyEmailPhoto:) withObject:photo afterDelay:0]; + } +} + +- (void)actuallyEmailPhoto:(id)photo { + if ([photo underlyingImage]) { + MFMailComposeViewController *emailer = [[MFMailComposeViewController alloc] init]; + emailer.mailComposeDelegate = self; + [emailer setSubject:NSLocalizedString(@"Photo", nil)]; + [emailer addAttachmentData:UIImagePNGRepresentation([photo underlyingImage]) mimeType:@"png" fileName:@"Photo.png"]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + emailer.modalPresentationStyle = UIModalPresentationPageSheet; + } + [self presentViewController:emailer animated:YES completion:nil]; + [self hideProgressHUD:NO]; + } +} + +- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { + if (result == MFMailComposeResultFailed) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Email", nil) + message:NSLocalizedString(@"Email failed to send. Please try again.", nil) + delegate:nil cancelButtonTitle:NSLocalizedString(@"Dismiss", nil) otherButtonTitles:nil]; + [alert show]; + } + [self dismissViewControllerAnimated:YES completion:nil]; +} + +-(void)selectBtnClick:(id)sender +{ + + if (_selectImgArray == nil) { + _selectImgArray = [[NSMutableArray alloc] init]; + } + if (!_selectBtn.selectBtn.selected) { + if (_selectImgArray.count >= _maxNum) { +// [RTUtil showStatusBarWarning:[NSString stringWithFormat:@"最多只能选择%ld张",_maxNum]]; + return; + } + [_selectBtn setNum:_selectImgArray.count+1]; + [_selectImgArray addObject:[NSNumber numberWithInt:self.currentIndex]]; + }else{ + for (int i=0; i<_selectImgArray.count; i++) { + NSNumber* num = [_selectImgArray objectAtIndex:i]; + if (num.integerValue == self.currentIndex) { + [_selectImgArray removeObjectAtIndex:i]; + [_selectBtn setSelectMode:NO]; + } + } + } + [_doSureBtn setNum:_selectImgArray.count]; + +} +-(void)sureBtnClick:(id)sender +{ + if ([_delegate respondsToSelector:@selector(selectImageIndexArray:)]) { + [_delegate selectImageIndexArray:_selectImgArray]; + } + [self.navigationController popViewControllerAnimated:YES]; +} +@end diff --git a/DoPhotoBrowserPrivate.h b/DoPhotoBrowserPrivate.h new file mode 100644 index 0000000..558202f --- /dev/null +++ b/DoPhotoBrowserPrivate.h @@ -0,0 +1,137 @@ +// +// DoPhotoBrowserPrivate.h +// XiaoYu +// +// Created by xmfish on 14-9-23. +// Copyright (c) 2014年 厦门小鱼网. All rights reserved. +// + +#import +#import "MBProgressHUD.h" +#import "MWGridViewController.h" +#import "MWZoomingScrollView.h" +#import "DoPhotoBrowser.h" +// Declare private methods of browser +@interface DoPhotoBrowser () { + + // Data + NSUInteger _photoCount; + NSMutableArray *_photos; + NSMutableArray *_thumbPhotos; + NSArray *_depreciatedPhotoData; // Depreciated + + // Views + UIScrollView *_pagingScrollView; + + // Paging & layout + NSMutableSet *_visiblePages, *_recycledPages; + NSUInteger _currentPageIndex; + NSUInteger _previousPageIndex; + CGRect _previousLayoutBounds; + NSUInteger _pageIndexBeforeRotation; + + // Navigation & controls + UIToolbar *_toolbar; + NSTimer *_controlVisibilityTimer; + UIBarButtonItem *_previousButton, *_nextButton, *_actionButton, *_doneButton; + MBProgressHUD *_progressHUD; + UIActionSheet *_actionsSheet; + + // Grid + MWGridViewController *_gridController; + UIBarButtonItem *_gridPreviousLeftNavItem; + UIBarButtonItem *_gridPreviousRightNavItem; + + // Appearance + BOOL _previousNavBarHidden; + BOOL _previousNavToolbarHidden; + BOOL _previousNavBarTranslucent; + UIBarStyle _previousNavBarStyle; + UIStatusBarStyle _previousStatusBarStyle; + UIColor *_previousNavBarTintColor; + UIColor *_previousNavBarBarTintColor; + UIBarButtonItem *_previousViewControllerBackButton; + UIImage *_previousNavigationBarBackgroundImageDefault; + UIImage *_previousNavigationBarBackgroundImageLandscapePhone; + + // Misc + BOOL _hasBelongedToViewController; + BOOL _isVCBasedStatusBarAppearance; + BOOL _statusBarShouldBeHidden; + BOOL _displayActionButton; + BOOL _leaveStatusBarAlone; + BOOL _performingLayout; + BOOL _rotating; + BOOL _viewIsActive; // active as in it's in the view heirarchy + BOOL _didSavePreviousStateOfNavBar; + BOOL _skipNextPagingScrollViewPositioning; + BOOL _viewHasAppearedInitially; + CGPoint _currentGridContentOffset; + +} + +// Properties +@property (nonatomic) UIActivityViewController *activityViewController; + +// Layout +- (void)layoutVisiblePages; +- (void)performLayout; +- (BOOL)presentingViewControllerPrefersStatusBarHidden; + +// Nav Bar Appearance +- (void)setNavBarAppearance:(BOOL)animated; +- (void)storePreviousNavBarAppearance; +- (void)restorePreviousNavBarAppearance:(BOOL)animated; + +// Paging +- (void)tilePages; +- (BOOL)isDisplayingPageForIndex:(NSUInteger)index; +- (MWZoomingScrollView *)pageDisplayedAtIndex:(NSUInteger)index; +- (MWZoomingScrollView *)pageDisplayingPhoto:(id)photo; +- (MWZoomingScrollView *)dequeueRecycledPage; +- (void)configurePage:(MWZoomingScrollView *)page forIndex:(NSUInteger)index; +- (void)didStartViewingPageAtIndex:(NSUInteger)index; + +// Frames +- (CGRect)frameForPagingScrollView; +- (CGRect)frameForPageAtIndex:(NSUInteger)index; +- (CGSize)contentSizeForPagingScrollView; +- (CGPoint)contentOffsetForPageAtIndex:(NSUInteger)index; +- (CGRect)frameForToolbarAtOrientation:(UIInterfaceOrientation)orientation; +- (CGRect)frameForCaptionView:(MWCaptionView *)captionView atIndex:(NSUInteger)index; +- (CGRect)frameForSelectedButton:(UIButton *)selectedButton atIndex:(NSUInteger)index; + +// Navigation +- (void)updateNavigation; +- (void)jumpToPageAtIndex:(NSUInteger)index animated:(BOOL)animated; +- (void)gotoPreviousPage; +- (void)gotoNextPage; + +// Grid +- (void)showGrid:(BOOL)animated; +- (void)hideGrid; + +// Controls +- (void)cancelControlHiding; +- (void)hideControlsAfterDelay; +- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated permanent:(BOOL)permanent; +- (void)toggleControls; +- (BOOL)areControlsHidden; + +// Data +- (NSUInteger)numberOfPhotos; +- (id)photoAtIndex:(NSUInteger)index; +- (id)thumbPhotoAtIndex:(NSUInteger)index; +- (UIImage *)imageForPhoto:(id)photo; +- (BOOL)photoIsSelectedAtIndex:(NSUInteger)index; +- (void)setPhotoSelected:(BOOL)selected atIndex:(NSUInteger)index; +- (void)loadAdjacentPhotosIfNecessary:(id)photo; +- (void)releaseAllUnderlyingPhotos:(BOOL)preserveCurrent; + +// Actions +- (void)savePhoto; +- (void)copyPhoto; +- (void)emailPhoto; + +@end + diff --git a/DoPhotoCell.h b/DoPhotoCell.h new file mode 100644 index 0000000..f71cd4c --- /dev/null +++ b/DoPhotoCell.h @@ -0,0 +1,27 @@ +// +// DoPhotoCell.h +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import + +@protocol DoPhotoCellDelegate + +-(void)selectAtIndex:(NSInteger)index; +@end +@interface DoPhotoCell : UICollectionViewCell +{ + __weak id _delegate; +} + +@property (weak, nonatomic) IBOutlet UIImageView *ivPhoto; +@property (weak, nonatomic) IBOutlet UIView *vSelect; +@property (weak, nonatomic) IBOutlet UILabel *indexLabel; +@property (weak, nonatomic) id delegate; +@property (weak, nonatomic) IBOutlet UIButton *isSelect; +- (IBAction)selectBtnClick:(id)sender; +- (void)setSelectMode:(BOOL)bSelect; +- (void)setSelectIndex:(NSInteger)index; +@end diff --git a/DoPhotoCell.m b/DoPhotoCell.m new file mode 100644 index 0000000..79440ab --- /dev/null +++ b/DoPhotoCell.m @@ -0,0 +1,57 @@ +// +// DoPhotoCell.m +// DoImagePickerController +// +// Created by Donobono on 2014. 1. 23.. +// + +#import "DoPhotoCell.h" + +@implementation DoPhotoCell + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + + } + return self; +} + +- (IBAction)selectBtnClick:(id)sender { + if ([self.delegate respondsToSelector:@selector(selectAtIndex:)]) { + [self.delegate selectAtIndex:self.tag]; + } +} + +- (void)setSelectMode:(BOOL)bSelect +{ + if (bSelect) +// _ivPhoto.alpha = 0.2; + _isSelect.selected = YES; + + else{ + // _ivPhoto.alpha = 1.0; + _isSelect.selected = NO; + _indexLabel.hidden = YES; + } + + +} +-(void)setSelectIndex:(NSInteger)index +{ + _indexLabel.hidden = NO; + _isSelect.selected = YES; + _indexLabel.text = [NSString stringWithFormat:@"%ld",index]; +} +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/DoPhotoCell.xib b/DoPhotoCell.xib new file mode 100644 index 0000000..73f25ba --- /dev/null +++ b/DoPhotoCell.xib @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoSelectBtn.h b/DoSelectBtn.h new file mode 100644 index 0000000..8579945 --- /dev/null +++ b/DoSelectBtn.h @@ -0,0 +1,17 @@ +// +// DoSelectBtn.h +// XiaoYu +// +// Created by xmfish on 14-9-26. +// Copyright (c) 2014年 厦门小鱼网. All rights reserved. +// + +#import + +@interface DoSelectBtn : UIView +@property (weak, nonatomic) IBOutlet UIButton *selectBtn; +@property (weak, nonatomic) IBOutlet UILabel *countLabel; ++(DoSelectBtn*)instance; +-(void)setNum:(NSUInteger)num; +- (void)setSelectMode:(BOOL)bSelect; +@end diff --git a/DoSelectBtn.m b/DoSelectBtn.m new file mode 100644 index 0000000..db969f0 --- /dev/null +++ b/DoSelectBtn.m @@ -0,0 +1,56 @@ +// +// DoSelectBtn.m +// XiaoYu +// +// Created by xmfish on 14-9-26. +// Copyright (c) 2014年 厦门小鱼网. All rights reserved. +// + +#import "DoSelectBtn.h" + +@implementation DoSelectBtn + ++(DoSelectBtn*)instance +{ + NSArray* nibView = [[NSBundle mainBundle] loadNibNamed:@"DoSelectBtn" owner:nil options:nil]; + return [nibView objectAtIndex:0]; +} +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} +-(void)awakeFromNib +{ + +} +-(void)setSelectMode:(BOOL)bSelect +{ + if (bSelect) + // _ivPhoto.alpha = 0.2; + _selectBtn.selected = YES; + + else{ + // _ivPhoto.alpha = 1.0; + _selectBtn.selected = NO; + _countLabel.hidden = YES; + } +} +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ +-(void)setNum:(NSUInteger)num +{ + _countLabel.text = [NSString stringWithFormat:@"%d",num]; + _countLabel.hidden = NO; + _selectBtn.selected = YES; +} +@end diff --git a/DoSelectBtn.xib b/DoSelectBtn.xib new file mode 100644 index 0000000..7be4c02 --- /dev/null +++ b/DoSelectBtn.xib @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DoSureBtn.h b/DoSureBtn.h new file mode 100644 index 0000000..7b722cd --- /dev/null +++ b/DoSureBtn.h @@ -0,0 +1,19 @@ +// +// DoSureBtn.h +// XiaoYu +// +// Created by xmfish on 14-9-26. +// Copyright (c) 2014年 厦门小鱼网. All rights reserved. +// + +#import + +@interface DoSureBtn : UIView +@property (nonatomic)NSUInteger maxCount; +@property (weak, nonatomic) IBOutlet UIButton *sureBtn; +@property (weak, nonatomic) IBOutlet UIImageView *imageView; +@property (weak, nonatomic) IBOutlet UILabel *countLabel; +- (IBAction)sureBtnClick:(id)sender; +-(void)setNum:(NSUInteger)num; ++(DoSureBtn*)instance; +@end diff --git a/DoSureBtn.m b/DoSureBtn.m new file mode 100644 index 0000000..bfbedc5 --- /dev/null +++ b/DoSureBtn.m @@ -0,0 +1,52 @@ +// +// DoSureBtn.m +// XiaoYu +// +// Created by xmfish on 14-9-26. +// Copyright (c) 2014年 厦门小鱼网. All rights reserved. +// + +#import "DoSureBtn.h" + +@implementation DoSureBtn + ++(DoSureBtn*)instance +{ + NSArray* nibView = [[NSBundle mainBundle] loadNibNamed:@"DoSureBtn" owner:nil options:nil]; + return [nibView objectAtIndex:0]; +} +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +-(void)awakeFromNib +{ + [_sureBtn setImageWithColor:[UIColor buttonMainColor]]; + _sureBtn.enabled = NO; +} +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} + + +-(void)setNum:(NSUInteger)num +{ + if (num==0) { + _sureBtn.enabled = NO; + }else{ + _sureBtn.enabled = YES; + } + [_sureBtn setTitle:[NSString stringWithFormat:@"完成(%d/%d)", num,_maxCount] forState:UIControlStateNormal]; + [_sureBtn setTitle:[NSString stringWithFormat:@"完成(%d/%d)", num, _maxCount] forState:UIControlStateDisabled]; +} +- (IBAction)sureBtnClick:(id)sender { +} +@end diff --git a/DoSureBtn.xib b/DoSureBtn.xib new file mode 100644 index 0000000..ccd989f --- /dev/null +++ b/DoSureBtn.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..b483f64 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# DoImagePicker \ No newline at end of file