You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.8 KiB

  1. //
  2. // FLEXLibrariesTableViewController.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 2014-05-02.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXLibrariesTableViewController.h"
  9. #import "FLEXUtility.h"
  10. #import "FLEXClassesTableViewController.h"
  11. #import "FLEXClassExplorerViewController.h"
  12. #import <objc/runtime.h>
  13. @interface FLEXLibrariesTableViewController () <UISearchBarDelegate>
  14. @property (nonatomic, strong) NSArray<NSString *> *imageNames;
  15. @property (nonatomic, strong) NSArray<NSString *> *filteredImageNames;
  16. @property (nonatomic, strong) UISearchBar *searchBar;
  17. @property (nonatomic, strong) Class foundClass;
  18. @end
  19. @implementation FLEXLibrariesTableViewController
  20. - (id)initWithStyle:(UITableViewStyle)style
  21. {
  22. self = [super initWithStyle:style];
  23. if (self) {
  24. [self loadImageNames];
  25. }
  26. return self;
  27. }
  28. - (void)viewDidLoad
  29. {
  30. [super viewDidLoad];
  31. self.searchBar = [[UISearchBar alloc] init];
  32. self.searchBar.delegate = self;
  33. self.searchBar.placeholder = [FLEXUtility searchBarPlaceholderText];
  34. [self.searchBar sizeToFit];
  35. self.tableView.tableHeaderView = self.searchBar;
  36. }
  37. #pragma mark - Binary Images
  38. - (void)loadImageNames
  39. {
  40. unsigned int imageNamesCount = 0;
  41. const char **imageNames = objc_copyImageNames(&imageNamesCount);
  42. if (imageNames) {
  43. NSMutableArray<NSString *> *imageNameStrings = [NSMutableArray array];
  44. NSString *appImageName = [FLEXUtility applicationImageName];
  45. for (unsigned int i = 0; i < imageNamesCount; i++) {
  46. const char *imageName = imageNames[i];
  47. NSString *imageNameString = [NSString stringWithUTF8String:imageName];
  48. // Skip the app's image. We're just showing system libraries and frameworks.
  49. if (![imageNameString isEqual:appImageName]) {
  50. [imageNameStrings addObject:imageNameString];
  51. }
  52. }
  53. // Sort alphabetically
  54. self.imageNames = [imageNameStrings sortedArrayWithOptions:0 usingComparator:^NSComparisonResult(NSString *name1, NSString *name2) {
  55. NSString *shortName1 = [self shortNameForImageName:name1];
  56. NSString *shortName2 = [self shortNameForImageName:name2];
  57. return [shortName1 caseInsensitiveCompare:shortName2];
  58. }];
  59. free(imageNames);
  60. }
  61. }
  62. - (NSString *)shortNameForImageName:(NSString *)imageName
  63. {
  64. NSArray<NSString *> *components = [imageName componentsSeparatedByString:@"/"];
  65. if (components.count >= 2) {
  66. return [NSString stringWithFormat:@"%@/%@", components[components.count - 2], components[components.count - 1]];
  67. }
  68. return imageName.lastPathComponent;
  69. }
  70. - (void)setImageNames:(NSArray<NSString *> *)imageNames
  71. {
  72. if (![_imageNames isEqual:imageNames]) {
  73. _imageNames = imageNames;
  74. self.filteredImageNames = imageNames;
  75. }
  76. }
  77. #pragma mark - Filtering
  78. - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
  79. {
  80. if ([searchText length] > 0) {
  81. NSPredicate *searchPreidcate = [NSPredicate predicateWithBlock:^BOOL(NSString *evaluatedObject, NSDictionary<NSString *, id> *bindings) {
  82. BOOL matches = NO;
  83. NSString *shortName = [self shortNameForImageName:evaluatedObject];
  84. if ([shortName rangeOfString:searchText options:NSCaseInsensitiveSearch].length > 0) {
  85. matches = YES;
  86. }
  87. return matches;
  88. }];
  89. self.filteredImageNames = [self.imageNames filteredArrayUsingPredicate:searchPreidcate];
  90. } else {
  91. self.filteredImageNames = self.imageNames;
  92. }
  93. self.foundClass = NSClassFromString(searchText);
  94. [self.tableView reloadData];
  95. }
  96. - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
  97. {
  98. [searchBar resignFirstResponder];
  99. }
  100. #pragma mark - Table View Data Source
  101. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  102. {
  103. return 1;
  104. }
  105. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  106. {
  107. return self.filteredImageNames.count + (self.foundClass ? 1 : 0);
  108. }
  109. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  110. {
  111. static NSString *cellIdentifier = @"Cell";
  112. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
  113. if (!cell) {
  114. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
  115. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  116. cell.textLabel.font = [FLEXUtility defaultTableViewCellLabelFont];
  117. }
  118. NSString *executablePath;
  119. if (self.foundClass) {
  120. if (indexPath.row == 0) {
  121. cell.textLabel.text = [NSString stringWithFormat:@"Class \"%@\"", self.searchBar.text];
  122. return cell;
  123. } else {
  124. executablePath = self.filteredImageNames[indexPath.row-1];
  125. }
  126. } else {
  127. executablePath = self.filteredImageNames[indexPath.row];
  128. }
  129. cell.textLabel.text = [self shortNameForImageName:executablePath];
  130. return cell;
  131. }
  132. #pragma mark - Table View Delegate
  133. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  134. {
  135. if (indexPath.row == 0 && self.foundClass) {
  136. FLEXClassExplorerViewController *objectExplorer = [FLEXClassExplorerViewController new];
  137. objectExplorer.object = self.foundClass;
  138. [self.navigationController pushViewController:objectExplorer animated:YES];
  139. } else {
  140. FLEXClassesTableViewController *classesViewController = [[FLEXClassesTableViewController alloc] init];
  141. classesViewController.binaryImageName = self.filteredImageNames[self.foundClass ? indexPath.row-1 : indexPath.row];
  142. [self.navigationController pushViewController:classesViewController animated:YES];
  143. }
  144. }
  145. @end