123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- //
- // FLEXShortcut.m
- // FLEX
- //
- // Created by Tanner Bennett on 12/10/19.
- // Copyright © 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXShortcut.h"
- #import "FLEXProperty.h"
- #import "FLEXPropertyAttributes.h"
- #import "FLEXIvar.h"
- #import "FLEXMethod.h"
- #import "FLEXRuntime+UIKitHelpers.h"
- #import "FLEXObjectExplorerFactory.h"
- #import "FLEXFieldEditorViewController.h"
- #import "FLEXMethodCallingViewController.h"
- #import "FLEXMetadataSection.h"
- #import "FLEXTableView.h"
- #pragma mark - FLEXShortcut
- @interface FLEXShortcut () {
- id _item;
- }
- @property (nonatomic, readonly) FLEXMetadataKind metadataKind;
- @property (nonatomic, readonly) FLEXProperty *property;
- @property (nonatomic, readonly) FLEXMethod *method;
- @property (nonatomic, readonly) FLEXIvar *ivar;
- @property (nonatomic, readonly) id<FLEXRuntimeMetadata> metadata;
- @end
- @implementation FLEXShortcut
- @synthesize defaults = _defaults;
- + (id<FLEXShortcut>)shortcutFor:(id)item {
- if ([item conformsToProtocol:@protocol(FLEXShortcut)]) {
- return item;
- }
-
- FLEXShortcut *shortcut = [self new];
- shortcut->_item = item;
- if ([item isKindOfClass:[FLEXProperty class]]) {
- if (shortcut.property.isClassProperty) {
- shortcut->_metadataKind = FLEXMetadataKindClassProperties;
- } else {
- shortcut->_metadataKind = FLEXMetadataKindProperties;
- }
- }
- if ([item isKindOfClass:[FLEXIvar class]]) {
- shortcut->_metadataKind = FLEXMetadataKindIvars;
- }
- if ([item isKindOfClass:[FLEXMethod class]]) {
- // We don't care if it's a class method or not
- shortcut->_metadataKind = FLEXMetadataKindMethods;
- }
- return shortcut;
- }
- - (id)propertyOrIvarValue:(id)object {
- return [self.metadata currentValueWithTarget:object];
- }
- - (NSString *)titleWith:(id)object {
- switch (self.metadataKind) {
- case FLEXMetadataKindClassProperties:
- case FLEXMetadataKindProperties:
- // Since we're outside of the "properties" section, prepend @property for clarity.
- return [@"@property " stringByAppendingString:[_item description]];
- default:
- return [_item description];
- }
- NSAssert(
- [_item isKindOfClass:[NSString class]],
- @"Unexpected type: %@", [_item class]
- );
- return _item;
- }
- - (NSString *)subtitleWith:(id)object {
- if (self.metadataKind) {
- return [self.metadata previewWithTarget:object];
- }
- // Item is probably a string; must return empty string since
- // these will be gathered into an array. If the object is a
- // just a string, it doesn't get a subtitle.
- return @"";
- }
- - (void (^)(UIViewController *))didSelectActionWith:(id)object {
- return nil;
- }
- - (UIViewController *)viewerWith:(id)object {
- NSAssert(self.metadataKind, @"Static titles cannot be viewed");
- return [self.metadata viewerWithTarget:object];
- }
- - (UIViewController *)editorWith:(id)object forSection:(FLEXTableViewSection *)section {
- NSAssert(self.metadataKind, @"Static titles cannot be edited");
- return [self.metadata editorWithTarget:object section:section];
- }
- - (UITableViewCellAccessoryType)accessoryTypeWith:(id)object {
- if (self.metadataKind) {
- return [self.metadata suggestedAccessoryTypeWithTarget:object];
- }
- return UITableViewCellAccessoryNone;
- }
- - (NSString *)customReuseIdentifierWith:(id)object {
- if (self.metadataKind) {
- return kFLEXCodeFontCell;
- }
- return kFLEXMultilineCell;
- }
- #pragma mark FLEXObjectExplorerDefaults
- - (void)setDefaults:(FLEXObjectExplorerDefaults *)defaults {
- _defaults = defaults;
-
- if (_metadataKind) {
- self.metadata.defaults = defaults;
- }
- }
- - (BOOL)isEditable {
- if (_metadataKind) {
- return self.metadata.isEditable;
- }
-
- return NO;
- }
- - (BOOL)isCallable {
- if (_metadataKind) {
- return self.metadata.isCallable;
- }
-
- return NO;
- }
- #pragma mark - Helpers
- - (FLEXProperty *)property { return _item; }
- - (FLEXMethodBase *)method { return _item; }
- - (FLEXIvar *)ivar { return _item; }
- - (id<FLEXRuntimeMetadata>)metadata { return _item; }
- @end
- #pragma mark - FLEXActionShortcut
- @interface FLEXActionShortcut ()
- @property (nonatomic, readonly) NSString *title;
- @property (nonatomic, readonly) NSString *(^subtitleFuture)(id);
- @property (nonatomic, readonly) UIViewController *(^viewerFuture)(id);
- @property (nonatomic, readonly) void (^selectionHandler)(UIViewController *, id);
- @property (nonatomic, readonly) UITableViewCellAccessoryType (^accessoryTypeFuture)(id);
- @end
- @implementation FLEXActionShortcut
- @synthesize defaults = _defaults;
- + (instancetype)title:(NSString *)title
- subtitle:(NSString *(^)(id))subtitle
- viewer:(UIViewController *(^)(id))viewer
- accessoryType:(UITableViewCellAccessoryType (^)(id))type {
- return [[self alloc] initWithTitle:title subtitle:subtitle viewer:viewer selectionHandler:nil accessoryType:type];
- }
- + (instancetype)title:(NSString *)title
- subtitle:(NSString * (^)(id))subtitle
- selectionHandler:(void (^)(UIViewController *, id))tapAction
- accessoryType:(UITableViewCellAccessoryType (^)(id))type {
- return [[self alloc] initWithTitle:title subtitle:subtitle viewer:nil selectionHandler:tapAction accessoryType:type];
- }
- - (id)initWithTitle:(NSString *)title
- subtitle:(id)subtitleFuture
- viewer:(id)viewerFuture
- selectionHandler:(id)tapAction
- accessoryType:(id)accessoryTypeFuture {
- NSParameterAssert(title.length);
- self = [super init];
- if (self) {
- id nilBlock = ^id (id obj) { return nil; };
-
- _title = title;
- _subtitleFuture = subtitleFuture ?: nilBlock;
- _viewerFuture = viewerFuture ?: nilBlock;
- _selectionHandler = tapAction;
- _accessoryTypeFuture = accessoryTypeFuture ?: nilBlock;
- }
- return self;
- }
- - (NSString *)titleWith:(id)object {
- return self.title;
- }
- - (NSString *)subtitleWith:(id)object {
- if (self.defaults.wantsDynamicPreviews) {
- return self.subtitleFuture(object);
- }
-
- return nil;
- }
- - (void (^)(UIViewController *))didSelectActionWith:(id)object {
- if (self.selectionHandler) {
- return ^(UIViewController *host) {
- self.selectionHandler(host, object);
- };
- }
-
- return nil;
- }
- - (UIViewController *)viewerWith:(id)object {
- return self.viewerFuture(object);
- }
- - (UITableViewCellAccessoryType)accessoryTypeWith:(id)object {
- return self.accessoryTypeFuture(object);
- }
- - (NSString *)customReuseIdentifierWith:(id)object {
- if (!self.subtitleFuture(object)) {
- // The text is more centered with this style if there is no subtitle
- return kFLEXDefaultCell;
- }
- return nil;
- }
- - (BOOL)isEditable { return NO; }
- - (BOOL)isCallable { return NO; }
- @end
|