FLEXMetadataSection.m 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. //
  2. // FLEXMetadataSection.m
  3. // FLEX
  4. //
  5. // Created by Tanner Bennett on 9/19/19.
  6. // Copyright © 2019 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXMetadataSection.h"
  9. #import "FLEXTableView.h"
  10. #import "FLEXTableViewCell.h"
  11. #import "FLEXObjectExplorerFactory.h"
  12. #import "FLEXFieldEditorViewController.h"
  13. #import "FLEXMethodCallingViewController.h"
  14. #import "FLEXIvar.h"
  15. #import "NSArray+Functional.h"
  16. #import "FLEXRuntime+UIKitHelpers.h"
  17. @interface FLEXMetadataSection ()
  18. @property (nonatomic, readonly) FLEXObjectExplorer *explorer;
  19. /// Filtered
  20. @property (nonatomic, copy) NSArray<id<FLEXRuntimeMetadata>> *metadata;
  21. /// Unfiltered
  22. @property (nonatomic, copy) NSArray<id<FLEXRuntimeMetadata>> *allMetadata;
  23. @end
  24. @implementation FLEXMetadataSection
  25. #pragma mark - Initialization
  26. + (instancetype)explorer:(FLEXObjectExplorer *)explorer kind:(FLEXMetadataKind)metadataKind {
  27. return [[self alloc] initWithExplorer:explorer kind:metadataKind];
  28. }
  29. - (id)initWithExplorer:(FLEXObjectExplorer *)explorer kind:(FLEXMetadataKind)metadataKind {
  30. self = [super init];
  31. if (self) {
  32. _explorer = explorer;
  33. _metadataKind = metadataKind;
  34. [self reloadData];
  35. }
  36. return self;
  37. }
  38. #pragma mark - Private
  39. - (NSString *)titleWithBaseName:(NSString *)baseName {
  40. unsigned long totalCount = self.allMetadata.count;
  41. unsigned long filteredCount = self.metadata.count;
  42. if (totalCount == filteredCount) {
  43. return [baseName stringByAppendingFormat:@" (%lu)", totalCount];
  44. } else {
  45. return [baseName stringByAppendingFormat:@" (%lu of %lu)", filteredCount, totalCount];
  46. }
  47. }
  48. - (UITableViewCellAccessoryType)accessoryTypeForRow:(NSInteger)row {
  49. return [self.metadata[row] suggestedAccessoryTypeWithTarget:self.explorer.object];
  50. }
  51. #pragma mark - Public
  52. - (void)setExcludedMetadata:(NSSet<NSString *> *)excludedMetadata {
  53. _excludedMetadata = excludedMetadata;
  54. [self reloadData];
  55. }
  56. #pragma mark - Overrides
  57. - (NSString *)titleForRow:(NSInteger)row {
  58. return [self.metadata[row] description];
  59. }
  60. - (NSString *)subtitleForRow:(NSInteger)row {
  61. return [self.metadata[row] previewWithTarget:self.explorer.object];
  62. }
  63. - (NSString *)title {
  64. switch (self.metadataKind) {
  65. case FLEXMetadataKindProperties:
  66. return [self titleWithBaseName:@"Properties"];
  67. case FLEXMetadataKindClassProperties:
  68. return [self titleWithBaseName:@"Class Properties"];
  69. case FLEXMetadataKindIvars:
  70. return [self titleWithBaseName:@"Ivars"];
  71. case FLEXMetadataKindMethods:
  72. return [self titleWithBaseName:@"Methods"];
  73. case FLEXMetadataKindClassMethods:
  74. return [self titleWithBaseName:@"Class Methods"];
  75. case FLEXMetadataKindProtocols:
  76. return [self titleWithBaseName:@"Protocols"];
  77. case FLEXMetadataKindOther:
  78. return @"Miscellaneous";
  79. }
  80. }
  81. - (NSInteger)numberOfRows {
  82. return self.metadata.count;
  83. }
  84. - (void)setFilterText:(NSString *)filterText {
  85. super.filterText = filterText;
  86. if (!self.filterText.length) {
  87. self.metadata = self.allMetadata;
  88. } else {
  89. self.metadata = [self.allMetadata flex_filtered:^BOOL(FLEXProperty *obj, NSUInteger idx) {
  90. return [obj.description localizedCaseInsensitiveContainsString:self.filterText];
  91. }];
  92. }
  93. }
  94. - (void)reloadData {
  95. switch (self.metadataKind) {
  96. case FLEXMetadataKindProperties:
  97. self.allMetadata = self.explorer.properties;
  98. break;
  99. case FLEXMetadataKindClassProperties:
  100. self.allMetadata = self.explorer.classProperties;
  101. break;
  102. case FLEXMetadataKindIvars:
  103. self.allMetadata = self.explorer.ivars;
  104. break;
  105. case FLEXMetadataKindMethods:
  106. self.allMetadata = self.explorer.methods;
  107. break;
  108. case FLEXMetadataKindClassMethods:
  109. self.allMetadata = self.explorer.classMethods;
  110. break;
  111. case FLEXMetadataKindProtocols:
  112. self.allMetadata = self.explorer.conformedProtocols;
  113. break;
  114. case FLEXMetadataKindOther:
  115. self.allMetadata = @[self.explorer.instanceSize, self.explorer.imageName];
  116. break;
  117. }
  118. // Remove excluded metadata
  119. if (self.excludedMetadata.count) {
  120. id filterBlock = ^BOOL(id<FLEXRuntimeMetadata> obj, NSUInteger idx) {
  121. return ![self.excludedMetadata containsObject:obj.name];
  122. };
  123. // Filter exclusions and sort
  124. self.allMetadata = [[self.allMetadata flex_filtered:filterBlock]
  125. sortedArrayUsingSelector:@selector(compare:)
  126. ];
  127. }
  128. // Re-filter data
  129. self.filterText = self.filterText;
  130. }
  131. - (BOOL)canSelectRow:(NSInteger)row {
  132. UITableViewCellAccessoryType accessory = [self accessoryTypeForRow:row];
  133. return accessory == UITableViewCellAccessoryDisclosureIndicator ||
  134. accessory == UITableViewCellAccessoryDetailDisclosureButton;
  135. }
  136. - (NSString *)reuseIdentifierForRow:(NSInteger)row {
  137. return [self.metadata[row] reuseIdentifierWithTarget:self.explorer.object] ?: kFLEXCodeFontCell;
  138. }
  139. - (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
  140. return [self.metadata[row] viewerWithTarget:self.explorer.object];
  141. }
  142. - (void (^)(UIViewController *))didPressInfoButtonAction:(NSInteger)row {
  143. return ^(UIViewController *host) {
  144. [host.navigationController pushViewController:[self editorForRow:row] animated:YES];
  145. };
  146. }
  147. - (UIViewController *)editorForRow:(NSInteger)row {
  148. return [self.metadata[row] editorWithTarget:self.explorer.object];
  149. }
  150. - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row {
  151. cell.titleLabel.text = [self titleForRow:row];
  152. cell.subtitleLabel.text = [self subtitleForRow:row];
  153. cell.accessoryType = [self accessoryTypeForRow:row];
  154. }
  155. @end