PageRenderTime 31ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Three20UI/Sources/TTPhotoViewController.m

https://github.com/GetMoPix/three20
Objective C | 999 lines | 636 code | 243 blank | 120 comment | 100 complexity | e061dccd355c5a7622e9b2c5009d142d MD5 | raw file
  1. //
  2. // Copyright 2009-2011 Facebook
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #import "Three20UI/TTPhotoViewController.h"
  17. // UI
  18. #import "Three20UI/TTNavigator.h"
  19. #import "Three20UI/TTThumbsViewController.h"
  20. #import "Three20UI/TTNavigationController.h"
  21. #import "Three20UI/TTPhotoSource.h"
  22. #import "Three20UI/TTPhoto.h"
  23. #import "Three20UI/TTPhotoView.h"
  24. #import "Three20UI/TTActivityLabel.h"
  25. #import "Three20UI/TTScrollView.h"
  26. #import "Three20UI/UIViewAdditions.h"
  27. #import "Three20UI/UINavigationControllerAdditions.h"
  28. #import "Three20UI/UIToolbarAdditions.h"
  29. // UINavigator
  30. #import "Three20UINavigator/TTGlobalNavigatorMetrics.h"
  31. #import "Three20UINavigator/TTURLObject.h"
  32. #import "Three20UINavigator/TTURLMap.h"
  33. #import "Three20UINavigator/TTBaseNavigationController.h"
  34. // UICommon
  35. #import "Three20UICommon/TTGlobalUICommon.h"
  36. #import "Three20UICommon/UIViewControllerAdditions.h"
  37. // Style
  38. #import "Three20Style/TTGlobalStyle.h"
  39. #import "Three20Style/TTDefaultStyleSheet.h"
  40. // Network
  41. #import "Three20Network/TTGlobalNetwork.h"
  42. #import "Three20Network/TTURLCache.h"
  43. // Core
  44. #import "Three20Core/TTCorePreprocessorMacros.h"
  45. #import "Three20Core/TTGlobalCoreLocale.h"
  46. static const NSTimeInterval kPhotoLoadLongDelay = 0.5;
  47. static const NSTimeInterval kPhotoLoadShortDelay = 0.25;
  48. static const NSTimeInterval kSlideshowInterval = 2;
  49. static const NSInteger kActivityLabelTag = 96;
  50. ///////////////////////////////////////////////////////////////////////////////////////////////////
  51. ///////////////////////////////////////////////////////////////////////////////////////////////////
  52. ///////////////////////////////////////////////////////////////////////////////////////////////////
  53. @implementation TTPhotoViewController
  54. @synthesize centerPhoto = _centerPhoto;
  55. @synthesize centerPhotoIndex = _centerPhotoIndex;
  56. @synthesize defaultImage = _defaultImage;
  57. @synthesize captionStyle = _captionStyle;
  58. @synthesize photoSource = _photoSource;
  59. ///////////////////////////////////////////////////////////////////////////////////////////////////
  60. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
  61. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  62. if (self) {
  63. self.navigationItem.backBarButtonItem =
  64. [[[UIBarButtonItem alloc]
  65. initWithTitle:
  66. TTLocalizedString(@"Photo",
  67. @"Title for back button that returns to photo browser")
  68. style: UIBarButtonItemStylePlain
  69. target: nil
  70. action: nil] autorelease];
  71. self.statusBarStyle = UIStatusBarStyleBlackTranslucent;
  72. self.navigationBarStyle = UIBarStyleBlackTranslucent;
  73. self.navigationBarTintColor = nil;
  74. self.wantsFullScreenLayout = YES;
  75. self.hidesBottomBarWhenPushed = YES;
  76. self.defaultImage = TTIMAGE(@"bundle://Three20.bundle/images/photoDefault.png");
  77. }
  78. return self;
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////
  81. - (id)initWithPhoto:(id<TTPhoto>)photo {
  82. self = [self initWithNibName:nil bundle:nil];
  83. if (self) {
  84. self.centerPhoto = photo;
  85. }
  86. return self;
  87. }
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////
  89. - (id)initWithPhotoSource:(id<TTPhotoSource>)photoSource {
  90. self = [self initWithNibName:nil bundle:nil];
  91. if (self) {
  92. self.photoSource = photoSource;
  93. }
  94. return self;
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////////////////////////
  97. - (id)init {
  98. self = [self initWithNibName:nil bundle:nil];
  99. if (self) {
  100. }
  101. return self;
  102. }
  103. ///////////////////////////////////////////////////////////////////////////////////////////////////
  104. - (void)dealloc {
  105. _thumbsController.delegate = nil;
  106. TT_INVALIDATE_TIMER(_slideshowTimer);
  107. TT_INVALIDATE_TIMER(_loadTimer);
  108. TT_RELEASE_SAFELY(_thumbsController);
  109. TT_RELEASE_SAFELY(_centerPhoto);
  110. TT_RELEASE_SAFELY(_photoSource);
  111. TT_RELEASE_SAFELY(_statusText);
  112. TT_RELEASE_SAFELY(_captionStyle);
  113. TT_RELEASE_SAFELY(_defaultImage);
  114. [super dealloc];
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////////////////////////
  117. ///////////////////////////////////////////////////////////////////////////////////////////////////
  118. #pragma mark -
  119. #pragma mark Private
  120. ///////////////////////////////////////////////////////////////////////////////////////////////////
  121. - (TTPhotoView*)centerPhotoView {
  122. return (TTPhotoView*)_scrollView.centerPage;
  123. }
  124. ///////////////////////////////////////////////////////////////////////////////////////////////////
  125. - (void)loadImageDelayed {
  126. _loadTimer = nil;
  127. [self.centerPhotoView loadImage];
  128. }
  129. ///////////////////////////////////////////////////////////////////////////////////////////////////
  130. - (void)startImageLoadTimer:(NSTimeInterval)delay {
  131. [_loadTimer invalidate];
  132. _loadTimer = [NSTimer scheduledTimerWithTimeInterval:delay
  133. target:self
  134. selector:@selector(loadImageDelayed)
  135. userInfo:nil
  136. repeats:NO];
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////////////////////////
  139. - (void)cancelImageLoadTimer {
  140. [_loadTimer invalidate];
  141. _loadTimer = nil;
  142. }
  143. ///////////////////////////////////////////////////////////////////////////////////////////////////
  144. - (void)loadImages {
  145. TTPhotoView* centerPhotoView = self.centerPhotoView;
  146. for (TTPhotoView* photoView in _scrollView.visiblePages.objectEnumerator) {
  147. if (photoView == centerPhotoView) {
  148. [photoView loadPreview:NO];
  149. } else {
  150. [photoView loadPreview:YES];
  151. }
  152. }
  153. if (_delayLoad) {
  154. _delayLoad = NO;
  155. [self startImageLoadTimer:kPhotoLoadLongDelay];
  156. } else {
  157. [centerPhotoView loadImage];
  158. }
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////////////////////////
  161. - (void)updateChrome {
  162. if (_photoSource.numberOfPhotos < 2) {
  163. self.title = _photoSource.title;
  164. } else {
  165. self.title = [NSString stringWithFormat:
  166. TTLocalizedString(@"%d of %d", @"Current page in photo browser (1 of 10)"),
  167. _centerPhotoIndex+1, _photoSource.numberOfPhotos];
  168. }
  169. if (![self.ttPreviousViewController isKindOfClass:[TTThumbsViewController class]]) {
  170. if (_photoSource.numberOfPhotos > 1) {
  171. self.navigationItem.rightBarButtonItem =
  172. [[[UIBarButtonItem alloc] initWithTitle:TTLocalizedString(@"See All",
  173. @"See all photo thumbnails")
  174. style:UIBarButtonItemStyleBordered
  175. target:self
  176. action:@selector(showThumbnails)]
  177. autorelease];
  178. } else {
  179. self.navigationItem.rightBarButtonItem = nil;
  180. }
  181. } else {
  182. self.navigationItem.rightBarButtonItem = nil;
  183. }
  184. UIBarButtonItem* playButton = [_toolbar itemWithTag:1];
  185. playButton.enabled = _photoSource.numberOfPhotos > 1;
  186. _previousButton.enabled = _centerPhotoIndex > 0;
  187. _nextButton.enabled = _centerPhotoIndex >= 0 && _centerPhotoIndex < _photoSource.numberOfPhotos-1;
  188. }
  189. ///////////////////////////////////////////////////////////////////////////////////////////////////
  190. - (void)updateToolbarWithOrientation:(UIInterfaceOrientation)interfaceOrientation {
  191. _toolbar.height = TTToolbarHeight();
  192. _toolbar.top = self.view.height - _toolbar.height;
  193. }
  194. ///////////////////////////////////////////////////////////////////////////////////////////////////
  195. - (void)updatePhotoView {
  196. _scrollView.centerPageIndex = _centerPhotoIndex;
  197. [self loadImages];
  198. [self updateChrome];
  199. }
  200. ///////////////////////////////////////////////////////////////////////////////////////////////////
  201. - (void)moveToPhoto:(id<TTPhoto>)photo {
  202. id<TTPhoto> previousPhoto = [_centerPhoto autorelease];
  203. _centerPhoto = [photo retain];
  204. [self didMoveToPhoto:_centerPhoto fromPhoto:previousPhoto];
  205. }
  206. ///////////////////////////////////////////////////////////////////////////////////////////////////
  207. - (void)moveToPhotoAtIndex:(NSInteger)photoIndex withDelay:(BOOL)withDelay {
  208. _centerPhotoIndex = photoIndex == TT_NULL_PHOTO_INDEX ? 0 : photoIndex;
  209. [self moveToPhoto:[_photoSource photoAtIndex:_centerPhotoIndex]];
  210. _delayLoad = withDelay;
  211. }
  212. ///////////////////////////////////////////////////////////////////////////////////////////////////
  213. - (void)showPhoto:(id<TTPhoto>)photo inView:(TTPhotoView*)photoView {
  214. photoView.photo = photo;
  215. if (!photoView.photo && _statusText) {
  216. [photoView showStatus:_statusText];
  217. }
  218. }
  219. ///////////////////////////////////////////////////////////////////////////////////////////////////
  220. - (void)updateVisiblePhotoViews {
  221. [self moveToPhoto:[_photoSource photoAtIndex:_centerPhotoIndex]];
  222. NSDictionary* photoViews = _scrollView.visiblePages;
  223. for (NSNumber* key in photoViews.keyEnumerator) {
  224. TTPhotoView* photoView = [photoViews objectForKey:key];
  225. [photoView showProgress:-1];
  226. id<TTPhoto> photo = [_photoSource photoAtIndex:key.intValue];
  227. [self showPhoto:photo inView:photoView];
  228. }
  229. }
  230. ///////////////////////////////////////////////////////////////////////////////////////////////////
  231. - (void)resetVisiblePhotoViews {
  232. NSDictionary* photoViews = _scrollView.visiblePages;
  233. for (TTPhotoView* photoView in photoViews.objectEnumerator) {
  234. if (!photoView.isLoading) {
  235. [photoView showProgress:-1];
  236. }
  237. }
  238. }
  239. ///////////////////////////////////////////////////////////////////////////////////////////////////
  240. - (BOOL)isShowingChrome {
  241. UINavigationBar* bar = self.navigationController.navigationBar;
  242. return bar ? bar.alpha != 0 : 1;
  243. }
  244. ///////////////////////////////////////////////////////////////////////////////////////////////////
  245. - (TTPhotoView*)statusView {
  246. if (!_photoStatusView) {
  247. _photoStatusView = [[TTPhotoView alloc] initWithFrame:_scrollView.frame];
  248. _photoStatusView.defaultImage = _defaultImage;
  249. _photoStatusView.photo = nil;
  250. [_innerView addSubview:_photoStatusView];
  251. }
  252. return _photoStatusView;
  253. }
  254. ///////////////////////////////////////////////////////////////////////////////////////////////////
  255. - (void)showProgress:(CGFloat)progress {
  256. if ((self.hasViewAppeared || self.isViewAppearing) && progress >= 0 && !self.centerPhotoView) {
  257. [self.statusView showProgress:progress];
  258. self.statusView.hidden = NO;
  259. } else {
  260. _photoStatusView.hidden = YES;
  261. }
  262. }
  263. ///////////////////////////////////////////////////////////////////////////////////////////////////
  264. - (void)showStatus:(NSString*)status {
  265. [_statusText release];
  266. _statusText = [status retain];
  267. if ((self.hasViewAppeared || self.isViewAppearing) && status && !self.centerPhotoView) {
  268. [self.statusView showStatus:status];
  269. self.statusView.hidden = NO;
  270. } else {
  271. _photoStatusView.hidden = YES;
  272. }
  273. }
  274. ///////////////////////////////////////////////////////////////////////////////////////////////////
  275. - (void)showCaptions:(BOOL)show {
  276. for (TTPhotoView* photoView in _scrollView.visiblePages.objectEnumerator) {
  277. photoView.hidesCaption = !show;
  278. }
  279. }
  280. ///////////////////////////////////////////////////////////////////////////////////////////////////
  281. - (NSString*)URLForThumbnails {
  282. if ([self.photoSource respondsToSelector:@selector(URLValueWithName:)]) {
  283. return [self.photoSource performSelector:@selector(URLValueWithName:)
  284. withObject:@"TTThumbsViewController"];
  285. } else {
  286. return nil;
  287. }
  288. }
  289. ///////////////////////////////////////////////////////////////////////////////////////////////////
  290. - (void)showThumbnails {
  291. NSString* URL = [self URLForThumbnails];
  292. if (!_thumbsController) {
  293. if (URL) {
  294. // The photo source has a URL mapping in TTURLMap, so we use that to show the thumbs
  295. NSDictionary* query = [NSDictionary dictionaryWithObject:self forKey:@"delegate"];
  296. TTBaseNavigator* navigator = [TTBaseNavigator navigatorForView:self.view];
  297. _thumbsController = [[navigator viewControllerForURL:URL query:query] retain];
  298. [navigator.URLMap setObject:_thumbsController forURL:URL];
  299. } else {
  300. // The photo source had no URL mapping in TTURLMap, so we let the subclass show the thumbs
  301. _thumbsController = [[self createThumbsViewController] retain];
  302. _thumbsController.photoSource = _photoSource;
  303. }
  304. }
  305. if (URL) {
  306. TTOpenURLFromView(URL, self.view);
  307. } else {
  308. if ([self.navigationController isKindOfClass:[TTNavigationController class]]) {
  309. [(TTNavigationController*)self.navigationController
  310. pushViewController: _thumbsController
  311. animatedWithTransition: UIViewAnimationTransitionCurlDown];
  312. } else {
  313. [self.navigationController pushViewController:_thumbsController animated:YES];
  314. }
  315. }
  316. }
  317. ///////////////////////////////////////////////////////////////////////////////////////////////////
  318. - (void)slideshowTimer {
  319. if (_centerPhotoIndex == _photoSource.numberOfPhotos-1) {
  320. _scrollView.centerPageIndex = 0;
  321. } else {
  322. _scrollView.centerPageIndex = _centerPhotoIndex+1;
  323. }
  324. }
  325. ///////////////////////////////////////////////////////////////////////////////////////////////////
  326. - (void)playAction {
  327. if (!_slideshowTimer) {
  328. UIBarButtonItem* pauseButton =
  329. [[[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemPause
  330. target: self
  331. action: @selector(pauseAction)]
  332. autorelease];
  333. pauseButton.tag = 1;
  334. [_toolbar replaceItemWithTag:1 withItem:pauseButton];
  335. _slideshowTimer = [NSTimer scheduledTimerWithTimeInterval:kSlideshowInterval
  336. target:self
  337. selector:@selector(slideshowTimer)
  338. userInfo:nil
  339. repeats:YES];
  340. }
  341. }
  342. ///////////////////////////////////////////////////////////////////////////////////////////////////
  343. - (void)pauseAction {
  344. if (_slideshowTimer) {
  345. UIBarButtonItem* playButton =
  346. [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay
  347. target:self
  348. action:@selector(playAction)]
  349. autorelease];
  350. playButton.tag = 1;
  351. [_toolbar replaceItemWithTag:1 withItem:playButton];
  352. [_slideshowTimer invalidate];
  353. _slideshowTimer = nil;
  354. }
  355. }
  356. ///////////////////////////////////////////////////////////////////////////////////////////////////
  357. - (void)nextAction {
  358. [self pauseAction];
  359. if (_centerPhotoIndex < _photoSource.numberOfPhotos-1) {
  360. _scrollView.centerPageIndex = _centerPhotoIndex+1;
  361. }
  362. }
  363. ///////////////////////////////////////////////////////////////////////////////////////////////////
  364. - (void)previousAction {
  365. [self pauseAction];
  366. if (_centerPhotoIndex > 0) {
  367. _scrollView.centerPageIndex = _centerPhotoIndex-1;
  368. }
  369. }
  370. ///////////////////////////////////////////////////////////////////////////////////////////////////
  371. - (void)showBarsAnimationDidStop {
  372. self.navigationController.navigationBarHidden = NO;
  373. }
  374. ///////////////////////////////////////////////////////////////////////////////////////////////////
  375. - (void)hideBarsAnimationDidStop {
  376. self.navigationController.navigationBarHidden = YES;
  377. }
  378. ///////////////////////////////////////////////////////////////////////////////////////////////////
  379. ///////////////////////////////////////////////////////////////////////////////////////////////////
  380. #pragma mark -
  381. #pragma mark UIViewController
  382. ///////////////////////////////////////////////////////////////////////////////////////////////////
  383. - (void)loadView {
  384. CGRect screenFrame = [UIScreen mainScreen].bounds;
  385. self.view = [[[UIView alloc] initWithFrame:screenFrame] autorelease];
  386. CGRect innerFrame = CGRectMake(0, 0,
  387. screenFrame.size.width, screenFrame.size.height);
  388. _innerView = [[UIView alloc] initWithFrame:innerFrame];
  389. _innerView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  390. [self.view addSubview:_innerView];
  391. _scrollView = [[TTScrollView alloc] initWithFrame:screenFrame];
  392. _scrollView.delegate = self;
  393. _scrollView.dataSource = self;
  394. _scrollView.rotateEnabled = NO;
  395. _scrollView.backgroundColor = [UIColor blackColor];
  396. _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
  397. [_innerView addSubview:_scrollView];
  398. _nextButton =
  399. [[UIBarButtonItem alloc] initWithImage:TTIMAGE(@"bundle://Three20.bundle/images/nextIcon.png")
  400. style:UIBarButtonItemStylePlain
  401. target:self
  402. action:@selector(nextAction)];
  403. _previousButton =
  404. [[UIBarButtonItem alloc] initWithImage:
  405. TTIMAGE(@"bundle://Three20.bundle/images/previousIcon.png")
  406. style:UIBarButtonItemStylePlain
  407. target:self
  408. action:@selector(previousAction)];
  409. UIBarButtonItem* playButton =
  410. [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay
  411. target:self
  412. action:@selector(playAction)]
  413. autorelease];
  414. playButton.tag = 1;
  415. UIBarItem* space = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:
  416. UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
  417. _toolbar = [[UIToolbar alloc] initWithFrame:
  418. CGRectMake(0, screenFrame.size.height - TT_ROW_HEIGHT,
  419. screenFrame.size.width, TT_ROW_HEIGHT)];
  420. if (self.navigationBarStyle == UIBarStyleDefault) {
  421. _toolbar.tintColor = TTSTYLEVAR(toolbarTintColor);
  422. }
  423. _toolbar.barStyle = self.navigationBarStyle;
  424. _toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin;
  425. _toolbar.items = [NSArray arrayWithObjects:
  426. space, _previousButton, space, _nextButton, space, nil];
  427. [_innerView addSubview:_toolbar];
  428. }
  429. ///////////////////////////////////////////////////////////////////////////////////////////////////
  430. - (void)viewDidUnload {
  431. [super viewDidUnload];
  432. _scrollView.delegate = nil;
  433. _scrollView.dataSource = nil;
  434. TT_RELEASE_SAFELY(_innerView);
  435. TT_RELEASE_SAFELY(_scrollView);
  436. TT_RELEASE_SAFELY(_photoStatusView);
  437. TT_RELEASE_SAFELY(_nextButton);
  438. TT_RELEASE_SAFELY(_previousButton);
  439. TT_RELEASE_SAFELY(_toolbar);
  440. }
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////
  442. - (void)viewWillAppear:(BOOL)animated {
  443. [super viewWillAppear:animated];
  444. [self updateToolbarWithOrientation:self.interfaceOrientation];
  445. }
  446. ///////////////////////////////////////////////////////////////////////////////////////////////////
  447. - (void)viewWillDisappear:(BOOL)animated {
  448. [super viewWillDisappear:animated];
  449. [_scrollView cancelTouches];
  450. [self pauseAction];
  451. if (self.nextViewController) {
  452. [self showBars:YES animated:NO];
  453. }
  454. }
  455. ///////////////////////////////////////////////////////////////////////////////////////////////////
  456. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
  457. return TTIsSupportedOrientation(interfaceOrientation);
  458. }
  459. ///////////////////////////////////////////////////////////////////////////////////////////////////
  460. - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
  461. duration:(NSTimeInterval)duration {
  462. [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
  463. [self updateToolbarWithOrientation:toInterfaceOrientation];
  464. }
  465. ///////////////////////////////////////////////////////////////////////////////////////////////////
  466. - (UIView *)rotatingFooterView {
  467. return _toolbar;
  468. }
  469. ///////////////////////////////////////////////////////////////////////////////////////////////////
  470. ///////////////////////////////////////////////////////////////////////////////////////////////////
  471. #pragma mark -
  472. #pragma mark UIViewController (TTCategory)
  473. ///////////////////////////////////////////////////////////////////////////////////////////////////
  474. - (void)showBars:(BOOL)show animated:(BOOL)animated {
  475. [super showBars:show animated:animated];
  476. CGFloat alpha = show ? 1 : 0;
  477. if (alpha == _toolbar.alpha)
  478. return;
  479. if (animated) {
  480. [UIView beginAnimations:nil context:nil];
  481. [UIView setAnimationDuration:TT_TRANSITION_DURATION];
  482. [UIView setAnimationDelegate:self];
  483. if (show) {
  484. [UIView setAnimationDidStopSelector:@selector(showBarsAnimationDidStop)];
  485. } else {
  486. [UIView setAnimationDidStopSelector:@selector(hideBarsAnimationDidStop)];
  487. }
  488. } else {
  489. if (show) {
  490. [self showBarsAnimationDidStop];
  491. } else {
  492. [self hideBarsAnimationDidStop];
  493. }
  494. }
  495. [self showCaptions:show];
  496. _toolbar.alpha = alpha;
  497. if (animated) {
  498. [UIView commitAnimations];
  499. }
  500. }
  501. ///////////////////////////////////////////////////////////////////////////////////////////////////
  502. ///////////////////////////////////////////////////////////////////////////////////////////////////
  503. #pragma mark -
  504. #pragma mark TTModelViewController
  505. ///////////////////////////////////////////////////////////////////////////////////////////////////
  506. - (BOOL)shouldLoad {
  507. return NO;
  508. }
  509. ///////////////////////////////////////////////////////////////////////////////////////////////////
  510. - (BOOL)shouldLoadMore {
  511. return !_centerPhoto;
  512. }
  513. ///////////////////////////////////////////////////////////////////////////////////////////////////
  514. - (BOOL)canShowModel {
  515. return _photoSource.numberOfPhotos > 0;
  516. }
  517. ///////////////////////////////////////////////////////////////////////////////////////////////////
  518. - (void)didRefreshModel {
  519. [super didRefreshModel];
  520. [self updatePhotoView];
  521. }
  522. ///////////////////////////////////////////////////////////////////////////////////////////////////
  523. - (void)didLoadModel:(BOOL)firstTime {
  524. [super didLoadModel:firstTime];
  525. if (firstTime) {
  526. [self updatePhotoView];
  527. }
  528. }
  529. ///////////////////////////////////////////////////////////////////////////////////////////////////
  530. - (void)showLoading:(BOOL)show {
  531. [self showProgress:show ? 0 : -1];
  532. }
  533. ///////////////////////////////////////////////////////////////////////////////////////////////////
  534. - (void)showEmpty:(BOOL)show {
  535. if (show) {
  536. [_scrollView reloadData];
  537. [self showStatus:TTLocalizedString(@"This photo set contains no photos.", @"")];
  538. } else {
  539. [self showStatus:nil];
  540. }
  541. }
  542. ///////////////////////////////////////////////////////////////////////////////////////////////////
  543. - (void)showError:(BOOL)show {
  544. if (show) {
  545. [self showStatus:TTDescriptionForError(_modelError)];
  546. } else {
  547. [self showStatus:nil];
  548. }
  549. }
  550. ///////////////////////////////////////////////////////////////////////////////////////////////////
  551. - (void)moveToNextValidPhoto {
  552. if (_centerPhotoIndex >= _photoSource.numberOfPhotos) {
  553. // We were positioned at an index that is past the end, so move to the last photo
  554. [self moveToPhotoAtIndex:_photoSource.numberOfPhotos - 1 withDelay:NO];
  555. } else {
  556. [self moveToPhotoAtIndex:_centerPhotoIndex withDelay:NO];
  557. }
  558. }
  559. ///////////////////////////////////////////////////////////////////////////////////////////////////
  560. ///////////////////////////////////////////////////////////////////////////////////////////////////
  561. #pragma mark -
  562. #pragma mark TTModelDelegate
  563. ///////////////////////////////////////////////////////////////////////////////////////////////////
  564. - (void)modelDidFinishLoad:(id<TTModel>)model {
  565. if (model == _model) {
  566. if (_centerPhotoIndex >= _photoSource.numberOfPhotos) {
  567. [self moveToNextValidPhoto];
  568. [_scrollView reloadData];
  569. [self resetVisiblePhotoViews];
  570. } else {
  571. [self updateVisiblePhotoViews];
  572. }
  573. }
  574. [super modelDidFinishLoad:model];
  575. }
  576. ///////////////////////////////////////////////////////////////////////////////////////////////////
  577. - (void)model:(id<TTModel>)model didFailLoadWithError:(NSError*)error {
  578. if (model == _model) {
  579. [self resetVisiblePhotoViews];
  580. }
  581. [super model:model didFailLoadWithError:error];
  582. }
  583. ///////////////////////////////////////////////////////////////////////////////////////////////////
  584. - (void)modelDidCancelLoad:(id<TTModel>)model {
  585. if (model == _model) {
  586. [self resetVisiblePhotoViews];
  587. }
  588. [super modelDidCancelLoad:model];
  589. }
  590. ///////////////////////////////////////////////////////////////////////////////////////////////////
  591. - (void)model:(id<TTModel>)model didUpdateObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
  592. }
  593. ///////////////////////////////////////////////////////////////////////////////////////////////////
  594. - (void)model:(id<TTModel>)model didInsertObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
  595. }
  596. ///////////////////////////////////////////////////////////////////////////////////////////////////
  597. - (void)model:(id<TTModel>)model didDeleteObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
  598. if (object == self.centerPhoto) {
  599. [self showActivity:nil];
  600. [self moveToNextValidPhoto];
  601. [_scrollView reloadData];
  602. [self refresh];
  603. }
  604. }
  605. ///////////////////////////////////////////////////////////////////////////////////////////////////
  606. ///////////////////////////////////////////////////////////////////////////////////////////////////
  607. #pragma mark -
  608. #pragma mark TTScrollViewDelegate
  609. ///////////////////////////////////////////////////////////////////////////////////////////////////
  610. - (void)scrollView:(TTScrollView*)scrollView didMoveToPageAtIndex:(NSInteger)pageIndex {
  611. if (pageIndex != _centerPhotoIndex) {
  612. [self moveToPhotoAtIndex:pageIndex withDelay:YES];
  613. [self refresh];
  614. }
  615. }
  616. ///////////////////////////////////////////////////////////////////////////////////////////////////
  617. - (void)scrollViewWillBeginDragging:(TTScrollView *)scrollView {
  618. [self cancelImageLoadTimer];
  619. [self showCaptions:NO];
  620. [self showBars:NO animated:YES];
  621. }
  622. ///////////////////////////////////////////////////////////////////////////////////////////////////
  623. - (void)scrollViewDidEndDecelerating:(TTScrollView*)scrollView {
  624. [self startImageLoadTimer:kPhotoLoadShortDelay];
  625. }
  626. ///////////////////////////////////////////////////////////////////////////////////////////////////
  627. - (void)scrollViewWillRotate:(TTScrollView*)scrollView
  628. toOrientation:(UIInterfaceOrientation)orientation {
  629. self.centerPhotoView.hidesExtras = YES;
  630. }
  631. ///////////////////////////////////////////////////////////////////////////////////////////////////
  632. - (void)scrollViewDidRotate:(TTScrollView*)scrollView {
  633. self.centerPhotoView.hidesExtras = NO;
  634. }
  635. ///////////////////////////////////////////////////////////////////////////////////////////////////
  636. - (BOOL)scrollViewShouldZoom:(TTScrollView*)scrollView {
  637. return self.centerPhotoView.image != self.centerPhotoView.defaultImage;
  638. }
  639. ///////////////////////////////////////////////////////////////////////////////////////////////////
  640. - (void)scrollViewDidBeginZooming:(TTScrollView*)scrollView {
  641. self.centerPhotoView.hidesExtras = YES;
  642. }
  643. ///////////////////////////////////////////////////////////////////////////////////////////////////
  644. - (void)scrollViewDidEndZooming:(TTScrollView*)scrollView {
  645. self.centerPhotoView.hidesExtras = NO;
  646. }
  647. ///////////////////////////////////////////////////////////////////////////////////////////////////
  648. - (void)scrollView:(TTScrollView*)scrollView tapped:(UITouch*)touch {
  649. if ([self isShowingChrome]) {
  650. [self showBars:NO animated:YES];
  651. } else {
  652. [self showBars:YES animated:NO];
  653. }
  654. }
  655. ///////////////////////////////////////////////////////////////////////////////////////////////////
  656. ///////////////////////////////////////////////////////////////////////////////////////////////////
  657. #pragma mark -
  658. #pragma mark TTScrollViewDataSource
  659. ///////////////////////////////////////////////////////////////////////////////////////////////////
  660. - (NSInteger)numberOfPagesInScrollView:(TTScrollView*)scrollView {
  661. return _photoSource.numberOfPhotos;
  662. }
  663. ///////////////////////////////////////////////////////////////////////////////////////////////////
  664. - (UIView*)scrollView:(TTScrollView*)scrollView pageAtIndex:(NSInteger)pageIndex {
  665. TTPhotoView* photoView = (TTPhotoView*)[_scrollView dequeueReusablePage];
  666. if (!photoView) {
  667. photoView = [self createPhotoView];
  668. photoView.captionStyle = _captionStyle;
  669. photoView.defaultImage = _defaultImage;
  670. photoView.hidesCaption = _toolbar.alpha == 0;
  671. }
  672. id<TTPhoto> photo = [_photoSource photoAtIndex:pageIndex];
  673. [self showPhoto:photo inView:photoView];
  674. return photoView;
  675. }
  676. ///////////////////////////////////////////////////////////////////////////////////////////////////
  677. - (CGSize)scrollView:(TTScrollView*)scrollView sizeOfPageAtIndex:(NSInteger)pageIndex {
  678. id<TTPhoto> photo = [_photoSource photoAtIndex:pageIndex];
  679. return photo ? photo.size : CGSizeZero;
  680. }
  681. ///////////////////////////////////////////////////////////////////////////////////////////////////
  682. ///////////////////////////////////////////////////////////////////////////////////////////////////
  683. #pragma mark -
  684. #pragma mark TTThumbsViewControllerDelegate
  685. ///////////////////////////////////////////////////////////////////////////////////////////////////
  686. - (void)thumbsViewController:(TTThumbsViewController*)controller didSelectPhoto:(id<TTPhoto>)photo {
  687. self.centerPhoto = photo;
  688. if ([self.navigationController isKindOfClass:[TTBaseNavigationController class]]) {
  689. [(TTBaseNavigationController*)self.navigationController
  690. popViewControllerAnimatedWithTransition:UIViewAnimationTransitionCurlUp];
  691. } else {
  692. [self.navigationController popViewControllerAnimated:YES];
  693. }
  694. }
  695. ///////////////////////////////////////////////////////////////////////////////////////////////////
  696. - (BOOL)thumbsViewController:(TTThumbsViewController*)controller
  697. shouldNavigateToPhoto:(id<TTPhoto>)photo {
  698. return NO;
  699. }
  700. ///////////////////////////////////////////////////////////////////////////////////////////////////
  701. ///////////////////////////////////////////////////////////////////////////////////////////////////
  702. #pragma mark -
  703. #pragma mark Public
  704. ///////////////////////////////////////////////////////////////////////////////////////////////////
  705. - (void)setPhotoSource:(id<TTPhotoSource>)photoSource {
  706. if (_photoSource != photoSource) {
  707. [_photoSource release];
  708. _photoSource = [photoSource retain];
  709. [self moveToPhotoAtIndex:0 withDelay:NO];
  710. self.model = _photoSource;
  711. }
  712. }
  713. ///////////////////////////////////////////////////////////////////////////////////////////////////
  714. - (void)setCenterPhoto:(id<TTPhoto>)photo {
  715. if (_centerPhoto != photo) {
  716. if (photo.photoSource != _photoSource) {
  717. [_photoSource release];
  718. _photoSource = [photo.photoSource retain];
  719. [self moveToPhotoAtIndex:photo.index withDelay:NO];
  720. self.model = _photoSource;
  721. } else {
  722. [self moveToPhotoAtIndex:photo.index withDelay:NO];
  723. [self refresh];
  724. }
  725. }
  726. }
  727. ///////////////////////////////////////////////////////////////////////////////////////////////////
  728. - (TTPhotoView*)createPhotoView {
  729. return [[[TTPhotoView alloc] init] autorelease];
  730. }
  731. ///////////////////////////////////////////////////////////////////////////////////////////////////
  732. - (TTThumbsViewController*)createThumbsViewController {
  733. return [[[TTThumbsViewController alloc] initWithDelegate:self] autorelease];
  734. }
  735. ///////////////////////////////////////////////////////////////////////////////////////////////////
  736. - (void)didMoveToPhoto:(id<TTPhoto>)photo fromPhoto:(id<TTPhoto>)fromPhoto {
  737. }
  738. ///////////////////////////////////////////////////////////////////////////////////////////////////
  739. - (void)showActivity:(NSString*)title {
  740. if (title) {
  741. TTActivityLabel* label = [[[TTActivityLabel alloc]
  742. initWithStyle:TTActivityLabelStyleBlackBezel] autorelease];
  743. label.tag = kActivityLabelTag;
  744. label.text = title;
  745. label.frame = _scrollView.frame;
  746. [_innerView addSubview:label];
  747. _scrollView.scrollEnabled = NO;
  748. } else {
  749. UIView* label = [_innerView viewWithTag:kActivityLabelTag];
  750. if (label) {
  751. [label removeFromSuperview];
  752. }
  753. _scrollView.scrollEnabled = YES;
  754. }
  755. }
  756. @end