FLEXShortcut.m 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //
  2. // FLEXShortcut.m
  3. // FLEX
  4. //
  5. // Created by Tanner Bennett on 12/10/19.
  6. // Copyright © 2019 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXShortcut.h"
  9. #import "FLEXProperty.h"
  10. #import "FLEXPropertyAttributes.h"
  11. #import "FLEXIvar.h"
  12. #import "FLEXMethod.h"
  13. #import "FLEXRuntime+UIKitHelpers.h"
  14. #import "FLEXObjectExplorerFactory.h"
  15. #import "FLEXFieldEditorViewController.h"
  16. #import "FLEXMethodCallingViewController.h"
  17. #import "FLEXMetadataSection.h"
  18. #pragma mark - FLEXShortcut
  19. @interface FLEXShortcut () {
  20. id _item;
  21. }
  22. @property (nonatomic, readonly) FLEXMetadataKind metadataKind;
  23. @property (nonatomic, readonly) FLEXProperty *property;
  24. @property (nonatomic, readonly) FLEXMethod *method;
  25. @property (nonatomic, readonly) FLEXIvar *ivar;
  26. @property (nonatomic, readonly) id<FLEXRuntimeMetadata> metadata;
  27. @end
  28. @implementation FLEXShortcut
  29. + (id<FLEXShortcut>)shortcutFor:(id)item {
  30. if ([item conformsToProtocol:@protocol(FLEXShortcut)]) {
  31. return item;
  32. }
  33. FLEXShortcut *shortcut = [self new];
  34. shortcut->_item = item;
  35. if ([item isKindOfClass:[FLEXProperty class]]) {
  36. if (shortcut.property.isClassProperty) {
  37. shortcut->_metadataKind = FLEXMetadataKindClassProperties;
  38. } else {
  39. shortcut->_metadataKind = FLEXMetadataKindProperties;
  40. }
  41. }
  42. if ([item isKindOfClass:[FLEXIvar class]]) {
  43. shortcut->_metadataKind = FLEXMetadataKindIvars;
  44. }
  45. if ([item isKindOfClass:[FLEXMethod class]]) {
  46. // We don't care if it's a class method or not
  47. shortcut->_metadataKind = FLEXMetadataKindMethods;
  48. }
  49. return shortcut;
  50. }
  51. - (id)propertyOrIvarValue:(id)object {
  52. return [self.metadata currentValueWithTarget:object];
  53. }
  54. - (NSString *)titleWith:(id)object {
  55. switch (self.metadataKind) {
  56. case FLEXMetadataKindClassProperties:
  57. case FLEXMetadataKindProperties:
  58. // Since we're outside of the "properties" section, prepend @property for clarity.
  59. return [@"@property " stringByAppendingString:[_item description]];
  60. default:
  61. return [_item description];
  62. }
  63. NSAssert(
  64. [_item isKindOfClass:[NSString class]],
  65. @"Unexpected type: %@", [_item class]
  66. );
  67. return _item;
  68. }
  69. - (NSString *)subtitleWith:(id)object {
  70. if (self.metadataKind) {
  71. return [self.metadata previewWithTarget:object];
  72. }
  73. // Item is probably a string; must return empty string since
  74. // these will be gathered into an array. If the object is a
  75. // just a string, it doesn't get a subtitle.
  76. return @"";
  77. }
  78. - (UIViewController *)viewerWith:(id)object {
  79. NSAssert(self.metadataKind, @"Static titles cannot be viewed");
  80. return [self.metadata viewerWithTarget:object];
  81. }
  82. - (UIViewController *)editorWith:(id)object {
  83. NSAssert(self.metadataKind, @"Static titles cannot be edited");
  84. return [self.metadata editorWithTarget:object];
  85. }
  86. - (UITableViewCellAccessoryType)accessoryTypeWith:(id)object {
  87. if (self.metadataKind) {
  88. return [self.metadata suggestedAccessoryTypeWithTarget:object];
  89. }
  90. return UITableViewCellAccessoryDisclosureIndicator;
  91. }
  92. #pragma mark - Helpers
  93. - (FLEXProperty *)property { return _item; }
  94. - (FLEXMethodBase *)method { return _item; }
  95. - (FLEXIvar *)ivar { return _item; }
  96. - (id<FLEXRuntimeMetadata>)metadata { return _item; }
  97. @end
  98. #pragma mark - FLEXActionShortcut
  99. @interface FLEXActionShortcut ()
  100. @property (nonatomic, readonly) NSString *title;
  101. @property (nonatomic, readonly) NSString *(^subtitleFuture)(id);
  102. @property (nonatomic, readonly) UIViewController *(^viewerFuture)(id);
  103. @property (nonatomic, readonly) UITableViewCellAccessoryType (^accessoryTypeFuture)(id);
  104. @end
  105. @implementation FLEXActionShortcut
  106. + (instancetype)title:(NSString *)title
  107. subtitle:(NSString *(^)(id))subtitle
  108. viewer:(UIViewController *(^)(id))viewer
  109. accessoryType:(UITableViewCellAccessoryType (^)(id))type {
  110. return [[self alloc] initWithTitle:title subtitle:subtitle viewer:viewer accessoryType:type];
  111. }
  112. - (id)initWithTitle:(NSString *)title
  113. subtitle:(id)subtitleFuture
  114. viewer:(id)viewerFuture
  115. accessoryType:(id)accessoryTypeFuture {
  116. NSParameterAssert(title.length);
  117. self = [super init];
  118. if (self) {
  119. id nilBlock = ^id (id obj) { return nil; };
  120. _title = title;
  121. _subtitleFuture = subtitleFuture ?: nilBlock;
  122. _viewerFuture = viewerFuture ?: nilBlock;
  123. _accessoryTypeFuture = accessoryTypeFuture ?: nilBlock;
  124. }
  125. return self;
  126. }
  127. - (NSString *)titleWith:(id)object {
  128. return self.title;
  129. }
  130. - (NSString *)subtitleWith:(id)object {
  131. return self.subtitleFuture(object);
  132. }
  133. - (UIViewController *)viewerWith:(id)object {
  134. return self.viewerFuture(object);
  135. }
  136. - (UITableViewCellAccessoryType)accessoryTypeWith:(id)object {
  137. return self.accessoryTypeFuture(object);
  138. }
  139. @end