diff --git a/FLEX/ActivityStreamAPI.h b/FLEX/ActivityStreamAPI.h new file mode 100644 index 00000000..0702db59 --- /dev/null +++ b/FLEX/ActivityStreamAPI.h @@ -0,0 +1,209 @@ +// +// Taken from https://github.com/llvm-mirror/lldb/blob/master/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h +// by Tanner Bennett on 03/03/2019 with minimal modifications. +// + +//===-- ActivityStreamAPI.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef ActivityStreamSPI_h +#define ActivityStreamSPI_h + +#include + +#include +// #include + +/* By default, XPC objects are declared as Objective-C types when building with + * an Objective-C compiler. This allows them to participate in ARC, in RR + * management by the Blocks runtime and in leaks checking by the static + * analyzer, and enables them to be added to Cocoa collections. + * + * See for details. + */ +#if !TARGET_OS_MACCATALYST +#if OS_OBJECT_USE_OBJC +OS_OBJECT_DECL(xpc_object); +#else +typedef void * xpc_object_t; +#endif +#endif + +#define OS_ACTIVITY_MAX_CALLSTACK 32 + +// Enums + +typedef NS_ENUM(uint32_t, os_activity_stream_flag_t) { + OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001, + OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002, + OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004, + OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008, + OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010, + OS_ACTIVITY_STREAM_DEBUG = 0x00000020, + OS_ACTIVITY_STREAM_BUFFERED = 0x00000040, + OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080, + OS_ACTIVITY_STREAM_INFO = 0x00000100, + OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200, + OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200 +}; + +typedef NS_ENUM(uint32_t, os_activity_stream_type_t) { + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201, + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202, + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203, + + OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300, + + OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400, + OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480, + + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601, + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602, + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603, + + OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00, +}; + +typedef NS_ENUM(uint32_t, os_activity_stream_event_t) { + OS_ACTIVITY_STREAM_EVENT_STARTED = 1, + OS_ACTIVITY_STREAM_EVENT_STOPPED = 2, + OS_ACTIVITY_STREAM_EVENT_FAILED = 3, + OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4, + OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5, +}; + +// Types + +typedef uint64_t os_activity_id_t; +typedef struct os_activity_stream_s *os_activity_stream_t; +typedef struct os_activity_stream_entry_s *os_activity_stream_entry_t; + +#define OS_ACTIVITY_STREAM_COMMON() \ +uint64_t trace_id; \ +uint64_t timestamp; \ +uint64_t thread; \ +const uint8_t *image_uuid; \ +const char *image_path; \ +struct timeval tv_gmt; \ +struct timezone tz; \ +uint32_t offset + +typedef struct os_activity_stream_common_s { + OS_ACTIVITY_STREAM_COMMON(); +} * os_activity_stream_common_t; + +struct os_activity_create_s { + OS_ACTIVITY_STREAM_COMMON(); + const char *name; + os_activity_id_t creator_aid; + uint64_t unique_pid; +}; + +struct os_activity_transition_s { + OS_ACTIVITY_STREAM_COMMON(); + os_activity_id_t transition_id; +}; + +typedef struct os_log_message_s { + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const uint8_t *buffer; + size_t buffer_sz; + const uint8_t *privdata; + size_t privdata_sz; + const char *subsystem; + const char *category; + uint32_t oversize_id; + uint8_t ttl; + bool persisted; +} * os_log_message_t; + +typedef struct os_trace_message_v2_s { + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const void *buffer; + size_t bufferLen; + xpc_object_t __unsafe_unretained payload; +} * os_trace_message_v2_t; + +typedef struct os_activity_useraction_s { + OS_ACTIVITY_STREAM_COMMON(); + const char *action; + bool persisted; +} * os_activity_useraction_t; + +typedef struct os_signpost_s { + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const uint8_t *buffer; + size_t buffer_sz; + const uint8_t *privdata; + size_t privdata_sz; + const char *subsystem; + const char *category; + uint64_t duration_nsec; + uint32_t callstack_depth; + uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK]; +} * os_signpost_t; + +typedef struct os_activity_statedump_s { + OS_ACTIVITY_STREAM_COMMON(); + char *message; + size_t message_size; + char image_path_buffer[PATH_MAX]; +} * os_activity_statedump_t; + +struct os_activity_stream_entry_s { + os_activity_stream_type_t type; + + // information about the process streaming the data + pid_t pid; + uint64_t proc_id; + const uint8_t *proc_imageuuid; + const char *proc_imagepath; + + // the activity associated with this streamed event + os_activity_id_t activity_id; + os_activity_id_t parent_id; + + union { + struct os_activity_stream_common_s common; + struct os_activity_create_s activity_create; + struct os_activity_transition_s activity_transition; + struct os_log_message_s log_message; + struct os_trace_message_v2_s trace_message; + struct os_activity_useraction_s useraction; + struct os_signpost_s signpost; + struct os_activity_statedump_s statedump; + }; +}; + +// Blocks + +typedef bool (^os_activity_stream_block_t)(os_activity_stream_entry_t entry, + int error); + +typedef void (^os_activity_stream_event_block_t)( + os_activity_stream_t stream, os_activity_stream_event_t event); + +// SPI entry point prototypes + +typedef os_activity_stream_t (*os_activity_stream_for_pid_t)( + pid_t pid, os_activity_stream_flag_t flags, + os_activity_stream_block_t stream_block); + +typedef void (*os_activity_stream_resume_t)(os_activity_stream_t stream); + +typedef void (*os_activity_stream_cancel_t)(os_activity_stream_t stream); + +typedef char *(*os_log_copy_formatted_message_t)(os_log_message_t log_message); + +typedef void (*os_activity_stream_set_event_handler_t)( + os_activity_stream_t stream, os_activity_stream_event_block_t block); + +#endif /* ActivityStreamSPI_h */ diff --git a/FLEX/CALayer+FLEX.h b/FLEX/CALayer+FLEX.h new file mode 100644 index 00000000..0f84bd33 --- /dev/null +++ b/FLEX/CALayer+FLEX.h @@ -0,0 +1,15 @@ +// +// CALayer+FLEX.h +// FLEX +// +// Created by Tanner on 2/28/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface CALayer (FLEX) + +@property (nonatomic) BOOL flex_continuousCorners; + +@end diff --git a/FLEX/FHSRangeSlider.h b/FLEX/FHSRangeSlider.h new file mode 100644 index 00000000..c5d3e60e --- /dev/null +++ b/FLEX/FHSRangeSlider.h @@ -0,0 +1,22 @@ +// +// FHSRangeSlider.h +// FLEX +// +// Created by Tanner Bennett on 1/7/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FHSRangeSlider : UIControl + +@property (nonatomic) CGFloat allowedMinValue; +@property (nonatomic) CGFloat allowedMaxValue; +@property (nonatomic) CGFloat minValue; +@property (nonatomic) CGFloat maxValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FHSSnapshotNodes.h b/FLEX/FHSSnapshotNodes.h new file mode 100644 index 00000000..8e32249a --- /dev/null +++ b/FLEX/FHSSnapshotNodes.h @@ -0,0 +1,37 @@ +// +// FHSSnapshotNodes.h +// FLEX +// +// Created by Tanner Bennett on 1/7/20. +// + +#import "FHSViewSnapshot.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Container that holds references to the SceneKit nodes associated with a snapshot. +@interface FHSSnapshotNodes : NSObject + ++ (instancetype)snapshot:(FHSViewSnapshot *)snapshot depth:(NSInteger)depth; + +@property (nonatomic, readonly) FHSViewSnapshot *snapshotItem; +@property (nonatomic, readonly) NSInteger depth; + +/// The view image itself +@property (nonatomic, nullable) SCNNode *snapshot; +/// Goes on top of the snapshot, has rounded top corners +@property (nonatomic, nullable) SCNNode *header; +/// The bounding box drawn around the snapshot +@property (nonatomic, nullable) SCNNode *border; + +/// Used to indicate when a view is selected +@property (nonatomic, getter=isHighlighted) BOOL highlighted; +/// Used to indicate when a view is de-emphasized +@property (nonatomic, getter=isDimmed) BOOL dimmed; + +@property (nonatomic) BOOL forceHideHeader; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FHSSnapshotView.h b/FLEX/FHSSnapshotView.h new file mode 100644 index 00000000..c0c92415 --- /dev/null +++ b/FLEX/FHSSnapshotView.h @@ -0,0 +1,46 @@ +// +// FHSSnapshotView.h +// FLEX +// +// Created by Tanner Bennett on 1/7/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FHSViewSnapshot.h" +#import "FHSRangeSlider.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol FHSSnapshotViewDelegate + +- (void)didSelectView:(FHSViewSnapshot *)snapshot; +- (void)didDeselectView:(FHSViewSnapshot *)snapshot; +- (void)didLongPressView:(FHSViewSnapshot *)snapshot; + +@end + +@interface FHSSnapshotView : UIView + ++ (instancetype)delegate:(id)delegate; + +@property (nonatomic, weak) id delegate; + +@property (nonatomic) NSArray *snapshots; +@property (nonatomic, nullable) FHSViewSnapshot *selectedView; + +/// Views of these classes will have their headers hidden +@property (nonatomic) NSArray *headerExclusions; + +@property (nonatomic, readonly) UISlider *spacingSlider; +@property (nonatomic, readonly) FHSRangeSlider *depthSlider; + +- (void)emphasizeViews:(NSArray *)emphasizedViews; + +- (void)toggleShowHeaders; +- (void)toggleShowBorders; + +- (void)hideView:(FHSViewSnapshot *)view; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FHSView.h b/FLEX/FHSView.h new file mode 100644 index 00000000..70122c12 --- /dev/null +++ b/FLEX/FHSView.h @@ -0,0 +1,35 @@ +// +// FHSView.h +// FLEX +// +// Created by Tanner Bennett on 1/6/20. +// + +#import + +@interface FHSView : NSObject { + @private + BOOL _inScrollView; +} + ++ (instancetype)forView:(UIView *)view isInScrollView:(BOOL)inScrollView; + +/// Intentionally not weak +@property (nonatomic, readonly) UIView *view; +@property (nonatomic, readonly) NSString *identifier; + +@property (nonatomic, readonly) NSString *title; +/// Whether or not this view item should be visually distinguished +@property (nonatomic, readwrite) BOOL important; + +@property (nonatomic, readonly) CGRect frame; +@property (nonatomic, readonly) BOOL hidden; +@property (nonatomic, readonly) UIImage *snapshotImage; + +@property (nonatomic, readonly) NSArray *children; +@property (nonatomic, readonly) NSString *summary; + +/// @return importantAttr if .important, otherwise normalAttr +//- (id)ifImportant:(id)importantAttr ifNormal:(id)normalAttr; + +@end diff --git a/FLEX/FHSViewController.h b/FLEX/FHSViewController.h new file mode 100644 index 00000000..32891dc3 --- /dev/null +++ b/FLEX/FHSViewController.h @@ -0,0 +1,29 @@ +// +// FHSViewController.h +// FLEX +// +// Created by Tanner Bennett on 1/6/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The view controller +/// "FHS" stands for "FLEX (view) hierarchy snapshot" +@interface FHSViewController : UIViewController + +/// Use this when you want to snapshot a set of windows. ++ (instancetype)snapshotWindows:(NSArray *)windows; +/// Use this when you want to snapshot a specific slice of the view hierarchy. ++ (instancetype)snapshotView:(UIView *)view; +/// Use this when you want to emphasize specific views on the screen. +/// These views must all be in the same window as the selected view. ++ (instancetype)snapshotViewsAtTap:(NSArray *)viewsAtTap selectedView:(UIView *)view; + +@property (nonatomic, nullable) UIView *selectedView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FHSViewSnapshot.h b/FLEX/FHSViewSnapshot.h new file mode 100644 index 00000000..eee84e4b --- /dev/null +++ b/FLEX/FHSViewSnapshot.h @@ -0,0 +1,37 @@ +// +// FHSViewSnapshot.h +// FLEX +// +// Created by Tanner Bennett on 1/9/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FHSView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FHSViewSnapshot : NSObject + ++ (instancetype)snapshotWithView:(FHSView *)view; + +@property (nonatomic, readonly) FHSView *view; + +@property (nonatomic, readonly) NSString *title; +/// Whether or not this view item should be visually distinguished +@property (nonatomic, readwrite) BOOL important; + +@property (nonatomic, readonly) CGRect frame; +@property (nonatomic, readonly) BOOL hidden; +@property (nonatomic, readonly) UIImage *snapshotImage; + +@property (nonatomic, readonly) NSArray *children; +@property (nonatomic, readonly) NSString *summary; + +/// Returns a different color based on whether or not the view is important +@property (nonatomic, readonly) UIColor *headerColor; + +- (FHSViewSnapshot *)snapshotForView:(UIView *)view; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEX-Categories.h b/FLEX/FLEX-Categories.h new file mode 100644 index 00000000..024b1161 --- /dev/null +++ b/FLEX/FLEX-Categories.h @@ -0,0 +1,22 @@ +// +// FLEX-Categories.h +// FLEX +// +// Created by Tanner on 3/12/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + + + +#import "UIBarButtonItem+FLEX.h" +#import "CALayer+FLEX.h" +#import "UIFont+FLEX.h" +#import "UIGestureRecognizer+Blocks.h" +#import "UIPasteboard+FLEX.h" +#import "UIMenu+FLEX.h" +#import "UITextField+Range.h" + +#import "NSObject+FLEX_Reflection.h" +#import "NSArray+FLEX.h" +#import "NSUserDefaults+FLEX.h" +#import "NSTimer+FLEX.h" diff --git a/FLEX/FLEX-Core.h b/FLEX/FLEX-Core.h new file mode 100644 index 00000000..f13b46a0 --- /dev/null +++ b/FLEX/FLEX-Core.h @@ -0,0 +1,23 @@ +// +// FLEX-Core.h +// FLEX +// +// Created by Tanner on 3/11/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" +#import "FLEXNavigationController.h" +#import "FLEXTableViewController.h" +#import "FLEXTableView.h" + +#import "FLEXSingleRowSection.h" +#import "FLEXTableViewSection.h" + +#import "FLEXCodeFontCell.h" +#import "FLEXSubtitleTableViewCell.h" +#import "FLEXTableViewCell.h" +#import "FLEXMultilineTableViewCell.h" +#import "FLEXKeyValueTableViewCell.h" + +#import "FLEXScopeCarousel.h" diff --git a/FLEX/FLEX-ObjectExploring.h b/FLEX/FLEX-ObjectExploring.h new file mode 100644 index 00000000..48219f4f --- /dev/null +++ b/FLEX/FLEX-ObjectExploring.h @@ -0,0 +1,30 @@ +// +// FLEX-ObjectExploring.h +// FLEX +// +// Created by Tanner on 3/11/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXObjectExplorerFactory.h" +#import "FLEXObjectExplorerViewController.h" + +#import "FLEXObjectExplorer.h" + +#import "FLEXShortcut.h" +#import "FLEXShortcutsFactory+Defaults.h" +#import "FLEXShortcutsSection.h" +#import "FLEXBlockShortcuts.h" +#import "FLEXBundleShortcuts.h" +#import "FLEXClassShortcuts.h" +#import "FLEXImageShortcuts.h" +#import "FLEXLayerShortcuts.h" +#import "FLEXViewControllerShortcuts.h" +#import "FLEXViewShortcuts.h" + +#import "FLEXCollectionContentSection.h" +#import "FLEXColorPreviewSection.h" +#import "FLEXDefaultsContentSection.h" +#import "FLEXMetadataSection.h" +#import "FLEXMutableListSection.h" +#import "FLEXObjectInfoSection.h" diff --git a/FLEX/FLEX-Runtime.h b/FLEX/FLEX-Runtime.h new file mode 100644 index 00000000..9fc8a69e --- /dev/null +++ b/FLEX/FLEX-Runtime.h @@ -0,0 +1,25 @@ +// +// FLEX-Runtime.h +// FLEX +// +// Created by Tanner on 3/11/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXObjcInternal.h" +#import "FLEXRuntimeSafety.h" +#import "FLEXBlockDescription.h" +#import "FLEXTypeEncodingParser.h" + +#import "FLEXMirror.h" +#import "FLEXProtocol.h" +#import "FLEXProperty.h" +#import "FLEXIvar.h" +#import "FLEXMethodBase.h" +#import "FLEXMethod.h" +#import "FLEXPropertyAttributes.h" +#import "FLEXRuntime+Compare.h" +#import "FLEXRuntime+UIKitHelpers.h" + +#import "FLEXProtocolBuilder.h" +#import "FLEXClassBuilder.h" diff --git a/FLEX/FLEX.h b/FLEX/FLEX.h new file mode 100644 index 00000000..6172068d --- /dev/null +++ b/FLEX/FLEX.h @@ -0,0 +1,25 @@ +// +// FLEX.h +// FLEX +// +// Created by Eric Horacek on 7/18/15. +// Modified by Tanner Bennett on 3/12/20. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXManager.h" +#import "FLEXManager+Extensibility.h" +#import "FLEXManager+Networking.h" + +#import "FLEXExplorerToolbar.h" +#import "FLEXExplorerToolbarItem.h" +#import "FLEXGlobalsEntry.h" + +#import "FLEX-Core.h" +#import "FLEX-Runtime.h" +#import "FLEX-Categories.h" +#import "FLEX-ObjectExploring.h" + +#import "FLEXMacros.h" +#import "FLEXAlert.h" +#import "FLEXResources.h" diff --git a/FLEX/FLEXASLLogController.h b/FLEX/FLEXASLLogController.h new file mode 100644 index 00000000..eeae7613 --- /dev/null +++ b/FLEX/FLEXASLLogController.h @@ -0,0 +1,18 @@ +// +// FLEXASLLogController.h +// FLEX +// +// Created by Tanner on 3/14/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXLogController.h" + +@interface FLEXASLLogController : NSObject + +/// Guaranteed to call back on the main thread. ++ (instancetype)withUpdateHandler:(void(^)(NSArray *newMessages))newMessagesHandler; + +- (BOOL)startMonitoring; + +@end diff --git a/FLEX/FLEXAddressExplorerCoordinator.h b/FLEX/FLEXAddressExplorerCoordinator.h new file mode 100644 index 00000000..16d94018 --- /dev/null +++ b/FLEX/FLEXAddressExplorerCoordinator.h @@ -0,0 +1,13 @@ +// +// FLEXAddressExplorerCoordinator.h +// FLEX +// +// Created by Tanner Bennett on 7/10/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXGlobalsEntry.h" + +@interface FLEXAddressExplorerCoordinator : NSObject + +@end diff --git a/FLEX/FLEXAlert.h b/FLEX/FLEXAlert.h new file mode 100644 index 00000000..8e003c7f --- /dev/null +++ b/FLEX/FLEXAlert.h @@ -0,0 +1,81 @@ +// +// FLEXAlert.h +// FLEX +// +// Created by Tanner Bennett on 8/20/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@class FLEXAlert, FLEXAlertAction; + +typedef void (^FLEXAlertReveal)(void); +typedef void (^FLEXAlertBuilder)(FLEXAlert *make); +typedef FLEXAlert *(^FLEXAlertStringProperty)(NSString *); +typedef FLEXAlert *(^FLEXAlertStringArg)(NSString *); +typedef FLEXAlert *(^FLEXAlertTextField)(void(^configurationHandler)(UITextField *textField)); +typedef FLEXAlertAction *(^FLEXAlertAddAction)(NSString *title); +typedef FLEXAlertAction *(^FLEXAlertActionStringProperty)(NSString *); +typedef FLEXAlertAction *(^FLEXAlertActionProperty)(void); +typedef FLEXAlertAction *(^FLEXAlertActionBOOLProperty)(BOOL); +typedef FLEXAlertAction *(^FLEXAlertActionHandler)(void(^handler)(NSArray *strings)); + +@interface FLEXAlert : NSObject + +/// Shows a simple alert with one button which says "Dismiss" ++ (void)showAlert:(NSString *)title message:(NSString *)message from:(UIViewController *)viewController; + +/// Construct and display an alert ++ (void)makeAlert:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController; +/// Construct and display an action sheet-style alert ++ (void)makeSheet:(FLEXAlertBuilder)block + showFrom:(UIViewController *)viewController + source:(id)viewOrBarItem; + +/// Construct an alert ++ (UIAlertController *)makeAlert:(FLEXAlertBuilder)block; +/// Construct an action sheet-style alert ++ (UIAlertController *)makeSheet:(FLEXAlertBuilder)block; + +/// Set the alert's title. +/// +/// Call in succession to append strings to the title. +@property (nonatomic, readonly) FLEXAlertStringProperty title; +/// Set the alert's message. +/// +/// Call in succession to append strings to the message. +@property (nonatomic, readonly) FLEXAlertStringProperty message; +/// Add a button with a given title with the default style and no action. +@property (nonatomic, readonly) FLEXAlertAddAction button; +/// Add a text field with the given (optional) placeholder text. +@property (nonatomic, readonly) FLEXAlertStringArg textField; +/// Add and configure the given text field. +/// +/// Use this if you need to more than set the placeholder, such as +/// supply a delegate, make it secure entry, or change other attributes. +@property (nonatomic, readonly) FLEXAlertTextField configuredTextField; + +@end + +@interface FLEXAlertAction : NSObject + +/// Set the action's title. +/// +/// Call in succession to append strings to the title. +@property (nonatomic, readonly) FLEXAlertActionStringProperty title; +/// Make the action destructive. It appears with red text. +@property (nonatomic, readonly) FLEXAlertActionProperty destructiveStyle; +/// Make the action cancel-style. It appears with a bolder font. +@property (nonatomic, readonly) FLEXAlertActionProperty cancelStyle; +/// Enable or disable the action. Enabled by default. +@property (nonatomic, readonly) FLEXAlertActionBOOLProperty enabled; +/// Give the button an action. The action takes an array of text field strings. +@property (nonatomic, readonly) FLEXAlertActionHandler handler; +/// Access the underlying UIAlertAction, should you need to change it while +/// the encompassing alert is being displayed. For example, you may want to +/// enable or disable a button based on the input of some text fields in the alert. +/// Do not call this more than once per instance. +@property (nonatomic, readonly) UIAlertAction *action; + +@end diff --git a/FLEX/FLEXArgumentInputColorView.h b/FLEX/FLEXArgumentInputColorView.h new file mode 100644 index 00000000..961caa12 --- /dev/null +++ b/FLEX/FLEXArgumentInputColorView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputColorView.h +// Flipboard +// +// Created by Ryan Olson on 6/30/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputColorView : FLEXArgumentInputView + +@end diff --git a/FLEX/FLEXArgumentInputDateView.h b/FLEX/FLEXArgumentInputDateView.h new file mode 100644 index 00000000..bbfdb66c --- /dev/null +++ b/FLEX/FLEXArgumentInputDateView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputDataView.h +// Flipboard +// +// Created by Daniel Rodriguez Troitino on 2/14/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputDateView : FLEXArgumentInputView + +@end diff --git a/FLEX/FLEXArgumentInputFontView.h b/FLEX/FLEXArgumentInputFontView.h new file mode 100644 index 00000000..7183f286 --- /dev/null +++ b/FLEX/FLEXArgumentInputFontView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputFontView.h +// Flipboard +// +// Created by Ryan Olson on 6/28/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputFontView : FLEXArgumentInputView + +@end diff --git a/FLEX/FLEXArgumentInputFontsPickerView.h b/FLEX/FLEXArgumentInputFontsPickerView.h new file mode 100644 index 00000000..a8bcb68c --- /dev/null +++ b/FLEX/FLEXArgumentInputFontsPickerView.h @@ -0,0 +1,12 @@ +// +// FLEXArgumentInputFontsPickerView.h +// FLEX +// +// Created by 啟倫 陳 on 2014/7/27. +// Copyright (c) 2014年 f. All rights reserved. +// + +#import "FLEXArgumentInputTextView.h" + +@interface FLEXArgumentInputFontsPickerView : FLEXArgumentInputTextView +@end diff --git a/FLEX/FLEXArgumentInputNotSupportedView.h b/FLEX/FLEXArgumentInputNotSupportedView.h new file mode 100644 index 00000000..9d2b39cc --- /dev/null +++ b/FLEX/FLEXArgumentInputNotSupportedView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputNotSupportedView.h +// Flipboard +// +// Created by Ryan Olson on 6/18/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputTextView.h" + +@interface FLEXArgumentInputNotSupportedView : FLEXArgumentInputTextView + +@end diff --git a/FLEX/FLEXArgumentInputNumberView.h b/FLEX/FLEXArgumentInputNumberView.h new file mode 100644 index 00000000..5d088979 --- /dev/null +++ b/FLEX/FLEXArgumentInputNumberView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputNumberView.h +// Flipboard +// +// Created by Ryan Olson on 6/15/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputTextView.h" + +@interface FLEXArgumentInputNumberView : FLEXArgumentInputTextView + +@end diff --git a/FLEX/FLEXArgumentInputObjectView.h b/FLEX/FLEXArgumentInputObjectView.h new file mode 100644 index 00000000..df2f7e6e --- /dev/null +++ b/FLEX/FLEXArgumentInputObjectView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputObjectView.h +// Flipboard +// +// Created by Ryan Olson on 6/15/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputTextView.h" + +@interface FLEXArgumentInputObjectView : FLEXArgumentInputTextView + +@end diff --git a/FLEX/FLEXArgumentInputStringView.h b/FLEX/FLEXArgumentInputStringView.h new file mode 100644 index 00000000..e17a26bb --- /dev/null +++ b/FLEX/FLEXArgumentInputStringView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputStringView.h +// Flipboard +// +// Created by Ryan Olson on 6/28/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputTextView.h" + +@interface FLEXArgumentInputStringView : FLEXArgumentInputTextView + +@end diff --git a/FLEX/FLEXArgumentInputStructView.h b/FLEX/FLEXArgumentInputStructView.h new file mode 100644 index 00000000..82270ae7 --- /dev/null +++ b/FLEX/FLEXArgumentInputStructView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputStructView.h +// Flipboard +// +// Created by Ryan Olson on 6/16/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputStructView : FLEXArgumentInputView + +@end diff --git a/FLEX/FLEXArgumentInputSwitchView.h b/FLEX/FLEXArgumentInputSwitchView.h new file mode 100644 index 00000000..26d2f313 --- /dev/null +++ b/FLEX/FLEXArgumentInputSwitchView.h @@ -0,0 +1,13 @@ +// +// FLEXArgumentInputSwitchView.h +// Flipboard +// +// Created by Ryan Olson on 6/16/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputSwitchView : FLEXArgumentInputView + +@end diff --git a/FLEX/FLEXArgumentInputTextView.h b/FLEX/FLEXArgumentInputTextView.h new file mode 100644 index 00000000..5bb8ec8a --- /dev/null +++ b/FLEX/FLEXArgumentInputTextView.h @@ -0,0 +1,18 @@ +// +// FLEXArgumentInputTextView.h +// FLEXInjected +// +// Created by Ryan Olson on 6/15/14. +// +// + +#import "FLEXArgumentInputView.h" + +@interface FLEXArgumentInputTextView : FLEXArgumentInputView + +// For subclass eyes only + +@property (nonatomic, readonly) UITextView *inputTextView; +@property (nonatomic) NSString *inputPlaceholderText; + +@end diff --git a/FLEX/FLEXArgumentInputView.h b/FLEX/FLEXArgumentInputView.h new file mode 100644 index 00000000..171139e5 --- /dev/null +++ b/FLEX/FLEXArgumentInputView.h @@ -0,0 +1,64 @@ +// +// FLEXArgumentInputView.h +// Flipboard +// +// Created by Ryan Olson on 5/30/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +typedef NS_ENUM(NSUInteger, FLEXArgumentInputViewSize) { + /// 2 lines, medium-sized + FLEXArgumentInputViewSizeDefault = 0, + /// One line + FLEXArgumentInputViewSizeSmall, + /// Several lines + FLEXArgumentInputViewSizeLarge +}; + +@protocol FLEXArgumentInputViewDelegate; + +@interface FLEXArgumentInputView : UIView + +- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding; + +/// The name of the field. Optional (can be nil). +@property (nonatomic, copy) NSString *title; + +/// To populate the filed with an initial value, set this property. +/// To reteive the value input by the user, access the property. +/// Primitive types and structs should/will be boxed in NSValue containers. +/// Concrete subclasses should override both the setter and getter for this property. +/// Subclasses can call super.inputValue to access a backing store for the value. +@property (nonatomic) id inputValue; + +/// Setting this value to large will make some argument input views increase the size of their input field(s). +/// Useful to increase the use of space if there is only one input view on screen (i.e. for property and ivar editing). +@property (nonatomic) FLEXArgumentInputViewSize targetSize; + +/// Users of the input view can get delegate callbacks for incremental changes in user input. +@property (nonatomic, weak) id delegate; + +// Subclasses can override + +/// If the input view has one or more text views, returns YES when one of them is focused. +@property (nonatomic, readonly) BOOL inputViewIsFirstResponder; + +/// For subclasses to indicate that they can handle editing a field the give type and value. +/// Used by FLEXArgumentInputViewFactory to create appropriate input views. ++ (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value; + +// For subclass eyes only + +@property (nonatomic, readonly) UILabel *titleLabel; +@property (nonatomic, readonly) NSString *typeEncoding; +@property (nonatomic, readonly) CGFloat topInputFieldVerticalLayoutGuide; + +@end + +@protocol FLEXArgumentInputViewDelegate + +- (void)argumentInputViewValueDidChange:(FLEXArgumentInputView *)argumentInputView; + +@end diff --git a/FLEX/FLEXArgumentInputViewFactory.h b/FLEX/FLEXArgumentInputViewFactory.h new file mode 100644 index 00000000..f72e9073 --- /dev/null +++ b/FLEX/FLEXArgumentInputViewFactory.h @@ -0,0 +1,24 @@ +// +// FLEXArgumentInputViewFactory.h +// FLEXInjected +// +// Created by Ryan Olson on 6/15/14. +// +// + +#import +#import "FLEXArgumentInputSwitchView.h" + +@interface FLEXArgumentInputViewFactory : NSObject + +/// Forwards to argumentInputViewForTypeEncoding:currentValue: with a nil currentValue. ++ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding; + +/// The main factory method for making argument input view subclasses that are the best fit for the type. ++ (FLEXArgumentInputView *)argumentInputViewForTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue; + +/// A way to check if we should try editing a filed given its type encoding and value. +/// Useful when deciding whether to edit or explore a property, ivar, or NSUserDefaults value. ++ (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue; + +@end diff --git a/FLEX/FLEXBlockDescription.h b/FLEX/FLEXBlockDescription.h new file mode 100644 index 00000000..037abcf7 --- /dev/null +++ b/FLEX/FLEXBlockDescription.h @@ -0,0 +1,58 @@ +// +// FLEXBlockDescription.h +// FLEX +// +// Created by Oliver Letterer on 2012-09-01 +// Forked from CTObjectiveCRuntimeAdditions (MIT License) +// https://github.com/ebf/CTObjectiveCRuntimeAdditions +// +// Copyright (c) 2020 FLEX Team-EDV Beratung Föllmer GmbH +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +typedef NS_OPTIONS(NSUInteger, FLEXBlockOptions) { + FLEXBlockOptionHasCopyDispose = (1 << 25), + FLEXBlockOptionHasCtor = (1 << 26), // helpers have C++ code + FLEXBlockOptionIsGlobal = (1 << 28), + FLEXBlockOptionHasStret = (1 << 29), // IFF BLOCK_HAS_SIGNATURE + FLEXBlockOptionHasSignature = (1 << 30), +}; + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - +@interface FLEXBlockDescription : NSObject + ++ (instancetype)describing:(id)block; + +@property (nonatomic, readonly, nullable) NSMethodSignature *signature; +@property (nonatomic, readonly, nullable) NSString *signatureString; +@property (nonatomic, readonly, nullable) NSString *sourceDeclaration; +@property (nonatomic, readonly) FLEXBlockOptions flags; +@property (nonatomic, readonly) NSUInteger size; +@property (nonatomic, readonly) NSString *summary; +@property (nonatomic, readonly) id block; + +- (BOOL)isCompatibleForBlockSwizzlingWithMethodSignature:(NSMethodSignature *)methodSignature; + +@end + +#pragma mark - +@interface NSBlock : NSObject +- (void)invoke; +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXBlockShortcuts.h b/FLEX/FLEXBlockShortcuts.h new file mode 100644 index 00000000..45cbed5f --- /dev/null +++ b/FLEX/FLEXBlockShortcuts.h @@ -0,0 +1,19 @@ +// +// FLEXBlockShortcuts.h +// FLEX +// +// Created by Tanner on 1/30/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a description of the block's signature +/// and access to an NSMethodSignature of the block +@interface FLEXBlockShortcuts : FLEXShortcutsSection + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXBookmarkManager.h b/FLEX/FLEXBookmarkManager.h new file mode 100644 index 00000000..5e4c84a6 --- /dev/null +++ b/FLEX/FLEXBookmarkManager.h @@ -0,0 +1,19 @@ +// +// FLEXBookmarkManager.h +// FLEX +// +// Created by Tanner on 2/6/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXBookmarkManager : NSObject + +@property (nonatomic, readonly, class) NSMutableArray *bookmarks; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXBookmarksViewController.h b/FLEX/FLEXBookmarksViewController.h new file mode 100644 index 00000000..514184ff --- /dev/null +++ b/FLEX/FLEXBookmarksViewController.h @@ -0,0 +1,17 @@ +// +// FLEXBookmarksViewController.h +// FLEX +// +// Created by Tanner on 2/6/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXBookmarksViewController : FLEXTableViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXBundleShortcuts.h b/FLEX/FLEXBundleShortcuts.h new file mode 100644 index 00000000..b88fb68d --- /dev/null +++ b/FLEX/FLEXBundleShortcuts.h @@ -0,0 +1,18 @@ +// +// FLEXBundleShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 12/12/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a "Browse Bundle Directory" action +@interface FLEXBundleShortcuts : FLEXShortcutsSection + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXCarouselCell.h b/FLEX/FLEXCarouselCell.h new file mode 100644 index 00000000..d8afbd02 --- /dev/null +++ b/FLEX/FLEXCarouselCell.h @@ -0,0 +1,15 @@ +// +// FLEXCarouselCell.h +// FLEX +// +// Created by Tanner Bennett on 7/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXCarouselCell : UICollectionViewCell + +@property (nonatomic, copy) NSString *title; + +@end diff --git a/FLEX/FLEXClassBuilder.h b/FLEX/FLEXClassBuilder.h new file mode 100644 index 00000000..f6d84413 --- /dev/null +++ b/FLEX/FLEXClassBuilder.h @@ -0,0 +1,80 @@ +// +// FLEXClassBuilder.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/3/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +@class FLEXIvarBuilder, FLEXMethodBase, FLEXProperty, FLEXProtocol; + + +#pragma mark FLEXClassBuilder +@interface FLEXClassBuilder : NSObject + +@property (nonatomic, readonly) Class workingClass; + +/// Begins constructing a class with the given name. +/// +/// This new class will implicitly inherits from \c NSObject with \c 0 extra bytes. +/// Classes created this way must be registered with \c -registerClass before being used. ++ (instancetype)allocateClass:(NSString *)name; +/// Begins constructing a class with the given name and superclass. +/// @discussion Calls \c -allocateClass:superclass:extraBytes: with \c 0 extra bytes. +/// Classes created this way must be registered with \c -registerClass before being used. ++ (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass; +/// Begins constructing a new class object with the given name and superclass. +/// @discussion Pass \c nil to \e superclass to create a new root class. +/// Classes created this way must be registered with \c -registerClass before being used. ++ (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass extraBytes:(size_t)bytes; +/// Begins constructing a new root class object with the given name and \c 0 extra bytes. +/// @discussion Classes created this way must be registered with \c -registerClass before being used. ++ (instancetype)allocateRootClass:(NSString *)name; +/// Use this to modify existing classes. @warning You cannot add instance variables to existing classes. ++ (instancetype)builderForClass:(Class)cls; + +/// @return Any methods that failed to be added. +- (NSArray *)addMethods:(NSArray *)methods; +/// @return Any properties that failed to be added. +- (NSArray *)addProperties:(NSArray *)properties; +/// @return Any protocols that failed to be added. +- (NSArray *)addProtocols:(NSArray *)protocols; +/// @warning Adding Ivars to existing classes is not supported and will always fail. +- (NSArray *)addIvars:(NSArray *)ivars; + +/// Finalizes construction of a new class. +/// @discussion Once a class is registered, instance variables cannot be added. +/// @note Raises an exception if called on a previously registered class. +- (Class)registerClass; +/// Uses \c objc_lookupClass to determine if the working class is registered. +@property (nonatomic, readonly) BOOL isRegistered; + +@end + + +#pragma mark FLEXIvarBuilder +@interface FLEXIvarBuilder : NSObject + +/// Consider using the \c FLEXIvarBuilderWithNameAndType() macro below. +/// @param name The name of the Ivar, such as \c \@"_value". +/// @param size The size of the Ivar. Usually \c sizeof(type). For objects, this is \c sizeof(id). +/// @param alignment The alignment of the Ivar. Usually \c log2(sizeof(type)). +/// @param encoding The type encoding of the Ivar. For objects, this is \c \@(\@encode(id)), and for others it is \c \@(\@encode(type)). ++ (instancetype)name:(NSString *)name size:(size_t)size alignment:(uint8_t)alignment typeEncoding:(NSString *)encoding; + +@property (nonatomic, readonly) NSString *name; +@property (nonatomic, readonly) NSString *encoding; +@property (nonatomic, readonly) size_t size; +@property (nonatomic, readonly) uint8_t alignment; + +@end + + +#define FLEXIvarBuilderWithNameAndType(nameString, type) [FLEXIvarBuilder \ + name:nameString \ + size:sizeof(type) \ + alignment:log2(sizeof(type)) \ + typeEncoding:@(@encode(type)) \ +] diff --git a/FLEX/FLEXClassShortcuts.h b/FLEX/FLEXClassShortcuts.h new file mode 100644 index 00000000..706ee2d1 --- /dev/null +++ b/FLEX/FLEXClassShortcuts.h @@ -0,0 +1,17 @@ +// +// FLEXClassShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 11/22/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +/// Provides handy shortcuts for class objects. +/// This is the default section used for all class objects. +@interface FLEXClassShortcuts : FLEXShortcutsSection + ++ (instancetype)forObject:(Class)cls; + +@end diff --git a/FLEX/FLEXCodeFontCell.h b/FLEX/FLEXCodeFontCell.h new file mode 100644 index 00000000..c4afbf7d --- /dev/null +++ b/FLEX/FLEXCodeFontCell.h @@ -0,0 +1,17 @@ +// +// FLEXCodeFontCell.h +// FLEX +// +// Created by Tanner on 12/27/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXMultilineTableViewCell.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXCodeFontCell : FLEXMultilineDetailTableViewCell + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXCollectionContentSection.h b/FLEX/FLEXCollectionContentSection.h new file mode 100644 index 00000000..8ca05f2b --- /dev/null +++ b/FLEX/FLEXCollectionContentSection.h @@ -0,0 +1,93 @@ +// +// FLEXCollectionContentSection.h +// FLEX +// +// Created by Tanner Bennett on 8/28/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewSection.h" +#import "FLEXObjectInfoSection.h" +@class FLEXCollectionContentSection, FLEXTableViewCell; +@protocol FLEXCollection, FLEXMutableCollection; + +/// Any foundation collection implicitly conforms to FLEXCollection. +/// This future should return one. We don't explicitly put FLEXCollection +/// here because making generic collections conform to FLEXCollection breaks +/// compile-time features of generic arrays, such as \c someArray[0].property +typedef id(^FLEXCollectionContentFuture)(__kindof FLEXCollectionContentSection *section); + +#pragma mark Collection +/// A protocol that enables \c FLEXCollectionContentSection to operate on any arbitrary collection. +/// \c NSArray, \c NSDictionary, \c NSSet, and \c NSOrderedSet all conform to this protocol. +@protocol FLEXCollection + +@property (nonatomic, readonly) NSUInteger count; + +- (id)copy; +- (id)mutableCopy; + +@optional + +/// Unordered, unkeyed collections must implement this +@property (nonatomic, readonly) NSArray *allObjects; +/// Keyed collections must implement this and \c objectForKeyedSubscript: +@property (nonatomic, readonly) NSArray *allKeys; + +/// Ordered, indexed collections must implement this. +- (id)objectAtIndexedSubscript:(NSUInteger)idx; +/// Keyed, unordered collections must implement this and \c allKeys +- (id)objectForKeyedSubscript:(id)idx; + +@end + +@protocol FLEXMutableCollection +- (void)filterUsingPredicate:(NSPredicate *)predicate; +@end + + +#pragma mark - FLEXCollectionContentSection +/// A custom section for viewing collection elements. +/// +/// Tapping on a row pushes an object explorer for that element. +@interface FLEXCollectionContentSection<__covariant ObjectType> : FLEXTableViewSection { + @protected + /// Unused if initialized with a future + id _collection; + /// Unused if initialized with a collection + FLEXCollectionContentFuture _collectionFuture; + /// The filtered collection from \c _collection or \c _collectionFuture + id _cachedCollection; +} + ++ (instancetype)forCollection:(id)collection; +/// The future given should be safe to call more than once. +/// The result of calling this future multiple times may yield +/// different results each time if the data is changing by nature. ++ (instancetype)forReusableFuture:(FLEXCollectionContentFuture)collectionFuture; + +/// Defaults to \c NO +@property (nonatomic) BOOL hideSectionTitle; +/// Defaults to \c nil +@property (nonatomic, copy) NSString *customTitle; +/// Defaults to \c NO +/// +/// Settings this to \c NO will not display the element index for ordered collections. +/// This property only applies to \c NSArray or \c NSOrderedSet and their subclasses. +@property (nonatomic) BOOL hideOrderIndexes; + +/// Set this property to provide a custom filter matcher. +/// +/// By default, the collection will filter on the title and subtitle of the row. +/// So if you don't ever call \c configureCell: for example, you will need to set +/// this property so that your filter logic will match how you're setting up the cell. +@property (nonatomic) BOOL (^customFilter)(NSString *filterText, ObjectType element); + +/// Get the object in the collection associated with the given row. +/// For dictionaries, this returns the value, not the key. +- (ObjectType)objectForRow:(NSInteger)row; + +/// Subclasses may override. +- (UITableViewCellAccessoryType)accessoryTypeForRow:(NSInteger)row; + +@end diff --git a/FLEX/FLEXColor.h b/FLEX/FLEXColor.h new file mode 100644 index 00000000..e472ba4b --- /dev/null +++ b/FLEX/FLEXColor.h @@ -0,0 +1,47 @@ +// +// FLEXColor.h +// FLEX +// +// Created by Benny Wong on 6/18/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXColor : NSObject + +@property (readonly, class) UIColor *primaryBackgroundColor; ++ (UIColor *)primaryBackgroundColorWithAlpha:(CGFloat)alpha; + +@property (readonly, class) UIColor *secondaryBackgroundColor; ++ (UIColor *)secondaryBackgroundColorWithAlpha:(CGFloat)alpha; + +@property (readonly, class) UIColor *tertiaryBackgroundColor; ++ (UIColor *)tertiaryBackgroundColorWithAlpha:(CGFloat)alpha; + +@property (readonly, class) UIColor *groupedBackgroundColor; ++ (UIColor *)groupedBackgroundColorWithAlpha:(CGFloat)alpha; + +@property (readonly, class) UIColor *secondaryGroupedBackgroundColor; ++ (UIColor *)secondaryGroupedBackgroundColorWithAlpha:(CGFloat)alpha; + +// Text colors +@property (readonly, class) UIColor *primaryTextColor; +@property (readonly, class) UIColor *deemphasizedTextColor; + +// UI element colors +@property (readonly, class) UIColor *tintColor; +@property (readonly, class) UIColor *scrollViewBackgroundColor; +@property (readonly, class) UIColor *iconColor; +@property (readonly, class) UIColor *borderColor; +@property (readonly, class) UIColor *toolbarItemHighlightedColor; +@property (readonly, class) UIColor *toolbarItemSelectedColor; +@property (readonly, class) UIColor *hairlineColor; +@property (readonly, class) UIColor *destructiveColor; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXColorPreviewSection.h b/FLEX/FLEXColorPreviewSection.h new file mode 100644 index 00000000..90e771cf --- /dev/null +++ b/FLEX/FLEXColorPreviewSection.h @@ -0,0 +1,16 @@ +// +// FLEXColorPreviewSection.h +// FLEX +// +// Created by Tanner Bennett on 12/12/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXSingleRowSection.h" +#import "FLEXObjectInfoSection.h" + +@interface FLEXColorPreviewSection : FLEXSingleRowSection + ++ (instancetype)forObject:(UIColor *)color; + +@end diff --git a/FLEX/FLEXCookiesViewController.h b/FLEX/FLEXCookiesViewController.h new file mode 100644 index 00000000..40bdaba7 --- /dev/null +++ b/FLEX/FLEXCookiesViewController.h @@ -0,0 +1,14 @@ +// +// FLEXCookiesViewController.h +// FLEX +// +// Created by Rich Robinson on 19/10/2015. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXGlobalsEntry.h" +#import "FLEXFilteringTableViewController.h" + +@interface FLEXCookiesViewController : FLEXFilteringTableViewController + +@end diff --git a/FLEX/FLEXDBQueryRowCell.h b/FLEX/FLEXDBQueryRowCell.h new file mode 100644 index 00000000..a4791a8c --- /dev/null +++ b/FLEX/FLEXDBQueryRowCell.h @@ -0,0 +1,19 @@ +// +// FLEXDBQueryRowCell.h +// FLEX +// +// Created by Peng Tao on 15/11/24. +// Copyright © 2015年 f. All rights reserved. +// + +#import + +extern NSString * const kFLEXDBQueryRowCellReuse; + + +@interface FLEXDBQueryRowCell : UITableViewCell + +/// An array of NSString, NSNumber, or NSData objects +@property (nonatomic) NSArray *data; + +@end diff --git a/FLEX/FLEXDatabaseManager.h b/FLEX/FLEXDatabaseManager.h new file mode 100644 index 00000000..a28d0ced --- /dev/null +++ b/FLEX/FLEXDatabaseManager.h @@ -0,0 +1,34 @@ +// +// PTDatabaseManager.h +// Derived from: +// +// FMDatabase.h +// FMDB( https://github.com/ccgus/fmdb ) +// +// Created by Peng Tao on 15/11/23. +// +// Licensed to Flying Meat Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Flying Meat Inc. licenses this file to you. + +#import +#import "FLEXSQLResult.h" + +/// Conformers should automatically open and close the database +@protocol FLEXDatabaseManager + +@required + +/// @return \c nil if the database couldn't be opened ++ (instancetype)managerForDatabase:(NSString *)path; + +/// @return a list of all table names +- (NSArray *)queryAllTables; +- (NSArray *)queryAllColumnsOfTable:(NSString *)tableName; +- (NSArray *)queryAllDataInTable:(NSString *)tableName; + +@optional + +- (FLEXSQLResult *)executeStatement:(NSString *)SQLStatement; + +@end diff --git a/FLEX/FLEXDefaultEditorViewController.h b/FLEX/FLEXDefaultEditorViewController.h new file mode 100644 index 00000000..8073b988 --- /dev/null +++ b/FLEX/FLEXDefaultEditorViewController.h @@ -0,0 +1,21 @@ +// +// FLEXDefaultEditorViewController.h +// Flipboard +// +// Created by Ryan Olson on 5/23/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFieldEditorViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXDefaultEditorViewController : FLEXVariableEditorViewController + ++ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit; + ++ (BOOL)canEditDefaultWithValue:(nullable id)currentValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXDefaultsContentSection.h b/FLEX/FLEXDefaultsContentSection.h new file mode 100644 index 00000000..d794c76c --- /dev/null +++ b/FLEX/FLEXDefaultsContentSection.h @@ -0,0 +1,27 @@ +// +// FLEXDefaultsContentSection.h +// FLEX +// +// Created by Tanner Bennett on 8/28/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXCollectionContentSection.h" +#import "FLEXObjectInfoSection.h" + +@interface FLEXDefaultsContentSection : FLEXCollectionContentSection + +/// Uses \c NSUserDefaults.standardUserDefaults ++ (instancetype)standard; ++ (instancetype)forDefaults:(NSUserDefaults *)userDefaults; + +/// Whether or not to filter out keys not present in the app's user defaults file. +/// +/// This is useful for filtering out some useless keys that seem to appear +/// in every app's defaults but are never actually used or touched by the app. +/// Only applies to instances using \c NSUserDefaults.standardUserDefaults. +/// This is the default for any instance using \c standardUserDefaults, so +/// you must opt-out in those instances if you don't want this behavior. +@property (nonatomic) BOOL onlyShowKeysForAppPrefs; + +@end diff --git a/FLEX/FLEXExplorerToolbar.h b/FLEX/FLEXExplorerToolbar.h new file mode 100644 index 00000000..f6cd0f9e --- /dev/null +++ b/FLEX/FLEXExplorerToolbar.h @@ -0,0 +1,58 @@ +// +// FLEXExplorerToolbar.h +// Flipboard +// +// Created by Ryan Olson on 4/4/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@class FLEXExplorerToolbarItem; + +NS_ASSUME_NONNULL_BEGIN + +/// Users of the toolbar can configure the enabled state +/// and event target/actions for each item. +@interface FLEXExplorerToolbar : UIView + +/// The items to be displayed in the toolbar. Defaults to: +/// globalsItem, hierarchyItem, selectItem, moveItem, closeItem +@property (nonatomic, copy) NSArray *toolbarItems; + +/// Toolbar item for selecting views. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *selectItem; + +/// Toolbar item for presenting a list with the view hierarchy. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *hierarchyItem; + +/// Toolbar item for moving views. +/// Its \c sibling is the \c lastTabItem +@property (nonatomic, readonly) FLEXExplorerToolbarItem *moveItem; + +/// Toolbar item for presenting the currently active tab. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *recentItem; + +/// Toolbar item for presenting a screen with various tools for inspecting the app. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *globalsItem; + +/// Toolbar item for hiding the explorer. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *closeItem; + +/// A view for moving the entire toolbar. +/// Users of the toolbar can attach a pan gesture recognizer to decide how to reposition the toolbar. +@property (nonatomic, readonly) UIView *dragHandle; + +/// A color matching the overlay on color on the selected view. +@property (nonatomic) UIColor *selectedViewOverlayColor; + +/// Description text for the selected view displayed below the toolbar items. +@property (nonatomic, copy) NSString *selectedViewDescription; + +/// Area where details of the selected view are shown +/// Users of the toolbar can attach a tap gesture recognizer to show additional details. +@property (nonatomic, readonly) UIView *selectedViewDescriptionContainer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXExplorerToolbarItem.h b/FLEX/FLEXExplorerToolbarItem.h new file mode 100644 index 00000000..80db5b29 --- /dev/null +++ b/FLEX/FLEXExplorerToolbarItem.h @@ -0,0 +1,44 @@ +// +// FLEXExplorerToolbarItem.h +// Flipboard +// +// Created by Ryan Olson on 4/4/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXExplorerToolbarItem : UIButton + ++ (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image; + +/// @param backupItem a toolbar item to use in place of this item when it becomes disabled. +/// Items without a sibling item exhibit expected behavior when they become disabled, and are greyed out. ++ (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image sibling:(nullable FLEXExplorerToolbarItem *)backupItem; + +/// If a toolbar item has a sibling, the item will replace itself with its +/// sibling when it becomes disabled, and vice versa when it becomes enabled again. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *sibling; + +/// When a toolbar item has a sibling and it becomes disabled, the sibling is the view +/// that should be added to or removed from a new or existing toolbar. This property +/// alleviates the programmer from determining whether to use \c item or \c item.sibling +/// or \c item.sibling.sibling and so on. Yes, sibling items can also have siblings so +/// that each item which becomes disabled may present another item in its place, creating +/// a "stack" of toolbar items. This behavior is useful for making buttons which occupy +/// the same space under different states. +/// +/// With this in mind, you should never access a stored toolbar item's view properties +/// such as \c frame or \c superview directly; you should access them on \c currentItem. +/// If you are trying to modify the frame of an item, and the item itself is not currently +/// displayed but instead its sibling is being displayed, then your changes could be ignored. +/// +/// @return the result of the item's sibling's \c currentItem, +/// if this item has a sibling and this item is disabled, otherwise this item. +@property (nonatomic, readonly) FLEXExplorerToolbarItem *currentItem; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXExplorerViewController.h b/FLEX/FLEXExplorerViewController.h new file mode 100644 index 00000000..5ec2d0ce --- /dev/null +++ b/FLEX/FLEXExplorerViewController.h @@ -0,0 +1,52 @@ +// +// FLEXExplorerViewController.h +// Flipboard +// +// Created by Ryan Olson on 4/4/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXExplorerToolbar.h" + +@class FLEXWindow; +@protocol FLEXExplorerViewControllerDelegate; + +/// A view controller that manages the FLEX toolbar. +@interface FLEXExplorerViewController : UIViewController + +@property (nonatomic, weak) id delegate; +@property (nonatomic, readonly) BOOL wantsWindowToBecomeKey; + +@property (nonatomic, readonly) FLEXExplorerToolbar *explorerToolbar; + +- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates; + +/// @brief Used to present (or dismiss) a modal view controller ("tool"), typically triggered by pressing a button in the toolbar. +/// +/// If a tool is already presented, this method simply dismisses it and calls the completion block. +/// If no tool is presented, @code future() @endcode is presented and the completion block is called. +- (void)toggleToolWithViewControllerProvider:(UINavigationController *(^)(void))future + completion:(void (^)(void))completion; + +// Keyboard shortcut helpers + +- (void)toggleSelectTool; +- (void)toggleMoveTool; +- (void)toggleViewsTool; +- (void)toggleMenuTool; + +/// @return YES if the explorer used the key press to perform an action, NO otherwise +- (BOOL)handleDownArrowKeyPressed; +/// @return YES if the explorer used the key press to perform an action, NO otherwise +- (BOOL)handleUpArrowKeyPressed; +/// @return YES if the explorer used the key press to perform an action, NO otherwise +- (BOOL)handleRightArrowKeyPressed; +/// @return YES if the explorer used the key press to perform an action, NO otherwise +- (BOOL)handleLeftArrowKeyPressed; + +@end + +#pragma mark - +@protocol FLEXExplorerViewControllerDelegate +- (void)explorerViewControllerDidFinish:(FLEXExplorerViewController *)explorerViewController; +@end diff --git a/FLEX/FLEXFieldEditorView.h b/FLEX/FLEXFieldEditorView.h new file mode 100644 index 00000000..19c0e63b --- /dev/null +++ b/FLEX/FLEXFieldEditorView.h @@ -0,0 +1,20 @@ +// +// FLEXFieldEditorView.h +// Flipboard +// +// Created by Ryan Olson on 5/16/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@class FLEXArgumentInputView; + +@interface FLEXFieldEditorView : UIView + +@property (nonatomic, copy) NSString *targetDescription; +@property (nonatomic, copy) NSString *fieldDescription; + +@property (nonatomic, copy) NSArray *argumentInputViews; + +@end diff --git a/FLEX/FLEXFieldEditorViewController.h b/FLEX/FLEXFieldEditorViewController.h new file mode 100644 index 00000000..205f6723 --- /dev/null +++ b/FLEX/FLEXFieldEditorViewController.h @@ -0,0 +1,29 @@ +// +// FLEXFieldEditorViewController.h +// FLEX +// +// Created by Tanner on 11/22/18. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXVariableEditorViewController.h" +#import "FLEXProperty.h" +#import "FLEXIvar.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXFieldEditorViewController : FLEXVariableEditorViewController + +/// @return nil if the property is readonly or if the type is unsupported ++ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)())onCommit; +/// @return nil if the ivar type is unsupported ++ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)())onCommit; + +/// Subclasses can change the button title via the \c title property +@property (nonatomic, readonly) UIBarButtonItem *getterButton; + +- (void)getterButtonPressed:(id)sender; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXFileBrowserController.h b/FLEX/FLEXFileBrowserController.h new file mode 100644 index 00000000..29dae965 --- /dev/null +++ b/FLEX/FLEXFileBrowserController.h @@ -0,0 +1,18 @@ +// +// FLEXFileBrowserController.h +// Flipboard +// +// Created by Ryan Olson on 6/9/14. +// Based on previous work by Evan Doll +// + +#import "FLEXTableViewController.h" +#import "FLEXGlobalsEntry.h" +#import "FLEXFileBrowserSearchOperation.h" + +@interface FLEXFileBrowserController : FLEXTableViewController + ++ (instancetype)path:(NSString *)path; +- (id)initWithPath:(NSString *)path; + +@end diff --git a/FLEX/FLEXFileBrowserSearchOperation.h b/FLEX/FLEXFileBrowserSearchOperation.h new file mode 100644 index 00000000..a9fa486d --- /dev/null +++ b/FLEX/FLEXFileBrowserSearchOperation.h @@ -0,0 +1,25 @@ +// +// FLEXFileBrowserSearchOperation.h +// FLEX +// +// Created by 啟倫 陳 on 2014/8/4. +// Copyright (c) 2014年 f. All rights reserved. +// + +#import + +@protocol FLEXFileBrowserSearchOperationDelegate; + +@interface FLEXFileBrowserSearchOperation : NSOperation + +@property (nonatomic, weak) id delegate; + +- (id)initWithPath:(NSString *)currentPath searchString:(NSString *)searchString; + +@end + +@protocol FLEXFileBrowserSearchOperationDelegate + +- (void)fileBrowserSearchOperationResult:(NSArray *)searchResult size:(uint64_t)size; + +@end diff --git a/FLEX/FLEXFilteringTableViewController.h b/FLEX/FLEXFilteringTableViewController.h new file mode 100644 index 00000000..f0488a17 --- /dev/null +++ b/FLEX/FLEXFilteringTableViewController.h @@ -0,0 +1,89 @@ +// +// FLEXFilteringTableViewController.h +// FLEX +// +// Created by Tanner on 3/9/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" + +#pragma mark - FLEXTableViewFiltering +@protocol FLEXTableViewFiltering + +/// An array of visible, "filtered" sections. For example, +/// if you have 3 sections in \c allSections and the user searches +/// for something that matches rows in only one section, then +/// this property would only contain that on matching section. +@property (nonatomic, copy) NSArray *sections; +/// An array of all possible sections. Empty sections are to be removed +/// and the resulting array stored in the \c section property. Setting +/// this property should immediately set \c sections to \c nonemptySections +/// +/// Do not manually initialize this property, it will be +/// initialized for you using the result of \c makeSections. +@property (nonatomic, copy) NSArray *allSections; + +/// This computed property should filter \c allSections for assignment to \c sections +@property (nonatomic, readonly, copy) NSArray *nonemptySections; + +/// This should be able to re-initialize \c allSections +- (NSArray *)makeSections; + +@end + + +#pragma mark - FLEXFilteringTableViewController +/// A table view which implements \c UITableView* methods using arrays of +/// \c FLEXTableViewSection objects provied by a special delegate. +@interface FLEXFilteringTableViewController : FLEXTableViewController + +/// Stores the current search query. +@property (nonatomic, copy) NSString *filterText; + +/// This property is set to \c self by default. +/// +/// This property is used to power almost all of the table view's data source +/// and delegate methods automatically, including row and section filtering +/// when the user searches, 3D Touch context menus, row selection, etc. +/// +/// Setting this property will also set \c searchDelegate to that object. +@property (nonatomic, weak) id filterDelegate; + +/// Defaults to \c NO. If enabled, all filtering will be done by calling +/// \c onBackgroundQueue:thenOnMainQueue: with the UI updated on the main queue. +@property (nonatomic) BOOL filterInBackground; + +/// Defaults to \c NO. If enabled, one • will be supplied as an index title for each section. +@property (nonatomic) BOOL wantsSectionIndexTitles; + +/// Recalculates the non-empty sections and reloads the table view. +/// +/// Subclasses may override to perform additional reloading logic, +/// such as calling \c -reloadSections if needed. Be sure to call +/// \c super after any logic that would affect the appearance of +/// the table view, since the table view is reloaded last. +/// +/// Called at the end of this class's implementation of \c updateSearchResults: +- (void)reloadData; + +/// Invoke this method to call \c -reloadData on each section +/// in \c self.filterDelegate.allSections. +- (void)reloadSections; + +#pragma mark FLEXTableViewFiltering + +@property (nonatomic, copy) NSArray *sections; +@property (nonatomic, copy) NSArray *allSections; + +/// Subclasses can override to hide specific sections under certain conditions +/// if using \c self as the \c filterDelegate, as is the default. +/// +/// For example, the object explorer hides the description section when searching. +@property (nonatomic, readonly, copy) NSArray *nonemptySections; + +/// If using \c self as the \c filterDelegate, as is the default, +/// subclasses should override to provide the sections for the table view. +- (NSArray *)makeSections; + +@end diff --git a/FLEX/FLEXGlobalsEntry.h b/FLEX/FLEXGlobalsEntry.h new file mode 100644 index 00000000..6b920b95 --- /dev/null +++ b/FLEX/FLEXGlobalsEntry.h @@ -0,0 +1,105 @@ +// +// FLEXGlobalsEntry.h +// FLEX +// +// Created by Javier Soto on 7/26/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, FLEXGlobalsRow) { + FLEXGlobalsRowProcessInfo, + FLEXGlobalsRowNetworkHistory, + FLEXGlobalsRowSystemLog, + FLEXGlobalsRowLiveObjects, + FLEXGlobalsRowAddressInspector, + FLEXGlobalsRowCookies, + FLEXGlobalsRowBrowseRuntime, + FLEXGlobalsRowAppKeychainItems, + FLEXGlobalsRowAppDelegate, + FLEXGlobalsRowRootViewController, + FLEXGlobalsRowUserDefaults, + FLEXGlobalsRowMainBundle, + FLEXGlobalsRowBrowseBundle, + FLEXGlobalsRowBrowseContainer, + FLEXGlobalsRowApplication, + FLEXGlobalsRowKeyWindow, + FLEXGlobalsRowMainScreen, + FLEXGlobalsRowCurrentDevice, + FLEXGlobalsRowPasteboard, + FLEXGlobalsRowURLSession, + FLEXGlobalsRowURLCache, + FLEXGlobalsRowNotificationCenter, + FLEXGlobalsRowMenuController, + FLEXGlobalsRowFileManager, + FLEXGlobalsRowTimeZone, + FLEXGlobalsRowLocale, + FLEXGlobalsRowCalendar, + FLEXGlobalsRowMainRunLoop, + FLEXGlobalsRowMainThread, + FLEXGlobalsRowOperationQueue, + FLEXGlobalsRowCount +}; + +typedef NSString * _Nonnull (^FLEXGlobalsEntryNameFuture)(void); +/// Simply return a view controller to be pushed on the navigation stack +typedef UIViewController * _Nullable (^FLEXGlobalsEntryViewControllerFuture)(void); +/// Do something like present an alert, then use the host +/// view controller to present or push another view controller. +typedef void (^FLEXGlobalsEntryRowAction)(__kindof UITableViewController * _Nonnull host); + +/// For view controllers to conform to to indicate they support being used +/// in the globals table view controller. These methods help create concrete entries. +/// +/// Previously, the concrete entries relied on "futures" for the view controller and title. +/// With this protocol, the conforming class itself can act as a future, since the methods +/// will not be invoked until the title and view controller / row action are needed. +/// +/// Entries can implement \c globalsEntryViewController: to unconditionally provide a +/// view controller, or \c globalsEntryRowAction: to conditionally provide one and +/// perform some action (such as present an alert) if no view controller is available, +/// or both if there is a mix of rows where some are guaranteed to work and some are not. +/// Where both are implemented, \c globalsEntryRowAction: takes precedence; if it returns +/// an action for the requested row, that will be used instead of \c globalsEntryViewController: +@protocol FLEXGlobalsEntry + ++ (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row; + +// Must respond to at least one of the below. +// globalsEntryRowAction: takes precedence if both are implemented. +@optional + ++ (nullable UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row; ++ (nullable FLEXGlobalsEntryRowAction)globalsEntryRowAction:(FLEXGlobalsRow)row; + +@end + +@interface FLEXGlobalsEntry : NSObject + +@property (nonatomic, readonly, nonnull) FLEXGlobalsEntryNameFuture entryNameFuture; +@property (nonatomic, readonly, nullable) FLEXGlobalsEntryViewControllerFuture viewControllerFuture; +@property (nonatomic, readonly, nullable) FLEXGlobalsEntryRowAction rowAction; + ++ (instancetype)entryWithEntry:(Class)entry row:(FLEXGlobalsRow)row; + ++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture + viewControllerFuture:(FLEXGlobalsEntryViewControllerFuture)viewControllerFuture; + ++ (instancetype)entryWithNameFuture:(FLEXGlobalsEntryNameFuture)nameFuture + action:(FLEXGlobalsEntryRowAction)rowSelectedAction; + +@end + + +@interface NSObject (FLEXGlobalsEntry) + +/// @return The result of passing self to +[FLEXGlobalsEntry entryWithEntry:] +/// if the class conforms to FLEXGlobalsEntry, else, nil. ++ (nullable FLEXGlobalsEntry *)flex_concreteGlobalsEntry:(FLEXGlobalsRow)row; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXGlobalsSection.h b/FLEX/FLEXGlobalsSection.h new file mode 100644 index 00000000..ae945532 --- /dev/null +++ b/FLEX/FLEXGlobalsSection.h @@ -0,0 +1,20 @@ +// +// FLEXGlobalsSection.h +// FLEX +// +// Created by Tanner Bennett on 7/11/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewSection.h" +#import "FLEXGlobalsEntry.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXGlobalsSection : FLEXTableViewSection + ++ (instancetype)title:(NSString *)title rows:(NSArray *)rows; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXGlobalsViewController.h b/FLEX/FLEXGlobalsViewController.h new file mode 100644 index 00000000..b4b79b8c --- /dev/null +++ b/FLEX/FLEXGlobalsViewController.h @@ -0,0 +1,28 @@ +// +// FLEXGlobalsViewController.h +// Flipboard +// +// Created by Ryan Olson on 2014-05-03. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" +@protocol FLEXGlobalsTableViewControllerDelegate; + +typedef NS_ENUM(NSUInteger, FLEXGlobalsSectionKind) { + FLEXGlobalsSectionCustom, + /// NSProcessInfo, Network history, system log, + /// heap, address explorer, libraries, app classes + FLEXGlobalsSectionProcessAndEvents, + /// Browse container, browse bundle, NSBundle.main, + /// NSUserDefaults.standard, UIApplication, + /// app delegate, key window, root VC, cookies + FLEXGlobalsSectionAppShortcuts, + /// UIPasteBoard.general, UIScreen, UIDevice + FLEXGlobalsSectionMisc, + FLEXGlobalsSectionCount +}; + +@interface FLEXGlobalsViewController : FLEXFilteringTableViewController + +@end diff --git a/FLEX/FLEXHeapEnumerator.h b/FLEX/FLEXHeapEnumerator.h new file mode 100644 index 00000000..37280861 --- /dev/null +++ b/FLEX/FLEXHeapEnumerator.h @@ -0,0 +1,17 @@ +// +// FLEXHeapEnumerator.h +// Flipboard +// +// Created by Ryan Olson on 5/28/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +typedef void (^flex_object_enumeration_block_t)(__unsafe_unretained id object, __unsafe_unretained Class actualClass); + +@interface FLEXHeapEnumerator : NSObject + ++ (void)enumerateLiveObjectsUsingBlock:(flex_object_enumeration_block_t)block; + +@end diff --git a/FLEX/FLEXHierarchyTableViewCell.h b/FLEX/FLEXHierarchyTableViewCell.h new file mode 100644 index 00000000..4b694780 --- /dev/null +++ b/FLEX/FLEXHierarchyTableViewCell.h @@ -0,0 +1,19 @@ +// +// FLEXHierarchyTableViewCell.h +// Flipboard +// +// Created by Ryan Olson on 2014-05-02. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXHierarchyTableViewCell : UITableViewCell + +- (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; + +@property (nonatomic) NSInteger viewDepth; +@property (nonatomic) UIColor *randomColorTag; +@property (nonatomic) UIColor *indicatedViewColor; + +@end diff --git a/FLEX/FLEXHierarchyTableViewController.h b/FLEX/FLEXHierarchyTableViewController.h new file mode 100644 index 00000000..1eca05e3 --- /dev/null +++ b/FLEX/FLEXHierarchyTableViewController.h @@ -0,0 +1,20 @@ +// +// FLEXHierarchyTableViewController.h +// Flipboard +// +// Created by Ryan Olson on 2014-05-01. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" + +@interface FLEXHierarchyTableViewController : FLEXTableViewController + ++ (instancetype)windows:(NSArray *)allWindows + viewsAtTap:(NSArray *)viewsAtTap + selectedView:(UIView *)selectedView; + +@property (nonatomic) UIView *selectedView; +@property (nonatomic) void(^didSelectRowAction)(UIView *selectedView); + +@end diff --git a/FLEX/FLEXHierarchyViewController.h b/FLEX/FLEXHierarchyViewController.h new file mode 100644 index 00000000..57fe94d5 --- /dev/null +++ b/FLEX/FLEXHierarchyViewController.h @@ -0,0 +1,26 @@ +// +// FLEXHierarchyViewController.h +// FLEX +// +// Created by Tanner Bennett on 1/9/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXNavigationController.h" + +@protocol FLEXHierarchyDelegate +- (void)viewHierarchyDidDismiss:(UIView *)selectedView; +@end + +/// A navigation controller which manages two child view controllers: +/// a 3D Reveal-like hierarchy explorer, and a 2D tree-list hierarchy explorer. +@interface FLEXHierarchyViewController : FLEXNavigationController + ++ (instancetype)delegate:(id)delegate; ++ (instancetype)delegate:(id)delegate + viewsAtTap:(NSArray *)viewsAtTap + selectedView:(UIView *)selectedView; + +- (void)toggleHierarchyMode; + +@end diff --git a/FLEX/FLEXImagePreviewViewController.h b/FLEX/FLEXImagePreviewViewController.h new file mode 100644 index 00000000..72bf7393 --- /dev/null +++ b/FLEX/FLEXImagePreviewViewController.h @@ -0,0 +1,17 @@ +// +// FLEXImagePreviewViewController.h +// Flipboard +// +// Created by Ryan Olson on 6/12/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXImagePreviewViewController : UIViewController + ++ (instancetype)previewForView:(UIView *)view; ++ (instancetype)previewForLayer:(CALayer *)layer; ++ (instancetype)forImage:(UIImage *)image; + +@end diff --git a/FLEX/FLEXImageShortcuts.h b/FLEX/FLEXImageShortcuts.h new file mode 100644 index 00000000..59bbba39 --- /dev/null +++ b/FLEX/FLEXImageShortcuts.h @@ -0,0 +1,16 @@ +// +// FLEXImageShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 8/29/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +/// Provides "view image" and "save image" shortcuts for UIImage objects +@interface FLEXImageShortcuts : FLEXShortcutsSection + ++ (instancetype)forObject:(UIImage *)image; + +@end diff --git a/FLEX/FLEXIvar.h b/FLEX/FLEXIvar.h new file mode 100644 index 00000000..86388332 --- /dev/null +++ b/FLEX/FLEXIvar.h @@ -0,0 +1,47 @@ +// +// FLEXIvar.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/30/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" + +@interface FLEXIvar : NSObject + ++ (instancetype)ivar:(Ivar)ivar; ++ (instancetype)named:(NSString *)name onClass:(Class)cls; + +/// The underlying \c Ivar data structure. +@property (nonatomic, readonly) Ivar objc_ivar; + +/// The name of the instance variable. +@property (nonatomic, readonly) NSString *name; +/// The type of the instance variable. +@property (nonatomic, readonly) FLEXTypeEncoding type; +/// The type encoding string of the instance variable. +@property (nonatomic, readonly) NSString *typeEncoding; +/// The offset of the instance variable. +@property (nonatomic, readonly) NSInteger offset; +/// The size of the instance variable. 0 if unknown. +@property (nonatomic, readonly) NSUInteger size; +/// Describes the type encoding, size, offset, and objc_ivar +@property (nonatomic, readonly) NSString *details; +/// The full path of the image that contains this ivar definition, +/// or \c nil if this ivar was probably defined at runtime. +@property (nonatomic, readonly) NSString *imagePath; + +/// For internal use +@property (nonatomic) id tag; + +- (id)getValue:(id)target; +- (void)setValue:(id)value onObject:(id)target; + +/// Calls into -getValue: and passes that value into +/// -[FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:type:] +/// and returns the result +- (id)getPotentiallyUnboxedValue:(id)target; + +@end diff --git a/FLEX/FLEXKBToolbarButton.h b/FLEX/FLEXKBToolbarButton.h new file mode 100644 index 00000000..f2ab468d --- /dev/null +++ b/FLEX/FLEXKBToolbarButton.h @@ -0,0 +1,31 @@ +// +// FLEXKBToolbarButton.h +// FLEX +// +// Created by Tanner on 6/11/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import + +typedef void (^FLEXKBToolbarAction)(NSString *buttonTitle, BOOL isSuggestion); + + +@interface FLEXKBToolbarButton : UIButton + +/// Set to `default` to use the system appearance on iOS 13+ +@property (nonatomic) UIKeyboardAppearance appearance; + ++ (instancetype)buttonWithTitle:(NSString *)title; ++ (instancetype)buttonWithTitle:(NSString *)title action:(FLEXKBToolbarAction)eventHandler; ++ (instancetype)buttonWithTitle:(NSString *)title action:(FLEXKBToolbarAction)action forControlEvents:(UIControlEvents)controlEvents; + +/// Adds the event handler for the button. +/// +/// @param eventHandler The event handler block. +/// @param controlEvents The type of event. +- (void)addEventHandler:(FLEXKBToolbarAction)eventHandler forControlEvents:(UIControlEvents)controlEvents; + +@end + +@interface FLEXKBToolbarSuggestedButton : FLEXKBToolbarButton @end diff --git a/FLEX/FLEXKeyPathSearchController.h b/FLEX/FLEXKeyPathSearchController.h new file mode 100644 index 00000000..98c2960b --- /dev/null +++ b/FLEX/FLEXKeyPathSearchController.h @@ -0,0 +1,38 @@ +// +// FLEXKeyPathSearchController.h +// FLEX +// +// Created by Tanner on 3/23/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import +#import "FLEXRuntimeBrowserToolbar.h" +#import "FLEXMethod.h" + +@protocol FLEXKeyPathSearchControllerDelegate + +@property (nonatomic, readonly) UITableView *tableView; +@property (nonatomic, readonly) UISearchController *searchController; + +/// For loaded images which don't have an NSBundle +- (void)didSelectImagePath:(NSString *)message shortName:(NSString *)shortName; +- (void)didSelectBundle:(NSBundle *)bundle; +- (void)didSelectClass:(Class)cls; + +@end + + +@interface FLEXKeyPathSearchController : NSObject + ++ (instancetype)delegate:(id)delegate; + +@property (nonatomic) FLEXRuntimeBrowserToolbar *toolbar; + +/// Suggestions for the toolbar +@property (nonatomic, readonly) NSArray *suggestions; + +- (void)didSelectKeyPathOption:(NSString *)text; +- (void)didPressButton:(NSString *)text insertInto:(UISearchBar *)searchBar; + +@end diff --git a/FLEX/FLEXKeyValueTableViewCell.h b/FLEX/FLEXKeyValueTableViewCell.h new file mode 100644 index 00000000..7e3074ca --- /dev/null +++ b/FLEX/FLEXKeyValueTableViewCell.h @@ -0,0 +1,13 @@ +// +// FLEXKeyValueTableViewCell.h +// FLEX +// +// Created by Tanner Bennett on 1/23/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewCell.h" + +@interface FLEXKeyValueTableViewCell : FLEXTableViewCell + +@end diff --git a/FLEX/FLEXKeyboardHelpViewController.h b/FLEX/FLEXKeyboardHelpViewController.h new file mode 100644 index 00000000..4fae64e4 --- /dev/null +++ b/FLEX/FLEXKeyboardHelpViewController.h @@ -0,0 +1,13 @@ +// +// FLEXKeyboardHelpViewController.h +// FLEX +// +// Created by Ryan Olson on 9/19/15. +// Copyright © 2015 f. All rights reserved. +// + +#import + +@interface FLEXKeyboardHelpViewController : UIViewController + +@end diff --git a/FLEX/FLEXKeyboardShortcutManager.h b/FLEX/FLEXKeyboardShortcutManager.h new file mode 100644 index 00000000..292f3d4c --- /dev/null +++ b/FLEX/FLEXKeyboardShortcutManager.h @@ -0,0 +1,29 @@ +// +// FLEXKeyboardShortcutManager.h +// FLEX +// +// Created by Ryan Olson on 9/19/15. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXKeyboardShortcutManager : NSObject + +@property (nonatomic, readonly, class) FLEXKeyboardShortcutManager *sharedManager; + +/// @param key A single character string matching a key on the keyboard +/// @param modifiers Modifier keys such as shift, command, or alt/option +/// @param action The block to run on the main thread when the key & modifier combination is recognized. +/// @param description Shown the the keyboard shortcut help menu, which is accessed via the '?' key. +/// @param allowOverride Allow registering even if there's an existing action associated with that key/modifier. +- (void)registerSimulatorShortcutWithKey:(NSString *)key + modifiers:(UIKeyModifierFlags)modifiers + action:(dispatch_block_t)action + description:(NSString *)description + allowOverride:(BOOL)allowOverride; + +@property (nonatomic, getter=isEnabled) BOOL enabled; +@property (nonatomic, readonly) NSString *keyboardShortcutsDescription; + +@end diff --git a/FLEX/FLEXKeyboardToolbar.h b/FLEX/FLEXKeyboardToolbar.h new file mode 100644 index 00000000..e44fdb6b --- /dev/null +++ b/FLEX/FLEXKeyboardToolbar.h @@ -0,0 +1,18 @@ +// +// FLEXKeyboardToolbar.h +// FLEX +// +// Created by Tanner on 6/11/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXKBToolbarButton.h" + +@interface FLEXKeyboardToolbar : UIView + ++ (instancetype)toolbarWithButtons:(NSArray *)buttons; + +@property (nonatomic) NSArray *buttons; +@property (nonatomic) UIKeyboardAppearance appearance; + +@end diff --git a/FLEX/FLEXKeychain.h b/FLEX/FLEXKeychain.h new file mode 100644 index 00000000..f26c68d5 --- /dev/null +++ b/FLEX/FLEXKeychain.h @@ -0,0 +1,141 @@ +// +// FLEXKeychain.h +// +// Derived from: +// SSKeychain.h in SSKeychain +// Created by Sam Soffes on 5/19/10. +// Copyright (c) 2010-2014 Sam Soffes. All rights reserved. +// + +#import + +/// Error code specific to FLEXKeychain that can be returned in NSError objects. +/// For codes returned by the operating system, refer to SecBase.h for your +/// platform. +typedef NS_ENUM(OSStatus, FLEXKeychainErrorCode) { + /// Some of the arguments were invalid. + FLEXKeychainErrorBadArguments = -1001, +}; + +/// FLEXKeychain error domain +extern NSString *const kFLEXKeychainErrorDomain; + +/// Account name. +extern NSString *const kFLEXKeychainAccountKey; + +/// Time the item was created. +/// +/// The value will be a string. +extern NSString *const kFLEXKeychainCreatedAtKey; + +/// Item class. +extern NSString *const kFLEXKeychainClassKey; + +/// Item description. +extern NSString *const kFLEXKeychainDescriptionKey; + +/// Item label. +extern NSString *const kFLEXKeychainLabelKey; + +/// Time the item was last modified. +/// +/// The value will be a string. +extern NSString *const kFLEXKeychainLastModifiedKey; + +/// Where the item was created. +extern NSString *const kFLEXKeychainWhereKey; + +/// A simple wrapper for accessing accounts, getting passwords, +/// setting passwords, and deleting passwords using the system Keychain. +@interface FLEXKeychain : NSObject + +#pragma mark - Classic methods + +/// @param serviceName The service for which to return the corresponding password. +/// @param account The account for which to return the corresponding password. +/// @return Returns a string containing the password for a given account and service, +/// or `nil` if the Keychain doesn't have a password for the given parameters. ++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; ++ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + +/// Returns a nsdata containing the password for a given account and service, +/// or `nil` if the Keychain doesn't have a password for the given parameters. +/// +/// @param serviceName The service for which to return the corresponding password. +/// @param account The account for which to return the corresponding password. +/// @return Returns a nsdata containing the password for a given account and service, +/// or `nil` if the Keychain doesn't have a password for the given parameters. ++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account; ++ (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + + +/// Deletes a password from the Keychain. +/// +/// @param serviceName The service for which to delete the corresponding password. +/// @param account The account for which to delete the corresponding password. +/// @return Returns `YES` on success, or `NO` on failure. ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + + +/// Sets a password in the Keychain. +/// +/// @param password The password to store in the Keychain. +/// @param serviceName The service for which to set the corresponding password. +/// @param account The account for which to set the corresponding password. +/// @return Returns `YES` on success, or `NO` on failure. ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + +/// Sets a password in the Keychain. +/// +/// @param password The password to store in the Keychain. +/// @param serviceName The service for which to set the corresponding password. +/// @param account The account for which to set the corresponding password. +/// @return Returns `YES` on success, or `NO` on failure. ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account; ++ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error; + +/// @return An array of dictionaries containing the Keychain's accounts, or `nil` if +/// the Keychain doesn't have any accounts. The order of the objects in the array isn't defined. +/// +/// @note See the `NSString` constants declared in FLEXKeychain.h for a list of keys that +/// can be used when accessing the dictionaries returned by this method. ++ (NSArray *> *)allAccounts; ++ (NSArray *> *)allAccounts:(NSError *__autoreleasing *)error; + +/// @param serviceName The service for which to return the corresponding accounts. +/// @return An array of dictionaries containing the Keychain's accounts for a given `serviceName`, +/// or `nil` if the Keychain doesn't have any accounts for the given `serviceName`. +/// The order of the objects in the array isn't defined. +/// +/// @note See the `NSString` constants declared in FLEXKeychain.h for a list of keys that +/// can be used when accessing the dictionaries returned by this method. ++ (NSArray *> *)accountsForService:(NSString *)serviceName; ++ (NSArray *> *)accountsForService:(NSString *)serviceName error:(NSError *__autoreleasing *)error; + + +#pragma mark - Configuration + +#if __IPHONE_4_0 && TARGET_OS_IPHONE +/// Returns the accessibility type for all future passwords saved to the Keychain. +/// +/// @return `NULL` or one of the "Keychain Item Accessibility +/// Constants" used for determining when a keychain item should be readable. ++ (CFTypeRef)accessibilityType; + +/// Sets the accessibility type for all future passwords saved to the Keychain. +/// +/// @param accessibilityType One of the "Keychain Item Accessibility Constants" +/// used for determining when a keychain item should be readable. +/// If the value is `NULL` (the default), the Keychain default will be used which +/// is highly insecure. You really should use at least `kSecAttrAccessibleAfterFirstUnlock` +/// for background applications or `kSecAttrAccessibleWhenUnlocked` for all +/// other applications. +/// +/// @note See Security/SecItem.h ++ (void)setAccessibilityType:(CFTypeRef)accessibilityType; +#endif + +@end + diff --git a/FLEX/FLEXKeychainQuery.h b/FLEX/FLEXKeychainQuery.h new file mode 100644 index 00000000..e5500bfe --- /dev/null +++ b/FLEX/FLEXKeychainQuery.h @@ -0,0 +1,112 @@ +// +// FLEXKeychainQuery.h +// +// Derived from: +// SSKeychainQuery.h in SSKeychain +// Created by Caleb Davenport on 3/19/13. +// Copyright (c) 2010-2014 Sam Soffes. All rights reserved. +// + +#import +#import + +#if __IPHONE_7_0 || __MAC_10_9 +// Keychain synchronization available at compile time +#define FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE 1 +#endif + +#if __IPHONE_3_0 || __MAC_10_9 +// Keychain access group available at compile time +#define FLEXKEYCHAIN_ACCESS_GROUP_AVAILABLE 1 +#endif + +#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE +typedef NS_ENUM(NSUInteger, FLEXKeychainQuerySynchronizationMode) { + FLEXKeychainQuerySynchronizationModeAny, + FLEXKeychainQuerySynchronizationModeNo, + FLEXKeychainQuerySynchronizationModeYes +}; +#endif + +/// Simple interface for querying or modifying keychain items. +@interface FLEXKeychainQuery : NSObject + +/// kSecAttrAccount +@property (nonatomic, copy) NSString *account; + +/// kSecAttrService +@property (nonatomic, copy) NSString *service; + +/// kSecAttrLabel +@property (nonatomic, copy) NSString *label; + +#ifdef FLEXKEYCHAIN_ACCESS_GROUP_AVAILABLE +/// kSecAttrAccessGroup (only used on iOS) +@property (nonatomic, copy) NSString *accessGroup; +#endif + +#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE +/// kSecAttrSynchronizable +@property (nonatomic) FLEXKeychainQuerySynchronizationMode synchronizationMode; +#endif + +/// Root storage for password information +@property (nonatomic, copy) NSData *passwordData; + +/// This property automatically transitions between an object and the value of +/// `passwordData` using NSKeyedArchiver and NSKeyedUnarchiver. +@property (nonatomic, copy) id passwordObject; + +/// Convenience accessor for setting and getting a password string. Passes through +/// to `passwordData` using UTF-8 string encoding. +@property (nonatomic, copy) NSString *password; + + +#pragma mark Saving & Deleting + +/// Save the receiver's attributes as a keychain item. Existing items with the +/// given account, service, and access group will first be deleted. +/// +/// @param error Populated should an error occur. +/// @return `YES` if saving was successful, `NO` otherwise. +- (BOOL)save:(NSError **)error; + +/// Delete keychain items that match the given account, service, and access group. +/// +/// @param error Populated should an error occur. +/// @return `YES` if saving was successful, `NO` otherwise. +- (BOOL)deleteItem:(NSError **)error; + + +#pragma mark Fetching + +/// Fetch all keychain items that match the given account, service, and access +/// group. The values of `password` and `passwordData` are ignored when fetching. +/// +/// @param error Populated should an error occur. +/// @return An array of dictionaries that represent all matching keychain items, +/// or `nil` should an error occur. The order of the items is not determined. +- (NSArray *> *)fetchAll:(NSError **)error; + +/// Fetch the keychain item that matches the given account, service, and access +/// group. The `password` and `passwordData` properties will be populated unless +/// an error occurs. The values of `password` and `passwordData` are ignored when +/// fetching. +/// +/// @param error Populated should an error occur. +/// @return `YES` if fetching was successful, `NO` otherwise. +- (BOOL)fetch:(NSError **)error; + + +#pragma mark Synchronization Status + +#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE +/// Returns a boolean indicating if keychain synchronization is available on the device at runtime. +/// The #define FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE is only for compile time. +/// If you are checking for the presence of synchronization, you should use this method. +/// +/// @return A value indicating if keychain synchronization is available ++ (BOOL)isSynchronizationAvailable; +#endif + +@end diff --git a/FLEX/FLEXKeychainViewController.h b/FLEX/FLEXKeychainViewController.h new file mode 100644 index 00000000..3545d214 --- /dev/null +++ b/FLEX/FLEXKeychainViewController.h @@ -0,0 +1,14 @@ +// +// FLEXKeychainViewController.h +// FLEX +// +// Created by ray on 2019/8/17. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXGlobalsEntry.h" +#import "FLEXFilteringTableViewController.h" + +@interface FLEXKeychainViewController : FLEXFilteringTableViewController + +@end diff --git a/FLEX/FLEXLayerShortcuts.h b/FLEX/FLEXLayerShortcuts.h new file mode 100644 index 00000000..dad8d959 --- /dev/null +++ b/FLEX/FLEXLayerShortcuts.h @@ -0,0 +1,15 @@ +// +// FLEXLayerShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 12/12/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +@interface FLEXLayerShortcuts : FLEXShortcutsSection + ++ (instancetype)forObject:(CALayer *)layer; + +@end diff --git a/FLEX/FLEXLiveObjectsController.h b/FLEX/FLEXLiveObjectsController.h new file mode 100644 index 00000000..a4060776 --- /dev/null +++ b/FLEX/FLEXLiveObjectsController.h @@ -0,0 +1,14 @@ +// +// FLEXLiveObjectsController.h +// Flipboard +// +// Created by Ryan Olson on 5/28/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" +#import "FLEXGlobalsEntry.h" + +@interface FLEXLiveObjectsController : FLEXTableViewController + +@end diff --git a/FLEX/FLEXLogController.h b/FLEX/FLEXLogController.h new file mode 100644 index 00000000..cb35088f --- /dev/null +++ b/FLEX/FLEXLogController.h @@ -0,0 +1,19 @@ +// +// FLEXLogController.h +// FLEX +// +// Created by Tanner on 3/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXSystemLogMessage.h" + +@protocol FLEXLogController + +/// Guaranteed to call back on the main thread. ++ (instancetype)withUpdateHandler:(void(^)(NSArray *newMessages))newMessagesHandler; + +- (BOOL)startMonitoring; + +@end diff --git a/FLEX/FLEXMacros.h b/FLEX/FLEXMacros.h new file mode 100644 index 00000000..ba741464 --- /dev/null +++ b/FLEX/FLEXMacros.h @@ -0,0 +1,96 @@ +// +// FLEXMacros.h +// FLEX +// +// Created by Tanner on 3/12/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#ifndef FLEXMacros_h +#define FLEXMacros_h + +#define flex_keywordify class NSObject; +#define ctor flex_keywordify __attribute__((constructor)) void __flex_ctor_##__LINE__() +#define dtor flex_keywordify __attribute__((destructor)) void __flex_dtor_##__LINE__() + +#define weakify(var) __weak __typeof(var) __weak__##var = var; + +#define strongify(var) \ +_Pragma("clang diagnostic push") \ +_Pragma("clang diagnostic ignored \"-Wshadow\"") \ +__strong typeof(var) var = __weak__##var; \ +_Pragma("clang diagnostic pop") + +// A macro to check if we are running in a test environment +#define FLEX_IS_TESTING() (NSClassFromString(@"XCTest") != nil) + +/// Whether we want the majority of constructors to run upon load or not. +extern BOOL FLEXConstructorsShouldRun(void); + +/// A macro to return from the current procedure if we don't want to run constructors +#define FLEX_EXIT_IF_NO_CTORS() if (!FLEXConstructorsShouldRun()) return; + +/// Rounds down to the nearest "point" coordinate +NS_INLINE CGFloat FLEXFloor(CGFloat x) { + return floor(UIScreen.mainScreen.scale * (x)) / UIScreen.mainScreen.scale; +} + +/// Returns the given number of points in pixels +NS_INLINE CGFloat FLEXPointsToPixels(CGFloat points) { + return points / UIScreen.mainScreen.scale; +} + +/// Creates a CGRect with all members rounded down to the nearest "point" coordinate +NS_INLINE CGRect FLEXRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height) { + return CGRectMake(FLEXFloor(x), FLEXFloor(y), FLEXFloor(width), FLEXFloor(height)); +} + +/// Adjusts the origin of an existing rect +NS_INLINE CGRect FLEXRectSetOrigin(CGRect r, CGPoint origin) { + r.origin = origin; return r; +} + +/// Adjusts the size of an existing rect +NS_INLINE CGRect FLEXRectSetSize(CGRect r, CGSize size) { + r.size = size; return r; +} + +/// Adjusts the origin.x of an existing rect +NS_INLINE CGRect FLEXRectSetX(CGRect r, CGFloat x) { + r.origin.x = x; return r; +} + +/// Adjusts the origin.y of an existing rect +NS_INLINE CGRect FLEXRectSetY(CGRect r, CGFloat y) { + r.origin.y = y ; return r; +} + +/// Adjusts the size.width of an existing rect +NS_INLINE CGRect FLEXRectSetWidth(CGRect r, CGFloat width) { + r.size.width = width; return r; +} + +/// Adjusts the size.height of an existing rect +NS_INLINE CGRect FLEXRectSetHeight(CGRect r, CGFloat height) { + r.size.height = height; return r; +} + +#ifdef __IPHONE_13_0 +#define FLEX_AT_LEAST_IOS13_SDK (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0) +#else +#define FLEX_AT_LEAST_IOS13_SDK NO +#endif + +#define FLEXPluralString(count, plural, singular) [NSString \ + stringWithFormat:@"%@ %@", @(count), (count == 1 ? singular : plural) \ +] + +#define FLEXPluralFormatString(count, pluralFormat, singularFormat) [NSString \ + stringWithFormat:(count == 1 ? singularFormat : pluralFormat), @(count) \ +] + +#define flex_dispatch_after(nSeconds, onQueue, block) \ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, \ + (int64_t)(nSeconds * NSEC_PER_SEC)), onQueue, block) + +#endif /* FLEXMacros_h */ diff --git a/FLEX/FLEXManager+Extensibility.h b/FLEX/FLEXManager+Extensibility.h new file mode 100644 index 00000000..1a71a0e3 --- /dev/null +++ b/FLEX/FLEXManager+Extensibility.h @@ -0,0 +1,78 @@ +// +// FLEXManager+Extensibility.h +// FLEX +// +// Created by Tanner on 2/2/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXManager.h" +#import "FLEXGlobalsEntry.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXManager (Extensibility) + +#pragma mark - Globals Screen Entries + +/// Adds an entry at the top of the list of Global State items. +/// Call this method before this view controller is displayed. +/// @param entryName The string to be displayed in the cell. +/// @param objectFutureBlock When you tap on the row, information about the object returned +/// by this block will be displayed. Passing a block that returns an object allows you to display +/// information about an object whose actual pointer may change at runtime (e.g. +currentUser) +/// @note This method must be called from the main thread. +/// The objectFutureBlock will be invoked from the main thread and may return nil. +/// @note The passed block will be copied and retain for the duration of the application, +/// you may want to use __weak references. +- (void)registerGlobalEntryWithName:(NSString *)entryName objectFutureBlock:(id (^)(void))objectFutureBlock; + +/// Adds an entry at the top of the list of Global State items. +/// Call this method before this view controller is displayed. +/// @param entryName The string to be displayed in the cell. +/// @param viewControllerFutureBlock When you tap on the row, view controller returned +/// by this block will be pushed on the navigation controller stack. +/// @note This method must be called from the main thread. +/// The viewControllerFutureBlock will be invoked from the main thread and may not return nil. +/// @note The passed block will be copied and retain for the duration of the application, +/// you may want to use __weak references as needed. +- (void)registerGlobalEntryWithName:(NSString *)entryName + viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock; + +/// Adds an entry at the top of the list of Global State items. +/// @param entryName The string to be displayed in the cell. +/// @param rowSelectedAction When you tap on the row, this block will be invoked +/// with the host table view view controller. Use it to deselect the row or present an alert. +/// @note This method must be called from the main thread. +/// The rowSelectedAction will be invoked from the main thread. +/// @note The passed block will be copied and retain for the duration of the application, +/// you may want to use __weak references as needed. +- (void)registerGlobalEntryWithName:(NSString *)entryName action:(FLEXGlobalsEntryRowAction)rowSelectedAction; + +/// Removes all registered global entries. +- (void)clearGlobalEntries; + +#pragma mark - Simulator Shortcuts + +/// Simulator keyboard shortcuts are enabled by default. +/// The shortcuts will not fire when there is an active text field, text view, or other responder +/// accepting key input. You can disable keyboard shortcuts if you have existing keyboard shortcuts +/// that conflict with FLEX, or if you like doing things the hard way ;) +/// Keyboard shortcuts are always disabled (and support is #if'd out) in non-simulator builds +@property (nonatomic) BOOL simulatorShortcutsEnabled; + +/// Adds an action to run when the specified key & modifier combination is pressed +/// @param key A single character string matching a key on the keyboard +/// @param modifiers Modifier keys such as shift, command, or alt/option +/// @param action The block to run on the main thread when the key & modifier combination is recognized. +/// @param description Shown the the keyboard shortcut help menu, which is accessed via the '?' key. +/// @note The action block will be retained for the duration of the application. You may want to use weak references. +/// @note FLEX registers several default keyboard shortcuts. Use the '?' key to see a list of shortcuts. +- (void)registerSimulatorShortcutWithKey:(NSString *)key + modifiers:(UIKeyModifierFlags)modifiers + action:(dispatch_block_t)action + description:(NSString *)description; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXManager+Networking.h b/FLEX/FLEXManager+Networking.h new file mode 100644 index 00000000..9e01e432 --- /dev/null +++ b/FLEX/FLEXManager+Networking.h @@ -0,0 +1,40 @@ +// +// FLEXManager+Networking.h +// FLEX +// +// Created by Tanner on 2/1/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXManager.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXManager (Networking) + +/// If this property is set to YES, FLEX will swizzle NSURLConnection*Delegate and NSURLSession*Delegate methods +/// on classes that conform to the protocols. This allows you to view network activity history from the main FLEX menu. +/// Full responses are kept temporarily in a size-limited cache and may be pruned under memory pressure. +@property (nonatomic, getter=isNetworkDebuggingEnabled) BOOL networkDebuggingEnabled; + +/// Defaults to 25 MB if never set. Values set here are persisted across launches of the app. +/// The response cache uses an NSCache, so it may purge prior to hitting the limit when the app is under memory pressure. +@property (nonatomic) NSUInteger networkResponseCacheByteLimit; + +/// Requests whose host ends with one of the blacklisted entries in this array will be not be recorded (eg. google.com). +/// Wildcard or subdomain entries are not required (eg. google.com will match any subdomain under google.com). +/// Useful to remove requests that are typically noisy, such as analytics requests that you aren't interested in tracking. +@property (nonatomic) NSMutableArray *networkRequestHostBlacklist; + +/// Sets custom viewer for specific content type. +/// @param contentType Mime type like application/json +/// @param viewControllerFutureBlock Viewer (view controller) creation block +/// @note This method must be called from the main thread. +/// The viewControllerFutureBlock will be invoked from the main thread and may not return nil. +/// @note The passed block will be copied and retain for the duration of the application, you may want to use __weak references. +- (void)setCustomViewerForContentType:(NSString *)contentType + viewControllerFutureBlock:(FLEXCustomContentViewerFuture)viewControllerFutureBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXManager+Private.h b/FLEX/FLEXManager+Private.h new file mode 100644 index 00000000..a4f5a913 --- /dev/null +++ b/FLEX/FLEXManager+Private.h @@ -0,0 +1,23 @@ +// +// FLEXManager+Private.h +// PebbleApp +// +// Created by Javier Soto on 7/26/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXManager.h" +#import "FLEXWindow.h" + +@class FLEXGlobalsEntry, FLEXExplorerViewController; + +@interface FLEXManager (Private) + +@property (nonatomic, readonly) FLEXWindow *explorerWindow; +@property (nonatomic, readonly) FLEXExplorerViewController *explorerViewController; + +/// An array of FLEXGlobalsEntry objects that have been registered by the user. +@property (nonatomic, readonly) NSMutableArray *userGlobalEntries; +@property (nonatomic, readonly) NSMutableDictionary *customContentTypeViewers; + +@end diff --git a/FLEX/FLEXManager.h b/FLEX/FLEXManager.h new file mode 100644 index 00000000..2f6a2762 --- /dev/null +++ b/FLEX/FLEXManager.h @@ -0,0 +1,51 @@ +// +// FLEXManager.h +// Flipboard +// +// Created by Ryan Olson on 4/4/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXExplorerToolbar.h" + +#if !FLEX_AT_LEAST_IOS13_SDK +@class UIWindowScene; +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXManager : NSObject + +@property (nonatomic, readonly, class) FLEXManager *sharedManager; + +@property (nonatomic, readonly) BOOL isHidden; +@property (nonatomic, readonly) FLEXExplorerToolbar *toolbar; + +- (void)showExplorer; +- (void)hideExplorer; +- (void)toggleExplorer; + +/// Programmatically dismiss anything presented by FLEX, leaving only the toolbar visible. +- (void)dismissAnyPresentedTools:(void (^_Nullable)(void))completion; +/// Programmatically present something on top of the FLEX toolbar. +/// This method will automatically dismiss any currently presented tool, +/// so you do not need to call \c dismissAnyPresentedTools: yourself. +- (void)presentTool:(UIViewController *(^)(void))viewControllerFuture + completion:(void (^_Nullable)(void))completion; + +/// Use this to present the explorer in a specific scene when the one +/// it chooses by default is not the one you wish to display it in. +- (void)showExplorerFromScene:(UIWindowScene *)scene API_AVAILABLE(ios(13.0)); + +#pragma mark - Misc + +/// Default database password is @c nil by default. +/// Set this to the password you want the databases to open with. +@property (copy, nonatomic) NSString *defaultSqliteDatabasePassword; + +@end + + +typedef UIViewController * _Nullable(^FLEXCustomContentViewerFuture)(NSData *data); + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXMetadataSection.h b/FLEX/FLEXMetadataSection.h new file mode 100644 index 00000000..e96724f7 --- /dev/null +++ b/FLEX/FLEXMetadataSection.h @@ -0,0 +1,37 @@ +// +// FLEXMetadataSection.h +// FLEX +// +// Created by Tanner Bennett on 9/19/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewSection.h" +#import "FLEXObjectExplorer.h" + +typedef NS_ENUM(NSUInteger, FLEXMetadataKind) { + FLEXMetadataKindProperties = 1, + FLEXMetadataKindClassProperties, + FLEXMetadataKindIvars, + FLEXMetadataKindMethods, + FLEXMetadataKindClassMethods, + FLEXMetadataKindClassHierarchy, + FLEXMetadataKindProtocols, + FLEXMetadataKindOther +}; + +/// This section is used for displaying ObjC runtime metadata +/// about a class or object, such as listing methods, properties, etc. +@interface FLEXMetadataSection : FLEXTableViewSection + ++ (instancetype)explorer:(FLEXObjectExplorer *)explorer kind:(FLEXMetadataKind)metadataKind; + +@property (nonatomic, readonly) FLEXMetadataKind metadataKind; + +/// The names of metadata to exclude. Useful if you wish to group specific +/// properties or methods together in their own section outside of this one. +/// +/// Setting this property calls \c reloadData on this section. +@property (nonatomic) NSSet *excludedMetadata; + +@end diff --git a/FLEX/FLEXMethod.h b/FLEX/FLEXMethod.h new file mode 100644 index 00000000..25650534 --- /dev/null +++ b/FLEX/FLEXMethod.h @@ -0,0 +1,96 @@ +// +// FLEXMethod.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/30/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" +#import "FLEXMethodBase.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A class representing a concrete method which already exists in a class. +/// This class contains helper methods for swizzling or invoking the method. +/// +/// Any of the initializers will return nil if the type encoding +/// of the method is unsupported by `NSMethodSignature`. In general, +/// any method whose return type or parameters involve a struct with +/// bitfields or arrays is unsupported. +/// +/// I do not remember why I didn't include \c signature in the base class +/// when I originally wrote this, but I probably had a good reason. We can +/// always go back and move it to \c FLEXMethodBase if we find we need to. +@interface FLEXMethod : FLEXMethodBase + +/// Defaults to instance method ++ (nullable instancetype)method:(Method)method; ++ (nullable instancetype)method:(Method)method isInstanceMethod:(BOOL)isInstanceMethod; + +/// Constructs an \c FLEXMethod for the given method on the given class. +/// @param cls the class, or metaclass if this is a class method +/// @return The newly constructed \c FLEXMethod object, or \c nil if the +/// specified class or its superclasses do not contain a method with the specified selector. ++ (nullable instancetype)selector:(SEL)selector class:(Class)cls; +/// Constructs an \c FLEXMethod for the given method on the given class, +/// only if the given class itself defines or overrides the desired method. +/// @param cls the class, or metaclass if this is a class method +/// @return The newly constructed \c FLEXMethod object, or \c nil \e if the +/// specified class does not define or override, or if the specified class +/// or its superclasses do not contain, a method with the specified selector. ++ (nullable instancetype)selector:(SEL)selector implementedInClass:(Class)cls; + +@property (nonatomic, readonly) Method objc_method; +/// The implementation of the method. +/// @discussion Setting \c implementation will change the implementation of this method +/// for the entire class which implements said method. It will also not modify the selector of said method. +@property (nonatomic ) IMP implementation; +/// Whether the method is an instance method or not. +@property (nonatomic, readonly) BOOL isInstanceMethod; +/// The number of arguments to the method. +@property (nonatomic, readonly) NSUInteger numberOfArguments; +/// The \c NSMethodSignature object corresponding to the method's type encoding. +@property (nonatomic, readonly) NSMethodSignature *signature; +/// Same as \e typeEncoding but with parameter sizes up front and offsets after the types. +@property (nonatomic, readonly) NSString *signatureString; +/// The return type of the method. +@property (nonatomic, readonly) FLEXTypeEncoding *returnType; +/// The return size of the method. +@property (nonatomic, readonly) NSUInteger returnSize; +/// The full path of the image that contains this method definition, +/// or \c nil if this ivar was probably defined at runtime. +@property (nonatomic, readonly) NSString *imagePath; + +/// Like @code - (void)foo:(int)bar @endcode +@property (nonatomic, readonly) NSString *description; +/// Like @code -[Class foo:] @endcode +- (NSString *)debugNameGivenClassName:(NSString *)name; + +/// Swizzles the recieving method with the given method. +- (void)swapImplementations:(FLEXMethod *)method; + +#define FLEXMagicNumber 0xdeadbeef +#define FLEXArg(expr) FLEXMagicNumber,/// @encode(__typeof__(expr)), (__typeof__(expr) []){ expr } + +/// Sends a message to \e target, and returns it's value, or \c nil if not applicable. +/// @discussion You may send any message with this method. Primitive return values will be wrapped +/// in instances of \c NSNumber and \c NSValue. \c void and bitfield returning methods return \c nil. +/// \c SEL return types are converted to strings using \c NSStringFromSelector. +/// @return The object returned by this method, or an instance of \c NSValue or \c NSNumber containing +/// the primitive return type, or a string for \c SEL return types. +- (id)sendMessage:(id)target, ...; +/// Used internally by \c sendMessage:target,. Pass \c NULL to the first parameter for void methods. +- (void)getReturnValue:(void *)retPtr forMessageSend:(id)target, ...; + +@end + + +@interface FLEXMethod (Comparison) + +- (NSComparisonResult)compare:(FLEXMethod *)method; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXMethodBase.h b/FLEX/FLEXMethodBase.h new file mode 100644 index 00000000..177ec1d4 --- /dev/null +++ b/FLEX/FLEXMethodBase.h @@ -0,0 +1,43 @@ +// +// FLEXMethodBase.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/5/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + + +/// A base class for methods which encompasses those that may not +/// have been added to a class yet. Useful on it's own for adding +/// methods to a class, or building a new class from the ground up. +@interface FLEXMethodBase : NSObject { +@protected + SEL _selector; + NSString *_name; + NSString *_typeEncoding; + IMP _implementation; + + NSString *_flex_description; +} + +/// Constructs and returns an \c FLEXSimpleMethod instance with the given name, type encoding, and implementation. ++ (instancetype)buildMethodNamed:(NSString *)name withTypes:(NSString *)typeEncoding implementation:(IMP)implementation; + +/// The selector of the method. +@property (nonatomic, readonly) SEL selector; +/// The selector string of the method. +@property (nonatomic, readonly) NSString *selectorString; +/// Same as selectorString. +@property (nonatomic, readonly) NSString *name; +/// The type encoding of the method. +@property (nonatomic, readonly) NSString *typeEncoding; +/// The implementation of the method. +@property (nonatomic, readonly) IMP implementation; + +/// For internal use +@property (nonatomic) id tag; + +@end diff --git a/FLEX/FLEXMethodCallingViewController.h b/FLEX/FLEXMethodCallingViewController.h new file mode 100644 index 00000000..6dc77a5d --- /dev/null +++ b/FLEX/FLEXMethodCallingViewController.h @@ -0,0 +1,16 @@ +// +// FLEXMethodCallingViewController.h +// Flipboard +// +// Created by Ryan Olson on 5/23/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXVariableEditorViewController.h" +#import "FLEXMethod.h" + +@interface FLEXMethodCallingViewController : FLEXVariableEditorViewController + ++ (instancetype)target:(id)target method:(FLEXMethod *)method; + +@end diff --git a/FLEX/FLEXMirror.h b/FLEX/FLEXMirror.h new file mode 100644 index 00000000..8cbd279f --- /dev/null +++ b/FLEX/FLEXMirror.h @@ -0,0 +1,60 @@ +// +// FLEXMirror.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/29/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +@class FLEXMethod, FLEXProperty, FLEXIvar, FLEXProtocol; +#import + + +#pragma mark FLEXMirror +@interface FLEXMirror : NSObject + +/// Reflects an instance of an object or \c Class. +/// @discussion \c FLEXMirror will immediately gather all useful information. Consider using the +/// \c NSObject categories provided if your code will only use a few pieces of information, +/// or if your code needs to run faster. +/// +/// If you reflect an instance of a class then \c methods and \c properties will be populated +/// with instance methods and properties. If you reflect a class itself, then \c methods +/// and \c properties will be populated with class methods and properties as you'd expect. +/// +/// @param objectOrClass An instance of an objct or a \c Class object. +/// @return An instance of \c FLEXMirror. ++ (instancetype)reflect:(id)objectOrClass; + +/// The underlying object or \c Class used to create this \c FLEXMirror instance. +@property (nonatomic, readonly) id value; +/// Whether the reflected thing was a class or a class instance. +@property (nonatomic, readonly) BOOL isClass; +/// The name of the \c Class of the \c value property. +@property (nonatomic, readonly) NSString *className; + +@property (nonatomic, readonly) NSArray *properties; +@property (nonatomic, readonly) NSArray *ivars; +@property (nonatomic, readonly) NSArray *methods; +@property (nonatomic, readonly) NSArray *protocols; + +/// @return A reflection of \c value.superClass. +@property (nonatomic, readonly) FLEXMirror *superMirror; + +@end + + +@interface FLEXMirror (ExtendedMirror) + +/// @return The method with the given name, or \c nil if one does not exist. +- (FLEXMethod *)methodNamed:(NSString *)name; +/// @return The property with the given name, or \c nil if one does not exist. +- (FLEXProperty *)propertyNamed:(NSString *)name; +/// @return The instance variable with the given name, or \c nil if one does not exist. +- (FLEXIvar *)ivarNamed:(NSString *)name; +/// @return The protocol with the given name, or \c nil if one does not exist. +- (FLEXProtocol *)protocolNamed:(NSString *)name; + +@end diff --git a/FLEX/FLEXMultiColumnTableView.h b/FLEX/FLEXMultiColumnTableView.h new file mode 100644 index 00000000..34ae1c11 --- /dev/null +++ b/FLEX/FLEXMultiColumnTableView.h @@ -0,0 +1,47 @@ +// +// PTMultiColumnTableView.h +// PTMultiColumnTableViewDemo +// +// Created by Peng Tao on 15/11/16. +// Copyright © 2015年 Peng Tao. All rights reserved. +// + +#import +#import "FLEXTableColumnHeader.h" + +@class FLEXMultiColumnTableView; + +@protocol FLEXMultiColumnTableViewDelegate + +@required +- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didSelectRow:(NSInteger)row; +- (void)multiColumnTableView:(FLEXMultiColumnTableView *)tableView didSelectHeaderForColumn:(NSInteger)column sortType:(FLEXTableColumnHeaderSortType)sortType; + +@end + +@protocol FLEXMultiColumnTableViewDataSource + +@required + +- (NSInteger)numberOfColumnsInTableView:(FLEXMultiColumnTableView *)tableView; +- (NSInteger)numberOfRowsInTableView:(FLEXMultiColumnTableView *)tableView; +- (NSString *)columnTitle:(NSInteger)column; +- (NSString *)rowTitle:(NSInteger)row; +- (NSArray *)contentForRow:(NSInteger)row; + +- (CGFloat)multiColumnTableView:(FLEXMultiColumnTableView *)tableView widthForContentCellInColumn:(NSInteger)column; +- (CGFloat)multiColumnTableView:(FLEXMultiColumnTableView *)tableView heightForContentCellInRow:(NSInteger)row; +- (CGFloat)heightForTopHeaderInTableView:(FLEXMultiColumnTableView *)tableView; +- (CGFloat)widthForLeftHeaderInTableView:(FLEXMultiColumnTableView *)tableView; + +@end + + +@interface FLEXMultiColumnTableView : UIView + +@property (nonatomic, weak) id dataSource; +@property (nonatomic, weak) id delegate; + +- (void)reloadData; + +@end diff --git a/FLEX/FLEXMultilineTableViewCell.h b/FLEX/FLEXMultilineTableViewCell.h new file mode 100644 index 00000000..914cf238 --- /dev/null +++ b/FLEX/FLEXMultilineTableViewCell.h @@ -0,0 +1,24 @@ +// +// FLEXMultilineTableViewCell.h +// FLEX +// +// Created by Ryan Olson on 2/13/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewCell.h" + +/// A cell with both labels set to be multi-line capable. +@interface FLEXMultilineTableViewCell : FLEXTableViewCell + ++ (CGFloat)preferredHeightWithAttributedText:(NSAttributedString *)attributedText + maxWidth:(CGFloat)contentViewWidth + style:(UITableViewStyle)style + showsAccessory:(BOOL)showsAccessory; + +@end + +/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleSubtitle +@interface FLEXMultilineDetailTableViewCell : FLEXMultilineTableViewCell + +@end diff --git a/FLEX/FLEXMutableListSection.h b/FLEX/FLEXMutableListSection.h new file mode 100644 index 00000000..6b49a02c --- /dev/null +++ b/FLEX/FLEXMutableListSection.h @@ -0,0 +1,58 @@ +// +// FLEXMutableListSection.h +// FLEX +// +// Created by Tanner on 3/9/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXCollectionContentSection.h" + +typedef void (^FLEXMutableListCellForElement)(__kindof UITableViewCell *cell, id element, NSInteger row); + +/// A section aimed at meeting the needs of table views with one section +/// (or, a section that shouldn't warrant the code duplication that comes +/// with creating a new section just for some specific table view) +/// +/// Use this section if you want to display a growing list of rows, +/// or even if you want to display a static list of rows. +/// +/// To support editing or inserting, implement the appropriate +/// table view delegate methods in your table view delegate class +/// and call \c mutate: (or \c setList: ) before updating the table view. +/// +/// By default, no section title is shown. Assign one to \c customTitle +/// +/// By default, \c kFLEXDetailCell is the reuse identifier used. If you need +/// to support multiple reuse identifiers in a single section, implement the +/// \c cellForRowAtIndexPath: method, dequeue the cell yourself and call +/// \c -configureCell: on the appropriate section object, passing in the cell +@interface FLEXMutableListSection<__covariant ObjectType> : FLEXCollectionContentSection + +/// Initializes a section with an empty list. ++ (instancetype)list:(NSArray *)list + cellConfiguration:(FLEXMutableListCellForElement)configurationBlock + filterMatcher:(BOOL(^)(NSString *filterText, id element))filterBlock; + +/// By default, rows are not selectable. If you want rows +/// to be selectable, provide a selection handler here. +@property (nonatomic, copy) void (^selectionHandler)(__kindof UIViewController *host, id element); + +/// The objects representing all possible rows in the section. +@property (nonatomic) NSArray *list; +/// The objects representing the currently unfiltered rows in the section. +@property (nonatomic, readonly) NSArray *filteredList; + +/// A readwrite version of the same property in \c FLEXTableViewSection.h +/// +/// This property expects one entry. An exception is thrown if more than one +/// entry is supplied. If you need more than one reuse identifier within a single +/// section, your view probably has more complexity than this class can handle. +@property (nonatomic, readwrite) NSDictionary *cellRegistrationMapping; + +/// Call this method to mutate the full, unfiltered list. +/// This ensures that \c filteredList is updated after any mutations. +- (void)mutate:(void(^)(NSMutableArray *list))block; + +@end + diff --git a/FLEX/FLEXNavigationController.h b/FLEX/FLEXNavigationController.h new file mode 100644 index 00000000..f0533a8c --- /dev/null +++ b/FLEX/FLEXNavigationController.h @@ -0,0 +1,19 @@ +// +// FLEXNavigationController.h +// FLEX +// +// Created by Tanner on 1/30/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXNavigationController : UINavigationController + ++ (instancetype)withRootViewController:(UIViewController *)rootVC; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXNetworkCurlLogger.h b/FLEX/FLEXNetworkCurlLogger.h new file mode 100644 index 00000000..6fb7eb63 --- /dev/null +++ b/FLEX/FLEXNetworkCurlLogger.h @@ -0,0 +1,19 @@ +// +// FLEXCurlLogger.h +// +// +// Created by Ji Pei on 07/27/16 +// + +#import + +@interface FLEXNetworkCurlLogger : NSObject + +/** + * Generates a cURL command equivalent to the given request. + * + * @param request The request to be translated + */ ++ (NSString *)curlCommandString:(NSURLRequest *)request; + +@end diff --git a/FLEX/FLEXNetworkMITMViewController.h b/FLEX/FLEXNetworkMITMViewController.h new file mode 100644 index 00000000..aef8fd41 --- /dev/null +++ b/FLEX/FLEXNetworkMITMViewController.h @@ -0,0 +1,14 @@ +// +// FLEXNetworkMITMViewController.h +// Flipboard +// +// Created by Ryan Olson on 2/8/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" +#import "FLEXGlobalsEntry.h" + +@interface FLEXNetworkMITMViewController : FLEXTableViewController + +@end diff --git a/FLEX/FLEXNetworkObserver.h b/FLEX/FLEXNetworkObserver.h new file mode 100644 index 00000000..6169bd27 --- /dev/null +++ b/FLEX/FLEXNetworkObserver.h @@ -0,0 +1,28 @@ +// +// FLEXNetworkObserver.h +// Derived from: +// +// PDAFNetworkDomainController.h +// PonyDebugger +// +// Created by Mike Lewis on 2/27/12. +// +// Licensed to Square, Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Square, Inc. licenses this file to you. +// + +#import + +FOUNDATION_EXTERN NSString *const kFLEXNetworkObserverEnabledStateChangedNotification; + +/// This class swizzles NSURLConnection and NSURLSession delegate methods to observe events in the URL loading system. +/// High level network events are sent to the default FLEXNetworkRecorder instance which maintains the request history and caches response bodies. +@interface FLEXNetworkObserver : NSObject + +/// Swizzling occurs when the observer is enabled for the first time. +/// This reduces the impact of FLEX if network debugging is not desired. +/// NOTE: this setting persists between launches of the app. +@property (nonatomic, class, getter=isEnabled) BOOL enabled; + +@end diff --git a/FLEX/FLEXNetworkRecorder.h b/FLEX/FLEXNetworkRecorder.h new file mode 100644 index 00000000..650a7dee --- /dev/null +++ b/FLEX/FLEXNetworkRecorder.h @@ -0,0 +1,75 @@ +// +// FLEXNetworkRecorder.h +// Flipboard +// +// Created by Ryan Olson on 2/4/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +// Notifications posted when the record is updated +extern NSString *const kFLEXNetworkRecorderNewTransactionNotification; +extern NSString *const kFLEXNetworkRecorderTransactionUpdatedNotification; +extern NSString *const kFLEXNetworkRecorderUserInfoTransactionKey; +extern NSString *const kFLEXNetworkRecorderTransactionsClearedNotification; + +@class FLEXNetworkTransaction; + +@interface FLEXNetworkRecorder : NSObject + +/// In general, it only makes sense to have one recorder for the entire application. +@property (nonatomic, readonly, class) FLEXNetworkRecorder *defaultRecorder; + +/// Defaults to 25 MB if never set. Values set here are persisted across launches of the app. +@property (nonatomic) NSUInteger responseCacheByteLimit; + +/// If NO, the recorder not cache will not cache response for content types +/// with an "image", "video", or "audio" prefix. +@property (nonatomic) BOOL shouldCacheMediaResponses; + +@property (nonatomic) NSMutableArray *hostBlacklist; + +/// Call this after adding to or setting the \c hostBlacklist to remove blacklisted transactions +- (void)clearBlacklistedTransactions; + +/// Call this to save the blacklist to the disk to be loaded next time +- (void)synchronizeBlacklist; + + +// Accessing recorded network activity + +/// Array of FLEXNetworkTransaction objects ordered by start time with the newest first. +- (NSArray *)networkTransactions; + +/// The full response data IFF it hasn't been purged due to memory pressure. +- (NSData *)cachedResponseBodyForTransaction:(FLEXNetworkTransaction *)transaction; + +/// Dumps all network transactions and cached response bodies. +- (void)clearRecordedActivity; + + +// Recording network activity + +/// Call when app is about to send HTTP request. +- (void)recordRequestWillBeSentWithRequestID:(NSString *)requestID + request:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse; + +/// Call when HTTP response is available. +- (void)recordResponseReceivedWithRequestID:(NSString *)requestID response:(NSURLResponse *)response; + +/// Call when data chunk is received over the network. +- (void)recordDataReceivedWithRequestID:(NSString *)requestID dataLength:(int64_t)dataLength; + +/// Call when HTTP request has finished loading. +- (void)recordLoadingFinishedWithRequestID:(NSString *)requestID responseBody:(NSData *)responseBody; + +/// Call when HTTP request has failed to load. +- (void)recordLoadingFailedWithRequestID:(NSString *)requestID error:(NSError *)error; + +/// Call to set the request mechanism anytime after recordRequestWillBeSent... has been called. +/// This string can be set to anything useful about the API used to make the request. +- (void)recordMechanism:(NSString *)mechanism forRequestID:(NSString *)requestID; + +@end diff --git a/FLEX/FLEXNetworkSettingsController.h b/FLEX/FLEXNetworkSettingsController.h new file mode 100644 index 00000000..1094fb50 --- /dev/null +++ b/FLEX/FLEXNetworkSettingsController.h @@ -0,0 +1,12 @@ +// +// FLEXNetworkSettingsController.h +// FLEXInjected +// +// Created by Ryan Olson on 2/20/15. +// + +#import "FLEXTableViewController.h" + +@interface FLEXNetworkSettingsController : FLEXTableViewController + +@end diff --git a/FLEX/FLEXNetworkTransaction.h b/FLEX/FLEXNetworkTransaction.h new file mode 100644 index 00000000..94b825ed --- /dev/null +++ b/FLEX/FLEXNetworkTransaction.h @@ -0,0 +1,44 @@ +// +// FLEXNetworkTransaction.h +// Flipboard +// +// Created by Ryan Olson on 2/8/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import "UIKit/UIKit.h" + +typedef NS_ENUM(NSInteger, FLEXNetworkTransactionState) { + FLEXNetworkTransactionStateUnstarted, + FLEXNetworkTransactionStateAwaitingResponse, + FLEXNetworkTransactionStateReceivingData, + FLEXNetworkTransactionStateFinished, + FLEXNetworkTransactionStateFailed +}; + +@interface FLEXNetworkTransaction : NSObject + +@property (nonatomic, copy) NSString *requestID; + +@property (nonatomic) NSURLRequest *request; +@property (nonatomic) NSURLResponse *response; +@property (nonatomic, copy) NSString *requestMechanism; +@property (nonatomic) FLEXNetworkTransactionState transactionState; +@property (nonatomic) NSError *error; + +@property (nonatomic) NSDate *startTime; +@property (nonatomic) NSTimeInterval latency; +@property (nonatomic) NSTimeInterval duration; + +@property (nonatomic) int64_t receivedDataLength; + +/// Only applicable for image downloads. A small thumbnail to preview the full response. +@property (nonatomic) UIImage *responseThumbnail; + +/// Populated lazily. Handles both normal HTTPBody data and HTTPBodyStreams. +@property (nonatomic, readonly) NSData *cachedRequestBody; + ++ (NSString *)readableStringFromTransactionState:(FLEXNetworkTransactionState)state; + +@end diff --git a/FLEX/FLEXNetworkTransactionCell.h b/FLEX/FLEXNetworkTransactionCell.h new file mode 100644 index 00000000..f13ad1bf --- /dev/null +++ b/FLEX/FLEXNetworkTransactionCell.h @@ -0,0 +1,21 @@ +// +// FLEXNetworkTransactionCell.h +// Flipboard +// +// Created by Ryan Olson on 2/8/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +extern NSString * const kFLEXNetworkTransactionCellIdentifier; + +@class FLEXNetworkTransaction; + +@interface FLEXNetworkTransactionCell : UITableViewCell + +@property (nonatomic) FLEXNetworkTransaction *transaction; + ++ (CGFloat)preferredCellHeight; + +@end diff --git a/FLEX/FLEXNetworkTransactionDetailController.h b/FLEX/FLEXNetworkTransactionDetailController.h new file mode 100644 index 00000000..2c71a4f8 --- /dev/null +++ b/FLEX/FLEXNetworkTransactionDetailController.h @@ -0,0 +1,17 @@ +// +// FLEXNetworkTransactionDetailController.h +// Flipboard +// +// Created by Ryan Olson on 2/10/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@class FLEXNetworkTransaction; + +@interface FLEXNetworkTransactionDetailController : UITableViewController + +@property (nonatomic) FLEXNetworkTransaction *transaction; + +@end diff --git a/FLEX/FLEXOSLogController.h b/FLEX/FLEXOSLogController.h new file mode 100644 index 00000000..154813cf --- /dev/null +++ b/FLEX/FLEXOSLogController.h @@ -0,0 +1,27 @@ +// +// FLEXOSLogController.h +// FLEX +// +// Created by Tanner on 12/19/18. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXLogController.h" + +#define FLEXOSLogAvailable() (NSProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 10) + +/// The log controller used for iOS 10 and up. +@interface FLEXOSLogController : NSObject + ++ (instancetype)withUpdateHandler:(void(^)(NSArray *newMessages))newMessagesHandler; + +- (BOOL)startMonitoring; + +/// Whether log messages are to be recorded and kept in-memory in the background. +/// You do not need to initialize this value, only change it. +@property (nonatomic) BOOL persistent; +/// Used mostly internally, but also used by the log VC to persist messages +/// that were created prior to enabling persistence. +@property (nonatomic) NSMutableArray *messages; + +@end diff --git a/FLEX/FLEXObjcInternal.h b/FLEX/FLEXObjcInternal.h new file mode 100644 index 00000000..d5e0ddc3 --- /dev/null +++ b/FLEX/FLEXObjcInternal.h @@ -0,0 +1,73 @@ +// +// FLEXObjcInternal.h +// FLEX +// +// Created by Tanner Bennett on 11/1/18. +// + +#import + +#ifdef __cplusplus +extern "C" { +#endif + +// The macros below are copied straight from +// objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with +// as few modifications as possible. Changes are noted in boxed comments. +// https://opensource.apple.com/source/objc4/objc4-723/ +// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html +// https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html + +///////////////////// +// objc-internal.h // +///////////////////// + +#if __LP64__ +#define OBJC_HAVE_TAGGED_POINTERS 1 +#endif + +#if OBJC_HAVE_TAGGED_POINTERS + +#if TARGET_OS_OSX && __x86_64__ +// 64-bit Mac - tag bit is LSB +# define OBJC_MSB_TAGGED_POINTERS 0 +#else +// Everything else - tag bit is MSB +# define OBJC_MSB_TAGGED_POINTERS 1 +#endif + +#if OBJC_MSB_TAGGED_POINTERS +# define _OBJC_TAG_MASK (1UL<<63) +# define _OBJC_TAG_EXT_MASK (0xfUL<<60) +#else +# define _OBJC_TAG_MASK 1UL +# define _OBJC_TAG_EXT_MASK 0xfUL +#endif + +#endif // OBJC_HAVE_TAGGED_POINTERS + +////////////////////////////////////// +// originally _objc_isTaggedPointer // +////////////////////////////////////// +NS_INLINE BOOL flex_isTaggedPointer(const void *ptr) { + #if OBJC_HAVE_TAGGED_POINTERS + return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK; + #else + return NO; + #endif +} + +#define FLEXPointerIsTaggedPointer(obj) flex_isTaggedPointer((__bridge void *)obj) + +BOOL FLEXPointerIsReadable(const void * ptr); + +/// @brief Assumes memory is valid and readable. +/// @discussion objc-internal.h, objc-private.h, and objc-config.h +/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/ +/// https://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py +/// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/ +BOOL FLEXPointerIsValidObjcObject(const void * ptr); + +#ifdef __cplusplus +} +#endif diff --git a/FLEX/FLEXObjcRuntimeViewController.h b/FLEX/FLEXObjcRuntimeViewController.h new file mode 100644 index 00000000..93ac54a5 --- /dev/null +++ b/FLEX/FLEXObjcRuntimeViewController.h @@ -0,0 +1,14 @@ +// +// FLEXObjcRuntimeViewController.h +// FLEX +// +// Created by Tanner on 3/23/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXTableViewController.h" +#import "FLEXGlobalsEntry.h" + +@interface FLEXObjcRuntimeViewController : FLEXTableViewController + +@end diff --git a/FLEX/FLEXObjectExplorer.h b/FLEX/FLEXObjectExplorer.h new file mode 100644 index 00000000..5b251f34 --- /dev/null +++ b/FLEX/FLEXObjectExplorer.h @@ -0,0 +1,73 @@ +// +// FLEXObjectExplorer.h +// FLEX +// +// Created by Tanner Bennett on 8/28/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntime+UIKitHelpers.h" + +/// Carries state about the current user defaults settings +@interface FLEXObjectExplorerDefaults : NSObject ++ (instancetype)canEdit:(BOOL)editable wantsPreviews:(BOOL)showPreviews; + +/// Only \c YES for properties and ivars +@property (nonatomic, readonly) BOOL isEditable; +/// Only affects properties and ivars +@property (nonatomic, readonly) BOOL wantsDynamicPreviews; +@end + +@interface FLEXObjectExplorer : NSObject + ++ (instancetype)forObject:(id)objectOrClass; + ++ (void)configureDefaultsForItems:(NSArray> *)items; + +@property (nonatomic, readonly) id object; +/// Subclasses can override to provide a more useful description +@property (nonatomic, readonly) NSString *objectDescription; + +/// @return \c YES if \c object is an instance of a class, +/// or \c NO if \c object is a class itself. +@property (nonatomic, readonly) BOOL objectIsInstance; + +/// An index into the `classHierarchy` array. +/// +/// This property determines which set of data comes out of the metadata arrays below +/// For example, \c properties contains the properties of the selected class scope, +/// while \c allProperties is an array of arrays where each array is a set of +/// properties for a class in the class hierarchy of the current object. +@property (nonatomic) NSInteger classScope; + +@property (nonatomic, readonly) NSArray *> *allProperties; +@property (nonatomic, readonly) NSArray *properties; + +@property (nonatomic, readonly) NSArray *> *allClassProperties; +@property (nonatomic, readonly) NSArray *classProperties; + +@property (nonatomic, readonly) NSArray *> *allIvars; +@property (nonatomic, readonly) NSArray *ivars; + +@property (nonatomic, readonly) NSArray *> *allMethods; +@property (nonatomic, readonly) NSArray *methods; + +@property (nonatomic, readonly) NSArray *> *allClassMethods; +@property (nonatomic, readonly) NSArray *classMethods; + +@property (nonatomic, readonly) NSArray *classHierarchyClasses; +@property (nonatomic, readonly) NSArray *classHierarchy; + +@property (nonatomic, readonly) NSArray *> *allConformedProtocols; +@property (nonatomic, readonly) NSArray *conformedProtocols; + +@property (nonatomic, readonly) NSArray *allInstanceSizes; +@property (nonatomic, readonly) FLEXStaticMetadata *instanceSize; + +@property (nonatomic, readonly) NSArray *allImageNames; +@property (nonatomic, readonly) FLEXStaticMetadata *imageName; + +- (void)reloadMetadata; +- (void)reloadClassHierarchy; + +@end diff --git a/FLEX/FLEXObjectExplorerFactory.h b/FLEX/FLEXObjectExplorerFactory.h new file mode 100644 index 00000000..2d5e8400 --- /dev/null +++ b/FLEX/FLEXObjectExplorerFactory.h @@ -0,0 +1,30 @@ +// +// FLEXObjectExplorerFactory.h +// Flipboard +// +// Created by Ryan Olson on 5/15/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXGlobalsEntry.h" + +#ifndef _FLEXObjectExplorerViewController_h +#import "FLEXObjectExplorerViewController.h" +#else +@class FLEXObjectExplorerViewController; +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXObjectExplorerFactory : NSObject + ++ (nullable FLEXObjectExplorerViewController *)explorerViewControllerForObject:(nullable id)object; + +/// Register a specific explorer view controller class to be used when exploring +/// an object of a specific class. Calls will overwrite existing registrations. +/// Sections must be initialized using \c forObject: like ++ (void)registerExplorerSection:(Class)sectionClass forClass:(Class)objectClass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXObjectExplorerViewController.h b/FLEX/FLEXObjectExplorerViewController.h new file mode 100644 index 00000000..6eab2b0c --- /dev/null +++ b/FLEX/FLEXObjectExplorerViewController.h @@ -0,0 +1,54 @@ +// +// FLEXObjectExplorerViewController.h +// Flipboard +// +// Created by Ryan Olson on 2014-05-03. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#ifndef _FLEXObjectExplorerViewController_h +#define _FLEXObjectExplorerViewController_h +#endif + +#import "FLEXFilteringTableViewController.h" +#import "FLEXObjectExplorer.h" +@class FLEXTableViewSection; + +NS_ASSUME_NONNULL_BEGIN + +/// A class that displays information about an object or class. +/// +/// The explorer view controller uses \c FLEXObjectExplorer to provide a description +/// of the object and list it's properties, ivars, methods, and it's superclasses. +/// Below the description and before properties, some shortcuts will be displayed +/// for certain classes like UIViews. At very bottom, there is an option to view +/// a list of other objects found to be referencing the object being explored. +@interface FLEXObjectExplorerViewController : FLEXFilteringTableViewController + +/// Uses the default \c FLEXShortcutsSection for this object as a custom section. ++ (instancetype)exploringObject:(id)objectOrClass; +/// No custom section unless you provide one. ++ (instancetype)exploringObject:(id)objectOrClass customSection:(nullable FLEXTableViewSection *)customSection; + +/// The object being explored, which may be an instance of a class or a class itself. +@property (nonatomic, readonly) id object; +/// This object provides the object's metadata for the explorer view controller. +@property (nonatomic, readonly) FLEXObjectExplorer *explorer; + +/// Called once to initialize the list of section objects. +/// +/// Subclasses can override this to add, remove, or rearrange sections of the explorer. +- (NSArray *)makeSections; + +/// Whether to allow showing/drilling in to current values for ivars and properties. Default is YES. +@property (nonatomic, readonly) BOOL canHaveInstanceState; + +/// Whether to allow drilling in to method calling interfaces for instance methods. Default is YES. +@property (nonatomic, readonly) BOOL canCallInstanceMethods; + +/// If the custom section data makes the description redundant, subclasses can choose to hide it. Default is YES. +@property (nonatomic, readonly) BOOL shouldShowDescription; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXObjectInfoSection.h b/FLEX/FLEXObjectInfoSection.h new file mode 100644 index 00000000..656955b5 --- /dev/null +++ b/FLEX/FLEXObjectInfoSection.h @@ -0,0 +1,19 @@ +// +// FLEXObjectInfoSection.h +// FLEX +// +// Created by Tanner Bennett on 8/28/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +/// \c FLEXTableViewSection itself doesn't know about the object being explored. +/// Subclasses might need this info to provide useful information about the object. Instead +/// of adding an abstract class to the class hierarchy, subclasses can conform to this protocol +/// to indicate that the only info they need to be initialized is the object being explored. +@protocol FLEXObjectInfoSection + ++ (instancetype)forObject:(id)object; + +@end diff --git a/FLEX/FLEXObjectListViewController.h b/FLEX/FLEXObjectListViewController.h new file mode 100644 index 00000000..f7875c7e --- /dev/null +++ b/FLEX/FLEXObjectListViewController.h @@ -0,0 +1,19 @@ +// +// FLEXObjectListViewController.h +// Flipboard +// +// Created by Ryan Olson on 5/28/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" + +@interface FLEXObjectListViewController : FLEXFilteringTableViewController + +/// This will either return a list of the instances, or take you straight +/// to the explorer itself if there is only one instance. ++ (UIViewController *)instancesOfClassWithName:(NSString *)className; ++ (instancetype)subclassesOfClassWithName:(NSString *)className; ++ (instancetype)objectsWithReferencesToObject:(id)object; + +@end diff --git a/FLEX/FLEXObjectRef.h b/FLEX/FLEXObjectRef.h new file mode 100644 index 00000000..32da8bd6 --- /dev/null +++ b/FLEX/FLEXObjectRef.h @@ -0,0 +1,27 @@ +// +// FLEXObjectRef.h +// FLEX +// +// Created by Tanner Bennett on 7/24/18. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXObjectRef : NSObject + ++ (instancetype)referencing:(id)object; ++ (instancetype)referencing:(id)object ivar:(NSString *)ivarName; + ++ (NSArray *)referencingAll:(NSArray *)objects; +/// Classes do not have a summary, and the reference is just the class name. ++ (NSArray *)referencingClasses:(NSArray *)classes; + +/// For example, "NSString 0x1d4085d0" or "NSLayoutConstraint _object" +@property (nonatomic, readonly) NSString *reference; +/// For instances, this is the result of -[FLEXRuntimeUtility summaryForObject:] +/// For classes, there is no summary. +@property (nonatomic, readonly) NSString *summary; +@property (nonatomic, readonly) id object; + +@end diff --git a/FLEX/FLEXProperty.h b/FLEX/FLEXProperty.h new file mode 100644 index 00000000..03d85099 --- /dev/null +++ b/FLEX/FLEXProperty.h @@ -0,0 +1,134 @@ +// +// FLEXProperty.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/30/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" +@class FLEXPropertyAttributes, FLEXMethodBase; + + +#pragma mark FLEXProperty +@interface FLEXProperty : NSObject + +/// You may use this initializer instead of \c property:onClass: if you don't need +/// to know anything about the uniqueness of this property or where it comes from. ++ (instancetype)property:(objc_property_t)property; +/// This initializer can be used to access additional information +/// in an efficient manner. That information being whether this property +/// is certainly not unique and the name of the binary image which declares it. +/// @param cls the class, or metaclass if this is a class property. ++ (instancetype)property:(objc_property_t)property onClass:(Class)cls; +/// @param cls the class, or metaclass if this is a class property ++ (instancetype)named:(NSString *)name onClass:(Class)cls; +/// Constructs a new property with the given name and attributes. ++ (instancetype)propertyWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes; + +/// \c 0 if the instance was created via \c +propertyWithName:attributes, +/// otherwise this is the first property in \c objc_properties +@property (nonatomic, readonly) objc_property_t objc_property; +@property (nonatomic, readonly) objc_property_t *objc_properties; +@property (nonatomic, readonly) NSInteger objc_propertyCount; +@property (nonatomic, readonly) BOOL isClassProperty; + +/// The name of the property. +@property (nonatomic, readonly) NSString *name; +/// The type of the property. Get the full type from the attributes. +@property (nonatomic, readonly) FLEXTypeEncoding type; +/// The property's attributes. +@property (nonatomic ) FLEXPropertyAttributes *attributes; +/// The (likely) setter, regardless of whether the property is readonly. +/// For example, this might be the custom setter. +@property (nonatomic, readonly) SEL likelySetter; +@property (nonatomic, readonly) NSString *likelySetterString; +/// Not valid unless initialized with the owning class. +@property (nonatomic, readonly) BOOL likelySetterExists; +/// The (likely) getter. For example, this might be the custom getter. +@property (nonatomic, readonly) SEL likelyGetter; +@property (nonatomic, readonly) NSString *likelyGetterString; +/// Not valid unless initialized with the owning class. +@property (nonatomic, readonly) BOOL likelyGetterExists; + +/// Whether there are certainly multiple definitions of this property, +/// such as in categories in other binary images or something. +/// @return Whether \c objc_property matches the return value of \c class_getProperty, +/// or \c NO if this property was not created with \c property:onClass +@property (nonatomic, readonly) BOOL multiple; +/// @return The bundle of the image that contains this property definition, +/// or \c nil if this property was not created with \c property:onClass or +/// if this property was probably defined at runtime. +@property (nonatomic, readonly) NSString *imageName; +/// The full path of the image that contains this property definition, +/// or \c nil if this property was not created with \c property:onClass or +/// if this property was probably defined at runtime. +@property (nonatomic, readonly) NSString *imagePath; + +/// For internal use +@property (nonatomic) id tag; + +/// @return The value of this property on \c target as given by \c -valueForKey: +/// A source-like description of the property, with all of its attributes. +@property (nonatomic, readonly) NSString *fullDescription; + +/// If this is a class property, you must class the class object. +- (id)getValue:(id)target; +/// Calls into -getValue: and passes that value into +/// -[FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:type:] +/// and returns the result. +/// +/// If this is a class property, you must class the class object. +- (id)getPotentiallyUnboxedValue:(id)target; + +/// Safe to use regardless of how the \c FLEXProperty instance was initialized. +/// +/// This uses \c self.objc_property if it exists, otherwise it uses \c self.attributes +- (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount; + +/// Replace the attributes of the current property in the given class, +/// using the attributes in \c self.attributes +/// +/// What happens when the property does not exist is undocumented. +- (void)replacePropertyOnClass:(Class)cls; + +#pragma mark Convenience getters and setters +/// @return A getter for the property with the given implementation. +/// @discussion Consider using the \c FLEXPropertyGetter macros. +- (FLEXMethodBase *)getterWithImplementation:(IMP)implementation; +/// @return A setter for the property with the given implementation. +/// @discussion Consider using the \c FLEXPropertySetter macros. +- (FLEXMethodBase *)setterWithImplementation:(IMP)implementation; + +#pragma mark FLEXMethod property getter / setter macros +// Easier than using the above methods yourself in most cases + +/// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and +/// uses the \c FLEXProperty's \c attribute's \c backingIvarName to get the Ivar. +#define FLEXPropertyGetter(FLEXProperty, type) [FLEXProperty \ + getterWithImplementation:imp_implementationWithBlock(^(id self) { \ + return *(type *)[self getIvarAddressByName:FLEXProperty.attributes.backingIvar]; \ + }) \ +]; +/// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and +/// uses the \c FLEXProperty's \c attribute's \c backingIvarName to set the Ivar. +#define FLEXPropertySetter(FLEXProperty, type) [FLEXProperty \ + setterWithImplementation:imp_implementationWithBlock(^(id self, type value) { \ + [self setIvarByName:FLEXProperty.attributes.backingIvar value:&value size:sizeof(type)]; \ + }) \ +]; +/// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and an Ivar name string to get the Ivar. +#define FLEXPropertyGetterWithIvar(FLEXProperty, ivarName, type) [FLEXProperty \ + getterWithImplementation:imp_implementationWithBlock(^(id self) { \ + return *(type *)[self getIvarAddressByName:ivarName]; \ + }) \ +]; +/// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and an Ivar name string to set the Ivar. +#define FLEXPropertySetterWithIvar(FLEXProperty, ivarName, type) [FLEXProperty \ + setterWithImplementation:imp_implementationWithBlock(^(id self, type value) { \ + [self setIvarByName:ivarName value:&value size:sizeof(type)]; \ + }) \ +]; + +@end diff --git a/FLEX/FLEXPropertyAttributes.h b/FLEX/FLEXPropertyAttributes.h new file mode 100644 index 00000000..e5771018 --- /dev/null +++ b/FLEX/FLEXPropertyAttributes.h @@ -0,0 +1,110 @@ +// +// FLEXPropertyAttributes.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/5/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark FLEXPropertyAttributes + +/// See \e FLEXRuntimeUtilitiy.h for valid string tokens. +/// See this link on how to construct a proper attributes string: +/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html +@interface FLEXPropertyAttributes : NSObject { +// These are necessary for the mutable subclass to function +@protected + NSUInteger _count; + NSString *_string, *_backingIvar, *_typeEncoding, *_oldTypeEncoding, *_fullDeclaration; + NSDictionary *_dictionary; + objc_property_attribute_t *_list; + SEL _customGetter, _customSetter; + BOOL _isReadOnly, _isCopy, _isRetained, _isNonatomic, _isDynamic, _isWeak, _isGarbageCollectable; +} + ++ (instancetype)attributesForProperty:(objc_property_t)property; +/// @warning Raises an exception if \e attributes is invalid, \c nil, or contains unsupported keys. ++ (instancetype)attributesFromDictionary:(NSDictionary *)attributes; + +/// Copies the attributes list to a buffer you must \c free() yourself. +/// Use \c list instead if you do not need more control over the lifetime of the list. +/// @param attributesCountOut the number of attributes is returned in this parameter. +- (objc_property_attribute_t *)copyAttributesList:(nullable unsigned int *)attributesCountOut; + +/// The number of property attributes. +@property (nonatomic, readonly) NSUInteger count; +/// For use with \c class_replaceProperty and the like. +@property (nonatomic, readonly) objc_property_attribute_t *list; +/// The string value of the property attributes. +@property (nonatomic, readonly) NSString *string; +/// A human-readable version of the property attributes. +@property (nonatomic, readonly) NSString *fullDeclaration; +/// A dictionary of the property attributes. +/// Values are either a string or \c YES. Boolean attributes +/// which are false will not be present in the dictionary. +@property (nonatomic, readonly) NSDictionary *dictionary; + +/// The name of the instance variable backing the property. +@property (nonatomic, readonly, nullable) NSString *backingIvar; +/// The type encoding of the property. +@property (nonatomic, readonly, nullable) NSString *typeEncoding; +/// The \e old type encoding of the property. +@property (nonatomic, readonly, nullable) NSString *oldTypeEncoding; +/// The property's custom getter, if any. +@property (nonatomic, readonly, nullable) SEL customGetter; +/// The property's custom setter, if any. +@property (nonatomic, readonly, nullable) SEL customSetter; +/// The property's custom getter as a string, if any. +@property (nonatomic, readonly, nullable) NSString *customGetterString; +/// The property's custom setter as a string, if any. +@property (nonatomic, readonly, nullable) NSString *customSetterString; + +@property (nonatomic, readonly) BOOL isReadOnly; +@property (nonatomic, readonly) BOOL isCopy; +@property (nonatomic, readonly) BOOL isRetained; +@property (nonatomic, readonly) BOOL isNonatomic; +@property (nonatomic, readonly) BOOL isDynamic; +@property (nonatomic, readonly) BOOL isWeak; +@property (nonatomic, readonly) BOOL isGarbageCollectable; + +@end + + +#pragma mark FLEXPropertyAttributes +@interface FLEXMutablePropertyAttributes : FLEXPropertyAttributes + +/// Creates and returns an empty property attributes object. ++ (instancetype)attributes; + +/// The name of the instance variable backing the property. +@property (nonatomic, nullable) NSString *backingIvar; +/// The type encoding of the property. +@property (nonatomic, nullable) NSString *typeEncoding; +/// The \e old type encoding of the property. +@property (nonatomic, nullable) NSString *oldTypeEncoding; +/// The property's custom getter, if any. +@property (nonatomic, nullable) SEL customGetter; +/// The property's custom setter, if any. +@property (nonatomic, nullable) SEL customSetter; + +@property (nonatomic) BOOL isReadOnly; +@property (nonatomic) BOOL isCopy; +@property (nonatomic) BOOL isRetained; +@property (nonatomic) BOOL isNonatomic; +@property (nonatomic) BOOL isDynamic; +@property (nonatomic) BOOL isWeak; +@property (nonatomic) BOOL isGarbageCollectable; + +/// A more convenient method of setting the \c typeEncoding property. +/// @discussion This will not work for complex types like structs and primitive pointers. +- (void)setTypeEncodingChar:(char)type; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXProtocol.h b/FLEX/FLEXProtocol.h new file mode 100644 index 00000000..ba1a9542 --- /dev/null +++ b/FLEX/FLEXProtocol.h @@ -0,0 +1,69 @@ +// +// FLEXProtocol.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/30/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" +@class FLEXProperty, FLEXMethodDescription; + +#pragma mark FLEXProtocol +@interface FLEXProtocol : NSObject + +/// Every protocol registered with the runtime. ++ (NSArray *)allProtocols; ++ (instancetype)protocol:(Protocol *)protocol; + +/// The underlying protocol data structure. +@property (nonatomic, readonly) Protocol *objc_protocol; + +/// The name of the protocol. +@property (nonatomic, readonly) NSString *name; +/// The required methods of the protocol, if any. This includes property getters and setters. +@property (nonatomic, readonly) NSArray *requiredMethods; +/// The optional methods of the protocol, if any. This includes property getters and setters. +@property (nonatomic, readonly) NSArray *optionalMethods; +/// All protocols that this protocol conforms to, if any. +@property (nonatomic, readonly) NSArray *protocols; +/// The full path of the image that contains this protocol definition, +/// or \c nil if this protocol was probably defined at runtime. +@property (nonatomic, readonly) NSString *imagePath; + +/// The properties in the protocol, if any. \c nil on iOS 10+ +@property (nonatomic, readonly) NSArray *properties API_DEPRECATED("Use the more specific accessors below", ios(2.0, 10.0)); + +/// The required properties in the protocol, if any. +@property (nonatomic, readonly) NSArray *requiredProperties API_AVAILABLE(ios(10.0)); +/// The optional properties in the protocol, if any. +@property (nonatomic, readonly) NSArray *optionalProperties API_AVAILABLE(ios(10.0)); + +/// For internal use +@property (nonatomic) id tag; + +/// Not to be confused with \c -conformsToProtocol:, which refers to the current +/// \c FLEXProtocol instance and not the underlying \c Protocol object. +- (BOOL)conformsTo:(Protocol *)protocol; + +@end + + +#pragma mark Method descriptions +@interface FLEXMethodDescription : NSObject + ++ (instancetype)description:(struct objc_method_description)description; ++ (instancetype)description:(struct objc_method_description)description instance:(BOOL)isInstance; + +/// The underlying method description data structure. +@property (nonatomic, readonly) struct objc_method_description objc_description; +/// The method's selector. +@property (nonatomic, readonly) SEL selector; +/// The method's type encoding. +@property (nonatomic, readonly) NSString *typeEncoding; +/// The method's return type. +@property (nonatomic, readonly) FLEXTypeEncoding returnType; +/// \c YES if this is an instance method, \c NO if it is a class method, or \c nil if unspecified +@property (nonatomic, readonly) NSNumber *instance; +@end diff --git a/FLEX/FLEXProtocolBuilder.h b/FLEX/FLEXProtocolBuilder.h new file mode 100644 index 00000000..e855cd3c --- /dev/null +++ b/FLEX/FLEXProtocolBuilder.h @@ -0,0 +1,41 @@ +// +// FLEXProtocolBuilder.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/4/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +@class FLEXProperty, FLEXProtocol, Protocol; + +@interface FLEXProtocolBuilder : NSObject + +/// Begins to construct a new protocol with the given name. +/// @discussion You must register the protocol with the +/// \c registerProtocol method before you can use it. ++ (instancetype)allocateProtocol:(NSString *)name; + +/// Adds a property to a protocol. +/// @param property The property to add. +/// @param isRequired Whether the property is required to implement the protocol. +- (void)addProperty:(FLEXProperty *)property isRequired:(BOOL)isRequired; +/// Adds a property to a protocol. +/// @param selector The selector of the method to add. +/// @param typeEncoding The type encoding of the method to add. +/// @param isRequired Whether the method is required to implement the protocol. +/// @param isInstanceMethod \c YES if the method is an instance method, \c NO if it is a class method. +- (void)addMethod:(SEL)selector + typeEncoding:(NSString *)typeEncoding + isRequired:(BOOL)isRequired + isInstanceMethod:(BOOL)isInstanceMethod; +/// Makes the recieving protocol conform to the given protocol. +- (void)addProtocol:(Protocol *)protocol; + +/// Registers and returns the recieving protocol, which was previously under construction. +- (FLEXProtocol *)registerProtocol; +/// Whether the protocol is still under construction or already registered. +@property (nonatomic, readonly) BOOL isRegistered; + +@end diff --git a/FLEX/FLEXRealmDatabaseManager.h b/FLEX/FLEXRealmDatabaseManager.h new file mode 100644 index 00000000..44c78fb3 --- /dev/null +++ b/FLEX/FLEXRealmDatabaseManager.h @@ -0,0 +1,14 @@ +// +// FLEXRealmDatabaseManager.h +// FLEX +// +// Created by Tim Oliver on 28/01/2016. +// Copyright © 2016 Realm. All rights reserved. +// + +#import +#import "FLEXDatabaseManager.h" + +@interface FLEXRealmDatabaseManager : NSObject + +@end diff --git a/FLEX/FLEXRealmDefines.h b/FLEX/FLEXRealmDefines.h new file mode 100644 index 00000000..992429a9 --- /dev/null +++ b/FLEX/FLEXRealmDefines.h @@ -0,0 +1,46 @@ +// +// Realm.h +// FLEX +// +// Created by Tim Oliver on 16/02/2016. +// Copyright © 2016 Realm. All rights reserved. +// + +#if __has_include() +#else + +@class RLMObject, RLMResults, RLMRealm, RLMRealmConfiguration, RLMSchema, RLMObjectSchema, RLMProperty; + +@interface RLMRealmConfiguration : NSObject +@property (nonatomic, copy) NSURL *fileURL; +@end + +@interface RLMRealm : NSObject +@property (nonatomic, readonly) RLMSchema *schema; ++ (RLMRealm *)realmWithConfiguration:(RLMRealmConfiguration *)configuration error:(NSError **)error; +- (RLMResults *)allObjects:(NSString *)className; +@end + +@interface RLMSchema : NSObject +@property (nonatomic, readonly) NSArray *objectSchema; +- (RLMObjectSchema *)schemaForClassName:(NSString *)className; +@end + +@interface RLMObjectSchema : NSObject +@property (nonatomic, readonly) NSString *className; +@property (nonatomic, readonly) NSArray *properties; +@end + +@interface RLMProperty : NSString +@property (nonatomic, readonly) NSString *name; +@end + +@interface RLMResults : NSObject +@property (nonatomic, readonly) NSInteger count; +@end + +@interface RLMObject : NSObject + +@end + +#endif diff --git a/FLEX/FLEXResources.h b/FLEX/FLEXResources.h new file mode 100644 index 00000000..563be1e4 --- /dev/null +++ b/FLEX/FLEXResources.h @@ -0,0 +1,59 @@ +// +// FLEXResources.h +// FLEX +// +// Created by Ryan Olson on 6/8/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXResources : NSObject + +#pragma mark - FLEX Toolbar Icons + +@property (readonly, class) UIImage *closeIcon; +@property (readonly, class) UIImage *dragHandle; +@property (readonly, class) UIImage *globalsIcon; +@property (readonly, class) UIImage *hierarchyIcon; +@property (readonly, class) UIImage *recentIcon; +@property (readonly, class) UIImage *moveIcon; +@property (readonly, class) UIImage *selectIcon; + +#pragma mark - Toolbar Icons + +@property (readonly, class) UIImage *bookmarksIcon; +@property (readonly, class) UIImage *openTabsIcon; +@property (readonly, class) UIImage *moreIcon; +@property (readonly, class) UIImage *gearIcon; +@property (readonly, class) UIImage *scrollToBottomIcon; + +#pragma mark - Content Type Icons + +@property (readonly, class) UIImage *jsonIcon; +@property (readonly, class) UIImage *textPlainIcon; +@property (readonly, class) UIImage *htmlIcon; +@property (readonly, class) UIImage *audioIcon; +@property (readonly, class) UIImage *jsIcon; +@property (readonly, class) UIImage *plistIcon; +@property (readonly, class) UIImage *textIcon; +@property (readonly, class) UIImage *videoIcon; +@property (readonly, class) UIImage *xmlIcon; +@property (readonly, class) UIImage *binaryIcon; + +#pragma mark - 3D Explorer Icons + +@property (readonly, class) UIImage *toggle2DIcon; +@property (readonly, class) UIImage *toggle3DIcon; +@property (readonly, class) UIImage *rangeSliderLeftHandle; +@property (readonly, class) UIImage *rangeSliderRightHandle; +@property (readonly, class) UIImage *rangeSliderTrack; +@property (readonly, class) UIImage *rangeSliderFill; + +#pragma mark - Misc Icons + +@property (readonly, class) UIImage *checkerPattern; +@property (readonly, class) UIColor *checkerPatternColor; +@property (readonly, class) UIImage *hierarchyIndentPattern; + +@end diff --git a/FLEX/FLEXRuntime+Compare.h b/FLEX/FLEXRuntime+Compare.h new file mode 100644 index 00000000..7c602f3f --- /dev/null +++ b/FLEX/FLEXRuntime+Compare.h @@ -0,0 +1,29 @@ +// +// FLEXRuntime+Compare.h +// FLEX +// +// Created by Tanner Bennett on 8/28/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXProperty.h" +#import "FLEXIvar.h" +#import "FLEXMethodBase.h" +#import "FLEXProtocol.h" + +@interface FLEXProperty (Compare) +- (NSComparisonResult)compare:(FLEXProperty *)other; +@end + +@interface FLEXIvar (Compare) +- (NSComparisonResult)compare:(FLEXIvar *)other; +@end + +@interface FLEXMethodBase (Compare) +- (NSComparisonResult)compare:(FLEXMethodBase *)other; +@end + +@interface FLEXProtocol (Compare) +- (NSComparisonResult)compare:(FLEXProtocol *)other; +@end diff --git a/FLEX/FLEXRuntime+UIKitHelpers.h b/FLEX/FLEXRuntime+UIKitHelpers.h new file mode 100644 index 00000000..c070e73a --- /dev/null +++ b/FLEX/FLEXRuntime+UIKitHelpers.h @@ -0,0 +1,94 @@ +// +// FLEXRuntime+UIKitHelpers.h +// FLEX +// +// Created by Tanner Bennett on 12/16/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXProperty.h" +#import "FLEXIvar.h" +#import "FLEXMethod.h" +#import "FLEXProtocol.h" +#import "FLEXTableViewSection.h" + +@class FLEXObjectExplorerDefaults; + +/// Model objects of an object explorer screen adopt this +/// protocol in order respond to user defaults changes +@protocol FLEXObjectExplorerItem +/// Current explorer settings. Set when settings change. +@property (nonatomic) FLEXObjectExplorerDefaults *defaults; + +/// YES for properties and ivars which surely support editing, NO for all methods. +@property (nonatomic, readonly) BOOL isEditable; +/// NO for ivars, YES for supported methods and properties +@property (nonatomic, readonly) BOOL isCallable; +@end + +@protocol FLEXRuntimeMetadata +/// Used as the main title of the row +- (NSString *)description; +/// Used to compare metadata objects for uniqueness +@property (nonatomic, readonly) NSString *name; + +/// For internal use +@property (nonatomic) id tag; + +/// Should return \c nil if not applicable +- (id)currentValueWithTarget:(id)object; +/// Used as the subtitle or description of a property, ivar, or method +- (NSString *)previewWithTarget:(id)object; +/// For methods, a method calling screen. For all else, an object explorer. +- (UIViewController *)viewerWithTarget:(id)object; +/// For methods and protocols, nil. For all else, an a field editor screen. +/// The given section is reloaded on commit of any changes. +- (UIViewController *)editorWithTarget:(id)object section:(FLEXTableViewSection *)section; +/// Used to determine present which interactions are possible to the user +- (UITableViewCellAccessoryType)suggestedAccessoryTypeWithTarget:(id)object; +/// Return nil to use the default reuse identifier +- (NSString *)reuseIdentifierWithTarget:(id)object; + +#if FLEX_AT_LEAST_IOS13_SDK + +/// An array of actions to place in the first section of the context menu. +- (NSArray *)additionalActionsWithTarget:(id)object sender:(UIViewController *)sender API_AVAILABLE(ios(13.0)); +/// An array where every 2 elements are a key-value pair. The key is a description +/// of what to copy like "Name" and the values are what will be copied. +- (NSArray *)copiableMetadataWithTarget:(id)object; +/// Properties and ivars return the address of an object, if they hold one. +- (NSString *)contextualSubtitleWithTarget:(id)object; + +#endif + +@end + +// Even if a property is readonly, it still may be editable +// via a setter. Checking isEditable will not reflect that +// unless the property was initialized with a class. +@interface FLEXProperty (UIKitHelpers) @end +@interface FLEXIvar (UIKitHelpers) @end +@interface FLEXMethodBase (UIKitHelpers) @end +@interface FLEXMethod (UIKitHelpers) @end +@interface FLEXProtocol (UIKitHelpers) @end + +typedef NS_ENUM(NSUInteger, FLEXStaticMetadataRowStyle) { + FLEXStaticMetadataRowStyleSubtitle, + FLEXStaticMetadataRowStyleKeyValue, + FLEXStaticMetadataRowStyleDefault = FLEXStaticMetadataRowStyleSubtitle, +}; + +/// Displays a small row as a static key-value pair of information. +@interface FLEXStaticMetadata : NSObject + ++ (instancetype)style:(FLEXStaticMetadataRowStyle)style title:(NSString *)title string:(NSString *)string; ++ (instancetype)style:(FLEXStaticMetadataRowStyle)style title:(NSString *)title number:(NSNumber *)number; + ++ (NSArray *)classHierarchy:(NSArray *)classes; + +@end + + +/// This is assigned to the \c tag property of each metadata. + diff --git a/FLEX/FLEXRuntimeBrowserToolbar.h b/FLEX/FLEXRuntimeBrowserToolbar.h new file mode 100644 index 00000000..ca917e85 --- /dev/null +++ b/FLEX/FLEXRuntimeBrowserToolbar.h @@ -0,0 +1,18 @@ +// +// FLEXRuntimeBrowserToolbar.h +// FLEX +// +// Created by Tanner on 6/11/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXKeyboardToolbar.h" +#import "FLEXRuntimeKeyPath.h" + +@interface FLEXRuntimeBrowserToolbar : FLEXKeyboardToolbar + ++ (instancetype)toolbarWithHandler:(FLEXKBToolbarAction)tapHandler suggestions:(NSArray *)suggestions; + +- (void)setKeyPath:(FLEXRuntimeKeyPath *)keyPath suggestions:(NSArray *)suggestions; + +@end diff --git a/FLEX/FLEXRuntimeClient.h b/FLEX/FLEXRuntimeClient.h new file mode 100644 index 00000000..03f263d7 --- /dev/null +++ b/FLEX/FLEXRuntimeClient.h @@ -0,0 +1,54 @@ +// +// FLEXRuntimeClient.h +// FLEX +// +// Created by Tanner on 3/22/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXSearchToken.h" +@class FLEXMethod; + +/// Accepts runtime queries given a token. +@interface FLEXRuntimeClient : NSObject + +@property (nonatomic, readonly, class) FLEXRuntimeClient *runtime; + +/// Called automatically when \c FLEXRuntime is first used. +/// You may call it again when you think a library has +/// been loaded since this method was first called. +- (void)reloadLibrariesList; + +/// You must call this method on the main thread +/// before you attempt to call \c copySafeClassList. ++ (void)initializeWebKitLegacy; + +/// Do not call unless you absolutely need all classes. This will cause +/// every class in the runtime to initialize itself, which is not common. +/// Before you call this method, call \c initializeWebKitLegacy on the main thread. +- (NSArray *)copySafeClassList; + +- (NSArray *)copyProtocolList; + +/// An array of strings representing the currently loaded libraries. +@property (nonatomic, readonly) NSArray *imageDisplayNames; + +/// "Image name" is the path of the bundle +- (NSString *)shortNameForImageName:(NSString *)imageName; +/// "Image name" is the path of the bundle +- (NSString *)imageNameForShortName:(NSString *)imageName; + +/// @return Bundle names for the UI +- (NSMutableArray *)bundleNamesForToken:(FLEXSearchToken *)token; +/// @return Bundle paths for more queries +- (NSMutableArray *)bundlePathsForToken:(FLEXSearchToken *)token; +/// @return Class names +- (NSMutableArray *)classesForToken:(FLEXSearchToken *)token + inBundles:(NSMutableArray *)bundlePaths; +/// @return A list of lists of \c FLEXMethods where +/// each list corresponds to one of the given classes +- (NSArray *> *)methodsForToken:(FLEXSearchToken *)token + instance:(NSNumber *)onlyInstanceMethods + inClasses:(NSArray *)classes; + +@end diff --git a/FLEX/FLEXRuntimeConstants.h b/FLEX/FLEXRuntimeConstants.h new file mode 100644 index 00000000..ddeb0d9a --- /dev/null +++ b/FLEX/FLEXRuntimeConstants.h @@ -0,0 +1,79 @@ +// +// FLEXRuntimeConstants.h +// FLEX +// +// Created by Tanner on 3/11/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import + +#define FLEXEncodeClass(class) ("@\"" #class "\"") +#define FLEXEncodeObject(obj) (obj ? [NSString stringWithFormat:@"@\"%@\"", [obj class]].UTF8String : @encode(id)) + +// Arguments 0 and 1 are self and _cmd always +extern const unsigned int kFLEXNumberOfImplicitArgs; + +// See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6 +extern NSString *const kFLEXPropertyAttributeKeyTypeEncoding; +extern NSString *const kFLEXPropertyAttributeKeyBackingIvarName; +extern NSString *const kFLEXPropertyAttributeKeyReadOnly; +extern NSString *const kFLEXPropertyAttributeKeyCopy; +extern NSString *const kFLEXPropertyAttributeKeyRetain; +extern NSString *const kFLEXPropertyAttributeKeyNonAtomic; +extern NSString *const kFLEXPropertyAttributeKeyCustomGetter; +extern NSString *const kFLEXPropertyAttributeKeyCustomSetter; +extern NSString *const kFLEXPropertyAttributeKeyDynamic; +extern NSString *const kFLEXPropertyAttributeKeyWeak; +extern NSString *const kFLEXPropertyAttributeKeyGarbageCollectable; +extern NSString *const kFLEXPropertyAttributeKeyOldStyleTypeEncoding; + +typedef NS_ENUM(NSUInteger, FLEXPropertyAttribute) { + FLEXPropertyAttributeTypeEncoding = 'T', + FLEXPropertyAttributeBackingIvarName = 'V', + FLEXPropertyAttributeCopy = 'C', + FLEXPropertyAttributeCustomGetter = 'G', + FLEXPropertyAttributeCustomSetter = 'S', + FLEXPropertyAttributeDynamic = 'D', + FLEXPropertyAttributeGarbageCollectible = 'P', + FLEXPropertyAttributeNonAtomic = 'N', + FLEXPropertyAttributeOldTypeEncoding = 't', + FLEXPropertyAttributeReadOnly = 'R', + FLEXPropertyAttributeRetain = '&', + FLEXPropertyAttributeWeak = 'W' +}; + +typedef NS_ENUM(char, FLEXTypeEncoding) { + FLEXTypeEncodingNull = '\0', + FLEXTypeEncodingUnknown = '?', + FLEXTypeEncodingChar = 'c', + FLEXTypeEncodingInt = 'i', + FLEXTypeEncodingShort = 's', + FLEXTypeEncodingLong = 'l', + FLEXTypeEncodingLongLong = 'q', + FLEXTypeEncodingUnsignedChar = 'C', + FLEXTypeEncodingUnsignedInt = 'I', + FLEXTypeEncodingUnsignedShort = 'S', + FLEXTypeEncodingUnsignedLong = 'L', + FLEXTypeEncodingUnsignedLongLong = 'Q', + FLEXTypeEncodingFloat = 'f', + FLEXTypeEncodingDouble = 'd', + FLEXTypeEncodingLongDouble = 'D', + FLEXTypeEncodingCBool = 'B', + FLEXTypeEncodingVoid = 'v', + FLEXTypeEncodingCString = '*', + FLEXTypeEncodingObjcObject = '@', + FLEXTypeEncodingObjcClass = '#', + FLEXTypeEncodingSelector = ':', + FLEXTypeEncodingArrayBegin = '[', + FLEXTypeEncodingArrayEnd = ']', + FLEXTypeEncodingStructBegin = '{', + FLEXTypeEncodingStructEnd = '}', + FLEXTypeEncodingUnionBegin = '(', + FLEXTypeEncodingUnionEnd = ')', + FLEXTypeEncodingQuote = '\"', + FLEXTypeEncodingBitField = 'b', + FLEXTypeEncodingPointer = '^', + FLEXTypeEncodingConst = 'r' +}; diff --git a/FLEX/FLEXRuntimeController.h b/FLEX/FLEXRuntimeController.h new file mode 100644 index 00000000..968c975d --- /dev/null +++ b/FLEX/FLEXRuntimeController.h @@ -0,0 +1,36 @@ +// +// FLEXRuntimeController.h +// FLEX +// +// Created by Tanner on 3/23/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXRuntimeKeyPath.h" + +/// Wraps FLEXRuntimeClient and provides extra caching mechanisms +@interface FLEXRuntimeController : NSObject + +/// @return An array of strings if the key path only evaluates +/// to a class or bundle; otherwise, a list of lists of FLEXMethods. ++ (NSArray *)dataForKeyPath:(FLEXRuntimeKeyPath *)keyPath; + +/// Useful when you need to specify which classes to search in. +/// \c dataForKeyPath: will only search classes matching the class key. +/// We use this elsewhere when we need to search a class hierarchy. ++ (NSArray *> *)methodsForToken:(FLEXSearchToken *)token + instance:(NSNumber *)onlyInstanceMethods + inClasses:(NSArray *)classes; + +/// Useful when you need the classes that are associated with the +/// double list of methods returned from \c dataForKeyPath ++ (NSMutableArray *)classesForKeyPath:(FLEXRuntimeKeyPath *)keyPath; + ++ (NSString *)shortBundleNameForClass:(NSString *)name; + ++ (NSString *)imagePathWithShortName:(NSString *)suffix; + +/// Gives back short names. For example, "Foundation.framework" ++ (NSArray *)allBundleNames; + +@end diff --git a/FLEX/FLEXRuntimeExporter.h b/FLEX/FLEXRuntimeExporter.h new file mode 100644 index 00000000..69ce1cf8 --- /dev/null +++ b/FLEX/FLEXRuntimeExporter.h @@ -0,0 +1,29 @@ +// +// FLEXRuntimeExporter.h +// FLEX +// +// Created by Tanner Bennett on 3/26/20. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A class for exporting all runtime metadata to an SQLite database. +//API_AVAILABLE(ios(10.0)) +@interface FLEXRuntimeExporter : NSObject + ++ (void)createRuntimeDatabaseAtPath:(NSString *)path + progressHandler:(void(^)(NSString *status))progress + completion:(void(^)(NSString *_Nullable error))completion; + ++ (void)createRuntimeDatabaseAtPath:(NSString *)path + forImages:(nullable NSArray *)images + progressHandler:(void(^)(NSString *status))progress + completion:(void(^)(NSString *_Nullable error))completion; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXRuntimeKeyPath.h b/FLEX/FLEXRuntimeKeyPath.h new file mode 100644 index 00000000..7babe801 --- /dev/null +++ b/FLEX/FLEXRuntimeKeyPath.h @@ -0,0 +1,43 @@ +// +// FLEXRuntimeKeyPath.h +// FLEX +// +// Created by Tanner on 3/22/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXSearchToken.h" +@class FLEXMethod; + +NS_ASSUME_NONNULL_BEGIN + +/// A key path represents a query into a set of bundles or classes +/// for a set of one or more methods. It is composed of three tokens: +/// bundle, class, and method. A key path may be incomplete if it +/// is missing any of the tokens. A key path is considered "absolute" +/// if all tokens have no options and if methodKey.string begins +/// with a + or a -. +/// +/// The @code TBKeyPathTokenizer @endcode class is used to create +/// a key path from a string. +@interface FLEXRuntimeKeyPath : NSObject + ++ (instancetype)empty; + +/// @param method must start with either a wildcard or a + or -. ++ (instancetype)bundle:(FLEXSearchToken *)bundle + class:(FLEXSearchToken *)cls + method:(FLEXSearchToken *)method + isInstance:(NSNumber *)instance + string:(NSString *)keyPathString; + +@property (nonatomic, nullable, readonly) FLEXSearchToken *bundleKey; +@property (nonatomic, nullable, readonly) FLEXSearchToken *classKey; +@property (nonatomic, nullable, readonly) FLEXSearchToken *methodKey; + +/// Indicates whether the method token specifies instance methods. +/// Nil if not specified. +@property (nonatomic, nullable, readonly) NSNumber *instanceMethods; + +@end +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXRuntimeKeyPathTokenizer.h b/FLEX/FLEXRuntimeKeyPathTokenizer.h new file mode 100644 index 00000000..1e8f6872 --- /dev/null +++ b/FLEX/FLEXRuntimeKeyPathTokenizer.h @@ -0,0 +1,18 @@ +// +// FLEXRuntimeKeyPathTokenizer.h +// FLEX +// +// Created by Tanner on 3/22/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXRuntimeKeyPath.h" + +@interface FLEXRuntimeKeyPathTokenizer : NSObject + ++ (NSUInteger)tokenCountOfString:(NSString *)userInput; ++ (FLEXRuntimeKeyPath *)tokenizeString:(NSString *)userInput; + ++ (BOOL)allowedInKeyPath:(NSString *)text; + +@end diff --git a/FLEX/FLEXRuntimeSafety.h b/FLEX/FLEXRuntimeSafety.h new file mode 100644 index 00000000..126f84f1 --- /dev/null +++ b/FLEX/FLEXRuntimeSafety.h @@ -0,0 +1,56 @@ +// +// FLEXRuntimeSafety.h +// FLEX +// +// Created by Tanner on 3/25/17. +// + +#import +#import + +#pragma mark - Classes + +extern NSUInteger const kFLEXKnownUnsafeClassCount; +extern const Class * FLEXKnownUnsafeClassList(void); +extern NSSet * FLEXKnownUnsafeClassNames(void); +extern CFSetRef FLEXKnownUnsafeClasses; + +static Class cNSObject = nil, cNSProxy = nil; + +__attribute__((constructor)) +static void FLEXInitKnownRootClasses() { + cNSObject = [NSObject class]; + cNSProxy = [NSProxy class]; +} + +static inline BOOL FLEXClassIsSafe(Class cls) { + // Is it nil or known to be unsafe? + if (!cls || CFSetContainsValue(FLEXKnownUnsafeClasses, (__bridge void *)cls)) { + return NO; + } + + // Is it a known root class? + if (!class_getSuperclass(cls)) { + return cls == cNSObject || cls == cNSProxy; + } + + // Probably safe + return YES; +} + +static inline BOOL FLEXClassNameIsSafe(NSString *cls) { + if (!cls) return NO; + + NSSet *ignored = FLEXKnownUnsafeClassNames(); + return ![ignored containsObject:cls]; +} + +#pragma mark - Ivars + +extern CFSetRef FLEXKnownUnsafeIvars; + +static inline BOOL FLEXIvarIsSafe(Ivar ivar) { + if (!ivar) return NO; + + return !CFSetContainsValue(FLEXKnownUnsafeIvars, ivar); +} diff --git a/FLEX/FLEXRuntimeUtility.h b/FLEX/FLEXRuntimeUtility.h new file mode 100644 index 00000000..d6141d00 --- /dev/null +++ b/FLEX/FLEXRuntimeUtility.h @@ -0,0 +1,93 @@ +// +// FLEXRuntimeUtility.h +// Flipboard +// +// Created by Ryan Olson on 6/8/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" + +#define PropertyKey(suffix) kFLEXPropertyAttributeKey##suffix : @"" +#define PropertyKeyGetter(getter) kFLEXPropertyAttributeKeyCustomGetter : NSStringFromSelector(@selector(getter)) +#define PropertyKeySetter(setter) kFLEXPropertyAttributeKeyCustomSetter : NSStringFromSelector(@selector(setter)) + +/// Takes: min iOS version, property name, target class, property type, and a list of attributes +#define FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, type, ...) ({ \ + if (@available(iOS iOS_atLeast, *)) { \ + NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithDictionary:@{ \ + kFLEXPropertyAttributeKeyTypeEncoding : @(type), \ + __VA_ARGS__ \ + }]; \ + [FLEXRuntimeUtility \ + tryAddPropertyWithName:#name \ + attributes:attrs \ + toClass:cls \ + ]; \ + } \ +}) + +/// Takes: min iOS version, property name, target class, property type, and a list of attributes +#define FLEXRuntimeUtilityTryAddNonatomicProperty(iOS_atLeast, name, cls, type, ...) \ + FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, @encode(type), PropertyKey(NonAtomic), __VA_ARGS__); +/// Takes: min iOS version, property name, target class, property type (class name), and a list of attributes +#define FLEXRuntimeUtilityTryAddObjectProperty(iOS_atLeast, name, cls, type, ...) \ + FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, FLEXEncodeClass(type), PropertyKey(NonAtomic), __VA_ARGS__); + +@interface FLEXRuntimeUtility : NSObject + +// General Helpers ++ (BOOL)pointerIsValidObjcObject:(const void *)pointer; +/// Unwraps raw pointers to objects stored in NSValue, and re-boxes C strings into NSStrings. ++ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType; +/// Some fields have a name in their encoded string (e.g. \"width\"d) +/// @return the offset to skip the field name, 0 if there is no name ++ (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncoding; +/// Given name "foo" and type "int" this would return "int foo", but +/// given name "foo" and type "T *" it would return "T *foo" ++ (NSString *)appendName:(NSString *)name toType:(NSString *)typeEncoding; + +/// @return The class hierarchy for the given object or class, +/// from the current class to the root-most class. ++ (NSArray *)classHierarchyOfObject:(id)objectOrClass; + +/// Used to describe an object in brief within an explorer row ++ (NSString *)summaryForObject:(id)value; ++ (NSString *)safeClassNameForObject:(id)object; ++ (NSString *)safeDescriptionForObject:(id)object; ++ (NSString *)safeDebugDescriptionForObject:(id)object; + ++ (BOOL)safeObject:(id)object isKindOfClass:(Class)cls; ++ (BOOL)safeObject:(id)object respondsToSelector:(SEL)sel; + +// Property Helpers ++ (BOOL)tryAddPropertyWithName:(const char *)name + attributes:(NSDictionary *)attributePairs + toClass:(__unsafe_unretained Class)theClass; ++ (NSArray *)allPropertyAttributeKeys; + +// Method Helpers ++ (NSArray *)prettyArgumentComponentsForMethod:(Method)method; + +// Method Calling/Field Editing ++ (id)performSelector:(SEL)selector onObject:(id)object; ++ (id)performSelector:(SEL)selector + onObject:(id)object + withArguments:(NSArray *)arguments + error:(NSError * __autoreleasing *)error; ++ (NSString *)editableJSONStringForObject:(id)object; ++ (id)objectValueFromEditableJSONString:(NSString *)string; ++ (NSValue *)valueForNumberWithObjCType:(const char *)typeEncoding fromInputString:(NSString *)inputString; ++ (void)enumerateTypesInStructEncoding:(const char *)structEncoding + usingBlock:(void (^)(NSString *structName, + const char *fieldTypeEncoding, + NSString *prettyTypeEncoding, + NSUInteger fieldIndex, + NSUInteger fieldOffset))typeBlock; ++ (NSValue *)valueForPrimitivePointer:(void *)pointer objCType:(const char *)type; + +#pragma mark - Metadata Helpers + ++ (NSString *)readableTypeForEncoding:(NSString *)encodingString; + +@end diff --git a/FLEX/FLEXSQLResult.h b/FLEX/FLEXSQLResult.h new file mode 100644 index 00000000..4fece3a7 --- /dev/null +++ b/FLEX/FLEXSQLResult.h @@ -0,0 +1,48 @@ +// +// FLEXSQLResult.h +// FLEX +// +// Created by Tanner on 3/3/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXSQLResult : NSObject + +/// Describes the result of a non-select query, or an error of any kind of query ++ (instancetype)message:(NSString *)message; +/// Describes the result of a known failed execution ++ (instancetype)error:(NSString *)message; + +/// @param rowData A list of rows, where each element in the row +/// corresponds to the column given in /c columnNames ++ (instancetype)columns:(NSArray *)columnNames + rows:(NSArray *> *)rowData; + +@property (nonatomic, readonly, nullable) NSString *message; + +/// A value of YES means this is surely an error, +/// but it still might be an error even with a value of NO +@property (nonatomic, readonly) BOOL isError; + +/// A list of column names +@property (nonatomic, readonly, nullable) NSArray *columns; +/// A list of rows, where each element in the row corresponds +/// to the value of the column at the same index in \c columns. +/// +/// That is, given a row, looping over the contents of the row and +/// the contents of \c columns will give you key-value pairs of +/// column names to column values for that row. +@property (nonatomic, readonly, nullable) NSArray *> *rows; +/// A list of rows where the fields are paired to column names. +/// +/// This property is lazily constructed by looping over +/// the rows and columns present in the other two properties. +@property (nonatomic, readonly, nullable) NSArray *> *keyedRows; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXSQLiteDatabaseManager.h b/FLEX/FLEXSQLiteDatabaseManager.h new file mode 100644 index 00000000..50dc4cd7 --- /dev/null +++ b/FLEX/FLEXSQLiteDatabaseManager.h @@ -0,0 +1,32 @@ +// +// PTDatabaseManager.h +// Derived from: +// +// FMDatabase.h +// FMDB( https://github.com/ccgus/fmdb ) +// +// Created by Peng Tao on 15/11/23. +// +// Licensed to Flying Meat Inc. under one or more contributor license agreements. +// See the LICENSE file distributed with this work for the terms under +// which Flying Meat Inc. licenses this file to you. + +#import +#import "FLEXDatabaseManager.h" +#import "FLEXSQLResult.h" + +@interface FLEXSQLiteDatabaseManager : NSObject + +/// Contains the result of the last operation, which may be an error +@property (nonatomic, readonly) FLEXSQLResult *lastResult; +/// Calls into \c sqlite3_last_insert_rowid() +@property (nonatomic, readonly) NSInteger lastRowID; + +/// Given a statement like 'SELECT * from @table where @col = @val' and arguments +/// like { @"table": @"Album", @"col": @"year", @"val" @1 } this method will +/// invoke the statement and properly bind the given arguments to the statement. +/// +/// You may pass NSStrings, NSData, NSNumbers, or NSNulls as values. +- (FLEXSQLResult *)executeStatement:(NSString *)statement arguments:(NSDictionary *)args; + +@end diff --git a/FLEX/FLEXScopeCarousel.h b/FLEX/FLEXScopeCarousel.h new file mode 100644 index 00000000..fb03676f --- /dev/null +++ b/FLEX/FLEXScopeCarousel.h @@ -0,0 +1,20 @@ +// +// FLEXScopeCarousel.h +// FLEX +// +// Created by Tanner Bennett on 7/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +/// Only use on iOS 10 and up. Requires iOS 10 APIs for calculating row sizes. +@interface FLEXScopeCarousel : UIControl + +@property (nonatomic, copy) NSArray *items; +@property (nonatomic) NSInteger selectedIndex; +@property (nonatomic) void(^selectedIndexChangedAction)(NSInteger idx); + +- (void)registerBlockForDynamicTypeChanges:(void(^)(FLEXScopeCarousel *))handler; + +@end diff --git a/FLEX/FLEXSearchToken.h b/FLEX/FLEXSearchToken.h new file mode 100644 index 00000000..07c627d5 --- /dev/null +++ b/FLEX/FLEXSearchToken.h @@ -0,0 +1,35 @@ +// +// FLEXSearchToken.h +// FLEX +// +// Created by Tanner on 3/22/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import + +typedef NS_OPTIONS(NSUInteger, TBWildcardOptions) { + TBWildcardOptionsNone = 0, + TBWildcardOptionsAny = 1, + TBWildcardOptionsPrefix = 1 << 1, + TBWildcardOptionsSuffix = 1 << 2, +}; + +/// A token may contain wildcards at one or either end, +/// but not in the middle of the token (as of now). +@interface FLEXSearchToken : NSObject + ++ (instancetype)any; ++ (instancetype)string:(NSString *)string options:(TBWildcardOptions)options; + +/// Will not contain the wildcard (*) symbol +@property (nonatomic, readonly) NSString *string; +@property (nonatomic, readonly) TBWildcardOptions options; + +/// Opposite of "is ambiguous" +@property (nonatomic, readonly) BOOL isAbsolute; +@property (nonatomic, readonly) BOOL isAny; +/// Still \c isAny, but checks that the string is empty +@property (nonatomic, readonly) BOOL isEmpty; + +@end diff --git a/FLEX/FLEXShortcut.h b/FLEX/FLEXShortcut.h new file mode 100644 index 00000000..cece75b4 --- /dev/null +++ b/FLEX/FLEXShortcut.h @@ -0,0 +1,71 @@ +// +// FLEXShortcut.h +// FLEX +// +// Created by Tanner Bennett on 12/10/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXObjectExplorer.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Represents a row in a shortcut section. +/// +/// The purpsoe of this protocol is to allow delegating a small +/// subset of the responsibilities of a \c FLEXShortcutsSection +/// to another object, for a single arbitrary row. +/// +/// It is useful to make your own shortcuts to append/prepend +/// them to the existing list of shortcuts for a class. +@protocol FLEXShortcut + +- (nonnull NSString *)titleWith:(id)object; +- (nullable NSString *)subtitleWith:(id)object; +- (nullable void (^)(UIViewController *host))didSelectActionWith:(id)object; +/// Called when the row is selected +- (nullable UIViewController *)viewerWith:(id)object; +/// Basically, whether or not to show a detail disclosure indicator +- (UITableViewCellAccessoryType)accessoryTypeWith:(id)object; +/// If nil is returned, the default reuse identifier is used +- (nullable NSString *)customReuseIdentifierWith:(id)object; + +@optional +/// Called when the (i) button is pressed if the accessory type includes it +- (UIViewController *)editorWith:(id)object forSection:(FLEXTableViewSection *)section; + +@end + + +/// Provides default behavior for FLEX metadata objects. Also works in a limited way with strings. +/// Used internally. If you wish to use this object, only pass in \c FLEX* metadata objects. +@interface FLEXShortcut : NSObject + +/// @param item An \c NSString or \c FLEX* metadata object. +/// @note You may also pass a \c FLEXShortcut conforming object, +/// and that object will be returned instead. ++ (id)shortcutFor:(id)item; + +@end + + +/// Provides a quick and dirty implementation of the \c FLEXShortcut protocol, +/// allowing you to specify a static title and dynamic atttributes for everything else. +/// The object passed into each block is the object passed to each \c FLEXShortcut method. +/// +/// Does not support the \c -editorWith: method. +@interface FLEXActionShortcut : NSObject + ++ (instancetype)title:(NSString *)title + subtitle:(nullable NSString *(^)(id object))subtitleFuture + viewer:(nullable UIViewController *(^)(id object))viewerFuture + accessoryType:(nullable UITableViewCellAccessoryType(^)(id object))accessoryTypeFuture; + ++ (instancetype)title:(NSString *)title + subtitle:(nullable NSString *(^)(id object))subtitleFuture + selectionHandler:(nullable void (^)(UIViewController *host, id object))tapAction + accessoryType:(nullable UITableViewCellAccessoryType(^)(id object))accessoryTypeFuture; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXShortcutsFactory+Defaults.h b/FLEX/FLEXShortcutsFactory+Defaults.h new file mode 100644 index 00000000..ba822557 --- /dev/null +++ b/FLEX/FLEXShortcutsFactory+Defaults.h @@ -0,0 +1,27 @@ +// +// FLEXShortcutsFactory+Defaults.h +// FLEX +// +// Created by Tanner Bennett on 8/29/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +@interface FLEXShortcutsFactory (UIApplication) @end + +@interface FLEXShortcutsFactory (Views) @end + +@interface FLEXShortcutsFactory (ViewControllers) @end + +@interface FLEXShortcutsFactory (UIImage) @end + +@interface FLEXShortcutsFactory (NSBundle) @end + +@interface FLEXShortcutsFactory (Classes) @end + +@interface FLEXShortcutsFactory (Activities) @end + +@interface FLEXShortcutsFactory (Blocks) @end + +@interface FLEXShortcutsFactory (Foundation) @end diff --git a/FLEX/FLEXShortcutsSection.h b/FLEX/FLEXShortcutsSection.h new file mode 100644 index 00000000..7e73f29b --- /dev/null +++ b/FLEX/FLEXShortcutsSection.h @@ -0,0 +1,125 @@ +// +// FLEXShortcutsSection.h +// FLEX +// +// Created by Tanner Bennett on 8/29/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewSection.h" +#import "FLEXObjectInfoSection.h" +@class FLEXProperty, FLEXIvar, FLEXMethod; + +/// An abstract base class for custom object "shortcuts" where every +/// row can possibly have some action. The section title is "Shortcuts". +/// +/// You should only subclass this class if you need simple shortcuts +/// with plain titles and/or subtitles. This class will automatically +/// configure each cell appropriately. Since this is intended as a +/// static section, subclasses should only need to implement the +/// \c viewControllerToPushForRow: and/or \c didSelectRowAction: methods. +/// +/// If you create the section using \c forObject:rows:numberOfLines: +/// then it will provide a view controller from \c viewControllerToPushForRow: +/// automatically for rows that are a property/ivar/method. +@interface FLEXShortcutsSection : FLEXTableViewSection + +/// Uses \c kFLEXDefaultCell ++ (instancetype)forObject:(id)objectOrClass rowTitles:(NSArray *)titles; +/// Uses \c kFLEXDetailCell for non-empty subtitles, otherwise uses \c kFLEXDefaultCell ++ (instancetype)forObject:(id)objectOrClass + rowTitles:(NSArray *)titles + rowSubtitles:(NSArray *)subtitles; + +/// Uses \c kFLEXDefaultCell for rows that are given a title, otherwise +/// this uses \c kFLEXDetailCell for any other allowed object. +/// +/// The section provide a view controller from \c viewControllerToPushForRow: +/// automatically for rows that are a property/ivar/method. +/// +/// @param rows A mixed array containing any of the following: +/// - any \c FLEXShortcut conforming object +/// - an \c NSString +/// - a \c FLEXProperty +/// - a \c FLEXIvar +/// - a \c FLEXMethodBase (includes \c FLEXMethod of course) +/// Passing one of the latter 3 will provide a shortcut to that property/ivar/method. +/// @return \c nil if no rows are provided ++ (instancetype)forObject:(id)objectOrClass rows:(NSArray *)rows; + +/// Same as \c forObject:rows: but the given rows are prepended +/// to the shortcuts already registered for the object's class. +/// \c forObject:rows: does not use the registered shortcuts at all. ++ (instancetype)forObject:(id)objectOrClass additionalRows:(NSArray *)rows; + +/// Calls into \c forObject:rows: using the registered shortcuts for the object's class. +/// @return \c nil if the object has no shortcuts registered at all ++ (instancetype)forObject:(id)objectOrClass; + +/// Subclasses \e may override this to hide the disclosure indicator +/// for some rows. It is shown for all rows by default, unless +/// you initialize it with \c forObject:rowTitles:rowSubtitles: +/// +/// When you hide the disclosure indicator, the row is not selectable. +- (UITableViewCellAccessoryType)accessoryTypeForRow:(NSInteger)row; + +/// The number of lines for the title and subtitle labels. Defaults to 1. +@property (nonatomic, readonly) NSInteger numberOfLines; +/// The object used to initialize this section. +@property (nonatomic, readonly) id object; + +/// Whether dynamic subtitles should always be computed as a cell is configured. +/// Defaults to NO. Has no effect on static subtitles that are passed explicitly. +@property (nonatomic) BOOL cacheSubtitles; + +@end + +@class FLEXShortcutsFactory; +typedef FLEXShortcutsFactory *(^FLEXShortcutsFactoryNames)(NSArray *names); +typedef void (^FLEXShortcutsFactoryTarget)(Class targetClass); + +/// The block properties below are to be used like SnapKit or Masonry. +/// \c FLEXShortcutsSection.append.properties(@[@"frame",@"bounds"]).forClass(UIView.class); +/// +/// To safely register your own classes at launch, subclass this class, +/// override \c +load, and call the appropriate methods on \c self +@interface FLEXShortcutsFactory : NSObject + +/// Returns the list of all registered shortcuts for the given object in this order: +/// Properties, ivars, methods. +/// +/// This method traverses up the object's class hierarchy until it finds +/// something registered. This allows you to show different shortcuts for +/// the same object in different parts of the class hierarchy. +/// +/// As an example, UIView may have a -layer shortcut registered. But if +/// you're inspecting a UIControl, you may not care about the layer or other +/// UIView-specific things; you might rather see the target-actions registered +/// for this control, and so you would register that property or ivar to UIControl, +/// And you would still be able to see the UIView-registered shorcuts by clicking +/// on the UIView "lens" at the top the explorer view controller screen. ++ (NSArray *)shortcutsForObjectOrClass:(id)objectOrClass; + +@property (nonatomic, readonly, class) FLEXShortcutsFactory *append; +@property (nonatomic, readonly, class) FLEXShortcutsFactory *prepend; +@property (nonatomic, readonly, class) FLEXShortcutsFactory *replace; + +@property (nonatomic, readonly) FLEXShortcutsFactoryNames properties; +/// Do not try to set \c classProperties at the same time as \c ivars or other instance things. +@property (nonatomic, readonly) FLEXShortcutsFactoryNames classProperties; +@property (nonatomic, readonly) FLEXShortcutsFactoryNames ivars; +@property (nonatomic, readonly) FLEXShortcutsFactoryNames methods; +/// Do not try to set \c classMethods at the same time as \c ivars or other instance things. +@property (nonatomic, readonly) FLEXShortcutsFactoryNames classMethods; + +/// Accepts the target class. If you pass a regular class object, +/// shortcuts will appear on instances. If you pass a metaclass object, +/// shortcuts will appear when exploring a class object. +/// +/// For example, some class method shortcuts are added to the NSObject meta +/// class by default so that you can see +alloc and +new when exploring +/// a class object. If you wanted these to show up when exploring +/// instances you would pass them to the classMethods method above. +@property (nonatomic, readonly) FLEXShortcutsFactoryTarget forClass; + +@end diff --git a/FLEX/FLEXSingleRowSection.h b/FLEX/FLEXSingleRowSection.h new file mode 100644 index 00000000..6b04a0e4 --- /dev/null +++ b/FLEX/FLEXSingleRowSection.h @@ -0,0 +1,28 @@ +// +// FLEXSingleRowSection.h +// FLEX +// +// Created by Tanner Bennett on 9/25/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewSection.h" + +/// A section providing a specific single row. +/// +/// You may optionally provide a view controller to push when the row +/// is selected, or an action to perform when it is selected. +/// Which one is used first is up to the table view data source. +@interface FLEXSingleRowSection : FLEXTableViewSection + +/// @param reuseIdentifier if nil, kFLEXDefaultCell is used. ++ (instancetype)title:(NSString *)sectionTitle + reuse:(NSString *)reuseIdentifier + cell:(void(^)(__kindof UITableViewCell *cell))cellConfiguration; + +@property (nonatomic) UIViewController *pushOnSelection; +@property (nonatomic) void (^selectionAction)(UIViewController *host); +/// Called to determine whether the single row should display itself or not. +@property (nonatomic) BOOL (^filterMatcher)(NSString *filterText); + +@end diff --git a/FLEX/FLEXSubtitleTableViewCell.h b/FLEX/FLEXSubtitleTableViewCell.h new file mode 100644 index 00000000..26858ab8 --- /dev/null +++ b/FLEX/FLEXSubtitleTableViewCell.h @@ -0,0 +1,14 @@ +// +// FLEXSubtitleTableViewCell.h +// FLEX +// +// Created by Tanner on 4/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewCell.h" + +/// A cell initialized with \c UITableViewCellStyleSubtitle +@interface FLEXSubtitleTableViewCell : FLEXTableViewCell + +@end diff --git a/FLEX/FLEXSystemLogCell.h b/FLEX/FLEXSystemLogCell.h new file mode 100644 index 00000000..4fdc629e --- /dev/null +++ b/FLEX/FLEXSystemLogCell.h @@ -0,0 +1,23 @@ +// +// FLEXSystemLogCell.h +// FLEX +// +// Created by Ryan Olson on 1/25/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewCell.h" + +@class FLEXSystemLogMessage; + +extern NSString *const kFLEXSystemLogCellIdentifier; + +@interface FLEXSystemLogCell : FLEXTableViewCell + +@property (nonatomic) FLEXSystemLogMessage *logMessage; +@property (nonatomic, copy) NSString *highlightedText; + ++ (NSString *)displayedTextForLogMessage:(FLEXSystemLogMessage *)logMessage; ++ (CGFloat)preferredHeightForLogMessage:(FLEXSystemLogMessage *)logMessage inWidth:(CGFloat)width; + +@end diff --git a/FLEX/FLEXSystemLogMessage.h b/FLEX/FLEXSystemLogMessage.h new file mode 100644 index 00000000..4976eacd --- /dev/null +++ b/FLEX/FLEXSystemLogMessage.h @@ -0,0 +1,30 @@ +// +// FLEXSystemLogMessage.h +// FLEX +// +// Created by Ryan Olson on 1/25/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import +#import "ActivityStreamAPI.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXSystemLogMessage : NSObject + ++ (instancetype)logMessageFromASLMessage:(aslmsg)aslMessage; ++ (instancetype)logMessageFromDate:(NSDate *)date text:(NSString *)text; + +// ASL specific properties +@property (nonatomic, readonly, nullable) NSString *sender; +@property (nonatomic, readonly, nullable) aslmsg aslMessage; + +@property (nonatomic, readonly) NSDate *date; +@property (nonatomic, readonly) NSString *messageText; +@property (nonatomic, readonly) long long messageID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXSystemLogViewController.h b/FLEX/FLEXSystemLogViewController.h new file mode 100644 index 00000000..59ce054e --- /dev/null +++ b/FLEX/FLEXSystemLogViewController.h @@ -0,0 +1,14 @@ +// +// FLEXSystemLogViewController.h +// FLEX +// +// Created by Ryan Olson on 1/19/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" +#import "FLEXGlobalsEntry.h" + +@interface FLEXSystemLogViewController : FLEXFilteringTableViewController + +@end diff --git a/FLEX/FLEXTabList.h b/FLEX/FLEXTabList.h new file mode 100644 index 00000000..24f21548 --- /dev/null +++ b/FLEX/FLEXTabList.h @@ -0,0 +1,45 @@ +// +// FLEXTabList.h +// FLEX +// +// Created by Tanner on 2/1/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXTabList : NSObject + +@property (nonatomic, readonly, class) FLEXTabList *sharedList; + +@property (nonatomic, readonly, nullable) UINavigationController *activeTab; +@property (nonatomic, readonly) NSArray *openTabs; +/// Snapshots of each tab when they were last active. +@property (nonatomic, readonly) NSArray *openTabSnapshots; +/// \c NSNotFound if no tabs are present. +/// Setting this property changes the active tab to one of the already open tabs. +@property (nonatomic) NSInteger activeTabIndex; + +/// Adds a new tab and sets the new tab as the active tab. +- (void)addTab:(UINavigationController *)newTab; +/// Closes the given tab. If this tab was the active tab, +/// the most recent tab before that becomes the active tab. +- (void)closeTab:(UINavigationController *)tab; +/// Closes a tab at the given index. If this tab was the active tab, +/// the most recent tab before that becomes the active tab. +- (void)closeTabAtIndex:(NSInteger)idx; +/// Closes all of the tabs at the given indexes. If the active tab +/// is included, the most recent still-open tab becomes the active tab. +- (void)closeTabsAtIndexes:(NSIndexSet *)indexes; +/// A shortcut to close the active tab. +- (void)closeActiveTab; +/// A shortcut to close \e every tab. +- (void)closeAllTabs; + +- (void)updateSnapshotForActiveTab; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXTableColumnHeader.h b/FLEX/FLEXTableColumnHeader.h new file mode 100644 index 00000000..474a8702 --- /dev/null +++ b/FLEX/FLEXTableColumnHeader.h @@ -0,0 +1,38 @@ +// +// FLEXTableContentHeaderCell.h +// FLEX +// +// Created by Peng Tao on 15/11/26. +// Copyright © 2015年 f. All rights reserved. +// + +#import + +typedef NS_ENUM(NSUInteger, FLEXTableColumnHeaderSortType) { + FLEXTableColumnHeaderSortTypeNone = 0, + FLEXTableColumnHeaderSortTypeAsc, + FLEXTableColumnHeaderSortTypeDesc, +}; + +NS_INLINE FLEXTableColumnHeaderSortType FLEXNextTableColumnHeaderSortType( + FLEXTableColumnHeaderSortType current) { + switch (current) { + case FLEXTableColumnHeaderSortTypeAsc: + return FLEXTableColumnHeaderSortTypeDesc; + case FLEXTableColumnHeaderSortTypeNone: + case FLEXTableColumnHeaderSortTypeDesc: + return FLEXTableColumnHeaderSortTypeAsc; + } + + return FLEXTableColumnHeaderSortTypeNone; +} + +@interface FLEXTableColumnHeader : UIView + +@property (nonatomic) NSInteger index; +@property (nonatomic, readonly) UILabel *titleLabel; + +@property (nonatomic) FLEXTableColumnHeaderSortType sortType; + +@end + diff --git a/FLEX/FLEXTableContentViewController.h b/FLEX/FLEXTableContentViewController.h new file mode 100644 index 00000000..077e3fc9 --- /dev/null +++ b/FLEX/FLEXTableContentViewController.h @@ -0,0 +1,16 @@ +// +// PTTableContentViewController.h +// PTDatabaseReader +// +// Created by Peng Tao on 15/11/23. +// Copyright © 2015年 Peng Tao. All rights reserved. +// + +#import + +@interface FLEXTableContentViewController : UIViewController + ++ (instancetype)columns:(NSArray *)columnNames + rows:(NSArray *> *)rowData; + +@end diff --git a/FLEX/FLEXTableLeftCell.h b/FLEX/FLEXTableLeftCell.h new file mode 100644 index 00000000..e3510729 --- /dev/null +++ b/FLEX/FLEXTableLeftCell.h @@ -0,0 +1,17 @@ +// +// FLEXTableLeftCell.h +// FLEX +// +// Created by Peng Tao on 15/11/24. +// Copyright © 2015年 f. All rights reserved. +// + +#import + +@interface FLEXTableLeftCell : UITableViewCell + +@property (nonatomic) UILabel *titlelabel; + ++ (instancetype)cellWithTableView:(UITableView *)tableView; + +@end diff --git a/FLEX/FLEXTableListViewController.h b/FLEX/FLEXTableListViewController.h new file mode 100644 index 00000000..b8662028 --- /dev/null +++ b/FLEX/FLEXTableListViewController.h @@ -0,0 +1,16 @@ +// +// PTTableListViewController.h +// PTDatabaseReader +// +// Created by Peng Tao on 15/11/23. +// Copyright © 2015年 Peng Tao. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" + +@interface FLEXTableListViewController : FLEXFilteringTableViewController + ++ (BOOL)supportsExtension:(NSString *)extension; +- (instancetype)initWithPath:(NSString *)path; + +@end diff --git a/FLEX/FLEXTableView.h b/FLEX/FLEXTableView.h new file mode 100644 index 00000000..9479b520 --- /dev/null +++ b/FLEX/FLEXTableView.h @@ -0,0 +1,48 @@ +// +// FLEXTableView.h +// FLEX +// +// Created by Tanner on 4/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark Reuse identifiers + +typedef NSString * FLEXTableViewCellReuseIdentifier; + +/// A regular \c FLEXTableViewCell initialized with \c UITableViewCellStyleDefault +extern FLEXTableViewCellReuseIdentifier const kFLEXDefaultCell; +/// A \c FLEXSubtitleTableViewCell initialized with \c UITableViewCellStyleSubtitle +extern FLEXTableViewCellReuseIdentifier const kFLEXDetailCell; +/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleDefault +extern FLEXTableViewCellReuseIdentifier const kFLEXMultilineCell; +/// A \c FLEXMultilineTableViewCell initialized with \c UITableViewCellStyleSubtitle +extern FLEXTableViewCellReuseIdentifier const kFLEXMultilineDetailCell; +/// A \c FLEXTableViewCell initialized with \c UITableViewCellStyleValue1 +extern FLEXTableViewCellReuseIdentifier const kFLEXKeyValueCell; +/// A \c FLEXSubtitleTableViewCell which uses monospaced fonts for both labels +extern FLEXTableViewCellReuseIdentifier const kFLEXCodeFontCell; + +#pragma mark - FLEXTableView +@interface FLEXTableView : UITableView + ++ (instancetype)flexDefaultTableView; ++ (instancetype)groupedTableView; ++ (instancetype)plainTableView; ++ (instancetype)style:(UITableViewStyle)style; + +/// You do not need to register classes for any of the default reuse identifiers above +/// (annotated as \c FLEXTableViewCellReuseIdentifier types) unless you wish to provide +/// a custom cell for any of those reuse identifiers. By default, \c FLEXTableViewCell, +/// \c FLEXSubtitleTableViewCell, and \c FLEXMultilineTableViewCell are used, respectively. +/// +/// @param registrationMapping A map of reuse identifiers to \c UITableViewCell (sub)class objects. +- (void)registerCells:(NSDictionary *)registrationMapping; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXTableViewCell.h b/FLEX/FLEXTableViewCell.h new file mode 100644 index 00000000..6d065988 --- /dev/null +++ b/FLEX/FLEXTableViewCell.h @@ -0,0 +1,23 @@ +// +// FLEXTableViewCell.h +// FLEX +// +// Created by Tanner on 4/17/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXTableViewCell : UITableViewCell + +/// Use this instead of .textLabel +@property (nonatomic, readonly) UILabel *titleLabel; +/// Use this instead of .detailTextLabel +@property (nonatomic, readonly) UILabel *subtitleLabel; + +/// Subclasses can override this instead of initializers to +/// perform additional initialization without lots of boilerplate. +/// Remember to call super! +- (void)postInit; + +@end diff --git a/FLEX/FLEXTableViewController.h b/FLEX/FLEXTableViewController.h new file mode 100644 index 00000000..956c3a9e --- /dev/null +++ b/FLEX/FLEXTableViewController.h @@ -0,0 +1,149 @@ +// +// FLEXTableViewController.h +// FLEX +// +// Created by Tanner on 7/5/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXTableView.h" +@class FLEXScopeCarousel, FLEXWindow, FLEXTableViewSection; + +typedef CGFloat FLEXDebounceInterval; +/// No delay, all events delivered +extern CGFloat const kFLEXDebounceInstant; +/// Small delay which makes UI seem smoother by avoiding rapid events +extern CGFloat const kFLEXDebounceFast; +/// Slower than Fast, faster than ExpensiveIO +extern CGFloat const kFLEXDebounceForAsyncSearch; +/// The least frequent, at just over once per second; for I/O or other expensive operations +extern CGFloat const kFLEXDebounceForExpensiveIO; + +@protocol FLEXSearchResultsUpdating +/// A method to handle search query update events. +/// +/// \c searchBarDebounceInterval is used to reduce the frequency at which this +/// method is called. This method is also called when the search bar becomes +/// the first responder, and when the selected search bar scope index changes. +- (void)updateSearchResults:(NSString *)newText; +@end + +@interface FLEXTableViewController : UITableViewController < + UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate +> + +/// A grouped table view. Inset on iOS 13. +/// +/// Simply calls into \c initWithStyle: +- (id)init; + +/// Subclasses may override to configure the controller before \c viewDidLoad: +- (id)initWithStyle:(UITableViewStyle)style; + +@property (nonatomic) FLEXTableView *tableView; + +/// If your subclass conforms to \c FLEXSearchResultsUpdating +/// then this property is assigned to \c self automatically. +/// +/// Setting \c filterDelegate will also set this property to that object. +@property (nonatomic, weak) id searchDelegate; + +/// Defaults to NO. +/// +/// Setting this to YES will initialize the carousel and the view. +@property (nonatomic) BOOL showsCarousel; +/// A horizontally scrolling list with functionality similar to +/// that of a search bar's scope bar. You'd want to use this when +/// you have potentially more than 4 scope options. +@property (nonatomic) FLEXScopeCarousel *carousel; + +/// Defaults to NO. +/// +/// Setting this to YES will initialize searchController and the view. +@property (nonatomic) BOOL showsSearchBar; +/// Defaults to NO. +/// +/// Setting this to YES will make the search bar appear whenever the view appears. +/// Otherwise, iOS will only show the search bar when you scroll up. +@property (nonatomic) BOOL showSearchBarInitially; + +/// nil unless showsSearchBar is set to YES. +/// +/// self is used as the default search results updater and delegate. +/// The search bar will not dim the background or hide the navigation bar by default. +/// On iOS 11 and up, the search bar will appear in the navigation bar below the title. +@property (nonatomic) UISearchController *searchController; +/// Used to initialize the search controller. Defaults to nil. +@property (nonatomic) UIViewController *searchResultsController; +/// Defaults to "Fast" +/// +/// Determines how often search bar results will be "debounced." +/// Empty query events are always sent instantly. Query events will +/// be sent when the user has not changed the query for this interval. +@property (nonatomic) FLEXDebounceInterval searchBarDebounceInterval; +/// Whether the search bar stays at the top of the view while scrolling. +/// +/// Calls into self.navigationItem.hidesSearchBarWhenScrolling. +/// Do not change self.navigationItem.hidesSearchBarWhenScrolling directly, +/// or it will not be respsected. Use this instead. +/// Defaults to NO. +@property (nonatomic) BOOL pinSearchBar; +/// By default, we will show the search bar's cancel button when +/// search becomes active and hide it when search is dismissed. +/// +/// Do not set the showsCancelButton property on the searchController's +/// searchBar manually. Set this property after turning on showsSearchBar. +/// +/// Does nothing pre-iOS 13, safe to call on any version. +@property (nonatomic) BOOL automaticallyShowsSearchBarCancelButton; + +/// If using the scope bar, self.searchController.searchBar.selectedScopeButtonIndex. +/// Otherwise, this is the selected index of the carousel, or NSNotFound if using neither. +@property (nonatomic) NSInteger selectedScope; +/// self.searchController.searchBar.text +@property (nonatomic, readonly, copy) NSString *searchText; + +/// A totally optional delegate to forward search results updater calls to. +/// If a delegate is set, updateSearchResults: is not called on this view controller. +@property (nonatomic, weak) id searchResultsUpdater; + +/// self.view.window as a \c FLEXWindow +@property (nonatomic, readonly) FLEXWindow *window; + +/// Convenient for doing some async processor-intensive searching +/// in the background before updating the UI back on the main queue. +- (void)onBackgroundQueue:(NSArray *(^)(void))backgroundBlock thenOnMainQueue:(void(^)(NSArray *))mainBlock; + +/// Adds up to 3 additional items to the toolbar in right-to-left order. +/// +/// That is, the first item in the given array will be the rightmost item behind +/// any existing toolbar items. By default, buttons for bookmarks and tabs are shown. +/// +/// If you wish to have more control over how the buttons are arranged or which +/// buttons are displayed, you can access the properties for the pre-existing +/// toolbar items directly and manually set \c self.toolbarItems by overriding +/// the \c setupToolbarItems method below. +- (void)addToolbarItems:(NSArray *)items; + +/// Subclasses may override. You should not need to call this method directly. +- (void)setupToolbarItems; + +@property (nonatomic, readonly) UIBarButtonItem *shareToolbarItem; +@property (nonatomic, readonly) UIBarButtonItem *bookmarksToolbarItem; +@property (nonatomic, readonly) UIBarButtonItem *openTabsToolbarItem; + +/// Whether or not to display the "share" icon in the middle of the toolbar. NO by default. +/// +/// Turning this on after you have added custom toolbar items will +/// push off the leftmost toolbar item and shift the others leftward. +@property (nonatomic) BOOL showsShareToolbarItem; +/// Called when the share button is pressed. +/// Default implementation does nothign. Subclasses may override. +- (void)shareButtonPressed:(UIBarButtonItem *)sender; + +/// Subclasses may call this to opt-out of all toolbar related behavior. +/// This is necessary if you want to disable the gesture which reveals the toolbar. +- (void)disableToolbar; + +@end diff --git a/FLEX/FLEXTableViewSection.h b/FLEX/FLEXTableViewSection.h new file mode 100644 index 00000000..f94ab7f8 --- /dev/null +++ b/FLEX/FLEXTableViewSection.h @@ -0,0 +1,149 @@ +// +// FLEXTableViewSection.h +// FLEX +// +// Created by Tanner on 1/29/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXMacros.h" +#import "NSArray+FLEX.h" +@class FLEXTableView; + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark FLEXTableViewSection + +/// An abstract base class for table view sections. +/// +/// Many properties or methods here return nil or some logical equivalent by default. +/// Even so, most of the methods with defaults are intended to be overriden by subclasses. +/// Some methods are not implemented at all and MUST be implemented by a subclass. +@interface FLEXTableViewSection : NSObject { + @protected + /// Unused by default, use if you want + NSString *_title; + + @private + __weak UITableView *_tableView; + NSInteger _sectionIndex; +} + +#pragma mark - Data + +/// A title to be displayed for the custom section. +/// Subclasses may override or use the \c _title ivar. +@property (nonatomic, readonly, nullable, copy) NSString *title; +/// The number of rows in this section. Subclasses must override. +/// This should not change until \c filterText is changed or \c reloadData is called. +@property (nonatomic, readonly) NSInteger numberOfRows; +/// A map of reuse identifiers to \c UITableViewCell (sub)class objects. +/// Subclasses \e may override this as necessary, but are not required to. +/// See \c FLEXTableView.h for more information. +/// @return nil by default. +@property (nonatomic, readonly, nullable) NSDictionary *cellRegistrationMapping; + +/// The section should filter itself based on the contents of this property +/// as it is set. If it is set to nil or an empty string, it should not filter. +/// Subclasses should override or observe this property and react to changes. +/// +/// It is common practice to use two arrays for the underlying model: +/// One to hold all rows, and one to hold unfiltered rows. When \c setFilterText: +/// is called, call \c super to store the new value, and re-filter your model accordingly. +@property (nonatomic, nullable) NSString *filterText; + +/// Provides an avenue for the section to refresh data or change the number of rows. +/// +/// This is called before reloading the table view itself. If your section pulls data +/// from an external data source, this is a good place to refresh that data entirely. +/// If your section does not, then it might be simpler for you to just override +/// \c setFilterText: to call \c super and call \c reloadData. +- (void)reloadData; + +/// Like \c reloadData, but optionally reloads the table view section +/// associated with this section object, if any. Do not override. +/// Do not call outside of the main thread. +- (void)reloadData:(BOOL)updateTable; + +/// Provide a table view and section index to allow the section to efficiently reload +/// its own section of the table when something changes it. The table reference is +/// held weakly, and subclasses cannot access it or the index. Call this method again +/// if the section numbers have changed since you last called it. +- (void)setTable:(UITableView *)tableView section:(NSInteger)index; + +#pragma mark - Row Selection + +/// Whether the given row should be selectable, such as if tapping the cell +/// should take the user to a new screen or trigger an action. +/// Subclasses \e may override this as necessary, but are not required to. +/// @return \c NO by default +- (BOOL)canSelectRow:(NSInteger)row; + +/// An action "future" to be triggered when the row is selected, if the row +/// supports being selected as indicated by \c canSelectRow:. Subclasses +/// must implement this in accordance with how they implement \c canSelectRow: +/// if they do not implement \c viewControllerToPushForRow: +/// @return This returns \c nil if no view controller is provided by +/// \c viewControllerToPushForRow: — otherwise it pushes that view controller +/// onto \c host.navigationController +- (nullable void(^)(__kindof UIViewController *host))didSelectRowAction:(NSInteger)row; + +/// A view controller to display when the row is selected, if the row +/// supports being selected as indicated by \c canSelectRow:. Subclasses +/// must implement this in accordance with how they implement \c canSelectRow: +/// if they do not implement \c didSelectRowAction: +/// @return \c nil by default +- (nullable UIViewController *)viewControllerToPushForRow:(NSInteger)row; + +/// Called when the accessory view's detail button is pressed. +/// @return \c nil by default. +- (nullable void(^)(__kindof UIViewController *host))didPressInfoButtonAction:(NSInteger)row; + +#pragma mark - Context Menus +#if FLEX_AT_LEAST_IOS13_SDK + +/// By default, this is the title of the row. +/// @return The title of the context menu, if any. +- (nullable NSString *)menuTitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); +/// Protected, not intended for public use. \c menuTitleForRow: +/// already includes the value returned from this method. +/// +/// By default, this returns \c @"". Subclasses may override to +/// provide a detailed description of the target of the context menu. +- (NSString *)menuSubtitleForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); +/// The context menu items, if any. Subclasses may override. +/// By default, only inludes items for \c copyMenuItemsForRow:. +- (nullable NSArray *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13.0)); +/// Subclasses may override to return a list of copiable items. +/// +/// Every two elements in the list compose a key-value pair, where the key +/// should be a description of what will be copied, and the values should be +/// the strings to copy. Return an empty string as a value to show a disabled action. +- (nullable NSArray *)copyMenuItemsForRow:(NSInteger)row API_AVAILABLE(ios(13.0)); +#endif + +#pragma mark - Cell Configuration + +/// Provide a reuse identifier for the given row. Subclasses should override. +/// +/// Custom reuse identifiers should be specified in \c cellRegistrationMapping. +/// You may return any of the identifiers in \c FLEXTableView.h +/// without including them in the \c cellRegistrationMapping. +/// @return \c kFLEXDefaultCell by default. +- (NSString *)reuseIdentifierForRow:(NSInteger)row; +/// Configure a cell for the given row. Subclasses must override. +- (void)configureCell:(__kindof UITableViewCell *)cell forRow:(NSInteger)row; + +#pragma mark - External Convenience + +/// For use by whatever view controller uses your section. Not required. +/// @return An optional title. +- (nullable NSString *)titleForRow:(NSInteger)row; +/// For use by whatever view controller uses your section. Not required. +/// @return An optional subtitle. +- (nullable NSString *)subtitleForRow:(NSInteger)row; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXTabsViewController.h b/FLEX/FLEXTabsViewController.h new file mode 100644 index 00000000..f288a0aa --- /dev/null +++ b/FLEX/FLEXTabsViewController.h @@ -0,0 +1,13 @@ +// +// FLEXTabsViewController.h +// FLEX +// +// Created by Tanner on 2/4/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" + +@interface FLEXTabsViewController : FLEXTableViewController + +@end diff --git a/FLEX/FLEXTypeEncodingParser.h b/FLEX/FLEXTypeEncodingParser.h new file mode 100644 index 00000000..7a8b1fb6 --- /dev/null +++ b/FLEX/FLEXTypeEncodingParser.h @@ -0,0 +1,46 @@ +// +// FLEXTypeEncodingParser.h +// FLEX +// +// Created by Tanner Bennett on 8/22/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// @return \c YES if the type is supported, \c NO otherwise +BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger * _Nullable sizep, NSUInteger * _Nullable alignp); + +@interface FLEXTypeEncodingParser : NSObject + +/// \c cleanedEncoding is necessary because a type encoding may contain a pointer +/// to an unsupported type. \c NSMethodSignature will pass each type to \c NSGetSizeAndAlignment +/// which will throw an exception on unsupported struct pointers, and this exception is caught +/// by \c NSMethodSignature, but it still bothers anyone debugging with \c objc_exception_throw +/// +/// @param cleanedEncoding the "safe" type encoding you can pass to \c NSMethodSignature +/// @return whether the given type encoding can be passed to +/// \c NSMethodSignature without it throwing an exception. ++ (BOOL)methodTypeEncodingSupported:(NSString *)typeEncoding cleaned:(NSString *_Nonnull*_Nullable)cleanedEncoding; + +/// @return The type encoding of an individual argument in a method's type encoding string. +/// Pass 0 to get the type of the return value. 1 and 2 are `self` and `_cmd` respectively. ++ (NSString *)type:(NSString *)typeEncoding forMethodArgumentAtIndex:(NSUInteger)idx; + +/// @return The size in bytes of the typeof an individual argument in a method's type encoding string. +/// Pass 0 to get the size of the return value. 1 and 2 are `self` and `_cmd` respectively. ++ (ssize_t)size:(NSString *)typeEncoding forMethodArgumentAtIndex:(NSUInteger)idx; + +/// @param unaligned whether to compute the aligned or unaligned size. +/// @return The size in bytes, or \c -1 if the type encoding is unsupported. +/// Do not pass in the result of \c method_getTypeEncoding ++ (ssize_t)sizeForTypeEncoding:(NSString *)type alignment:(nullable ssize_t *)alignOut unaligned:(BOOL)unaligned; + +/// Defaults to \C unaligned:NO ++ (ssize_t)sizeForTypeEncoding:(NSString *)type alignment:(nullable ssize_t *)alignOut; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXUIAppShortcuts.h b/FLEX/FLEXUIAppShortcuts.h new file mode 100644 index 00000000..d0b0db16 --- /dev/null +++ b/FLEX/FLEXUIAppShortcuts.h @@ -0,0 +1,13 @@ +// +// FLEXUIAppShortcuts.h +// FLEX +// +// Created by Tanner on 5/25/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +@interface FLEXUIAppShortcuts : FLEXShortcutsSection + +@end diff --git a/FLEX/FLEXUtility.h b/FLEX/FLEXUtility.h new file mode 100644 index 00000000..c74317f3 --- /dev/null +++ b/FLEX/FLEXUtility.h @@ -0,0 +1,66 @@ +// +// FLEXUtility.h +// Flipboard +// +// Created by Ryan Olson on 4/18/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import +#import +#import +#import +#import "FLEXTypeEncodingParser.h" +#import "FLEXAlert.h" +#import "NSArray+FLEX.h" +#import "UIFont+FLEX.h" +#import "FLEXMacros.h" + +#if !FLEX_AT_LEAST_IOS13_SDK +@class UIWindowScene; +#endif + +@interface FLEXUtility : NSObject + +/// The key window of the app, if it is not a \c FLEXWindow. +/// If it is, then \c FLEXWindow.previousKeyWindow is returned. +@property (nonatomic, readonly, class) UIWindow *appKeyWindow; +/// @return the result of +[UIWindow allWindowsIncludingInternalWindows:onlyVisibleWindows:] +@property (nonatomic, readonly, class) NSArray *allWindows; +/// The first active \c UIWindowScene of the app. +@property (nonatomic, readonly, class) UIWindowScene *activeScene API_AVAILABLE(ios(13.0)); +/// @return top-most view controller of the given window ++ (UIViewController *)topViewControllerInWindow:(UIWindow *)window; + ++ (UIColor *)consistentRandomColorForObject:(id)object; ++ (NSString *)descriptionForView:(UIView *)view includingFrame:(BOOL)includeFrame; ++ (NSString *)stringForCGRect:(CGRect)rect; ++ (UIViewController *)viewControllerForView:(UIView *)view; ++ (UIViewController *)viewControllerForAncestralView:(UIView *)view; ++ (UIImage *)previewImageForView:(UIView *)view; ++ (UIImage *)previewImageForLayer:(CALayer *)layer; ++ (NSString *)detailDescriptionForView:(UIView *)view; ++ (UIImage *)circularImageWithColor:(UIColor *)color radius:(CGFloat)radius; ++ (UIColor *)hierarchyIndentPatternColor; ++ (NSString *)pointerToString:(void *)ptr; ++ (NSString *)addressOfObject:(id)object; ++ (NSString *)stringByEscapingHTMLEntitiesInString:(NSString *)originalString; ++ (UIInterfaceOrientationMask)infoPlistSupportedInterfaceOrientationsMask; ++ (UIImage *)thumbnailedImageWithMaxPixelDimension:(NSInteger)dimension fromImageData:(NSData *)data; ++ (NSString *)stringFromRequestDuration:(NSTimeInterval)duration; ++ (NSString *)statusCodeStringFromURLResponse:(NSURLResponse *)response; ++ (BOOL)isErrorStatusCodeFromURLResponse:(NSURLResponse *)response; ++ (NSArray *)itemsFromQueryString:(NSString *)query; ++ (NSString *)prettyJSONStringFromData:(NSData *)data; ++ (BOOL)isValidJSONData:(NSData *)data; ++ (NSData *)inflatedDataFromCompressedData:(NSData *)compressedData; + +// Swizzling utilities + ++ (SEL)swizzledSelectorForSelector:(SEL)selector; ++ (BOOL)instanceRespondsButDoesNotImplementSelector:(SEL)selector class:(Class)cls; ++ (void)replaceImplementationOfKnownSelector:(SEL)originalSelector onClass:(Class)class withBlock:(id)block swizzledSelector:(SEL)swizzledSelector; ++ (void)replaceImplementationOfSelector:(SEL)selector withSelector:(SEL)swizzledSelector forClass:(Class)cls withMethodDescription:(struct objc_method_description)methodDescription implementationBlock:(id)implementationBlock undefinedBlock:(id)undefinedBlock; + +@end diff --git a/FLEX/FLEXVariableEditorViewController.h b/FLEX/FLEXVariableEditorViewController.h new file mode 100644 index 00000000..9e14c93b --- /dev/null +++ b/FLEX/FLEXVariableEditorViewController.h @@ -0,0 +1,55 @@ +// +// FLEXVariableEditorViewController.h +// Flipboard +// +// Created by Ryan Olson on 5/16/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@class FLEXFieldEditorView; +@class FLEXArgumentInputView; + +NS_ASSUME_NONNULL_BEGIN + +/// An abstract screen for editing or configuring one or more variables. +/// "Target" is the target of the edit operation, and "data" is the data +/// you want to mutate or pass to the target when the action is performed. +/// The action may be something like calling a method, setting an ivar, etc. +@interface FLEXVariableEditorViewController : UIViewController { + @protected + id _target; + _Nullable id _data; + void (^_Nullable _commitHandler)(); +} + +/// @param target The target of the operation +/// @param data The data associated with the operation +/// @param onCommit An action to perform when the data changes ++ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit; +/// @param target The target of the operation +/// @param data The data associated with the operation +/// @param onCommit An action to perform when the data changes +- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit; + +@property (nonatomic, readonly) id target; + +/// Convenience accessor since many subclasses only use one input view +@property (nonatomic, readonly, nullable) FLEXArgumentInputView *firstInputView; + +@property (nonatomic, readonly) FLEXFieldEditorView *fieldEditorView; +/// Subclasses can change the button title via the button's \c title property +@property (nonatomic, readonly) UIBarButtonItem *actionButton; + +/// Subclasses should override to provide "set" functionality. +/// The commit handler--if present--is called here. +- (void)actionButtonPressed:(nullable id)sender; + +/// Pushes an explorer view controller for the given object +/// or pops the current view controller. +- (void)exploreObjectOrPopViewController:(nullable id)objectOrNil; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXViewControllerShortcuts.h b/FLEX/FLEXViewControllerShortcuts.h new file mode 100644 index 00000000..1d09e696 --- /dev/null +++ b/FLEX/FLEXViewControllerShortcuts.h @@ -0,0 +1,15 @@ +// +// FLEXViewControllerShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 12/12/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +@interface FLEXViewControllerShortcuts : FLEXShortcutsSection + ++ (instancetype)forObject:(UIViewController *)viewController; + +@end diff --git a/FLEX/FLEXViewControllersViewController.h b/FLEX/FLEXViewControllersViewController.h new file mode 100644 index 00000000..b2d9ec4c --- /dev/null +++ b/FLEX/FLEXViewControllersViewController.h @@ -0,0 +1,19 @@ +// +// FLEXViewControllersViewController.h +// FLEX +// +// Created by Tanner Bennett on 2/13/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXFilteringTableViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXViewControllersViewController : FLEXFilteringTableViewController + ++ (instancetype)controllersForViews:(NSArray *)views; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/FLEXViewShortcuts.h b/FLEX/FLEXViewShortcuts.h new file mode 100644 index 00000000..f1df0aa8 --- /dev/null +++ b/FLEX/FLEXViewShortcuts.h @@ -0,0 +1,14 @@ +// +// FLEXViewShortcuts.h +// FLEX +// +// Created by Tanner Bennett on 12/11/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXShortcutsSection.h" + +/// Adds "Nearest View Controller" and "Preview Image" shortcuts to all views +@interface FLEXViewShortcuts : FLEXShortcutsSection + +@end diff --git a/FLEX/FLEXWebViewController.h b/FLEX/FLEXWebViewController.h new file mode 100644 index 00000000..e65bd0f8 --- /dev/null +++ b/FLEX/FLEXWebViewController.h @@ -0,0 +1,18 @@ +// +// FLEXWebViewController.m +// Flipboard +// +// Created by Ryan Olson on 6/10/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface FLEXWebViewController : UIViewController + +- (id)initWithURL:(NSURL *)url; +- (id)initWithText:(NSString *)text; + ++ (BOOL)supportsPathExtension:(NSString *)extension; + +@end diff --git a/FLEX/FLEXWindow.h b/FLEX/FLEXWindow.h new file mode 100644 index 00000000..4de7ae46 --- /dev/null +++ b/FLEX/FLEXWindow.h @@ -0,0 +1,29 @@ +// +// FLEXWindow.h +// Flipboard +// +// Created by Ryan Olson on 4/13/14. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@protocol FLEXWindowEventDelegate + +- (BOOL)shouldHandleTouchAtPoint:(CGPoint)pointInWindow; +- (BOOL)canBecomeKeyWindow; + +@end + +#pragma mark - +@interface FLEXWindow : UIWindow + +@property (nonatomic, weak) id eventDelegate; + +/// Tracked so we can restore the key window after dismissing a modal. +/// We need to become key after modal presentation so we can correctly capture input. +/// If we're just showing the toolbar, we want the main app's window to remain key +/// so that we don't interfere with input, status bar, etc. +@property (nonatomic, readonly) UIWindow *previousKeyWindow; + +@end diff --git a/FLEX/FLEXWindowManagerController.h b/FLEX/FLEXWindowManagerController.h new file mode 100644 index 00000000..d0dd05e7 --- /dev/null +++ b/FLEX/FLEXWindowManagerController.h @@ -0,0 +1,17 @@ +// +// FLEXWindowManagerController.h +// FLEX +// +// Created by Tanner on 2/6/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXTableViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXWindowManagerController : FLEXTableViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/NSArray+FLEX.h b/FLEX/NSArray+FLEX.h new file mode 100644 index 00000000..2f5b96fd --- /dev/null +++ b/FLEX/NSArray+FLEX.h @@ -0,0 +1,38 @@ +// +// NSArray+FLEX.h +// FLEX +// +// Created by Tanner Bennett on 9/25/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface NSArray (Functional) + +/// Actually more like flatmap, but it seems like the objc way to allow returning nil to omit objects. +/// So, return nil from the block to omit objects, and return an object to include it in the new array. +/// Unlike flatmap, however, this will not flatten arrays of arrays into a single array. +- (__kindof NSArray *)flex_mapped:(id(^)(T obj, NSUInteger idx))mapFunc; +/// Like flex_mapped, but expects arrays to be returned, and flattens them into one array. +- (__kindof NSArray *)flex_flatmapped:(NSArray *(^)(id, NSUInteger idx))block; +- (instancetype)flex_filtered:(BOOL(^)(T obj, NSUInteger idx))filterFunc; +- (void)flex_forEach:(void(^)(T obj, NSUInteger idx))block; + +/// Unlike \c subArrayWithRange: this will not throw an exception if \c maxLength +/// is greater than the size of the array. If the array has one element and +/// \c maxLength is greater than 1, you get an array with 1 element back. +- (instancetype)flex_subArrayUpto:(NSUInteger)maxLength; + ++ (instancetype)flex_forEachUpTo:(NSUInteger)bound map:(T(^)(NSUInteger i))block; ++ (instancetype)flex_mapped:(id)collection block:(id(^)(T obj, NSUInteger idx))mapFunc; + +- (instancetype)flex_sortedUsingSelector:(SEL)selector; + +@end + +@interface NSMutableArray (Functional) + +- (void)flex_filter:(BOOL(^)(T obj, NSUInteger idx))filterFunc; + +@end diff --git a/FLEX/NSDictionary+ObjcRuntime.h b/FLEX/NSDictionary+ObjcRuntime.h new file mode 100644 index 00000000..60d73edb --- /dev/null +++ b/FLEX/NSDictionary+ObjcRuntime.h @@ -0,0 +1,21 @@ +// +// NSDictionary+ObjcRuntime.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/5/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import + +@interface NSDictionary (ObjcRuntime) + +/// \c kFLEXPropertyAttributeKeyTypeEncoding is the only required key. +/// Keys representing a boolean value should have a value of \c YES instead of an empty string. +- (NSString *)propertyAttributesString; + ++ (instancetype)attributesDictionaryForProperty:(objc_property_t)property; + +@end diff --git a/FLEX/NSMapTable+FLEX_Subscripting.h b/FLEX/NSMapTable+FLEX_Subscripting.h new file mode 100644 index 00000000..f3b660b5 --- /dev/null +++ b/FLEX/NSMapTable+FLEX_Subscripting.h @@ -0,0 +1,20 @@ +// +// NSMapTable+FLEX_Subscripting.h +// FLEX +// +// Created by Tanner Bennett on 1/9/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSMapTable (FLEX_Subscripting) + +- (nullable ObjectType)objectForKeyedSubscript:(KeyType)key; +- (void)setObject:(nullable ObjectType)obj forKeyedSubscript:(KeyType )key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/NSObject+FLEX_Reflection.h b/FLEX/NSObject+FLEX_Reflection.h new file mode 100644 index 00000000..dcff9635 --- /dev/null +++ b/FLEX/NSObject+FLEX_Reflection.h @@ -0,0 +1,234 @@ +// +// NSObject+FLEX_Reflection.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 6/30/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import +#import +@class FLEXMirror, FLEXMethod, FLEXIvar, FLEXProperty, FLEXMethodBase, FLEXPropertyAttributes, FLEXProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/// Returns the type encoding string given the encoding for the return type and parameters, if any. +/// @discussion Example usage for a \c void returning method which takes +/// an \c int: @code FLEXTypeEncoding(@encode(void), @encode(int)); +/// @param returnType The encoded return type. \c void for exmaple would be \c @encode(void). +/// @param count The number of parameters in this type encoding string. +/// @return The type encoding string, or \c nil if \e returnType is \c NULL. +NSString * FLEXTypeEncodingString(const char *returnType, NSUInteger count, ...); + +NSArray *FLEXGetAllSubclasses(_Nullable Class cls, BOOL includeSelf); +NSArray *FLEXGetClassHierarchy(_Nullable Class cls, BOOL includeSelf); +NSArray *FLEXGetConformedProtocols(_Nullable Class cls); + +NSArray *FLEXGetAllIvars(_Nullable Class cls); +/// @param cls a class object to get instance properties, +/// or a metaclass object to get class properties +NSArray *FLEXGetAllProperties(_Nullable Class cls); +/// @param cls a class object to get instance methods, +/// or a metaclass object to get class methods +/// @param instance used to mark methods as instance methods or not. +/// Not used to determine whether to get instance or class methods. +NSArray *FLEXGetAllMethods(_Nullable Class cls, BOOL instance); +/// @param cls a class object to get all instance and class methods. +NSArray *FLEXGetAllInstanceAndClassMethods(_Nullable Class cls); + + + +#pragma mark Reflection +@interface NSObject (Reflection) + +@property (nonatomic, readonly ) FLEXMirror *flex_reflection; +@property (nonatomic, readonly, class) FLEXMirror *flex_reflection; + +/// Calls into /c FLEXGetAllSubclasses +/// @return Every subclass of the receiving class, including the receiver itself. +@property (nonatomic, readonly, class) NSArray *flex_allSubclasses; + +/// @return The \c Class object for the metaclass of the recieving class, or \c Nil if the class is Nil or not registered. +@property (nonatomic, readonly, class) Class flex_metaclass; +/// @return The size in bytes of instances of the recieving class, or \c 0 if \e cls is \c Nil. +@property (nonatomic, readonly, class) size_t flex_instanceSize; + +/// Changes the class of an object instance. +/// @return The previous value of the objects \c class, or \c Nil if the object is \c nil. +- (Class)flex_setClass:(Class)cls; +/// Sets the recieving class's superclass. "You should not use this method" — Apple. +/// @return The old superclass. ++ (Class)flex_setSuperclass:(Class)superclass; + +/// Calls into \c FLEXGetClassHierarchy() +/// @return a list of classes going up the class hierarchy, +/// starting with the receiver and ending with the root class. +@property (nonatomic, readonly, class) NSArray *flex_classHierarchy; + +/// Calls into \c FLEXGetConformedProtocols +/// @return a list of protocols this class itself conforms to. +@property (nonatomic, readonly, class) NSArray *flex_protocols; + +@end + + +#pragma mark Methods +@interface NSObject (Methods) + +/// All instance and class methods specific to the recieving class. +/// @discussion This method will only retrieve methods specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXMethod objects. +@property (nonatomic, readonly, class) NSArray *flex_allMethods; +/// All instance methods specific to the recieving class. +/// @discussion This method will only retrieve methods specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXMethod objects. +@property (nonatomic, readonly, class) NSArray *flex_allInstanceMethods; +/// All class methods specific to the recieving class. +/// @discussion This method will only retrieve methods specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXMethod objects. +@property (nonatomic, readonly, class) NSArray *flex_allClassMethods; + +/// Retrieves the class's instance method with the given name. +/// @return An initialized \c FLEXMethod object, or \c nil if the method wasn't found. ++ (FLEXMethod *)flex_methodNamed:(NSString *)name; + +/// Retrieves the class's class method with the given name. +/// @return An initialized \c FLEXMethod object, or \c nil if the method wasn't found. ++ (FLEXMethod *)flex_classMethodNamed:(NSString *)name; + +/// Adds a new method to the recieving class with a given name and implementation. +/// @discussion This method will add an override of a superclass's implementation, +/// but will not replace an existing implementation in the class. +/// To change an existing implementation, use \c replaceImplementationOfMethod:with:. +/// +/// Type encodings start with the return type and end with the parameter types in order. +/// The type encoding for \c NSArray's \c count property getter looks like this: +/// @code [NSString stringWithFormat:@"%s%s%s%s", @encode(void), @encode(id), @encode(SEL), @encode(NSUInteger)] @endcode +/// Using the \c FLEXTypeEncoding function for the same method looks like this: +/// @code FLEXTypeEncodingString(@encode(void), 1, @encode(NSUInteger)) @endcode +/// @param typeEncoding The type encoding string. Consider using the \c FLEXTypeEncodingString() function. +/// @param instanceMethod NO to add the method to the class itself or YES to add it as an instance method. +/// @return YES if the method was added successfully, \c NO otherwise +/// (for example, the class already contains a method implementation with that name). ++ (BOOL)addMethod:(SEL)selector + typeEncoding:(NSString *)typeEncoding + implementation:(IMP)implementaiton + toInstances:(BOOL)instanceMethod; + +/// Replaces the implementation of a method in the recieving class. +/// @param instanceMethod YES to replace the instance method, NO to replace the class method. +/// @note This function behaves in two different ways: +/// +/// - If the method does not yet exist in the recieving class, it is added as if +/// \c addMethod:typeEncoding:implementation were called. +/// +/// - If the method does exist, its \c IMP is replaced. +/// @return The previous \c IMP of \e method. ++ (IMP)replaceImplementationOfMethod:(FLEXMethodBase *)method with:(IMP)implementation useInstance:(BOOL)instanceMethod; +/// Swaps the implementations of the given methods. +/// @discussion If one or neither of the given methods exist in the recieving class, +/// they are added to the class with their implementations swapped as if each method did exist. +/// This method will not fail if each \c FLEXSimpleMethod contains a valid selector. +/// @param instanceMethod YES to swizzle the instance method, NO to swizzle the class method. ++ (void)swizzle:(FLEXMethodBase *)original with:(FLEXMethodBase *)other onInstance:(BOOL)instanceMethod; +/// Swaps the implementations of the given methods. +/// @param instanceMethod YES to swizzle the instance method, NO to swizzle the class method. +/// @return \c YES if successful, and \c NO if selectors could not be retrieved from the given strings. ++ (BOOL)swizzleByName:(NSString *)original with:(NSString *)other onInstance:(BOOL)instanceMethod; +/// Swaps the implementations of methods corresponding to the given selectors. ++ (void)swizzleBySelector:(SEL)original with:(SEL)other onInstance:(BOOL)instanceMethod; + +@end + + +#pragma mark Properties +@interface NSObject (Ivars) + +/// All of the instance variables specific to the recieving class. +/// @discussion This method will only retrieve instance varibles specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call \c [[self superclass] allIvars]. +/// @return An array of \c FLEXIvar objects. +@property (nonatomic, readonly, class) NSArray *flex_allIvars; + +/// Retrieves an instance variable with the corresponding name. +/// @return An initialized \c FLEXIvar object, or \c nil if the Ivar wasn't found. ++ (FLEXIvar *)flex_ivarNamed:(NSString *)name; + +/// @return The address of the given ivar in the recieving object in memory, +/// or \c NULL if it could not be found. +- (void *)flex_getIvarAddress:(FLEXIvar *)ivar; +/// @return The address of the given ivar in the recieving object in memory, +/// or \c NULL if it could not be found. +- (void *)flex_getIvarAddressByName:(NSString *)name; +/// @discussion This method faster than creating an \c FLEXIvar and calling +/// \c -getIvarAddress: if you already have an \c Ivar on hand +/// @return The address of the given ivar in the recieving object in memory, +/// or \c NULL if it could not be found\. +- (void *)flex_getObjcIvarAddress:(Ivar)ivar; + +/// Sets the value of the given instance variable on the recieving object. +/// @discussion Use only when the target instance variable is an object. +- (void)flex_setIvar:(FLEXIvar *)ivar object:(id)value; +/// Sets the value of the given instance variable on the recieving object. +/// @discussion Use only when the target instance variable is an object. +/// @return \c YES if successful, or \c NO if the instance variable could not be found. +- (BOOL)flex_setIvarByName:(NSString *)name object:(id)value; +/// @discussion Use only when the target instance variable is an object. +/// This method is faster than creating an \c FLEXIvar and calling +/// \c -setIvar: if you already have an \c Ivar on hand. +- (void)flex_setObjcIvar:(Ivar)ivar object:(id)value; + +/// Sets the value of the given instance variable on the recieving object to the +/// \e size number of bytes of data at \e value. +/// @discussion Use one of the other methods if you can help it. +- (void)flex_setIvar:(FLEXIvar *)ivar value:(void *)value size:(size_t)size; +/// Sets the value of the given instance variable on the recieving object to the +/// \e size number of bytes of data at \e value. +/// @discussion Use one of the other methods if you can help it +/// @return \c YES if successful, or \c NO if the instance variable could not be found. +- (BOOL)flex_setIvarByName:(NSString *)name value:(void *)value size:(size_t)size; +/// Sets the value of the given instance variable on the recieving object to the +/// \e size number of bytes of data at \e value. +/// @discussion This is faster than creating an \c FLEXIvar and calling +/// \c -setIvar:value:size if you already have an \c Ivar on hand. +- (void)flex_setObjcIvar:(Ivar)ivar value:(void *)value size:(size_t)size; + +@end + +#pragma mark Properties +@interface NSObject (Properties) + +/// All instance and class properties specific to the recieving class. +/// @discussion This method will only retrieve properties specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXProperty objects. +@property (nonatomic, readonly, class) NSArray *flex_allProperties; +/// All instance properties specific to the recieving class. +/// @discussion This method will only retrieve properties specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXProperty objects. +@property (nonatomic, readonly, class) NSArray *flex_allInstanceProperties; +/// All class properties specific to the recieving class. +/// @discussion This method will only retrieve properties specific to the recieving class. +/// To retrieve instance variables on a parent class, simply call this on \c [self superclass]. +/// @return An array of \c FLEXProperty objects. +@property (nonatomic, readonly, class) NSArray *flex_allClassProperties; + +/// Retrieves the class's property with the given name. +/// @return An initialized \c FLEXProperty object, or \c nil if the property wasn't found. ++ (FLEXProperty *)flex_propertyNamed:(NSString *)name; +/// @return An initialized \c FLEXProperty object, or \c nil if the property wasn't found. ++ (FLEXProperty *)flex_classPropertyNamed:(NSString *)name; + +/// Replaces the given property on the recieving class. ++ (void)flex_replaceProperty:(FLEXProperty *)property; +/// Replaces the given property on the recieving class. Useful for changing a property's attributes. ++ (void)flex_replaceProperty:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/FLEX/NSString+FLEX.h b/FLEX/NSString+FLEX.h new file mode 100644 index 00000000..87194994 --- /dev/null +++ b/FLEX/NSString+FLEX.h @@ -0,0 +1,33 @@ +// +// NSString+FLEX.h +// FLEX +// +// Created by Tanner on 3/26/17. +// Copyright © 2017 Tanner Bennett. All rights reserved. +// + +#import "FLEXRuntimeConstants.h" + +@interface NSString (FLEXTypeEncoding) + +///@return whether this type starts with the const specifier +@property (nonatomic, readonly) BOOL flex_typeIsConst; +/// @return the first char in the type encoding that is not the const specifier +@property (nonatomic, readonly) FLEXTypeEncoding flex_firstNonConstType; +/// @return the first char in the type encoding after the pointer specifier, if it is a pointer +@property (nonatomic, readonly) FLEXTypeEncoding flex_pointeeType; +/// @return whether this type is an objc object of any kind, even if it's const +@property (nonatomic, readonly) BOOL flex_typeIsObjectOrClass; +/// @return the class named in this type encoding if it is of the form \c @"MYClass" +@property (nonatomic, readonly) Class flex_typeClass; +/// Includes C strings and selectors as well as regular pointers +@property (nonatomic, readonly) BOOL flex_typeIsNonObjcPointer; + +@end + +@interface NSString (KeyPaths) + +- (NSString *)flex_stringByRemovingLastKeyPathComponent; +- (NSString *)flex_stringByReplacingLastKeyPathComponent:(NSString *)replacement; + +@end diff --git a/FLEX/NSString+ObjcRuntime.h b/FLEX/NSString+ObjcRuntime.h new file mode 100644 index 00000000..85cdae69 --- /dev/null +++ b/FLEX/NSString+ObjcRuntime.h @@ -0,0 +1,23 @@ +// +// NSString+ObjcRuntime.h +// FLEX +// +// Derived from MirrorKit. +// Created by Tanner on 7/1/15. +// Copyright (c) 2020 FLEX Team. All rights reserved. +// + +#import + +@interface NSString (Utilities) + +/// A dictionary of property attributes if the receiver is a valid property attributes string. +/// Values are either a string or \c YES. Boolean attributes which are false will not be +/// present in the dictionary. See this link on how to construct a proper attributes string: +/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html +/// +/// Note: this method doesn't work properly for certain type encodings, and neither does +/// the property_copyAttributeValue function in the runtime itself. Radar: FB7499230 +- (NSDictionary *)propertyAttributes; + +@end diff --git a/FLEX/NSTimer+FLEX.h b/FLEX/NSTimer+FLEX.h new file mode 100644 index 00000000..c1e883c9 --- /dev/null +++ b/FLEX/NSTimer+FLEX.h @@ -0,0 +1,19 @@ +// +// NSTimer+Blocks.h +// FLEX +// +// Created by Tanner on 3/23/17. +// + +#import + +typedef void (^VoidBlock)(void); + +@interface NSTimer (Blocks) + ++ (instancetype)flex_fireSecondsFromNow:(NSTimeInterval)delay block:(VoidBlock)block; + +// Forward declaration +//+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block; + +@end diff --git a/FLEX/NSUserDefaults+FLEX.h b/FLEX/NSUserDefaults+FLEX.h new file mode 100644 index 00000000..38d2d8b9 --- /dev/null +++ b/FLEX/NSUserDefaults+FLEX.h @@ -0,0 +1,46 @@ +// +// NSUserDefaults+FLEX.h +// FLEX +// +// Created by Tanner on 3/10/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +// Only use these if the getters and setters aren't good enough for whatever reason +extern NSString * const kFLEXDefaultsToolbarTopMarginKey; +extern NSString * const kFLEXDefaultsiOSPersistentOSLogKey; +extern NSString * const kFLEXDefaultsHidePropertyIvarsKey; +extern NSString * const kFLEXDefaultsHidePropertyMethodsKey; +extern NSString * const kFLEXDefaultsHidePrivateMethodsKey; +extern NSString * const kFLEXDefaultsShowMethodOverridesKey; +extern NSString * const kFLEXDefaultsHideVariablePreviewsKey; +extern NSString * const kFLEXDefaultsNetworkHostBlacklistKey; +extern NSString * const kFLEXDefaultsDisableOSLogForceASLKey; +extern NSString * const kFLEXDefaultsRegisterJSONExplorerKey; + +/// All BOOL preferences are NO by default +@interface NSUserDefaults (FLEX) + +- (void)flex_toggleBoolForKey:(NSString *)key; + +@property (nonatomic) double flex_toolbarTopMargin; + +// Not actually stored in defaults, but written to a file +@property (nonatomic) NSArray *flex_networkHostBlacklist; + +/// Whether or not to register the object explorer as a JSON viewer on launch +@property (nonatomic) BOOL flex_registerDictionaryJSONViewerOnLaunch; + +/// Disable os_log and re-enable ASL. May break Console.app output. +@property (nonatomic) BOOL flex_disableOSLog; +@property (nonatomic) BOOL flex_cacheOSLogMessages; + +@property (nonatomic) BOOL flex_explorerHidesPropertyIvars; +@property (nonatomic) BOOL flex_explorerHidesPropertyMethods; +@property (nonatomic) BOOL flex_explorerHidesPrivateMethods; +@property (nonatomic) BOOL flex_explorerShowsMethodOverrides; +@property (nonatomic) BOOL flex_explorerHidesVariablePreviews; + +@end diff --git a/FLEX/SceneKit+Snapshot.h b/FLEX/SceneKit+Snapshot.h new file mode 100644 index 00000000..8148ff9b --- /dev/null +++ b/FLEX/SceneKit+Snapshot.h @@ -0,0 +1,62 @@ +// +// SceneKit+Snapshot.h +// FLEX +// +// Created by Tanner Bennett on 1/8/20. +// + +#import +#import "FHSViewSnapshot.h" +@class FHSSnapshotNodes; + +extern CGFloat const kFHSSmallZOffset; + +#pragma mark SCNNode +@interface SCNNode (Snapshot) + +/// @return the nearest ancestor snapshot node starting at this node +@property (nonatomic, readonly) SCNNode *nearestAncestorSnapshot; + +/// @return a node that renders a highlight overlay over a specified snapshot ++ (instancetype)highlight:(FHSViewSnapshot *)view color:(UIColor *)color; +/// @return a node that renders a snapshot image ++ (instancetype)snapshot:(FHSViewSnapshot *)view; +/// @return a node that draws a line between two vertices ++ (instancetype)lineFrom:(SCNVector3)v1 to:(SCNVector3)v2 color:(UIColor *)lineColor; + +/// @return a node that can be used to render a colored border around the specified node +- (instancetype)borderWithColor:(UIColor *)color; +/// @return a node that renders a header above a snapshot node +/// using the title text from the view, if specified ++ (instancetype)header:(FHSViewSnapshot *)view; + +/// @return a SceneKit node that recursively renders a hierarchy +/// of UI elements starting at the specified snapshot ++ (instancetype)snapshot:(FHSViewSnapshot *)view + parent:(FHSViewSnapshot *)parentView + parentNode:(SCNNode *)parentNode + root:(SCNNode *)rootNode + depth:(NSInteger *)depthOut + nodesMap:(NSMutableDictionary *)nodesMap + hideHeaders:(BOOL)hideHeaders; + +@end + + +#pragma mark SCNShape +@interface SCNShape (Snapshot) +/// @return a shape with the given path, 0 extrusion depth, and a double-sided +/// material with the given diffuse contents inserted at index 0 ++ (instancetype)shapeWithPath:(UIBezierPath *)path materialDiffuse:(id)contents; +/// @return a shape that is used to render the background of the snapshot header ++ (instancetype)nameHeader:(UIColor *)color frame:(CGRect)frame corners:(CGFloat)cornerRadius; + +@end + + +#pragma mark SCNText +@interface SCNText (Snapshot) +/// @return text geometry used to render text inside the snapshot header ++ (instancetype)labelGeometry:(NSString *)text font:(UIFont *)font; + +@end diff --git a/FLEX/UIBarButtonItem+FLEX.h b/FLEX/UIBarButtonItem+FLEX.h new file mode 100644 index 00000000..eff4a60f --- /dev/null +++ b/FLEX/UIBarButtonItem+FLEX.h @@ -0,0 +1,38 @@ +// +// UIBarButtonItem+FLEX.h +// FLEX +// +// Created by Tanner on 2/4/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +#define FLEXBarButtonItemSystem(item, tgt, sel) \ + [UIBarButtonItem flex_systemItem:UIBarButtonSystemItem##item target:tgt action:sel] + +@interface UIBarButtonItem (FLEX) + +@property (nonatomic, readonly, class) UIBarButtonItem *flex_flexibleSpace; +@property (nonatomic, readonly, class) UIBarButtonItem *flex_fixedSpace; + ++ (instancetype)flex_itemWithCustomView:(UIView *)customView; ++ (instancetype)flex_backItemWithTitle:(NSString *)title; + ++ (instancetype)flex_systemItem:(UIBarButtonSystemItem)item target:(id)target action:(SEL)action; + ++ (instancetype)flex_itemWithTitle:(NSString *)title target:(id)target action:(SEL)action; ++ (instancetype)flex_doneStyleitemWithTitle:(NSString *)title target:(id)target action:(SEL)action; + ++ (instancetype)flex_itemWithImage:(UIImage *)image target:(id)target action:(SEL)action; + ++ (instancetype)flex_disabledSystemItem:(UIBarButtonSystemItem)item; ++ (instancetype)flex_disabledItemWithTitle:(NSString *)title style:(UIBarButtonItemStyle)style; ++ (instancetype)flex_disabledItemWithImage:(UIImage *)image; + +/// @return the receiver +- (UIBarButtonItem *)flex_withTintColor:(UIColor *)tint; + +- (void)_setWidth:(CGFloat)width; + +@end diff --git a/FLEX/UIFont+FLEX.h b/FLEX/UIFont+FLEX.h new file mode 100644 index 00000000..b668ea2c --- /dev/null +++ b/FLEX/UIFont+FLEX.h @@ -0,0 +1,17 @@ +// +// UIFont+FLEX.h +// FLEX +// +// Created by Tanner Bennett on 12/20/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface UIFont (FLEX) + +@property (nonatomic, readonly, class) UIFont *flex_defaultTableCellFont; +@property (nonatomic, readonly, class) UIFont *flex_codeFont; +@property (nonatomic, readonly, class) UIFont *flex_smallCodeFont; + +@end diff --git a/FLEX/UIGestureRecognizer+Blocks.h b/FLEX/UIGestureRecognizer+Blocks.h new file mode 100644 index 00000000..91b39be4 --- /dev/null +++ b/FLEX/UIGestureRecognizer+Blocks.h @@ -0,0 +1,21 @@ +// +// UIGestureRecognizer+Blocks.h +// FLEX +// +// Created by Tanner Bennett on 12/20/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +typedef void (^GestureBlock)(UIGestureRecognizer *gesture); + + +@interface UIGestureRecognizer (Blocks) + ++ (instancetype)flex_action:(GestureBlock)action; + +@property (nonatomic, setter=flex_setAction:) GestureBlock flex_action; + +@end + diff --git a/FLEX/UIMenu+FLEX.h b/FLEX/UIMenu+FLEX.h new file mode 100644 index 00000000..4ec59569 --- /dev/null +++ b/FLEX/UIMenu+FLEX.h @@ -0,0 +1,19 @@ +// +// UIMenu+FLEX.h +// FLEX +// +// Created by Tanner on 1/28/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface UIMenu (FLEX) + ++ (instancetype)flex_inlineMenuWithTitle:(NSString *)title + image:(UIImage *)image + children:(NSArray *)children; + +- (instancetype)flex_collapsed; + +@end diff --git a/FLEX/UIPasteboard+FLEX.h b/FLEX/UIPasteboard+FLEX.h new file mode 100644 index 00000000..20f1b0c7 --- /dev/null +++ b/FLEX/UIPasteboard+FLEX.h @@ -0,0 +1,16 @@ +// +// UIPasteboard+FLEX.h +// FLEX +// +// Created by Tanner Bennett on 12/9/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +@interface UIPasteboard (FLEX) + +/// For copying an object which could be a string, data, or number +- (void)flex_copy:(id)unknownType; + +@end diff --git a/FLEX/UITextField+Range.h b/FLEX/UITextField+Range.h new file mode 100644 index 00000000..a86a4ce1 --- /dev/null +++ b/FLEX/UITextField+Range.h @@ -0,0 +1,14 @@ +// +// UITextField+Range.h +// FLEX +// +// Created by Tanner on 6/13/17. +// + +#import + +@interface UITextField (Range) + +@property (nonatomic, readonly) NSRange flex_selectedRange; + +@end diff --git a/FLEX/UIView+FLEX_Layout.h b/FLEX/UIView+FLEX_Layout.h new file mode 100644 index 00000000..c50f7d17 --- /dev/null +++ b/FLEX/UIView+FLEX_Layout.h @@ -0,0 +1,23 @@ +// +// UIView+FLEX_Layout.h +// FLEX +// +// Created by Tanner Bennett on 7/18/19. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +#define Padding(p) UIEdgeInsetsMake(p, p, p, p) + +@interface UIView (FLEX_Layout) + +- (void)flex_centerInView:(UIView *)view; +- (void)flex_pinEdgesTo:(UIView *)view; +- (void)flex_pinEdgesTo:(UIView *)view withInsets:(UIEdgeInsets)insets; +- (void)flex_pinEdgesToSuperview; +- (void)flex_pinEdgesToSuperviewWithInsets:(UIEdgeInsets)insets; +- (void)flex_pinEdgesToSuperviewWithInsets:(UIEdgeInsets)insets aboveView:(UIView *)sibling; +- (void)flex_pinEdgesToSuperviewWithInsets:(UIEdgeInsets)insets belowView:(UIView *)sibling; + +@end diff --git a/FLEX/flex_fishhook.h b/FLEX/flex_fishhook.h new file mode 100644 index 00000000..1f02191d --- /dev/null +++ b/FLEX/flex_fishhook.h @@ -0,0 +1,77 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef fishhook_h +#define fishhook_h + +#include +#include + +#if !defined(FISHHOOK_EXPORT) +#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/** + * A structure representing a particular intended rebinding from a symbol + * name to its replacement + */ +struct rebinding { + const char *name; + void *replacement; + void **replaced; +}; + +/** + * For each rebinding in rebindings, rebinds references to external, indirect + * symbols with the specified name to instead point at replacement for each + * image in the calling process as well as for all future images that are loaded + * by the process. If rebind_functions is called more than once, the symbols to + * rebind are added to the existing list of rebindings, and if a given symbol + * is rebound more than once, the later rebinding will take precedence. + * @return 0 on success + */ +FISHHOOK_VISIBILITY +int flex_rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); + +/** + * Rebinds as above, but only in the specified image. The header should point + * to the mach-o header, the slide should be the slide offset. Others as above. + * @return 0 on success + */ +FISHHOOK_VISIBILITY +int flex_rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //fishhook_h diff --git a/FLEX/module.modulemap b/FLEX/module.modulemap new file mode 100644 index 00000000..7a10ccdb --- /dev/null +++ b/FLEX/module.modulemap @@ -0,0 +1,8 @@ +module FLEX { + umbrella header "FLEX.h" + + link "flex" + + export * + module * { export * } +}