123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- //
- // FLEXMetadataSection.m
- // FLEX
- //
- // Created by Tanner Bennett on 9/19/19.
- // Copyright © 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXMetadataSection.h"
- #import "FLEXTableView.h"
- #import "FLEXTableViewCell.h"
- #import "FLEXObjectExplorerFactory.h"
- #import "FLEXFieldEditorViewController.h"
- #import "FLEXMethodCallingViewController.h"
- #import "FLEXIvar.h"
- #import "NSArray+FLEX.h"
- #import "FLEXRuntime+UIKitHelpers.h"
- #if TARGET_OS_TV
- #import "fakes.h"
- #endif
- @interface FLEXMetadataSection ()
- @property (nonatomic, readonly) FLEXObjectExplorer *explorer;
- /// Filtered
- @property (nonatomic, copy) NSArray<id<FLEXRuntimeMetadata>> *metadata;
- /// Unfiltered
- @property (nonatomic, copy) NSArray<id<FLEXRuntimeMetadata>> *allMetadata;
- @end
- @implementation FLEXMetadataSection
- #pragma mark - Initialization
- + (instancetype)explorer:(FLEXObjectExplorer *)explorer kind:(FLEXMetadataKind)metadataKind {
- return [[self alloc] initWithExplorer:explorer kind:metadataKind];
- }
- - (id)initWithExplorer:(FLEXObjectExplorer *)explorer kind:(FLEXMetadataKind)metadataKind {
- self = [super init];
- if (self) {
- _explorer = explorer;
- _metadataKind = metadataKind;
- [self reloadData];
- }
- return self;
- }
- #pragma mark - Private
- - (NSString *)titleWithBaseName:(NSString *)baseName {
- unsigned long totalCount = self.allMetadata.count;
- unsigned long filteredCount = self.metadata.count;
- if (totalCount == filteredCount) {
- return [baseName stringByAppendingFormat:@" (%lu)", totalCount];
- } else {
- return [baseName stringByAppendingFormat:@" (%lu of %lu)", filteredCount, totalCount];
- }
- }
- - (UITableViewCellAccessoryType)accessoryTypeForRow:(NSInteger)row {
- return [self.metadata[row] suggestedAccessoryTypeWithTarget:self.explorer.object];
- }
- #pragma mark - Public
- - (void)setExcludedMetadata:(NSSet<NSString *> *)excludedMetadata {
- _excludedMetadata = excludedMetadata;
- [self reloadData];
- }
- #pragma mark - Overrides
- - (NSString *)titleForRow:(NSInteger)row {
- return [self.metadata[row] description];
- }
- - (NSString *)subtitleForRow:(NSInteger)row {
- return [self.metadata[row] previewWithTarget:self.explorer.object];
- }
- - (NSString *)title {
- switch (self.metadataKind) {
- case FLEXMetadataKindProperties:
- return [self titleWithBaseName:@"Properties"];
- case FLEXMetadataKindClassProperties:
- return [self titleWithBaseName:@"Class Properties"];
- case FLEXMetadataKindIvars:
- return [self titleWithBaseName:@"Ivars"];
- case FLEXMetadataKindMethods:
- return [self titleWithBaseName:@"Methods"];
- case FLEXMetadataKindClassMethods:
- return [self titleWithBaseName:@"Class Methods"];
- case FLEXMetadataKindClassHierarchy:
- return [self titleWithBaseName:@"Class Hierarchy"];
- case FLEXMetadataKindProtocols:
- return [self titleWithBaseName:@"Protocols"];
- case FLEXMetadataKindOther:
- return @"Miscellaneous";
- }
- }
- - (NSInteger)numberOfRows {
- return self.metadata.count;
- }
- - (void)setFilterText:(NSString *)filterText {
- super.filterText = filterText;
- if (!self.filterText.length) {
- self.metadata = self.allMetadata;
- } else {
- self.metadata = [self.allMetadata flex_filtered:^BOOL(FLEXProperty *obj, NSUInteger idx) {
- return [obj.description localizedCaseInsensitiveContainsString:self.filterText];
- }];
- }
- }
- - (void)reloadData {
- switch (self.metadataKind) {
- case FLEXMetadataKindProperties:
- self.allMetadata = self.explorer.properties;
- break;
- case FLEXMetadataKindClassProperties:
- self.allMetadata = self.explorer.classProperties;
- break;
- case FLEXMetadataKindIvars:
- self.allMetadata = self.explorer.ivars;
- break;
- case FLEXMetadataKindMethods:
- self.allMetadata = self.explorer.methods;
- break;
- case FLEXMetadataKindClassMethods:
- self.allMetadata = self.explorer.classMethods;
- break;
- case FLEXMetadataKindProtocols:
- self.allMetadata = self.explorer.conformedProtocols;
- break;
- case FLEXMetadataKindClassHierarchy:
- self.allMetadata = self.explorer.classHierarchy;
- break;
- case FLEXMetadataKindOther:
- self.allMetadata = @[self.explorer.instanceSize, self.explorer.imageName];
- break;
- }
- // Remove excluded metadata
- if (self.excludedMetadata.count) {
- id filterBlock = ^BOOL(id<FLEXRuntimeMetadata> obj, NSUInteger idx) {
- return ![self.excludedMetadata containsObject:obj.name];
- };
- // Filter exclusions and sort
- self.allMetadata = [[self.allMetadata flex_filtered:filterBlock]
- sortedArrayUsingSelector:@selector(compare:)
- ];
- }
- // Re-filter data
- self.filterText = self.filterText;
- }
- - (BOOL)canSelectRow:(NSInteger)row {
- UITableViewCellAccessoryType accessory = [self accessoryTypeForRow:row];
- #if !TARGET_OS_TV
- return accessory == UITableViewCellAccessoryDisclosureIndicator ||
- accessory == UITableViewCellAccessoryDetailDisclosureButton;
- #else
- return accessory == UITableViewCellAccessoryDisclosureIndicator ||
- accessory == TVTableViewCellAccessoryDetailDisclosureButton;
- #endif
- return accessory == UITableViewCellAccessoryDisclosureIndicator;
- }
- - (NSString *)reuseIdentifierForRow:(NSInteger)row {
- return [self.metadata[row] reuseIdentifierWithTarget:self.explorer.object] ?: kFLEXCodeFontCell;
- }
- - (UIViewController *)viewControllerToPushForRow:(NSInteger)row {
- return [self.metadata[row] viewerWithTarget:self.explorer.object];
- }
- - (void (^)(__kindof UIViewController *))didPressInfoButtonAction:(NSInteger)row {
- return ^(UIViewController *host) {
- [host.navigationController pushViewController:[self editorForRow:row] animated:YES];
- };
- }
- - (UIViewController *)editorForRow:(NSInteger)row {
- return [self.metadata[row] editorWithTarget:self.explorer.object section:self];
- }
- - (void)configureCell:(__kindof FLEXTableViewCell *)cell forRow:(NSInteger)row {
- cell.titleLabel.text = [self titleForRow:row];
- cell.subtitleLabel.text = [self subtitleForRow:row];
- cell.accessoryType = [self accessoryTypeForRow:row];
- }
- #if FLEX_AT_LEAST_IOS13_SDK
- - (NSString *)menuSubtitleForRow:(NSInteger)row {
- return [self.metadata[row] contextualSubtitleWithTarget:self.explorer.object];
- }
- - (NSArray<UIMenuElement *> *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender {
- NSArray<UIMenuElement *> *existingItems = [super menuItemsForRow:row sender:sender];
-
- // These two metadata kinds don't any of the additional options below
- switch (self.metadataKind) {
- case FLEXMetadataKindClassHierarchy:
- case FLEXMetadataKindOther:
- return existingItems;
-
- default: break;
- }
-
- id<FLEXRuntimeMetadata> metadata = self.metadata[row];
- NSMutableArray<UIMenuElement *> *menuItems = [NSMutableArray new];
-
- [menuItems addObject:[UIAction
- actionWithTitle:@"Explore Metadata"
- image:nil
- identifier:nil
- handler:^(__kindof UIAction *action) {
- [sender.navigationController pushViewController:[FLEXObjectExplorerFactory
- explorerViewControllerForObject:metadata
- ] animated:YES];
- }
- ]];
- [menuItems addObjectsFromArray:[metadata
- additionalActionsWithTarget:self.explorer.object sender:sender
- ]];
- [menuItems addObjectsFromArray:existingItems];
-
- return menuItems.copy;
- }
- - (NSArray<NSString *> *)copyMenuItemsForRow:(NSInteger)row {
- return [self.metadata[row] copiableMetadataWithTarget:self.explorer.object];
- }
- #endif
- @end
|