QBAssetCollectionViewController.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. Copyright (c) 2013 Katsuma Tanaka
  3. 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:
  4. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  5. 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.
  6. */
  7. #import "QBAssetCollectionViewController.h"
  8. // Views
  9. #import "QBImagePickerAssetCell.h"
  10. #import "QBImagePickerFooterView.h"
  11. @interface QBAssetCollectionViewController ()
  12. @property (nonatomic, strong) NSMutableArray *assets;
  13. @property (nonatomic, strong) NSMutableOrderedSet *selectedAssets;
  14. @property (nonatomic, strong) UITableView *tableView;
  15. @property (nonatomic, strong) UIBarButtonItem *doneButton;
  16. @property (nonatomic, assign) UIView *navigationBarView;
  17. - (void)reloadData;
  18. - (void)updateRightBarButtonItem;
  19. - (void)updateDoneButton;
  20. - (void)done;
  21. - (void)cancel;
  22. @end
  23. @implementation QBAssetCollectionViewController
  24. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  25. {
  26. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  27. if(self) {
  28. /* Initialization */
  29. self.assets = [NSMutableArray array];
  30. self.selectedAssets = [NSMutableOrderedSet orderedSet];
  31. self.imageSize = CGSizeMake(75, 75);
  32. // Table View
  33. UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, JX_SCREEN_TOP, JX_SCREEN_WIDTH, JX_SCREEN_HEIGHT - JX_SCREEN_TOP) style:UITableViewStylePlain];
  34. tableView.dataSource = self;
  35. tableView.delegate = self;
  36. tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  37. tableView.allowsSelection = YES;
  38. tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  39. [self.view addSubview:tableView];
  40. self.tableView = tableView;
  41. // [tableView release];
  42. }
  43. return self;
  44. }
  45. - (void)viewWillAppear:(BOOL)animated
  46. {
  47. [super viewWillAppear:animated];
  48. // Reload
  49. [self reloadData];
  50. self.navigationController.navigationBar.hidden = YES;
  51. [self createNavgationBar];
  52. [self updateRightBarButtonItem];
  53. if(self.fullScreenLayoutEnabled) {
  54. // Set bar styles
  55. self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
  56. self.navigationController.navigationBar.translucent = YES;
  57. [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:NO];
  58. // CGFloat top = 0;
  59. // if(![[UIApplication sharedApplication] isStatusBarHidden]) top = top + 20;
  60. // if(!self.navigationController.navigationBarHidden) top = top + 44;
  61. // self.tableView.contentInset = UIEdgeInsetsMake(top, 0, 0, 0);
  62. // self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(top, 0, 0, 0);
  63. //
  64. // [self setWantsFullScreenLayout:YES];
  65. }
  66. // Scroll to bottom
  67. // [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentSize.height) animated:NO];
  68. }
  69. - (void) createNavgationBar {
  70. UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, JX_SCREEN_WIDTH, JX_SCREEN_TOP)];
  71. if (THESIMPLESTYLE) {
  72. view.backgroundColor = [UIColor whiteColor];
  73. }else {
  74. view.backgroundColor = THEMECOLOR;
  75. }
  76. [self.view addSubview:view];
  77. UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, JX_SCREEN_TOP - 30, 200, 20)];
  78. label.font = [UIFont systemFontOfSize:17];
  79. label.textColor = [UIColor whiteColor];
  80. label.textAlignment = NSTextAlignmentCenter;
  81. label.text = self.title;
  82. label.center = CGPointMake(view.frame.size.width / 2, label.center.y);
  83. [view addSubview:label];
  84. UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(8, JX_SCREEN_TOP - 38, 31, 31)];
  85. [btn setBackgroundImage:[UIImage imageNamed:@"title_back"] forState:UIControlStateNormal];
  86. [btn addTarget:self action:@selector(actionQuit) forControlEvents:UIControlEventTouchUpInside];
  87. [view addSubview:btn];
  88. self.navigationBarView = view;
  89. }
  90. - (void)actionQuit {
  91. [self.navigationController popViewControllerAnimated:YES];
  92. }
  93. - (void)viewDidAppear:(BOOL)animated
  94. {
  95. [super viewDidAppear:animated];
  96. // Flash scroll indicators
  97. [self.tableView flashScrollIndicators];
  98. }
  99. - (void)setShowsCancelButton:(BOOL)showsCancelButton
  100. {
  101. _showsCancelButton = showsCancelButton;
  102. [self updateRightBarButtonItem];
  103. }
  104. - (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
  105. {
  106. _allowsMultipleSelection = allowsMultipleSelection;
  107. [self updateRightBarButtonItem];
  108. }
  109. - (void)dealloc
  110. {
  111. // [_assetsGroup release];
  112. //
  113. // [_assets release];
  114. // [_selectedAssets release];
  115. //
  116. // [_tableView release];
  117. // [_doneButton release];
  118. //
  119. // [super dealloc];
  120. }
  121. #pragma mark - Instance Methods
  122. - (void)reloadData
  123. {
  124. // Reload assets
  125. [self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  126. if(result) {
  127. [self.assets addObject:result];
  128. }
  129. }];
  130. [self.tableView reloadData];
  131. // Set footer view
  132. self.showsFooterDescription = NO;
  133. if(self.showsFooterDescription) {
  134. [self.assetsGroup setAssetsFilter:[ALAssetsFilter allPhotos]];
  135. NSUInteger numberOfPhotos = self.assetsGroup.numberOfAssets;
  136. [self.assetsGroup setAssetsFilter:[ALAssetsFilter allVideos]];
  137. NSUInteger numberOfVideos = self.assetsGroup.numberOfAssets;
  138. switch(self.filterType) {
  139. case QBImagePickerFilterTypeAllAssets:
  140. [self.assetsGroup setAssetsFilter:[ALAssetsFilter allAssets]];
  141. break;
  142. case QBImagePickerFilterTypeAllPhotos:
  143. [self.assetsGroup setAssetsFilter:[ALAssetsFilter allPhotos]];
  144. break;
  145. case QBImagePickerFilterTypeAllVideos:
  146. [self.assetsGroup setAssetsFilter:[ALAssetsFilter allVideos]];
  147. break;
  148. }
  149. QBImagePickerFooterView *footerView = [[QBImagePickerFooterView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 48)];
  150. if(self.filterType == QBImagePickerFilterTypeAllAssets) {
  151. footerView.titleLabel.text = [self.delegate assetCollectionViewController:self descriptionForNumberOfPhotos:numberOfPhotos numberOfVideos:numberOfVideos];
  152. } else if(self.filterType == QBImagePickerFilterTypeAllPhotos) {
  153. footerView.titleLabel.text = [self.delegate assetCollectionViewController:self descriptionForNumberOfPhotos:numberOfPhotos];
  154. } else if(self.filterType == QBImagePickerFilterTypeAllVideos) {
  155. footerView.titleLabel.text = [self.delegate assetCollectionViewController:self descriptionForNumberOfVideos:numberOfVideos];
  156. }
  157. self.tableView.tableFooterView = footerView;
  158. // [footerView release];
  159. } else {
  160. QBImagePickerFooterView *footerView = [[QBImagePickerFooterView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 4)];
  161. self.tableView.tableFooterView = footerView;
  162. // [footerView release];
  163. }
  164. [self gotoLastRow:NO];
  165. }
  166. - (void)updateRightBarButtonItem
  167. {
  168. if(self.allowsMultipleSelection) {
  169. // Set done button
  170. // UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)];
  171. // doneButton.enabled = NO;
  172. UIButton *doneButton = [[UIButton alloc] initWithFrame:CGRectMake(JX_SCREEN_WIDTH -90, JX_SCREEN_TOP - 34, 80, 25)];
  173. doneButton.enabled = NO;
  174. [doneButton setTitle:Localized(@"JX_Finish") forState:UIControlStateNormal];
  175. doneButton.titleLabel.font = [UIFont systemFontOfSize:17];
  176. [doneButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
  177. [doneButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
  178. [doneButton addTarget:self action:@selector(done) forControlEvents:UIControlEventTouchUpInside];
  179. [self.navigationBarView addSubview:doneButton];
  180. // [self.navigationItem setRightBarButtonItem:doneButton animated:NO];
  181. self.doneButton = [[UIBarButtonItem alloc] initWithCustomView:doneButton];
  182. // [doneButton release];
  183. } else if(self.showsCancelButton) {
  184. // Set cancel button
  185. UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)];
  186. [self.navigationItem setRightBarButtonItem:cancelButton animated:NO];
  187. // [cancelButton release];
  188. } else {
  189. [self.navigationItem setRightBarButtonItem:nil animated:NO];
  190. }
  191. }
  192. - (void)updateDoneButton
  193. {
  194. if(self.limitsMinimumNumberOfSelection) {
  195. self.doneButton.enabled = (self.selectedAssets.count >= self.minimumNumberOfSelection);
  196. } else {
  197. self.doneButton.enabled = (self.selectedAssets.count > 0);
  198. }
  199. }
  200. - (void)done
  201. {
  202. [self.delegate assetCollectionViewController:self didFinishPickingAssets:self.selectedAssets.array];
  203. }
  204. - (void)cancel
  205. {
  206. [self.delegate assetCollectionViewControllerDidCancel:self];
  207. }
  208. #pragma mark - UITableViewDataSource
  209. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  210. {
  211. return 1;
  212. }
  213. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  214. {
  215. NSInteger numberOfRowsInSection = 0;
  216. switch(section) {
  217. /* case 0: case 1:
  218. {
  219. if(self.allowsMultipleSelection && !self.limitsMaximumNumberOfSelection && self.showsHeaderButton) {
  220. numberOfRowsInSection = 1;
  221. }
  222. }
  223. break;*/
  224. case 0:
  225. {
  226. NSInteger numberOfAssetsInRow = self.view.bounds.size.width / self.imageSize.width;
  227. numberOfRowsInSection = self.assets.count / numberOfAssetsInRow;
  228. if((self.assets.count - numberOfRowsInSection * numberOfAssetsInRow) > 0) numberOfRowsInSection++;
  229. }
  230. break;
  231. }
  232. return numberOfRowsInSection;
  233. }
  234. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  235. {
  236. UITableViewCell *cell = nil;
  237. switch(indexPath.section) {
  238. /* case 0:
  239. {
  240. NSString *cellIdentifier = @"HeaderCell";
  241. cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  242. if(cell == nil) {
  243. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
  244. cell.selectionStyle = UITableViewCellSelectionStyleBlue;
  245. }
  246. if(self.selectedAssets.count == self.assets.count) {
  247. cell.textLabel.text = [self.delegate descriptionForDeselectingAllAssets:self];
  248. // Set accessory view
  249. UIImageView *accessoryView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 23, 23)];
  250. accessoryView.image = [UIImage imageNamed:@"QBImagePickerController.bundle/minus.png"];
  251. accessoryView.layer.shadowColor = [[UIColor colorWithWhite:0 alpha:1.0] CGColor];
  252. accessoryView.layer.shadowOpacity = 0.70;
  253. accessoryView.layer.shadowOffset = CGSizeMake(0, 1.4);
  254. accessoryView.layer.shadowRadius = 2;
  255. cell.accessoryView = accessoryView;
  256. [accessoryView release];
  257. } else {
  258. cell.textLabel.text = [self.delegate descriptionForSelectingAllAssets:self];
  259. // Set accessory view
  260. UIImageView *accessoryView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 23, 23)];
  261. accessoryView.image = [UIImage imageNamed:@"QBImagePickerController.bundle/plus.png"];
  262. accessoryView.layer.shadowColor = [[UIColor colorWithWhite:0 alpha:1.0] CGColor];
  263. accessoryView.layer.shadowOpacity = 0.70;
  264. accessoryView.layer.shadowOffset = CGSizeMake(0, 1.4);
  265. accessoryView.layer.shadowRadius = 2;
  266. cell.accessoryView = accessoryView;
  267. [accessoryView release];
  268. }
  269. }
  270. break;
  271. case 1:
  272. {
  273. NSString *cellIdentifier = @"SeparatorCell";
  274. cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  275. if(cell == nil) {
  276. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
  277. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  278. // Set background view
  279. UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 1)];
  280. backgroundView.backgroundColor = [UIColor colorWithWhite:0.878 alpha:1.0];
  281. cell.backgroundView = backgroundView;
  282. [backgroundView release];
  283. }
  284. }
  285. break;*/
  286. case 0:
  287. {
  288. NSString *cellIdentifier = @"AssetCell";
  289. cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  290. if(cell == nil) {
  291. NSInteger numberOfAssetsInRow = self.view.bounds.size.width / self.imageSize.width;
  292. CGFloat margin = round((self.view.bounds.size.width - self.imageSize.width * numberOfAssetsInRow) / (numberOfAssetsInRow + 1));
  293. cell = [[QBImagePickerAssetCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier imageSize:self.imageSize numberOfAssets:numberOfAssetsInRow margin:margin];
  294. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  295. [(QBImagePickerAssetCell *)cell setDelegate:self];
  296. [(QBImagePickerAssetCell *)cell setAllowsMultipleSelection:self.allowsMultipleSelection];
  297. }
  298. // Set assets
  299. NSInteger numberOfAssetsInRow = self.view.bounds.size.width / self.imageSize.width;
  300. NSInteger offset = numberOfAssetsInRow * indexPath.row;
  301. NSInteger numberOfAssetsToSet = (offset + numberOfAssetsInRow > self.assets.count) ? (self.assets.count - offset) : numberOfAssetsInRow;
  302. NSMutableArray *assets = [NSMutableArray array];
  303. for(NSUInteger i = 0; i < numberOfAssetsToSet; i++) {
  304. ALAsset *asset = [self.assets objectAtIndex:(offset + i)];
  305. [assets addObject:asset];
  306. }
  307. [(QBImagePickerAssetCell *)cell setAssets:assets];
  308. // Set selection states
  309. for(NSUInteger i = 0; i < numberOfAssetsToSet; i++) {
  310. ALAsset *asset = [self.assets objectAtIndex:(offset + i)];
  311. if([self.selectedAssets containsObject:asset]) {
  312. [(QBImagePickerAssetCell *)cell selectAssetAtIndex:i];
  313. } else {
  314. [(QBImagePickerAssetCell *)cell deselectAssetAtIndex:i];
  315. }
  316. }
  317. }
  318. break;
  319. }
  320. return cell;
  321. }
  322. #pragma mark - UITableViewDelegate
  323. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  324. {
  325. CGFloat heightForRow = 0;
  326. switch(indexPath.section) {
  327. /* case 0:
  328. {
  329. heightForRow = 44;
  330. }
  331. break;
  332. case 1:
  333. {
  334. heightForRow = 1;
  335. }
  336. break;*/
  337. case 0:
  338. {
  339. NSInteger numberOfAssetsInRow = self.view.bounds.size.width / self.imageSize.width;
  340. CGFloat margin = round((self.view.bounds.size.width - self.imageSize.width * numberOfAssetsInRow) / (numberOfAssetsInRow + 1));
  341. heightForRow = margin + self.imageSize.height;
  342. }
  343. break;
  344. }
  345. return heightForRow;
  346. }
  347. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  348. {
  349. if(indexPath.section == 0 && indexPath.row == 0) {
  350. if(self.selectedAssets.count == self.assets.count) {
  351. // Deselect all assets
  352. [self.selectedAssets removeAllObjects];
  353. } else {
  354. // Select all assets
  355. [self.selectedAssets addObjectsFromArray:self.assets];
  356. }
  357. // Set done button state
  358. [self updateDoneButton];
  359. // // Update assets
  360. // [tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationNone];
  361. // // Update header text
  362. // [tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
  363. // Cancel table view selection
  364. [tableView deselectRowAtIndexPath:indexPath animated:YES];
  365. }
  366. }
  367. #pragma mark - QBImagePickerAssetCellDelegate
  368. - (BOOL)assetCell:(QBImagePickerAssetCell *)assetCell canSelectAssetAtIndex:(NSUInteger)index
  369. {
  370. BOOL canSelect = YES;
  371. if(self.allowsMultipleSelection && self.limitsMaximumNumberOfSelection) {
  372. canSelect = (self.selectedAssets.count < self.maximumNumberOfSelection);
  373. }
  374. return canSelect;
  375. }
  376. - (void)assetCell:(QBImagePickerAssetCell *)assetCell didChangeAssetSelectionState:(BOOL)selected atIndex:(NSUInteger)index
  377. {
  378. NSIndexPath *indexPath = [self.tableView indexPathForCell:assetCell];
  379. NSInteger numberOfAssetsInRow = self.view.bounds.size.width / self.imageSize.width;
  380. NSInteger assetIndex = indexPath.row * numberOfAssetsInRow + index;
  381. ALAsset *asset = [self.assets objectAtIndex:assetIndex];
  382. if(self.allowsMultipleSelection) {
  383. if(selected) {
  384. [self.selectedAssets addObject:asset];
  385. } else {
  386. [self.selectedAssets removeObject:asset];
  387. }
  388. // Set done button state
  389. [self updateDoneButton];
  390. // Update header text
  391. if((selected && self.selectedAssets.count == self.assets.count) ||
  392. (!selected && self.selectedAssets.count == self.assets.count - 1)) {
  393. [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
  394. }
  395. } else {
  396. [self.delegate assetCollectionViewController:self didFinishPickingAsset:asset];
  397. }
  398. }
  399. - (void) gotoLastRow:(BOOL)animated{
  400. NSInteger n = [self.tableView numberOfRowsInSection:0]-1;
  401. if(n>=1)
  402. [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:n inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
  403. }
  404. @end