FLEXMetadataSection.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. }
  76. }
  77. - (NSInteger)numberOfRows {
  78. return self.metadata.count;
  79. }
  80. - (void)setFilterText:(NSString *)filterText {
  81. super.filterText = filterText;
  82. if (!self.filterText.length) {
  83. self.metadata = self.allMetadata;
  84. } else {
  85. self.metadata = [self.allMetadata flex_filtered:^BOOL(FLEXProperty *obj, NSUInteger idx) {
  86. return [obj.description localizedCaseInsensitiveContainsString:self.filterText];
  87. }];
  88. }
  89. }
  90. - (void)reloadData {
  91. switch (self.metadataKind) {
  92. case FLEXMetadataKindProperties:
  93. self.allMetadata = self.explorer.properties;
  94. break;
  95. case FLEXMetadataKindClassProperties:
  96. self.allMetadata = self.explorer.classProperties;
  97. break;
  98. case FLEXMetadataKindIvars:
  99. self.allMetadata = self.explorer.ivars;
  100. break;
  101. case FLEXMetadataKindMethods:
  102. self.allMetadata = self.explorer.methods;
  103. break;
  104. case FLEXMetadataKindClassMethods:
  105. self.allMetadata = self.explorer.classMethods;
  106. break;
  107. }
  108. // Remove excluded metadata
  109. if (self.excludedMetadata.count) {
  110. id filterBlock = ^BOOL(id obj, NSUInteger idx) {
  111. return ![self.excludedMetadata containsObject:[obj name]];
  112. };
  113. // Filter exclusions and sort
  114. self.allMetadata = [[self.allMetadata flex_filtered:filterBlock]
  115. sortedArrayUsingSelector:@selector(compare:)
  116. ];
  117. }
  118. // Re-filter data
  119. self.filterText = self.filterText;
  120. }
  121. - (BOOL)canSelectRow:(NSInteger)row {
  122. UITableViewCellAccessoryType accessory = [self accessoryTypeForRow:row];
  123. return accessory == UITableViewCellAccessoryDisclosureIndicator ||
  124. accessory == UITableViewCellAccessoryDetailDisclosureButton;
  125. }
  126. - (NSString *)reuseIdentifierForRow:(NSInteger)row {
  127. return kFLEXDetailCell;
  128. }
  129. - (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
  130. return [self.metadata[row] viewerWithTarget:self.explorer.object];
  131. }
  132. - (void (^)(UIViewController *))didPressInfoButtonAction:(NSInteger)row {
  133. return ^(UIViewController *host) {
  134. [host.navigationController pushViewController:[self editorForRow:row] animated:YES];
  135. };
  136. }
  137. - (UIViewController *)editorForRow:(NSInteger)row {
  138. return [self.metadata[row] editorWithTarget:self.explorer.object];
  139. }
  140. - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row {
  141. cell.titleLabel.text = [self titleForRow:row];
  142. cell.subtitleLabel.text = [self subtitleForRow:row];
  143. cell.accessoryType = [self accessoryTypeForRow:row];
  144. }
  145. @end