ThumbsViewController.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. //
  2. // ThumbsViewController.m
  3. // Reader v2.8.6
  4. //
  5. // Created by Julius Oklamcak on 2011-09-01.
  6. // Copyright © 2011-2015 Julius Oklamcak. All rights reserved.
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files (the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights to
  11. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  12. // of the Software, and to permit persons to whom the Software is furnished to
  13. // do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in all
  16. // copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. //
  25. #import "ReaderConstants.h"
  26. #import "ThumbsViewController.h"
  27. #import "ReaderThumbRequest.h"
  28. #import "ReaderThumbCache.h"
  29. #import "ReaderDocument.h"
  30. #import <QuartzCore/QuartzCore.h>
  31. @interface ThumbsViewController () <ThumbsMainToolbarDelegate, ReaderThumbsViewDelegate>
  32. @end
  33. @implementation ThumbsViewController
  34. {
  35. ReaderDocument *document;
  36. ThumbsMainToolbar *mainToolbar;
  37. ReaderThumbsView *theThumbsView;
  38. NSMutableArray *bookmarked;
  39. CGPoint thumbsOffset;
  40. CGPoint markedOffset;
  41. BOOL updateBookmarked;
  42. BOOL showBookmarked;
  43. }
  44. #pragma mark - Constants
  45. #define STATUS_HEIGHT 20.0f
  46. #define TOOLBAR_HEIGHT 44.0f
  47. #define PAGE_THUMB_SMALL 160
  48. #define PAGE_THUMB_LARGE 256
  49. #pragma mark - Properties
  50. @synthesize delegate;
  51. #pragma mark - UIViewController methods
  52. - (instancetype)initWithReaderDocument:(ReaderDocument *)object
  53. {
  54. if ((self = [super initWithNibName:nil bundle:nil])) // Initialize superclass
  55. {
  56. if ((object != nil) && ([object isKindOfClass:[ReaderDocument class]])) // Valid object
  57. {
  58. updateBookmarked = YES; bookmarked = [NSMutableArray new]; // Bookmarked pages
  59. document = object; // Retain the ReaderDocument object for our use
  60. }
  61. else // Invalid ReaderDocument object
  62. {
  63. self = nil;
  64. }
  65. }
  66. return self;
  67. }
  68. - (void)viewDidLoad
  69. {
  70. [super viewDidLoad];
  71. assert(delegate != nil); assert(document != nil);
  72. self.view.backgroundColor = [UIColor grayColor]; // Neutral gray
  73. CGRect scrollViewRect = self.view.bounds; UIView *fakeStatusBar = nil;
  74. if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) // iOS 7+
  75. {
  76. if ([self prefersStatusBarHidden] == NO) // Visible status bar
  77. {
  78. CGRect statusBarRect = self.view.bounds; // Status bar frame
  79. statusBarRect.size.height = STATUS_HEIGHT; // Default status height
  80. fakeStatusBar = [[UIView alloc] initWithFrame:statusBarRect]; // UIView
  81. fakeStatusBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
  82. fakeStatusBar.backgroundColor = [UIColor blackColor];
  83. fakeStatusBar.contentMode = UIViewContentModeRedraw;
  84. fakeStatusBar.userInteractionEnabled = NO;
  85. scrollViewRect.origin.y += STATUS_HEIGHT; scrollViewRect.size.height -= STATUS_HEIGHT;
  86. }
  87. }
  88. NSString *toolbarTitle = [document.fileName stringByDeletingPathExtension];
  89. CGRect toolbarRect = scrollViewRect; // Toolbar frame
  90. toolbarRect.size.height = TOOLBAR_HEIGHT; // Default toolbar height
  91. mainToolbar = [[ThumbsMainToolbar alloc] initWithFrame:toolbarRect title:toolbarTitle]; // ThumbsMainToolbar
  92. mainToolbar.delegate = self; // ThumbsMainToolbarDelegate
  93. [self.view addSubview:mainToolbar];
  94. if (fakeStatusBar != nil) [self.view addSubview:fakeStatusBar]; // Add status bar background view
  95. UIEdgeInsets scrollViewInsets = UIEdgeInsetsZero; // Scroll view toolbar insets
  96. if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) // iPad
  97. {
  98. scrollViewRect.origin.y += TOOLBAR_HEIGHT; scrollViewRect.size.height -= TOOLBAR_HEIGHT;
  99. }
  100. else // Set UIScrollView insets for non-UIUserInterfaceIdiomPad case
  101. {
  102. scrollViewInsets.top = TOOLBAR_HEIGHT;
  103. }
  104. theThumbsView = [[ReaderThumbsView alloc] initWithFrame:scrollViewRect]; // ReaderThumbsView
  105. theThumbsView.contentInset = scrollViewInsets; theThumbsView.scrollIndicatorInsets = scrollViewInsets;
  106. theThumbsView.delegate = self; // ReaderThumbsViewDelegate
  107. [self.view insertSubview:theThumbsView belowSubview:mainToolbar];
  108. if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone)
  109. {
  110. CGRect viewRect = self.view.bounds; CGSize viewSize = viewRect.size; // View size
  111. CGFloat min = ((viewSize.width < viewSize.height) ? viewSize.width : viewSize.height);
  112. CGFloat thumbSize = ((min > 320.0f) ? floorf(min / 3.0f) : PAGE_THUMB_SMALL);
  113. [theThumbsView setThumbSize:CGSizeMake(thumbSize, thumbSize)];
  114. }
  115. else // Set thumb size for large (iPad) devices
  116. {
  117. [theThumbsView setThumbSize:CGSizeMake(PAGE_THUMB_LARGE, PAGE_THUMB_LARGE)];
  118. }
  119. }
  120. - (void)viewWillAppear:(BOOL)animated
  121. {
  122. [super viewWillAppear:animated];
  123. [theThumbsView reloadThumbsCenterOnIndex:([document.pageNumber integerValue] - 1)]; // Page
  124. }
  125. - (void)viewDidAppear:(BOOL)animated
  126. {
  127. [super viewDidAppear:animated];
  128. }
  129. - (void)viewWillDisappear:(BOOL)animated
  130. {
  131. [super viewWillDisappear:animated];
  132. }
  133. - (void)viewDidDisappear:(BOOL)animated
  134. {
  135. [super viewDidDisappear:animated];
  136. }
  137. - (void)viewDidUnload
  138. {
  139. #ifdef DEBUG
  140. NSLog(@"%s", __FUNCTION__);
  141. #endif
  142. mainToolbar = nil; theThumbsView = nil;
  143. [super viewDidUnload];
  144. }
  145. - (BOOL)prefersStatusBarHidden
  146. {
  147. return YES;
  148. }
  149. - (UIStatusBarStyle)preferredStatusBarStyle
  150. {
  151. return UIStatusBarStyleLightContent;
  152. }
  153. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  154. {
  155. return YES;
  156. }
  157. /*
  158. - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
  159. {
  160. }
  161. - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
  162. {
  163. }
  164. - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
  165. {
  166. //if (fromInterfaceOrientation == self.interfaceOrientation) return;
  167. }
  168. */
  169. - (void)didReceiveMemoryWarning
  170. {
  171. #ifdef DEBUG
  172. NSLog(@"%s", __FUNCTION__);
  173. #endif
  174. [super didReceiveMemoryWarning];
  175. }
  176. #pragma mark - ThumbsMainToolbarDelegate methods
  177. - (void)tappedInToolbar:(ThumbsMainToolbar *)toolbar showControl:(UISegmentedControl *)control
  178. {
  179. switch (control.selectedSegmentIndex)
  180. {
  181. case 0: // Show all page thumbs
  182. {
  183. showBookmarked = NO; // Show all thumbs
  184. markedOffset = [theThumbsView insetContentOffset];
  185. [theThumbsView reloadThumbsContentOffset:thumbsOffset];
  186. break; // We're done
  187. }
  188. case 1: // Show bookmarked thumbs
  189. {
  190. showBookmarked = YES; // Only bookmarked
  191. thumbsOffset = [theThumbsView insetContentOffset];
  192. if (updateBookmarked == YES) // Update bookmarked list
  193. {
  194. [bookmarked removeAllObjects]; // Empty the list first
  195. [document.bookmarks enumerateIndexesUsingBlock: // Enumerate
  196. ^(NSUInteger page, BOOL *stop)
  197. {
  198. [bookmarked addObject:[NSNumber numberWithInteger:page]];
  199. }
  200. ];
  201. markedOffset = CGPointZero; updateBookmarked = NO; // Reset
  202. }
  203. [theThumbsView reloadThumbsContentOffset:markedOffset];
  204. break; // We're done
  205. }
  206. }
  207. }
  208. - (void)tappedInToolbar:(ThumbsMainToolbar *)toolbar doneButton:(UIButton *)button
  209. {
  210. [delegate dismissThumbsViewController:self]; // Dismiss thumbs display
  211. }
  212. #pragma mark - UIThumbsViewDelegate methods
  213. - (NSUInteger)numberOfThumbsInThumbsView:(ReaderThumbsView *)thumbsView
  214. {
  215. return (showBookmarked ? bookmarked.count : [document.pageCount integerValue]);
  216. }
  217. - (id)thumbsView:(ReaderThumbsView *)thumbsView thumbCellWithFrame:(CGRect)frame
  218. {
  219. return [[ThumbsPageThumb alloc] initWithFrame:frame];
  220. }
  221. - (void)thumbsView:(ReaderThumbsView *)thumbsView updateThumbCell:(ThumbsPageThumb *)thumbCell forIndex:(NSInteger)index
  222. {
  223. CGSize size = [thumbCell maximumContentSize]; // Get the cell's maximum content size
  224. NSInteger page = (showBookmarked ? [[bookmarked objectAtIndex:index] integerValue] : (index + 1));
  225. [thumbCell showText:[[NSString alloc] initWithFormat:@"%i", (int)page]]; // Page number place holder
  226. [thumbCell showBookmark:[document.bookmarks containsIndex:page]]; // Show bookmarked status
  227. NSURL *fileURL = document.fileURL; NSString *guid = document.guid; NSString *phrase = document.password; // Document info
  228. ReaderThumbRequest *thumbRequest = [ReaderThumbRequest newForView:thumbCell fileURL:fileURL password:phrase guid:guid page:page size:size];
  229. UIImage *image = [[ReaderThumbCache sharedInstance] thumbRequest:thumbRequest priority:YES]; // Request the thumbnail
  230. if ([image isKindOfClass:[UIImage class]]) [thumbCell showImage:image]; // Show image from cache
  231. }
  232. - (void)thumbsView:(ReaderThumbsView *)thumbsView refreshThumbCell:(ThumbsPageThumb *)thumbCell forIndex:(NSInteger)index
  233. {
  234. NSInteger page = (showBookmarked ? [[bookmarked objectAtIndex:index] integerValue] : (index + 1));
  235. [thumbCell showBookmark:[document.bookmarks containsIndex:page]]; // Show bookmarked status
  236. }
  237. - (void)thumbsView:(ReaderThumbsView *)thumbsView didSelectThumbWithIndex:(NSInteger)index
  238. {
  239. NSInteger page = (showBookmarked ? [[bookmarked objectAtIndex:index] integerValue] : (index + 1));
  240. [delegate thumbsViewController:self gotoPage:page]; // Show the selected page
  241. [delegate dismissThumbsViewController:self]; // Dismiss thumbs display
  242. }
  243. - (void)thumbsView:(ReaderThumbsView *)thumbsView didPressThumbWithIndex:(NSInteger)index
  244. {
  245. NSInteger page = (showBookmarked ? [[bookmarked objectAtIndex:index] integerValue] : (index + 1));
  246. if ([document.bookmarks containsIndex:page]) [document.bookmarks removeIndex:page]; else [document.bookmarks addIndex:page];
  247. updateBookmarked = YES; [thumbsView refreshThumbWithIndex:index]; // Refresh page thumb
  248. }
  249. @end
  250. #pragma mark -
  251. //
  252. // ThumbsPageThumb class implementation
  253. //
  254. @implementation ThumbsPageThumb
  255. {
  256. UIView *backView;
  257. UIView *tintView;
  258. UILabel *textLabel;
  259. UIImageView *bookMark;
  260. CGSize maximumSize;
  261. CGRect defaultRect;
  262. }
  263. #pragma mark - Constants
  264. #define CONTENT_INSET 8.0f
  265. #pragma mark - ThumbsPageThumb instance methods
  266. - (CGRect)markRectInImageView
  267. {
  268. CGRect iconRect = bookMark.frame; iconRect.origin.y = (-2.0f);
  269. iconRect.origin.x = (imageView.bounds.size.width - bookMark.image.size.width - 8.0f);
  270. return iconRect; // Frame position rect inside of image view
  271. }
  272. - (instancetype)initWithFrame:(CGRect)frame
  273. {
  274. if ((self = [super initWithFrame:frame]))
  275. {
  276. imageView.contentMode = UIViewContentModeCenter;
  277. defaultRect = CGRectInset(self.bounds, CONTENT_INSET, CONTENT_INSET);
  278. maximumSize = defaultRect.size; // Maximum thumb content size
  279. CGFloat newWidth = ((defaultRect.size.width / 4.0f) * 3.0f);
  280. CGFloat offsetX = ((defaultRect.size.width - newWidth) * 0.5f);
  281. defaultRect.size.width = newWidth; defaultRect.origin.x += offsetX;
  282. imageView.frame = defaultRect; // Update the image view frame
  283. CGFloat fontSize = (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ? 19.0f : 16.0f);
  284. textLabel = [[UILabel alloc] initWithFrame:defaultRect];
  285. textLabel.autoresizesSubviews = NO;
  286. textLabel.userInteractionEnabled = NO;
  287. textLabel.contentMode = UIViewContentModeRedraw;
  288. textLabel.autoresizingMask = UIViewAutoresizingNone;
  289. textLabel.textAlignment = NSTextAlignmentCenter;
  290. textLabel.font = [UIFont systemFontOfSize:fontSize];
  291. textLabel.textColor = [UIColor colorWithWhite:0.24f alpha:1.0f];
  292. textLabel.backgroundColor = [UIColor whiteColor];
  293. [self insertSubview:textLabel belowSubview:imageView];
  294. backView = [[UIView alloc] initWithFrame:defaultRect];
  295. backView.autoresizesSubviews = NO;
  296. backView.userInteractionEnabled = NO;
  297. backView.contentMode = UIViewContentModeRedraw;
  298. backView.autoresizingMask = UIViewAutoresizingNone;
  299. backView.backgroundColor = [UIColor whiteColor];
  300. #if (READER_SHOW_SHADOWS == TRUE) // Option
  301. backView.layer.shadowOffset = CGSizeMake(0.0f, 1.0f);
  302. backView.layer.shadowRadius = 3.0f; backView.layer.shadowOpacity = 1.0f;
  303. backView.layer.shadowPath = [UIBezierPath bezierPathWithRect:backView.bounds].CGPath;
  304. #endif // end of READER_SHOW_SHADOWS Option
  305. [self insertSubview:backView belowSubview:textLabel];
  306. tintView = [[UIView alloc] initWithFrame:imageView.bounds];
  307. tintView.hidden = YES;
  308. tintView.autoresizesSubviews = NO;
  309. tintView.userInteractionEnabled = NO;
  310. tintView.contentMode = UIViewContentModeRedraw;
  311. tintView.autoresizingMask = UIViewAutoresizingNone;
  312. tintView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.25f];
  313. [imageView addSubview:tintView];
  314. UIImage *image = [UIImage imageNamed:@"Reader-Mark-Y"];
  315. bookMark = [[UIImageView alloc] initWithImage:image];
  316. bookMark.hidden = YES;
  317. bookMark.autoresizesSubviews = NO;
  318. bookMark.userInteractionEnabled = NO;
  319. bookMark.contentMode = UIViewContentModeCenter;
  320. bookMark.autoresizingMask = UIViewAutoresizingNone;
  321. bookMark.frame = [self markRectInImageView];
  322. [imageView addSubview:bookMark];
  323. }
  324. return self;
  325. }
  326. - (CGSize)maximumContentSize
  327. {
  328. return maximumSize;
  329. }
  330. - (void)showImage:(UIImage *)image
  331. {
  332. NSInteger x = (self.bounds.size.width * 0.5f);
  333. NSInteger y = (self.bounds.size.height * 0.5f);
  334. CGPoint location = CGPointMake(x, y); // Center point
  335. CGRect viewRect = CGRectZero; viewRect.size = image.size;
  336. textLabel.bounds = viewRect; textLabel.center = location; // Position
  337. imageView.bounds = viewRect; imageView.center = location; imageView.image = image;
  338. bookMark.frame = [self markRectInImageView]; // Position bookmark image
  339. tintView.frame = imageView.bounds; backView.bounds = viewRect; backView.center = location;
  340. #if (READER_SHOW_SHADOWS == TRUE) // Option
  341. backView.layer.shadowPath = [UIBezierPath bezierPathWithRect:backView.bounds].CGPath;
  342. #endif // end of READER_SHOW_SHADOWS Option
  343. }
  344. - (void)reuse
  345. {
  346. [super reuse]; // Reuse thumb view
  347. textLabel.text = nil; textLabel.frame = defaultRect;
  348. imageView.image = nil; imageView.frame = defaultRect;
  349. bookMark.hidden = YES; bookMark.frame = [self markRectInImageView];
  350. tintView.hidden = YES; tintView.frame = imageView.bounds; backView.frame = defaultRect;
  351. #if (READER_SHOW_SHADOWS == TRUE) // Option
  352. backView.layer.shadowPath = [UIBezierPath bezierPathWithRect:backView.bounds].CGPath;
  353. #endif // end of READER_SHOW_SHADOWS Option
  354. }
  355. - (void)showBookmark:(BOOL)show
  356. {
  357. bookMark.hidden = (show ? NO : YES);
  358. }
  359. - (void)showTouched:(BOOL)touched
  360. {
  361. tintView.hidden = (touched ? NO : YES);
  362. }
  363. - (void)showText:(NSString *)text
  364. {
  365. textLabel.text = text;
  366. }
  367. @end