FLEXFileBrowserTableViewController.m 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //
  2. // FLEXFileBrowserTableViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 6/9/14.
  6. //
  7. //
  8. #import "FLEXFileBrowserTableViewController.h"
  9. #import "FLEXUtility.h"
  10. #import "FLEXWebViewController.h"
  11. @interface FLEXFileBrowserTableViewController ()
  12. @property (nonatomic, copy) NSString *path;
  13. @property (nonatomic, copy) NSArray *childPaths;
  14. @property (nonatomic, strong) NSNumber *recursiveSize;
  15. @end
  16. @implementation FLEXFileBrowserTableViewController
  17. - (id)initWithStyle:(UITableViewStyle)style
  18. {
  19. return [self initWithPath:NSHomeDirectory()];
  20. }
  21. - (id)initWithPath:(NSString *)path
  22. {
  23. self = [super initWithStyle:UITableViewStyleGrouped];
  24. if (self) {
  25. self.path = path;
  26. self.title = [path lastPathComponent];
  27. FLEXFileBrowserTableViewController *__weak weakSelf = self;
  28. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  29. NSFileManager *fileManager = [[NSFileManager alloc] init];
  30. NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
  31. uint64_t totalSize = [attributes fileSize];
  32. for (NSString *fileName in [fileManager enumeratorAtPath:path]) {
  33. attributes = [fileManager attributesOfItemAtPath:[path stringByAppendingPathComponent:fileName] error:NULL];
  34. totalSize += [attributes fileSize];
  35. // Bail if the interested view controller has gone away.
  36. if (!weakSelf) {
  37. return;
  38. }
  39. }
  40. dispatch_async(dispatch_get_main_queue(), ^{
  41. weakSelf.recursiveSize = @(totalSize);
  42. [weakSelf.tableView reloadData];
  43. });
  44. });
  45. self.childPaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
  46. }
  47. return self;
  48. }
  49. - (BOOL)prefersStatusBarHidden
  50. {
  51. return YES;
  52. }
  53. #pragma mark - Table view data source
  54. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  55. {
  56. return 1;
  57. }
  58. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  59. {
  60. return [self.childPaths count];
  61. }
  62. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
  63. {
  64. NSString *sizeString = nil;
  65. if (!self.recursiveSize) {
  66. sizeString = @"Computing size…";
  67. } else {
  68. sizeString = [NSByteCountFormatter stringFromByteCount:[self.recursiveSize longLongValue] countStyle:NSByteCountFormatterCountStyleFile];
  69. }
  70. return [NSString stringWithFormat:@"%lu files (%@)", (unsigned long)[self.childPaths count], sizeString];
  71. }
  72. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  73. {
  74. NSString *subpath = [self.childPaths objectAtIndex:indexPath.row];
  75. NSString *fullPath = [self.path stringByAppendingPathComponent:subpath];
  76. NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
  77. BOOL isDirectory = [[attributes fileType] isEqual:NSFileTypeDirectory];
  78. NSString *subtitle = nil;
  79. if (isDirectory) {
  80. NSUInteger count = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:fullPath error:NULL] count];
  81. subtitle = [NSString stringWithFormat:@"%lu file%@", (unsigned long)count, (count == 1 ? @"" : @"s")];
  82. } else {
  83. NSString *sizeString = [NSByteCountFormatter stringFromByteCount:[attributes fileSize] countStyle:NSByteCountFormatterCountStyleFile];
  84. subtitle = [NSString stringWithFormat:@"%@ - %@", sizeString, [attributes fileModificationDate]];
  85. }
  86. static NSString *cellIdentifier = @"Cell";
  87. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  88. if (!cell) {
  89. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
  90. cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  91. cell.detailTextLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  92. cell.detailTextLabel.textColor = [UIColor grayColor];
  93. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  94. }
  95. cell.textLabel.text = [subpath lastPathComponent];
  96. cell.detailTextLabel.text = subtitle;
  97. return cell;
  98. }
  99. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  100. {
  101. NSString *subpath = [self.childPaths objectAtIndex:indexPath.row];
  102. NSString *fullPath = [self.path stringByAppendingPathComponent:subpath];
  103. BOOL isDirectory = NO;
  104. BOOL stillExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory];
  105. if (stillExists) {
  106. UIViewController *drillInViewController = nil;
  107. if (isDirectory) {
  108. drillInViewController = [[[self class] alloc] initWithPath:fullPath];
  109. } else {
  110. // Special case keyed archives, json, and plists to get more readable data.
  111. NSString *prettyString = nil;
  112. if ([[subpath pathExtension] isEqual:@"archive"]) {
  113. prettyString = [[NSKeyedUnarchiver unarchiveObjectWithFile:fullPath] description];
  114. } else if ([[subpath pathExtension] isEqualToString:@"json"]) {
  115. NSData *fileData = [NSData dataWithContentsOfFile:fullPath];
  116. id jsonObject = [NSJSONSerialization JSONObjectWithData:fileData options:0 error:NULL];
  117. prettyString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:NULL] encoding:NSUTF8StringEncoding];
  118. } else if ([[subpath pathExtension] isEqualToString:@"plist"]) {
  119. NSData *fileData = [NSData dataWithContentsOfFile:fullPath];
  120. prettyString = [[NSPropertyListSerialization propertyListWithData:fileData options:0 format:NULL error:NULL] description];
  121. }
  122. if ([prettyString length] > 0) {
  123. drillInViewController = [[FLEXWebViewController alloc] initWithText:prettyString];
  124. } else if ([FLEXWebViewController supportsPathExtension:[subpath pathExtension]]) {
  125. drillInViewController = [[FLEXWebViewController alloc] initWithURL:[NSURL fileURLWithPath:fullPath]];
  126. } else {
  127. NSString *fileString = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:NULL];
  128. if ([fileString length] > 0) {
  129. drillInViewController = [[FLEXWebViewController alloc] initWithText:fileString];
  130. }
  131. }
  132. }
  133. if (drillInViewController) {
  134. drillInViewController.title = [subpath lastPathComponent];
  135. [self.navigationController pushViewController:drillInViewController animated:YES];
  136. } else {
  137. [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
  138. }
  139. } else {
  140. [[[UIAlertView alloc] initWithTitle:@"File Removed" message:@"The file at the specified path no longer exists." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
  141. }
  142. }
  143. @end