Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e1fcf4682 | |||
| 4d50fd2020 | |||
| 2c510c8ca1 | |||
| 8283e2a8e7 | |||
| 3f82631a95 | |||
| d77864494d | |||
| c5ed6d4ece | |||
| 9412f6eccf | |||
| d9aa102e77 | |||
| 6f80476135 |
@@ -360,7 +360,9 @@ typedef NS_ENUM(NSUInteger, FLEXFileBrowserSortAttribute) {
|
||||
|
||||
#if FLEX_AT_LEAST_IOS13_SDK
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil
|
||||
previewProvider:nil
|
||||
|
||||
@@ -265,8 +265,30 @@ static BOOL my_os_log_shim_enabled(void *addr) {
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
if (action == @selector(copy:)) {
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText;
|
||||
UIPasteboard.generalPasteboard.string = self.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
}
|
||||
}
|
||||
|
||||
#if FLEX_AT_LEAST_IOS13_SDK
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil
|
||||
previewProvider:nil
|
||||
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
|
||||
UIAction *copy = [UIAction actionWithTitle:@"Copy"
|
||||
image:nil
|
||||
identifier:@"Copy"
|
||||
handler:^(__kindof UIAction *action) {
|
||||
// We usually only want to copy the log message itself, not any metadata associated with it.
|
||||
UIPasteboard.generalPasteboard.string = weakSelf.logMessages.filteredList[indexPath.row].messageText ?: @"";
|
||||
}];
|
||||
return [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[copy]];
|
||||
}];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,6 +38,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)registerGlobalEntryWithName:(NSString *)entryName
|
||||
viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock;
|
||||
|
||||
/// Removes all registered global entries.
|
||||
- (void)clearGlobalEntries;
|
||||
|
||||
#pragma mark - Simulator Shortcuts
|
||||
|
||||
/// Simulator keyboard shortcuts are enabled by default.
|
||||
|
||||
@@ -58,6 +58,11 @@
|
||||
[self.userGlobalEntries addObject:entry];
|
||||
}
|
||||
|
||||
- (void)clearGlobalEntries
|
||||
{
|
||||
[self.userGlobalEntries removeAllObjects];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Simulator Shortcuts
|
||||
|
||||
@@ -95,60 +100,60 @@
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"f" modifiers:0 action:^{
|
||||
[self toggleExplorer];
|
||||
} description:@"Toggle FLEX toolbar"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"g" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleMenuTool];
|
||||
} description:@"Toggle FLEX globals menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"v" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleViewsTool];
|
||||
} description:@"Toggle view hierarchy menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"s" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleSelectTool];
|
||||
} description:@"Toggle select tool"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"m" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
[self.explorerViewController toggleMoveTool];
|
||||
} description:@"Toggle move tool"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"n" modifiers:0 action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXNetworkMITMViewController class]];
|
||||
} description:@"Toggle network history view"];
|
||||
|
||||
|
||||
// 't' is for testing: quickly present an object explorer for debugging
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"t" modifiers:0 action:^{
|
||||
[self showExplorerIfNeeded];
|
||||
|
||||
|
||||
[self.explorerViewController toggleToolWithViewControllerProvider:^UINavigationController *{
|
||||
return [FLEXNavigationController withRootViewController:[FLEXObjectExplorerFactory
|
||||
explorerViewControllerForObject:NSBundle.mainBundle
|
||||
]];
|
||||
} completion:nil];
|
||||
} description:@"Present an object explorer for debugging"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputDownArrow modifiers:0 action:^{
|
||||
if (self.isHidden || ![self.explorerViewController handleDownArrowKeyPressed]) {
|
||||
[self tryScrollDown];
|
||||
}
|
||||
} description:@"Cycle view selection\n\t\tMove view down\n\t\tScroll down"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputUpArrow modifiers:0 action:^{
|
||||
if (self.isHidden || ![self.explorerViewController handleUpArrowKeyPressed]) {
|
||||
[self tryScrollUp];
|
||||
}
|
||||
} description:@"Cycle view selection\n\t\tMove view up\n\t\tScroll up"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputRightArrow modifiers:0 action:^{
|
||||
if (!self.isHidden) {
|
||||
[self.explorerViewController handleRightArrowKeyPressed];
|
||||
}
|
||||
} description:@"Move selected view right"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputLeftArrow modifiers:0 action:^{
|
||||
if (self.isHidden) {
|
||||
[self tryGoBack];
|
||||
@@ -156,15 +161,15 @@
|
||||
[self.explorerViewController handleLeftArrowKeyPressed];
|
||||
}
|
||||
} description:@"Move selected view left"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"?" modifiers:0 action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXKeyboardHelpViewController class]];
|
||||
} description:@"Toggle (this) help menu"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:UIKeyInputEscape modifiers:0 action:^{
|
||||
[[self.topViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];
|
||||
} description:@"End editing text\n\t\tDismiss top view controller"];
|
||||
|
||||
|
||||
[self registerDefaultSimulatorShortcutWithKey:@"o" modifiers:UIKeyModifierCommand|UIKeyModifierShift action:^{
|
||||
[self toggleTopViewControllerOfClass:[FLEXFileBrowserController class]];
|
||||
} description:@"Toggle file browser menu"];
|
||||
@@ -183,7 +188,7 @@
|
||||
if (@available(iOS 11, *)) {
|
||||
return scrollView.adjustedContentInset;
|
||||
}
|
||||
|
||||
|
||||
return scrollView.contentInset;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,14 @@ static NSMutableDictionary<Class, Class> *classesToRegisteredSections = nil;
|
||||
|
||||
+ (void)initialize {
|
||||
if (self == [FLEXObjectExplorerFactory class]) {
|
||||
// DO NOT USE STRING KEYS HERE
|
||||
// We NEED to use the class as a key, because we CANNOT
|
||||
// differentiate a class's name from the metaclass's name.
|
||||
// These mappings are per-class-object, not per-class-name.
|
||||
//
|
||||
// For example, if we used class names, this would result in
|
||||
// the object explorer trying to render a color preview for
|
||||
// the UIColor class object, which is not a color itself.
|
||||
#define ClassKey(name) (Class<NSCopying>)[name class]
|
||||
#define ClassKeyByName(str) (Class<NSCopying>)NSClassFromString(@ #str)
|
||||
#define MetaclassKey(meta) (Class<NSCopying>)object_getClass([meta class])
|
||||
|
||||
@@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@optional
|
||||
/// Called when the (i) button is pressed if the accessory type includes it
|
||||
- (UIViewController *)editorWith:(id)object;
|
||||
- (UIViewController *)editorWith:(id)object forSection:(FLEXTableViewSection *)section;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -201,10 +201,10 @@
|
||||
|
||||
- (void (^)(__kindof UIViewController *))didPressInfoButtonAction:(NSInteger)row {
|
||||
id<FLEXShortcut> shortcut = self.shortcuts[row];
|
||||
if ([shortcut respondsToSelector:@selector(editorWith:)]) {
|
||||
if ([shortcut respondsToSelector:@selector(editorWith:forSection:)]) {
|
||||
id object = self.object;
|
||||
return ^(UIViewController *host) {
|
||||
UIViewController *editor = [shortcut editorWith:object];
|
||||
UIViewController *editor = [shortcut editorWith:object forSection:self];
|
||||
[host.navigationController pushViewController:editor animated:YES];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
return item;
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)withTintColor:(UIColor *)tint {
|
||||
- (UIBarButtonItem *)flex_withTintColor:(UIColor *)tint {
|
||||
self.tintColor = tint;
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#define FLEX_IS_TESTING() (NSClassFromString(@"XCTest") != nil)
|
||||
|
||||
/// Whether we want the majority of constructors to run upon load or not.
|
||||
extern BOOL FLEXConstructorsShouldRun();
|
||||
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;
|
||||
|
||||
@@ -21,11 +21,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
UserDefaults.standard.set("foo", forKey: "FLEXamplePrefFoo")
|
||||
|
||||
// To show off the system log viewer, send 10 example log messages at 3 second intervals
|
||||
self.repeatingLogExampleTimer = Timer(
|
||||
timeInterval: 3, target: self,
|
||||
selector: #selector(sendExampleLogMessage),
|
||||
userInfo: nil, repeats: true
|
||||
)
|
||||
self.repeatingLogExampleTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] (_) in
|
||||
if let self = self {
|
||||
NSLog("Example log \(self.exampleLogSent)")
|
||||
|
||||
self.exampleLogSent += 1
|
||||
if self.exampleLogSent > self.exampleLogLimit {
|
||||
self.repeatingLogExampleTimer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To show off the network logger, send several misc network requests
|
||||
MiscNetworkRequests.sendExampleRequests()
|
||||
@@ -56,13 +61,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
let exampleLogLimit = 10
|
||||
var exampleLogSent = 0
|
||||
|
||||
func sendExampleLogMessage() {
|
||||
NSLog("Example log \(self.exampleLogSent)")
|
||||
|
||||
self.exampleLogSent += 1
|
||||
if self.exampleLogSent > self.exampleLogLimit {
|
||||
self.repeatingLogExampleTimer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "FLEX"
|
||||
spec.version = "4.2.0"
|
||||
spec.version = "4.2.2"
|
||||
spec.summary = "A set of in-app debugging and exploration tools for iOS"
|
||||
spec.description = <<-DESC
|
||||
- Inspect and modify views in the hierarchy.
|
||||
|
||||
Reference in New Issue
Block a user