FLEXFileBrowserTableViewController.m 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. #pragma mark - Table view data source
  50. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  51. {
  52. return 1;
  53. }
  54. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  55. {
  56. return [self.childPaths count];
  57. }
  58. - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
  59. {
  60. NSString *sizeString = nil;
  61. if (!self.recursiveSize) {
  62. sizeString = @"Computing size…";
  63. } else {
  64. sizeString = [NSByteCountFormatter stringFromByteCount:[self.recursiveSize longLongValue] countStyle:NSByteCountFormatterCountStyleFile];
  65. }
  66. return [NSString stringWithFormat:@"%lu files (%@)", (unsigned long)[self.childPaths count], sizeString];
  67. }
  68. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  69. {
  70. NSString *subpath = [self.childPaths objectAtIndex:indexPath.row];
  71. NSString *fullPath = [self.path stringByAppendingPathComponent:subpath];
  72. NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
  73. BOOL isDirectory = [[attributes fileType] isEqual:NSFileTypeDirectory];
  74. NSString *subtitle = nil;
  75. if (isDirectory) {
  76. NSUInteger count = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:fullPath error:NULL] count];
  77. subtitle = [NSString stringWithFormat:@"%lu file%@", (unsigned long)count, (count == 1 ? @"" : @"s")];
  78. } else {
  79. NSString *sizeString = [NSByteCountFormatter stringFromByteCount:[attributes fileSize] countStyle:NSByteCountFormatterCountStyleFile];
  80. subtitle = [NSString stringWithFormat:@"%@ - %@", sizeString, [attributes fileModificationDate]];
  81. }
  82. static NSString *cellIdentifier = @"Cell";
  83. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  84. if (!cell) {
  85. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
  86. cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  87. cell.detailTextLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  88. cell.detailTextLabel.textColor = [UIColor grayColor];
  89. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  90. }
  91. cell.textLabel.text = [subpath lastPathComponent];
  92. cell.detailTextLabel.text = subtitle;
  93. return cell;
  94. }
  95. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  96. {
  97. NSString *subpath = [self.childPaths objectAtIndex:indexPath.row];
  98. NSString *fullPath = [self.path stringByAppendingPathComponent:subpath];
  99. BOOL isDirectory = NO;
  100. BOOL stillExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory];
  101. if (stillExists) {
  102. UIViewController *drillInViewController = nil;
  103. if (isDirectory) {
  104. drillInViewController = [[[self class] alloc] initWithPath:fullPath];
  105. } else {
  106. // Special case keyed archives, json, and plists to get more readable data.
  107. NSString *prettyString = nil;
  108. if ([[subpath pathExtension] isEqual:@"archive"]) {
  109. prettyString = [[NSKeyedUnarchiver unarchiveObjectWithFile:fullPath] description];
  110. } else if ([[subpath pathExtension] isEqualToString:@"json"]) {
  111. NSData *fileData = [NSData dataWithContentsOfFile:fullPath];
  112. id jsonObject = [NSJSONSerialization JSONObjectWithData:fileData options:0 error:NULL];
  113. prettyString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:NULL] encoding:NSUTF8StringEncoding];
  114. } else if ([[subpath pathExtension] isEqualToString:@"plist"]) {
  115. NSData *fileData = [NSData dataWithContentsOfFile:fullPath];
  116. prettyString = [[NSPropertyListSerialization propertyListWithData:fileData options:0 format:NULL error:NULL] description];
  117. }
  118. if ([prettyString length] > 0) {
  119. drillInViewController = [[FLEXWebViewController alloc] initWithText:prettyString];
  120. } else if ([FLEXWebViewController supportsPathExtension:[subpath pathExtension]]) {
  121. drillInViewController = [[FLEXWebViewController alloc] initWithURL:[NSURL fileURLWithPath:fullPath]];
  122. } else {
  123. NSString *fileString = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:NULL];
  124. if ([fileString length] > 0) {
  125. drillInViewController = [[FLEXWebViewController alloc] initWithText:fileString];
  126. }
  127. }
  128. }
  129. if (drillInViewController) {
  130. drillInViewController.title = [subpath lastPathComponent];
  131. [self.navigationController pushViewController:drillInViewController animated:YES];
  132. } else {
  133. [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
  134. }
  135. } else {
  136. [[[UIAlertView alloc] initWithTitle:@"File Removed" message:@"The file at the specified path no longer exists." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
  137. }
  138. }
  139. @end