Compare commits

...

111 Commits

Author SHA1 Message Date
Tanner Bennett 258ec8697b Bump version 2021-03-30 14:20:02 -05:00
Tanner Bennett 8f9a6e88ec Fix toolbar appearing when empty 2021-03-30 14:20:02 -05:00
Tanner Bennett c37270e6ac Add shortcuts for NSString and NSData 2021-03-30 14:20:02 -05:00
Tanner Bennett ce10d45c29 Fix "hide likely private methods" behavior
Hide relevant private properties too, also class properties and methods
2021-03-30 14:20:02 -05:00
Tanner Bennett b2716c4b2e Catch potential exceptions thrown from descriptions 2021-03-30 14:20:02 -05:00
Tanner Bennett ab135ba94e Remove uninclusive terms
Blacklist → exclude[d] / denylist
Whitelist → allow[ed] / unexcluded
2021-03-30 14:20:02 -05:00
Tanner Bennett bcc04f4113 Make FLEXMacros.h private 2021-03-30 14:20:02 -05:00
Tanner Bennett 470b3fa3b3 Add tintColor as real property 2021-03-30 14:20:02 -05:00
Tanner Bennett e84dfeae5c Fix object explorer class pan gesture… again… 2021-03-30 14:20:02 -05:00
Tanner Bennett 44e86e59b7 Fix Xcode 12 compile errors 2021-03-30 14:20:02 -05:00
Tanner Bennett ac6d9cfa3f Misc refactoring 2021-03-30 14:20:02 -05:00
Tanner Bennett 1a59711760 Fix a crash, add some missing nullabilities 2021-03-30 14:20:01 -05:00
Tanner Bennett b60ce7a057 Add UIAlertController shortcuts
Fix alert controller
2021-03-30 14:20:01 -05:00
Tanner Bennett b4ac210bef Use likely ivar to determine matching property 2021-03-29 13:55:52 -05:00
Tanner Bennett 9360c58975 Add likely ivar data to FLEXProperty 2021-03-29 13:55:52 -05:00
Tanner Bennett 43d9a460ce Make the keyboard seem to appear faster
On screens where the keyboard is set to appear right away, make it appear faster—or at least, make it look like it appears faster…

Also add a property to make the search bar appear initially instead of duplicating becomeFirstResponder code across several classes
2021-03-29 13:55:51 -05:00
ray 15fee5a8a5 Fix keychain viewer crash (#521) 2021-03-23 10:36:29 -05:00
Alexey Salangin fad038392b Don't show toolbar when tapping on a nav bar button (#517) 2021-03-11 13:45:23 -06:00
Tanner Bennett 558d65a0b0 Update license 2021-02-02 14:18:09 -06:00
Tanner Bennett 077fca36c0 Bump deployment targets (oops?) 2021-01-27 23:24:39 -06:00
Tanner Bennett 947769f6f9 Bump version 2021-01-27 17:10:26 -06:00
Tanner Bennett 7c480c5faf Mention tvOS fork in README 2021-01-27 17:09:41 -06:00
Tanner Bennett fa6c72cb08 Fix memory leak 2021-01-27 16:49:10 -06:00
Tanner Bennett 9af2926ec1 Use weakify/strongify throughout project 2021-01-26 12:46:53 -06:00
Tanner Bennett 366a8266bd Add weakify/strongify macros 2021-01-26 12:46:53 -06:00
Tanner Bennett 713fbac54a Move 't' simulator shortcut to the example project
This demonstrates how to register a shortcut from a project with the new pubilc APIs for presenting tools.

I put it in the commit list screen because I didn't feel like rewriting it in Swift.
2021-01-26 12:46:53 -06:00
Tanner Bennett 8198fba689 Add public API to dismiss/present FLEX tools
This API will allow you to present a tool in front of the FLEX toolbar and will automatically dismiss any existing FLEX tool
2021-01-26 12:46:53 -06:00
Tanner Bennett 20e14a36c9 Add -[NSMutableArray flex_filter:] 2021-01-26 11:18:43 -06:00
Tanner Bennett 176e98518d Add context menu item to view references to object 2021-01-20 17:00:37 -06:00
Tanner Bennett 31440056c1 Add option to hide potentially private methods 2021-01-20 17:00:10 -06:00
Tanner Bennett 6c7b39ed03 Fix object explorer swipe gesture precedence 2021-01-20 15:31:25 -06:00
Tanner Bennett 96989f7e0c Refactor FLEXample's AppDelegate.swift 2021-01-20 15:08:06 -06:00
Tanner Bennett 22a23b3b12 Add the Person class back to the example project 2021-01-20 14:59:09 -06:00
Tanner Bennett 90a855a289 Allow registration of global entries with actions
This was previously a private API
2021-01-20 14:37:44 -06:00
matrush fd67373995 Revise object reference section titles logic 2021-01-20 14:37:13 -06:00
Tanner Bennett 3b5e095f74 Add some tests, fix some tests
- Test safeClassNameForObject:
- Test safeObject:respondsToSelector:
- Fix testAssumptionsAboutClasses: which was incorrectly written
2020-12-30 20:06:49 -06:00
Tanner Bennett c7850df186 Add safeClassNameForObject: and use it 2020-12-30 20:06:49 -06:00
Tanner Bennett 6bbcc55cf6 Improve safeObject:respondsToSelector:
The old code assumes the object at least responds to respondsToSelector: which may not always be true. I also I think the old code was not quite correct for all cases anyway.

Using the runtime functions ensures no methods are ever called on the object, and properly handles metaclass objects, in theory.
2020-12-30 20:06:49 -06:00
Tanner Bennett e63ea4bbff Group FLEX objects together in the object refs list 2020-12-30 20:06:49 -06:00
Tanner Bennett 5a760fb1ac Update issue templates 2020-12-30 20:06:49 -06:00
Tanner Bennett e63f2ee3ad Prefix some categories, fix #496 2020-12-30 20:06:49 -06:00
Tanner Bennett 46c6dcb7e6 Fix bug introduced in cb2e0789 2020-12-30 17:31:37 -06:00
Alexey Salangin bf42bbe27b Fix bug with navbar tap gesture
Tap gesture in FLEXNavigationController's navigation bar causes buttons to reportedly become unresponsive on iOS 11 and 12 unless `cancelsTouchesInView` is turned off
2020-12-30 15:27:04 -08:00
Tanner Bennett e89fec4b2d Bump version 2020-12-17 01:57:25 -06:00
Tanner Bennett 715bb92929 Add confirm dialog for clearing the keychain 2020-12-17 01:35:03 -06:00
Tanner Bennett 109074f98e Show service AND account in keychain rows 2020-12-17 01:34:44 -06:00
Tanner Bennett 45fbdb7914 Move keychain buttons to toolbar 2020-12-17 01:34:33 -06:00
Tanner Bennett cb2e0789d8 Fix several memory leaks, fix #483
Also move a bunch of globals related to FLEXShortcutsFactory into ivars of a FLEXShortcutsFactory singleton so that it is easier to trace the origin of the global storage of FLEX[Property|Ivar|Method] objects in a memory graph
2020-12-17 01:17:40 -06:00
vvveiii de1ca783b6 Fix flex_copy: crash when object is nil 2020-12-16 22:30:11 -08:00
vvveiii 3a9c24b784 Add missing else for flex_copy method 2020-12-16 22:30:11 -08:00
Tanner Bennett b57a333fc9 Fix #491, close #473
Remove (most) uses of +[NSString stringWithCString:encoding:]
2020-12-17 00:20:17 -06:00
matrush 288bf1343e Add ability to toggle bg color for image previews
Also fix availability warning
2020-12-15 16:35:27 -08:00
matrush a0b1caed54 Use UITableViewCellAccessoryNone instead of 0 in FLEX[Layer/View]Shortcuts 2020-12-14 18:38:04 -08:00
Tanner Bennett 9282c61183 Allow scrubbing between selected views
Instead of a singular swipe gesture to navigate between views in the view hierarchy at the tap point, we can now pan or drag along that same area to "srub" the hierarchy.
2020-12-14 18:36:44 -06:00
Tanner Bennett ee6677ee08 Add GUI shortcut for initializeWebKitLegacy
We call initializeWebKitLegacy automatically before you search all bundles just to be safe (since touching some classes before WebKit is initialized will initialize it on a thread other than the main thread), but sometimes you can encounter this crash without searching through all bundles, of course.

In this case, you can now long press on the navigation bar to call initializeWebKitLegacy
2020-12-14 17:10:48 -06:00
Tanner Bennett 3276eb3516 Automatically activate search bar in heap explorer
2f952c38 apparently didn't do this, oops
2020-12-14 17:10:48 -06:00
Chaoshuai Lü a3fa7bbadc Fix view/controller preview image issue (#493) 2020-12-14 16:08:58 -06:00
matrush 637074b354 Use id<NSCopying> as key instead of Class<NSCopying> in FLEXObjectExplorerFactory 2020-12-01 16:56:08 -08:00
Tanner Bennett 547bfbaec0 Disallow preview of views with no rect 2020-11-02 20:42:10 -06:00
Tanner Bennett 4e1fcf4682 Bump version, 4.2.2 2020-11-02 19:36:15 -06:00
Tanner Bennett 4d50fd2020 Revert "Use NSString as key …" in d7786449
We NEED to use the class as a key, because you cannot differentiate a class's name from the metaclass's name.
2020-11-02 19:36:15 -06:00
Tanner Bennett 2c510c8ca1 Fix log timer in example app not firing 2020-11-02 17:45:21 -06:00
Tanner Bennett 8283e2a8e7 Fix #415, restore ability to copy log messages 2020-11-02 17:32:29 -06:00
Tanner Bennett 3f82631a95 Fix bug introduced in 4.2.0, unable to edit members
Oopsie
2020-11-02 17:03:37 -06:00
matrush d77864494d Use NSString as key instead of Class<NSCopying> in FLEXObjectExplorerFactory 2020-11-02 16:58:59 -06:00
matrush c5ed6d4ece Add void to function definition of FLEXConstructorsShouldRun 2020-11-02 16:58:59 -06:00
matrush 9412f6eccf Add a clear global entries method for FLEXManager 2020-11-02 16:58:59 -06:00
Tanner Bennett d9aa102e77 Bump version 2020-10-23 16:42:44 -05:00
Oleg 6f80476135 Fix crash on flex_withTintColor (#476) 2020-10-23 16:23:39 -05:00
Tanner Bennett e18a854a9f Bump version, close #465 #466 2020-10-22 18:18:26 -05:00
Tanner Bennett 0d676e2504 Add FLEX_DISABLE_CTORS, close #471 2020-10-22 18:16:18 -05:00
Tanner Bennett fcca09e74a Fix #428, not scrolling to selected view 2020-10-22 17:57:25 -05:00
Tanner Bennett 107e44a399 Fix #410, prefix all categories 2020-10-22 17:57:21 -05:00
Tanner Bennett e79a3db255 Fix #426
Move explicit FLEXCollection protocol conformances to the .m file to prevent protocol methods from overriding the methods in their headers
2020-10-21 22:55:32 -05:00
Tanner Bennett bec9ffd981 Allow inspecting non-NSObject classes 2020-10-21 21:02:49 -05:00
Tanner Bennett d4070ed9b7 Reverse view snapshot slider ends, fix #429 2020-10-21 21:02:49 -05:00
Tanner Bennett 01e4af47e2 Fix #433, refresh explorer after edits 2020-10-21 21:02:49 -05:00
Tanner Bennett 220af5c350 Table sections can update themselves 2020-10-21 21:02:49 -05:00
Tanner Bennett 15fd16d395 FLEXample project Xcode 12 update
Fix warning in FLEXample
2020-10-21 21:02:49 -05:00
Tanner Bennett af87ea14e0 Update copyright 2020-10-20 18:18:47 -05:00
Tanner Bennett 5c8b334a84 Fix #450: broken search on NSUserDefaults 2020-10-18 17:44:04 -05:00
Tanner Bennett d3c3c61ab1 FLEXMethod.imagePath should use the method's IMP
We can already tell which image the class comes from, and that is usually the same as the original method implementation. What is more useful to know is the image of the _current_ implementation.
2020-10-18 17:17:06 -05:00
Tanner Bennett c28952f6e9 Silence new weird documentation warning… 2020-10-18 17:17:06 -05:00
Tanner Bennett aaf7ffec85 Commit FLEXTests scheme 2020-10-18 17:17:06 -05:00
Tanner Bennett 3ef55eac62 Xcode 12 upgrade check for main scheme 2020-10-18 17:17:06 -05:00
Tanner Bennett 515806e194 Add FLEX_EXIT_IF_NO_CTORS, fix #470 2020-10-18 17:17:06 -05:00
Justin Lam d0d1632ca1 Add foundation header to ActivityStreamSPI. (#461)
* Add C++ ifdefs around C++ code.

The purpose of this change is to gate C++ code behind a cplusplus define so that FLEX can be made into a module for Swift code.  Swift modules do not allow for C++ code.  However this means if FLEX is used a Swift module, it will not have functionality of the excluded code. Ideally in the future, FLEX can be converted fully to support Swift without bridging headers.

* Revert "Add C++ ifdefs around C++ code."

This reverts commit 77c02207f9.

* Add include <Foundation/Foundation.h> to ActivityStreamSPI header

We use a different build setup internally, and we need all headers to be able to stand on their own. This file is using NS_ENUM, which is defined in Foundation, without importing it, so we're adding the import to resolve that.
2020-10-13 14:31:31 -05:00
matrush 79e22cf828 Remove a retain cylce in FLEXSystemLogViewController 2020-10-13 14:31:31 -05:00
Iulian Onofrei 563cb514a1 Fix crash when opening Keychain item without a password 2020-10-13 14:31:31 -05:00
matrush 84131d8533 Return empty array when the rows are nil in FLEXSQLResult 2020-10-13 14:31:31 -05:00
Evan Emelga 55cb7ebf8f Sort realm table names alphabetically (#453) 2020-10-12 23:07:18 -05:00
Anıl Taşkıran b9e2c1ebd9 fix baseResumeClass name for iOS14+ 2020-10-12 23:07:18 -05:00
Maxime Ollivier 7377399673 Skip keyboard shortcut override when setting defaults 2020-10-12 23:07:18 -05:00
Tanner Bennett 21199b2a56 Add sharedApplication property at runtime for iOS 9 2020-10-12 23:07:18 -05:00
matrush e72c6aa349 Add better debugging message for FLEXProperty and FLEXIvar 2020-10-12 23:06:55 -05:00
ph661 13c583d32b Add SceneKit to podspec frameworks 2020-10-12 19:19:34 -05:00
Chaoshuai Lü 129c291469 Move custom additions to the top (#439)
- Move custom additions to the top
- Fix header
2020-10-12 19:19:34 -05:00
Chris Ellsworth 67609b28a4 Add sorting in File Browser 2020-10-12 19:17:58 -05:00
matrush 4dc206eaa6 Add copy action for database browser row selection alert 2020-10-12 19:17:57 -05:00
matrush 28e91507db Remove retain cycles from selectionHandler in several files 2020-07-07 12:05:05 -05:00
matrush 5f74fb0d43 Remove redundant FLEXPointerIsTaggedPointer function 2020-07-07 12:04:34 -05:00
Tanner Bennett 09f5859feb Add InAppViewDebugger thanks to README 2020-06-30 16:25:12 -05:00
Hao Nguyen cee416889a use __typeof instead of typeof to compile for Cxx instead of GNUxx 2020-06-19 01:39:48 -05:00
Tanner Bennett e2a334384a Misc cleanup and bug fixes 2020-05-25 17:23:18 -05:00
Tanner Bennett a840e909a1 Add UIApplication shortcuts 2020-05-25 17:12:46 -05:00
Tanner Bennett 2f952c380f Automatically activate search bar in heap explorer 2020-04-27 17:53:34 -05:00
Tanner Bennett 5d919eb329 Don't access ivars on tagged pointers 2020-04-25 00:51:58 -05:00
Tanner Bennett 1d5d825135 Fix class properties not showing previews 2020-04-25 00:51:36 -05:00
opa334 2a8cdbdb84 Fix heap enumeration on arm64e 2020-04-23 22:04:41 -05:00
Tanner Bennett 5e2081b8f9 Various performance improvements
- Remove ARC from -[FLEXTypeEncodingParser canScanChar:]
- Make FLEXMethod.imagePath lazy
2020-04-23 22:04:41 -05:00
Bas Broek fbaeda1956 Remove parenthesis in Swift (#414) 2020-04-16 10:34:27 -05:00
303 changed files with 2529 additions and 1118 deletions
+27
View File
@@ -0,0 +1,27 @@
---
name: Bug report
about: Report a bug in FLEX
title: ''
labels: bug
assignees: ''
---
### Environment
- Platform+version: **iOS 14** <!--- Change to match your platform and version -->
- FLEX version: **9.9.9** <!--- Change to the version of FLEX you're using -->
<!--- FLEXing / libFLEX users: please include FLEXing and libFLEX versions separately -->
### Bug Report
Here, you can provide a description of the bug. Some tips:
- Please do not paste an entire crash log. Upload the crash log to something like [ghostbin.co](https://ghostbin.co/) or another paste service. Alternatively, you can cut out the relevant stack trace and paste that inside a ` ```code block``` `
- If the bug is more complex than "this button is broken" or a crash, consider including a sample project. For example, if your app's requests aren't showing up in the network history page.
- Providing steps to reproduce is always helpful!
- If you want to include a screenshot or GIF, consider modifying the default markdown for uploaded images to use this code to make the image smaller on desktop:
```
<img width="50%" src=your-image-url >
```
This template is a suggestion. You may format your issue however you want, but generally you should at least include your iOS version and FLEX version.
+10
View File
@@ -0,0 +1,10 @@
---
name: Feature request
about: Suggest a new feature for FLEX
title: ''
labels: enhancement
assignees: ''
---
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/9/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -25,7 +25,7 @@
@property (nonatomic, copy) NSArray<FLEXTableViewSection *> *allSections;
/// This computed property should filter \c allSections for assignment to \c sections
@property (nonatomic, readonly) NSArray<FLEXTableViewSection *> *nonemptySections;
@property (nonatomic, readonly, copy) NSArray<FLEXTableViewSection *> *nonemptySections;
/// This should be able to re-initialize \c allSections
- (NSArray<FLEXTableViewSection *> *)makeSections;
@@ -80,7 +80,7 @@
/// 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) NSArray<FLEXTableViewSection *> *nonemptySections;
@property (nonatomic, readonly, copy) NSArray<FLEXTableViewSection *> *nonemptySections;
/// If using \c self as the \c filterDelegate, as is the default,
/// subclasses should override to provide the sections for the table view.
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/9/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
@@ -111,9 +111,18 @@
- (void)setAllSections:(NSArray<FLEXTableViewSection *> *)allSections {
_allSections = allSections.copy;
// Only display nonempty sections
self.sections = self.nonemptySections;
}
- (void)setSections:(NSArray<FLEXTableViewSection *> *)sections {
// Allow sections to reload a portion of the table view at will
[sections enumerateObjectsUsingBlock:^(FLEXTableViewSection *s, NSUInteger idx, BOOL *stop) {
[s setTable:self.tableView section:idx];
}];
_sections = sections.copy;
}
#pragma mark - UITableViewDataSource
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 1/30/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 1/30/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXNavigationController.h"
@@ -20,6 +20,7 @@
@interface FLEXNavigationController ()
@property (nonatomic, readonly) BOOL toolbarWasHidden;
@property (nonatomic) BOOL waitingToAddTab;
@property (nonatomic, readonly) BOOL canShowToolbar;
@property (nonatomic) BOOL didSetupPendingDismissButtons;
@property (nonatomic) UISwipeGestureRecognizer *navigationBarSwipeGesture;
@end
@@ -36,10 +37,13 @@
self.waitingToAddTab = YES;
// Add gesture to reveal toolbar if hidden
self.navigationBar.userInteractionEnabled = YES;
[self.navigationBar addGestureRecognizer:[[UITapGestureRecognizer alloc]
UITapGestureRecognizer *navbarTapGesture = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleNavigationBarTap:)
]];
];
// Don't cancel touches to work around bug on versions of iOS prior to 13
navbarTapGesture.cancelsTouchesInView = NO;
[self.navigationBar addGestureRecognizer:navbarTapGesture];
// Add gesture to dismiss if not presented with a sheet style
if (@available(iOS 13, *)) {
@@ -96,6 +100,10 @@
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)canShowToolbar {
return self.topViewController.toolbarItems.count;
}
- (void)addNavigationBarItemsToViewController:(UINavigationItem *)navigationItem {
if (!self.presentingViewController) {
return;
@@ -145,8 +153,15 @@
}
- (void)handleNavigationBarTap:(UIGestureRecognizer *)sender {
// Don't reveal the toolbar if we were just tapping a button
CGPoint location = [sender locationInView:self.navigationBar];
UIView *hitView = [self.navigationBar hitTest:location withEvent:nil];
if ([hitView isKindOfClass:[UIControl class]]) {
return;
}
if (sender.state == UIGestureRecognizerStateRecognized) {
if (self.toolbarHidden) {
if (self.toolbarHidden && self.canShowToolbar) {
[self setToolbarHidden:NO animated:YES];
}
}
@@ -162,7 +177,7 @@
- (void)_gestureRecognizedInteractiveHide:(UIPanGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateRecognized) {
BOOL show = self.topViewController.toolbarItems.count;
BOOL show = self.canShowToolbar;
CGFloat yTranslation = [sender translationInView:self.view].y;
CGFloat yVelocity = [sender velocityInView:self.view].y;
if (yVelocity > 2000) {
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 7/5/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -67,6 +67,10 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
/// 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;
/// Defaults to NO.
///
/// Setting this to YES will make the search bar activate whenever the view appears.
@property (nonatomic) BOOL activatesSearchBarAutomatically;
/// nil unless showsSearchBar is set to YES.
///
@@ -89,7 +93,7 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
/// 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
/// 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
@@ -102,11 +106,11 @@ extern CGFloat const kFLEXDebounceForExpensiveIO;
/// 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) NSString *searchText;
@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<FLEXSearchResultsUpdating> searchResultsUpdater;
/// If a delegate is set, updateSearchResults: is not called on this view controller.
@property (nonatomic, weak) id<FLEXSearchResultsUpdating> searchResultsUpdater;
/// self.view.window as a \c FLEXWindow
@property (nonatomic, readonly) FLEXWindow *window;
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 7/5/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -124,18 +124,15 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
_showsCarousel = showsCarousel;
if (showsCarousel) {
_carousel = ({
__weak __typeof(self) weakSelf = self;
_carousel = ({ weakify(self)
FLEXScopeCarousel *carousel = [FLEXScopeCarousel new];
carousel.selectedIndexChangedAction = ^(NSInteger idx) {
__typeof(self) self = weakSelf;
carousel.selectedIndexChangedAction = ^(NSInteger idx) { strongify(self);
[self.searchDelegate updateSearchResults:self.searchText];
};
// UITableView won't update the header size unless you reset the header view
[carousel registerBlockForDynamicTypeChanges:^(FLEXScopeCarousel *carousel) {
__typeof(self) self = weakSelf;
[carousel registerBlockForDynamicTypeChanges:^(FLEXScopeCarousel *_) { strongify(self);
[self layoutTableHeaderIfNeeded];
}];
@@ -224,10 +221,10 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
_shareToolbarItem = FLEXBarButtonItemSystem(Action, self, @selector(shareButtonPressed:));
_bookmarksToolbarItem = [UIBarButtonItem
itemWithImage:FLEXResources.bookmarksIcon target:self action:@selector(showBookmarks)
flex_itemWithImage:FLEXResources.bookmarksIcon target:self action:@selector(showBookmarks)
];
_openTabsToolbarItem = [UIBarButtonItem
itemWithImage:FLEXResources.openTabsIcon target:self action:@selector(showTabSwitcher)
flex_itemWithImage:FLEXResources.openTabsIcon target:self action:@selector(showTabSwitcher)
];
self.leftmostToolbarItem = UIBarButtonItem.flex_fixedSpace;
@@ -241,7 +238,7 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
// Toolbar
self.navigationController.toolbarHidden = NO;
self.navigationController.toolbarHidden = self.toolbarItems.count > 0;
self.navigationController.hidesBarsOnSwipe = YES;
// On iOS 13, the root view controller shows it's search bar no matter what.
@@ -259,12 +256,17 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// When going back, make the search bar reappear instead of hiding
if (@available(iOS 11.0, *)) {
// When going back, make the search bar reappear instead of hiding
if ((self.pinSearchBar || self.showSearchBarInitially) && !self.didInitiallyRevealSearchBar) {
self.navigationItem.hidesSearchBarWhenScrolling = NO;
}
}
// Make the keyboard seem to appear faster
if (self.activatesSearchBarAutomatically) {
[self makeKeyboardAppearNow];
}
[self setupToolbarItems];
}
@@ -286,6 +288,17 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
}];
}
}
if (self.activatesSearchBarAutomatically) {
// Keyboard has appeared, now we call this as we soon present our search bar
[self removeDummyTextField];
// Activate the search bar
dispatch_async(dispatch_get_main_queue(), ^{
// This doesn't work unless it's wrapped in this dispatch_async call
[self.searchController.searchBar becomeFirstResponder];
});
}
// We only want to reveal the search bar when the view controller first appears.
self.didInitiallyRevealSearchBar = YES;
@@ -525,6 +538,30 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
#pragma mark - Search Bar
#pragma mark Faster keyboard
static UITextField *kDummyTextField = nil;
/// Make the keyboard appear instantly. We use this to make the
/// keyboard appear faster when the search bar is set to appear initially.
/// You must call \c -removeDummyTextField before your search bar is to appear.
- (void)makeKeyboardAppearNow {
if (!kDummyTextField) {
kDummyTextField = [UITextField new];
kDummyTextField.autocorrectionType = UITextAutocorrectionTypeNo;
}
kDummyTextField.inputAccessoryView = self.searchController.searchBar.inputAccessoryView;
[UIApplication.sharedApplication.keyWindow addSubview:kDummyTextField];
[kDummyTextField becomeFirstResponder];
}
- (void)removeDummyTextField {
if (kDummyTextField.superview) {
[kDummyTextField removeFromSuperview];
}
}
#pragma mark UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 9/25/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewSection.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 9/25/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSingleRowSection.h"
+17 -3
View File
@@ -3,11 +3,10 @@
// FLEX
//
// Created by Tanner on 1/29/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "FLEXMacros.h"
#import "NSArray+FLEX.h"
@class FLEXTableView;
@@ -24,13 +23,17 @@ NS_ASSUME_NONNULL_BEGIN
@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) NSString *title;
@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;
@@ -57,6 +60,17 @@ NS_ASSUME_NONNULL_BEGIN
/// \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
+16 -3
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 1/29/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewSection.h"
@@ -22,6 +22,19 @@
- (void)reloadData { }
- (void)reloadData:(BOOL)updateTable {
[self reloadData];
if (updateTable) {
NSIndexSet *index = [NSIndexSet indexSetWithIndex:_sectionIndex];
[_tableView reloadSections:index withRowAnimation:UITableViewRowAnimationNone];
}
}
- (void)setTable:(UITableView *)tableView section:(NSInteger)index {
_tableView = tableView;
_sectionIndex = index;
}
- (NSDictionary<NSString *,Class> *)cellRegistrationMapping {
return nil;
}
@@ -99,13 +112,13 @@
}
UIMenu *copyMenu = [UIMenu
inlineMenuWithTitle:@"Copy…"
flex_inlineMenuWithTitle:@"Copy…"
image:copyIcon
children:actions
];
if (collapseMenu) {
return @[[copyMenu collapsed]];
return @[[copyMenu flex_collapsed]];
} else {
return @[copyMenu];
}
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCarouselCell.h"
@@ -77,7 +77,7 @@
self.selectionIndicatorStripe.translatesAutoresizingMaskIntoConstraints = NO;
UIView *superview = self.contentView;
[self.titleLabel pinEdgesToSuperviewWithInsets:UIEdgeInsetsMake(10, 15, 8 + stripeHeight, 15)];
[self.titleLabel flex_pinEdgesToSuperviewWithInsets:UIEdgeInsetsMake(10, 15, 8 + stripeHeight, 15)];
[self.selectionIndicatorStripe.leadingAnchor constraintEqualToAnchor:superview.leadingAnchor].active = YES;
[self.selectionIndicatorStripe.bottomAnchor constraintEqualToAnchor:superview.bottomAnchor].active = YES;
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,12 +3,13 @@
// FLEX
//
// Created by Tanner Bennett on 7/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXScopeCarousel.h"
#import "FLEXCarouselCell.h"
#import "FLEXColor.h"
#import "FLEXMacros.h"
#import "UIView+FLEX_Layout.h"
const CGFloat kCarouselItemSpacing = 0;
@@ -72,15 +73,14 @@ NSString * const kCarouselCellReuseIdentifier = @"kCarouselCellReuseIdentifier";
self.sizingCell.title = @"NSObject";
// Dynamic type
__weak __typeof(self) weakSelf = self;
weakify(self);
_dynamicTypeObserver = [NSNotificationCenter.defaultCenter
addObserverForName:UIContentSizeCategoryDidChangeNotification
object:nil queue:nil usingBlock:^(NSNotification *note) {
object:nil queue:nil usingBlock:^(NSNotification *note) { strongify(self)
[self.collectionView setNeedsLayout];
[self setNeedsUpdateConstraints];
// Notify observers
__typeof(self) self = weakSelf;
for (void (^block)(FLEXScopeCarousel *) in self.dynamicTypeHandlers) {
block(self);
}
@@ -118,7 +118,7 @@ NSString * const kCarouselCellReuseIdentifier = @"kCarouselCellReuseIdentifier";
- (void)updateConstraints {
if (!self.constraintsInstalled) {
self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
[self.collectionView pinEdgesToSuperview];
[self.collectionView flex_pinEdgesToSuperview];
self.constraintsInstalled = YES;
}
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 12/27/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXMultilineTableViewCell.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 12/27/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCodeFontCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 1/23/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 1/23/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXKeyValueTableViewCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Ryan Olson on 2/13/15.
// Copyright (c) 2015 f. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Ryan Olson on 2/13/15.
// Copyright (c) 2015 f. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXMultilineTableViewCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSubtitleTableViewCell.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 4/17/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/30/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/30/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputColorView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Daniel Rodriguez Troitino on 2/14/15.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Daniel Rodriguez Troitino on 2/14/15.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputDateView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputFontView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/18/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/18/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputNotSupportedView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/15/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/15/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputNumberView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/15/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/15/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputObjectView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputStringView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputStructView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputSwitchView.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/30/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/30/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
@@ -3,15 +3,19 @@
// Flipboard
//
// Created by Ryan Olson on 5/23/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorViewController.h"
@interface FLEXDefaultEditorViewController : FLEXFieldEditorViewController
NS_ASSUME_NONNULL_BEGIN
- (id)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key;
@interface FLEXDefaultEditorViewController : FLEXVariableEditorViewController
+ (BOOL)canEditDefaultWithValue:(id)currentValue;
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit;
+ (BOOL)canEditDefaultWithValue:(nullable id)currentValue;
@end
NS_ASSUME_NONNULL_END
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/23/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXDefaultEditorViewController.h"
@@ -15,23 +15,24 @@
@interface FLEXDefaultEditorViewController ()
@property (nonatomic, readonly) NSUserDefaults *defaults;
@property (nonatomic) NSString *key;
@property (nonatomic, readonly) NSString *key;
@end
@implementation FLEXDefaultEditorViewController
- (id)initWithDefaults:(NSUserDefaults *)defaults key:(NSString *)key {
self = [super initWithTarget:defaults];
if (self) {
self.key = key;
self.title = @"Edit Default";
}
return self;
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit {
FLEXDefaultEditorViewController *editor = [self target:defaults data:key commitHandler:onCommit];
editor.title = @"Edit Default";
return editor;
}
- (NSUserDefaults *)defaults {
return [self.target isKindOfClass:[NSUserDefaults class]] ? self.target : nil;
return [_target isKindOfClass:[NSUserDefaults class]] ? _target : nil;
}
- (NSString *)key {
return _data;
}
- (void)viewDidLoad {
@@ -50,8 +51,6 @@
}
- (void)actionButtonPressed:(id)sender {
[super actionButtonPressed:sender];
id value = self.firstInputView.inputValue;
if (value) {
[self.defaults setObject:value forKey:self.key];
@@ -59,14 +58,16 @@
[self.defaults removeObjectForKey:self.key];
}
[self.defaults synchronize];
self.firstInputView.inputValue = [self.defaults objectForKey:self.key];
}
- (void)getterButtonPressed:(id)sender {
[super getterButtonPressed:sender];
id returnedObject = [self.defaults objectForKey:self.key];
[self exploreObjectOrPopViewController:returnedObject];
// Dismiss keyboard and handle committed changes
[super actionButtonPressed:sender];
// Go back after setting, but not for switches.
if (sender) {
[self.navigationController popViewControllerAnimated:YES];
} else {
self.firstInputView.inputValue = [self.defaults objectForKey:self.key];
}
}
+ (BOOL)canEditDefaultWithValue:(id)currentValue {
+1 -1
View File
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorView.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 11/22/18.
// Copyright © 2018 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXVariableEditorViewController.h"
@@ -15,9 +15,9 @@ 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;
+ (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;
+ (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;
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 11/22/18.
// Copyright © 2018 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorViewController.h"
@@ -30,20 +30,20 @@
#pragma mark - Initialization
+ (instancetype)target:(id)target property:(FLEXProperty *)property {
+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^_Nullable)())onCommit {
id value = [property getValue:target];
if (![self canEditProperty:property onObject:target currentValue:value]) {
return nil;
}
FLEXFieldEditorViewController *editor = [self target:target];
FLEXFieldEditorViewController *editor = [self target:target data:property commitHandler:onCommit];
editor.title = [@"Property: " stringByAppendingString:property.name];
editor.property = property;
return editor;
}
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar {
FLEXFieldEditorViewController *editor = [self target:target];
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^_Nullable)())onCommit {
FLEXFieldEditorViewController *editor = [self target:target data:ivar commitHandler:onCommit];
editor.title = [@"Ivar: " stringByAppendingString:ivar.name];
editor.ivar = ivar;
return editor;
@@ -86,8 +86,6 @@
}
- (void)actionButtonPressed:(id)sender {
[super actionButtonPressed:sender];
if (self.property) {
id userInputObject = self.firstInputView.inputValue;
NSArray *arguments = userInputObject ? @[userInputObject] : nil;
@@ -103,6 +101,9 @@
// this currently could and would assign NSArray to NSMutableArray
[self.ivar setValue:self.firstInputView.inputValue onObject:self.target];
}
// Dismiss keyboard and handle committed changes
[super actionButtonPressed:sender];
// Go back after setting, but not for switches.
if (sender) {
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/23/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXVariableEditorViewController.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/23/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXMethodCallingViewController.h"
@@ -16,7 +16,7 @@
#import "FLEXUtility.h"
@interface FLEXMethodCallingViewController ()
@property (nonatomic) FLEXMethod *method;
@property (nonatomic, readonly) FLEXMethod *method;
@end
@implementation FLEXMethodCallingViewController
@@ -28,9 +28,8 @@
- (id)initWithTarget:(id)target method:(FLEXMethod *)method {
NSParameterAssert(method.isInstanceMethod == !object_isClass(target));
self = [super initWithTarget:target];
self = [super initWithTarget:target data:method commitHandler:nil];
if (self) {
self.method = method;
self.title = method.isInstanceMethod ? @"Method: " : @"Class Method: ";
self.title = [self.title stringByAppendingString:method.selectorString];
}
@@ -72,8 +71,6 @@
}
- (void)actionButtonPressed:(id)sender {
[super actionButtonPressed:sender];
// Gather arguments
NSMutableArray *arguments = [NSMutableArray new];
for (FLEXArgumentInputView *inputView in self.fieldEditorView.argumentInputViews) {
@@ -89,6 +86,9 @@
withArguments:arguments
error:&error
];
// Dismiss keyboard and handle committed changes
[super actionButtonPressed:sender];
// Display return value or error
if (error) {
@@ -103,4 +103,8 @@
}
}
- (FLEXMethod *)method {
return _data;
}
@end
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -11,25 +11,45 @@
@class FLEXFieldEditorView;
@class FLEXArgumentInputView;
/// Provides a screen for editing or configuring one or more variables.
@interface FLEXVariableEditorViewController : UIViewController
NS_ASSUME_NONNULL_BEGIN
+ (instancetype)target:(id)target;
- (id)initWithTarget:(id)target;
/// 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)();
}
// Convenience accessor since many subclasses only use one input view
@property (nonatomic, readonly) FLEXArgumentInputView *firstInputView;
/// @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;
// For subclass use only.
@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;
- (void)actionButtonPressed:(id)sender;
/// 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:(id)objectOrNil;
- (void)exploreObjectOrPopViewController:(nullable id)objectOrNil;
@end
NS_ASSUME_NONNULL_END
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/16/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXColor.h"
@@ -19,21 +19,22 @@
@interface FLEXVariableEditorViewController () <UIScrollViewDelegate>
@property (nonatomic) UIScrollView *scrollView;
@property (nonatomic) id target;
@end
@implementation FLEXVariableEditorViewController
#pragma mark - Initialization
+ (instancetype)target:(id)target {
return [[self alloc] initWithTarget:target];
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
return [[self alloc] initWithTarget:target data:data commitHandler:onCommit];
}
- (id)initWithTarget:(id)target {
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
self = [super init];
if (self) {
self.target = target;
_target = target;
_data = data;
_commitHandler = onCommit;
[NSNotificationCenter.defaultCenter
addObserver:self selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil
@@ -120,6 +121,9 @@
- (void)actionButtonPressed:(id)sender {
// Subclasses can override
[self.fieldEditorView endEditing:YES];
if (_commitHandler) {
_commitHandler();
}
}
- (void)exploreObjectOrPopViewController:(id)objectOrNil {
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <Foundation/Foundation.h>
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXBookmarkManager.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXBookmarksViewController.h"
@@ -68,10 +68,10 @@
- (void)setupEditingBarItems {
self.navigationItem.rightBarButtonItem = nil;
self.toolbarItems = @[
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
[UIBarButtonItem flex_itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
UIBarButtonItem.flex_flexibleSpace,
// We use a non-system done item because we change its title dynamically
[UIBarButtonItem doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
[UIBarButtonItem flex_doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
];
self.toolbarItems.firstObject.tintColor = FLEXColor.destructiveColor;
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 4/4/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXExplorerToolbar.h"
@@ -25,7 +25,8 @@
///
/// 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;
- (void)toggleToolWithViewControllerProvider:(UINavigationController *(^)(void))future
completion:(void (^)(void))completion;
// Keyboard shortcut helpers
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 4/4/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXExplorerViewController.h"
@@ -45,6 +45,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
/// Only valid while a toolbar drag pan gesture is in progress.
@property (nonatomic) CGRect toolbarFrameBeforeDragging;
/// Only valid while a selected view pan gesture is in progress.
@property (nonatomic) CGFloat selectedViewLastPanX;
/// Borders of all the visible views in the hierarchy at the selection point.
/// The keys are NSValues with the corresponding view (nonretained).
@property (nonatomic) NSDictionary<NSValue *, UIView *> *outlineViewsForVisibleViews;
@@ -58,6 +61,9 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
/// A colored transparent overlay to indicate that the view is selected.
@property (nonatomic) UIView *selectedViewOverlay;
/// Used to actuate changes in view selection on iOS 10+
@property (nonatomic, readonly) UISelectionFeedbackGenerator *selectionFBG API_AVAILABLE(ios(10.0));
/// self.view.window as a \c FLEXWindow
@property (nonatomic, readonly) FLEXWindow *window;
@@ -118,6 +124,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
self.movePanGR = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMovePan:)];
self.movePanGR.enabled = self.currentMode == FLEXExplorerModeMove;
[self.view addGestureRecognizer:self.movePanGR];
// Feedback
if (@available(iOS 10.0, *)) {
_selectionFBG = [UISelectionFeedbackGenerator new];
}
}
- (void)viewWillAppear:(BOOL)animated {
@@ -450,16 +461,16 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
];
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
// Swipe gestures for selecting deeper / higher views at a point
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]
UIPanGestureRecognizer *leftSwipe = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
];
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
// UIPanGestureRecognizer *rightSwipe = [[UIPanGestureRecognizer alloc]
// initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
// ];
// leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
// rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:leftSwipe];
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
// [toolbar.selectedViewDescriptionContainer addGestureRecognizer:rightSwipe];
// Long press gesture to present tabs manager
[toolbar.globalsItem addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
@@ -598,19 +609,54 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
}
}
- (void)handleChangeViewAtPointGesture:(UISwipeGestureRecognizer *)sender {
- (void)handleChangeViewAtPointGesture:(UIPanGestureRecognizer *)sender {
NSInteger max = self.viewsAtTapPoint.count - 1;
NSInteger currentIdx = [self.viewsAtTapPoint indexOfObject:self.selectedView];
switch (sender.direction) {
case UISwipeGestureRecognizerDirectionLeft:
self.selectedView = self.viewsAtTapPoint[MIN(max, currentIdx + 1)];
break;
case UISwipeGestureRecognizerDirectionRight:
self.selectedView = self.viewsAtTapPoint[MAX(0, currentIdx - 1)];
CGFloat locationX = [sender locationInView:self.view].x;
// Track the pan gesture: every N points we move along the X axis,
// actuate some haptic feedback and move up or down the hierarchy.
// We only store the "last" location when we've met the threshold.
// We only change the view and actuate feedback if the view selection
// changes; that is, as long as we don't go outside or under the array.
switch (sender.state) {
case UIGestureRecognizerStateBegan: {
self.selectedViewLastPanX = locationX;
break;
}
case UIGestureRecognizerStateChanged: {
static CGFloat kNextLevelThreshold = 20.f;
CGFloat lastX = self.selectedViewLastPanX;
NSInteger newSelection = currentIdx;
// Left, go down the hierarchy
if (locationX < lastX && (lastX - locationX) >= kNextLevelThreshold) {
// Choose a new view index up to the max index
newSelection = MIN(max, currentIdx + 1);
self.selectedViewLastPanX = locationX;
}
// Right, go up the hierarchy
else if (lastX < locationX && (locationX - lastX) >= kNextLevelThreshold) {
// Choose a new view index down to the min index
newSelection = MAX(0, currentIdx - 1);
self.selectedViewLastPanX = locationX;
}
if (currentIdx != newSelection) {
self.selectedView = self.viewsAtTapPoint[newSelection];
[self actuateSelectionChangedFeedback];
}
default:
break;
}
default: break;
}
}
- (void)actuateSelectionChangedFeedback {
if (@available(iOS 10.0, *)) {
[self.selectionFBG selectionChanged];
}
}
@@ -872,13 +918,12 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
[super dismissViewControllerAnimated:animated completion:completion];
}
- (BOOL)wantsWindowToBecomeKey
{
- (BOOL)wantsWindowToBecomeKey {
return self.window.previousKeyWindow != nil;
}
- (void)toggleToolWithViewControllerProvider:(UINavigationController *(^)(void))future
completion:(void(^)(void))completion {
completion:(void (^)(void))completion {
if (self.presentedViewController) {
[self dismissViewControllerAnimated:YES completion:completion];
} else if (future) {
@@ -924,11 +969,7 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
} else {
return [FLEXHierarchyViewController delegate:self];
}
} completion:^{
if (completion) {
completion();
}
}];
} completion:completion];
}
- (void)toggleMenuTool {
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 2/13/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 2/13/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXViewControllersViewController.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 4/13/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 4/13/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXWindow.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/6/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXWindowManagerController.h"
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/1/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/1/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTabList.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/4/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 2/4/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTabsViewController.h"
@@ -121,12 +121,12 @@
- (void)setupEditingBarItems {
self.navigationItem.rightBarButtonItem = nil;
self.toolbarItems = @[
[UIBarButtonItem itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
[UIBarButtonItem flex_itemWithTitle:@"Close All" target:self action:@selector(closeAllButtonPressed:)],
UIBarButtonItem.flex_flexibleSpace,
[UIBarButtonItem disabledSystemItem:UIBarButtonSystemItemAdd],
[UIBarButtonItem flex_disabledSystemItem:UIBarButtonSystemItemAdd],
UIBarButtonItem.flex_flexibleSpace,
// We use a non-system done item because we change its title dynamically
[UIBarButtonItem doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
[UIBarButtonItem flex_doneStyleitemWithTitle:@"Done" target:self action:@selector(toggleEditing)]
];
self.toolbarItems.firstObject.tintColor = FLEXColor.destructiveColor;
+1 -6
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/12/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
@@ -12,16 +12,11 @@
#import <FLEX/CALayer+FLEX.h>
#import <FLEX/UIFont+FLEX.h>
#import <FLEX/UIGestureRecognizer+Blocks.h>
#import <FLEX/UIView+FLEX_Layout.h>
#import <FLEX/UIPasteboard+FLEX.h>
#import <FLEX/UIMenu+FLEX.h>
#import <FLEX/UITextField+Range.h>
#import <FLEX/NSObject+FLEX_Reflection.h>
#import <FLEX/NSArray+FLEX.h>
#import <FLEX/NSDictionary+ObjcRuntime.h>
#import <FLEX/NSString+ObjcRuntime.h>
#import <FLEX/NSString+FLEX.h>
#import <FLEX/NSUserDefaults+FLEX.h>
#import <FLEX/NSMapTable+FLEX_Subscripting.h>
#import <FLEX/NSTimer+FLEX.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/11/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXFilteringTableViewController.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/11/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXObjectExplorerFactory.h>
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/11/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXObjcInternal.h>
+1 -2
View File
@@ -4,7 +4,7 @@
//
// Created by Eric Horacek on 7/18/15.
// Modified by Tanner Bennett on 3/12/20.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXManager.h>
@@ -20,6 +20,5 @@
#import <FLEX/FLEX-Categories.h>
#import <FLEX/FLEX-ObjectExploring.h>
#import <FLEX/FLEXMacros.h>
#import <FLEX/FLEXAlert.h>
#import <FLEX/FLEXResources.h>
@@ -68,9 +68,11 @@ static Class RLMRealmClass = nil;
- (NSArray<NSString *> *)queryAllTables {
// Map each schema to its name
return [self.realm.schema.objectSchema flex_mapped:^id(RLMObjectSchema *schema, NSUInteger idx) {
NSArray<NSString *> *tableNames = [self.realm.schema.objectSchema flex_mapped:^id(RLMObjectSchema *schema, NSUInteger idx) {
return schema.className ?: nil;
}];
return [tableNames sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}
- (NSArray<NSString *> *)queryAllColumnsOfTable:(NSString *)tableName {
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/3/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <Foundation/Foundation.h>
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner on 3/3/20.
// Copyright © 2020 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSQLResult.h"
@@ -101,22 +101,22 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
- (NSArray<NSString *> *)queryAllTables {
return [[self executeStatement:QUERY_TABLENAMES].rows flex_mapped:^id(NSArray *table, NSUInteger idx) {
return table.firstObject;
}];
}] ?: @[];
}
- (NSArray<NSString *> *)queryAllColumnsOfTable:(NSString *)tableName {
NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')",tableName];
FLEXSQLResult *results = [self executeStatement:sql];
return [results.keyedRows flex_mapped:^id(NSDictionary *column, NSUInteger idx) {
return column[@"name"];
}];
}] ?: @[];
}
- (NSArray<NSArray *> *)queryAllDataInTable:(NSString *)tableName {
return [self executeStatement:[@"SELECT * FROM "
stringByAppendingString:tableName
]].rows;
]].rows ?: @[];
}
- (FLEXSQLResult *)executeStatement:(NSString *)sql {
@@ -113,7 +113,11 @@
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title([@"Row " stringByAppendingString:@(row).stringValue]);
make.message([fields componentsJoinedByString:@"\n\n"]);
NSString *message = [fields componentsJoinedByString:@"\n\n"];
make.message(message);
make.button(@"Copy").handler(^(NSArray<NSString *> *strings) {
UIPasteboard.generalPasteboard.string = message;
});
make.button(@"Dismiss").cancelStyle();
} showFrom:self];
}
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/10/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXGlobalsEntry.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/10/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXAddressExplorerCoordinator.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Rich Robinson on 19/10/2015.
// Copyright © 2015 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXGlobalsEntry.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Rich Robinson on 19/10/2015.
// Copyright © 2015 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCookiesViewController.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXLiveObjectsController.h"
@@ -34,6 +34,8 @@ static const NSInteger kFLEXLiveObjectsSortBySizeIndex = 2;
[super viewDidLoad];
self.showsSearchBar = YES;
self.showSearchBarInitially = YES;
self.activatesSearchBarAutomatically = YES;
self.searchBarDebounceInterval = kFLEXDebounceInstant;
self.showsCarousel = YES;
self.carousel.items = @[@"A→Z", @"Count", @"Size"];
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 5/28/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXObjectListViewController.h"
@@ -20,11 +20,25 @@
#import <malloc/malloc.h>
typedef NS_ENUM(NSUInteger, FLEXObjectReferenceSection) {
FLEXObjectReferenceSectionMain,
FLEXObjectReferenceSectionAutoLayout,
FLEXObjectReferenceSectionKVO,
FLEXObjectReferenceSectionFLEX,
FLEXObjectReferenceSectionCount
};
@interface FLEXObjectListViewController ()
@property (nonatomic, readonly, class) NSArray<NSPredicate *> *defaultPredicates;
@property (nonatomic, readonly, class) NSArray<NSString *> *defaultSectionTitles;
@property (nonatomic, copy) NSArray<FLEXMutableListSection *> *sections;
@property (nonatomic, copy) NSArray<FLEXMutableListSection *> *allSections;
@property (nonatomic, readonly) NSArray<FLEXObjectRef *> *references;
@property (nonatomic, readonly, nullable) NSArray<FLEXObjectRef *> *references;
@property (nonatomic, readonly) NSArray<NSPredicate *> *predicates;
@property (nonatomic, readonly) NSArray<NSString *> *sectionTitles;
@@ -38,7 +52,7 @@
+ (NSPredicate *)defaultPredicateForSection:(NSInteger)section {
// These are the types of references that we typically don't care about.
// We want this list of "object-ivar pairs" split into two sections.
BOOL(^isObserver)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
BOOL(^isKVORelated)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
NSString *row = ref.reference;
return [row isEqualToString:@"__NSObserver object"] ||
[row isEqualToString:@"_CFXNotificationObjcObserverRegistration _object"];
@@ -65,34 +79,50 @@
([row hasPrefix:@"_NSAutoresizingMask"] && [row hasSuffix:@" _referenceItem"]) ||
[ignored containsObject:row];
};
/// These are FLEX classes and usually you aren't looking for FLEX references inside FLEX itself
BOOL(^isFLEXClass)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
return [ref.reference hasPrefix:@"FLEX"];
};
BOOL(^isEssential)(FLEXObjectRef *, NSDictionary *) = ^BOOL(FLEXObjectRef *ref, NSDictionary *bindings) {
return !(isObserver(ref, bindings) || isConstraintRelated(ref, bindings));
return !(
isKVORelated(ref, bindings) ||
isConstraintRelated(ref, bindings) ||
isFLEXClass(ref, bindings)
);
};
switch (section) {
case 0: return [NSPredicate predicateWithBlock:isEssential];
case 1: return [NSPredicate predicateWithBlock:isConstraintRelated];
case 2: return [NSPredicate predicateWithBlock:isObserver];
case FLEXObjectReferenceSectionMain:
return [NSPredicate predicateWithBlock:isEssential];
case FLEXObjectReferenceSectionAutoLayout:
return [NSPredicate predicateWithBlock:isConstraintRelated];
case FLEXObjectReferenceSectionKVO:
return [NSPredicate predicateWithBlock:isKVORelated];
case FLEXObjectReferenceSectionFLEX:
return [NSPredicate predicateWithBlock:isFLEXClass];
default: return nil;
}
}
+ (NSArray<NSPredicate *> *)defaultPredicates {
return @[[self defaultPredicateForSection:0],
[self defaultPredicateForSection:1],
[self defaultPredicateForSection:2]];
return [NSArray flex_forEachUpTo:FLEXObjectReferenceSectionCount map:^id(NSUInteger i) {
return [self defaultPredicateForSection:i];
}];
}
+ (NSArray<NSString *> *)defaultSectionTitles {
return @[@"", @"AutoLayout", @"Trivial"];
return @[
@"", @"AutoLayout", @"Key-Value Observing", @"FLEX"
];
}
#pragma mark - Initialization
- (id)initWithReferences:(NSArray<FLEXObjectRef *> *)references {
- (id)initWithReferences:(nullable NSArray<FLEXObjectRef *> *)references {
return [self initWithReferences:references predicates:nil sectionTitles:nil];
}
@@ -125,14 +155,14 @@
}
}
}];
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingAll:instances];
if (references.count == 1) {
return [FLEXObjectExplorerFactory
explorerViewControllerForObject:references.firstObject.object
];
}
FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
controller.title = [NSString stringWithFormat:@"%@ (%lu)", className, (unsigned long)instances.count];
return controller;
@@ -145,7 +175,7 @@
controller.title = [NSString stringWithFormat:@"Subclasses of %@ (%lu)",
className, (unsigned long)classes.count
];
return controller;
}
@@ -158,7 +188,7 @@
SwiftObjectClass = NSClassFromString(@"Swift._SwiftObject");
}
});
NSMutableArray<FLEXObjectRef *> *instances = [NSMutableArray new];
[FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id tryObject, __unsafe_unretained Class actualClass) {
// Get all the ivars on the object. Start with the class and and travel up the inheritance chain.
@@ -167,15 +197,15 @@
while (tryClass) {
unsigned int ivarCount = 0;
Ivar *ivars = class_copyIvarList(tryClass, &ivarCount);
for (unsigned int ivarIndex = 0; ivarIndex < ivarCount; ivarIndex++) {
Ivar ivar = ivars[ivarIndex];
NSString *typeEncoding = @(ivar_getTypeEncoding(ivar) ?: "");
if (typeEncoding.flex_typeIsObjectOrClass) {
ptrdiff_t offset = ivar_getOffset(ivar);
uintptr_t *fieldPointer = (__bridge void *)tryObject + offset;
if (*fieldPointer == (uintptr_t)(__bridge void *)object) {
NSString *ivarName = @(ivar_getName(ivar) ?: "???");
[instances addObject:[FLEXObjectRef referencing:tryObject ivar:ivarName]];
@@ -183,20 +213,19 @@
}
}
}
free(ivars);
tryClass = class_getSuperclass(tryClass);
}
}];
NSArray<NSPredicate *> *predicates = [self defaultPredicates];
NSArray<NSString *> *sectionTitles = [self defaultSectionTitles];
FLEXObjectListViewController *viewController = [[self alloc]
initWithReferences:instances
predicates:predicates
sectionTitles:sectionTitles
predicates:self.defaultPredicates
sectionTitles:self.defaultSectionTitles
];
viewController.title = [NSString stringWithFormat:@"Referencing %@ %p",
NSStringFromClass(object_getClass(object)), object
[FLEXRuntimeUtility safeClassNameForObject:object], object
];
return viewController;
}
@@ -206,7 +235,7 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.showsSearchBar = YES;
}
@@ -224,14 +253,14 @@
- (NSArray *)buildSections:(NSArray<NSString *> *)titles predicates:(NSArray<NSPredicate *> *)predicates {
NSParameterAssert(titles.count == predicates.count);
NSParameterAssert(titles); NSParameterAssert(predicates);
return [NSArray flex_forEachUpTo:titles.count map:^id(NSUInteger i) {
NSArray *rows = [self.references filteredArrayUsingPredicate:predicates[i]];
return [self makeSection:rows title:titles[i]];
}];
}
- (FLEXMutableListSection *)makeSection:(NSArray *)rows title:(NSString *)title {
- (FLEXMutableListSection *)makeSection:(NSArray *)rows title:(NSString *)title { weakify(self)
FLEXMutableListSection *section = [FLEXMutableListSection list:rows
cellConfiguration:^(FLEXTableViewCell *cell, FLEXObjectRef *ref, NSInteger row) {
cell.textLabel.text = ref.reference;
@@ -241,18 +270,18 @@
if (ref.summary && [ref.summary localizedCaseInsensitiveContainsString:filterText]) {
return YES;
}
return [ref.reference localizedCaseInsensitiveContainsString:filterText];
}
];
section.selectionHandler = ^(__kindof UIViewController *host, FLEXObjectRef *ref) {
section.selectionHandler = ^(UIViewController *host, FLEXObjectRef *ref) { strongify(self)
[self.navigationController pushViewController:[
FLEXObjectExplorerFactory explorerViewControllerForObject:ref.object
] animated:YES];
};
section.customTitle = title;
section.customTitle = title;
return section;
}
+1 -1
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/24/18.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <Foundation/Foundation.h>
+2 -2
View File
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/24/18.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXObjectRef.h"
@@ -47,7 +47,7 @@
_object = object;
_wantsSummary = showSummary;
NSString *class = NSStringFromClass(object_getClass(object));
NSString *class = [FLEXRuntimeUtility safeClassNameForObject:object];
if (ivar) {
_reference = [NSString stringWithFormat:@"%@ %@", class, ivar];
} else if (showSummary) {
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/10/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,7 +3,7 @@
// Flipboard
//
// Created by Ryan Olson on 6/10/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXWebViewController.h"
@@ -25,7 +25,7 @@
WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
if (@available(iOS 10.0, *)) {
configuration.dataDetectorTypes = UIDataDetectorTypeLink;
configuration.dataDetectorTypes = WKDataDetectorTypeLink;
}
self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
@@ -18,6 +18,12 @@
@interface FLEXFileBrowserTableViewCell : UITableViewCell
@end
typedef NS_ENUM(NSUInteger, FLEXFileBrowserSortAttribute) {
FLEXFileBrowserSortAttributeNone = 0,
FLEXFileBrowserSortAttributeName,
FLEXFileBrowserSortAttributeCreationDate,
};
@interface FLEXFileBrowserController () <FLEXFileBrowserSearchOperationDelegate>
@property (nonatomic, copy) NSString *path;
@@ -27,6 +33,7 @@
@property (nonatomic) NSNumber *searchPathsSize;
@property (nonatomic) NSOperationQueue *operationQueue;
@property (nonatomic) UIDocumentInteractionController *documentController;
@property (nonatomic) FLEXFileBrowserSortAttribute sortAttribute;
@end
@@ -47,9 +54,8 @@
self.title = [path lastPathComponent];
self.operationQueue = [NSOperationQueue new];
//computing path size
FLEXFileBrowserController *__weak weakSelf = self;
// Compute path size
weakify(self)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *fileManager = NSFileManager.defaultManager;
NSDictionary<NSString *, id> *attributes = [fileManager attributesOfItemAtPath:path error:NULL];
@@ -59,16 +65,15 @@
attributes = [fileManager attributesOfItemAtPath:[path stringByAppendingPathComponent:fileName] error:NULL];
totalSize += [attributes fileSize];
// Bail if the interested view controller has gone away.
if (!weakSelf) {
// Bail if the interested view controller has gone away
if (!self) {
return;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
FLEXFileBrowserController *__strong strongSelf = weakSelf;
strongSelf.recursiveSize = @(totalSize);
[strongSelf.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{ strongify(self)
self.recursiveSize = @(totalSize);
[self.tableView reloadData];
});
});
@@ -84,6 +89,39 @@
self.showsSearchBar = YES;
self.searchBarDebounceInterval = kFLEXDebounceForAsyncSearch;
[self addToolbarItems:@[
[[UIBarButtonItem alloc] initWithTitle:@"Sort"
style:UIBarButtonItemStylePlain
target:self
action:@selector(sortDidTouchUpInside:)]
]];
}
- (void)sortDidTouchUpInside:(UIBarButtonItem *)sortButton {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sort"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
[alertController addAction:[UIAlertAction actionWithTitle:@"None"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
[self sortWithAttribute:FLEXFileBrowserSortAttributeNone];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Name"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self sortWithAttribute:FLEXFileBrowserSortAttributeName];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Creation Date"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self sortWithAttribute:FLEXFileBrowserSortAttributeCreationDate];
}]];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)sortWithAttribute:(FLEXFileBrowserSortAttribute)attribute {
self.sortAttribute = attribute;
[self reloadDisplayedPaths];
}
#pragma mark - FLEXGlobalsEntry
@@ -320,38 +358,41 @@
#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 * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) {
UITableViewCell * const cell = [tableView cellForRowAtIndexPath:indexPath];
UIAction *rename = [UIAction actionWithTitle:@"Rename"
image:nil
identifier:@"Rename"
handler:^(__kindof UIAction * _Nonnull action) {
[weakSelf fileBrowserRename:cell];
}];
UIAction *delete = [UIAction actionWithTitle:@"Delete"
image:nil
identifier:@"Delete"
handler:^(__kindof UIAction * _Nonnull action) {
[weakSelf fileBrowserDelete:cell];
}];
UIAction *copyPath = [UIAction actionWithTitle:@"Copy Path"
image:nil
identifier:@"Copy Path"
handler:^(__kindof UIAction * _Nonnull action) {
[weakSelf fileBrowserCopyPath:cell];
}];
UIAction *share = [UIAction actionWithTitle:@"Share"
image:nil
identifier:@"Share"
handler:^(__kindof UIAction * _Nonnull action) {
[weakSelf fileBrowserShare:cell];
}];
return [UIMenu menuWithTitle:@"Manage File" image:nil identifier:@"Manage File" options:UIMenuOptionsDisplayInline children:@[rename, delete, copyPath, share]];
}];
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
point:(CGPoint)point __IOS_AVAILABLE(13.0) {
weakify(self)
return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
UITableViewCell * const cell = [tableView cellForRowAtIndexPath:indexPath];
UIAction *rename = [UIAction actionWithTitle:@"Rename" image:nil identifier:@"Rename"
handler:^(UIAction *action) { strongify(self)
[self fileBrowserRename:cell];
}
];
UIAction *delete = [UIAction actionWithTitle:@"Delete" image:nil identifier:@"Delete"
handler:^(UIAction *action) { strongify(self)
[self fileBrowserDelete:cell];
}
];
UIAction *copyPath = [UIAction actionWithTitle:@"Copy Path" image:nil identifier:@"Copy Path"
handler:^(UIAction *action) { strongify(self)
[self fileBrowserCopyPath:cell];
}
];
UIAction *share = [UIAction actionWithTitle:@"Share" image:nil identifier:@"Share"
handler:^(UIAction *action) { strongify(self)
[self fileBrowserShare:cell];
}
];
return [UIMenu menuWithTitle:@"Manage File" image:nil
identifier:@"Manage File"
options:UIMenuOptionsDisplayInline
children:@[rename, delete, copyPath, share]
];
}
];
}
#endif
@@ -452,6 +493,27 @@
for (NSString *subpath in subpaths) {
[childPaths addObject:[self.path stringByAppendingPathComponent:subpath]];
}
if (self.sortAttribute != FLEXFileBrowserSortAttributeNone) {
[childPaths sortUsingComparator:^NSComparisonResult(NSString *path1, NSString *path2) {
switch (self.sortAttribute) {
case FLEXFileBrowserSortAttributeNone:
// invalid state
return NSOrderedSame;
case FLEXFileBrowserSortAttributeName:
return [path1 compare:path2];
case FLEXFileBrowserSortAttributeCreationDate: {
NSDictionary<NSFileAttributeKey, id> *path1Attributes = [NSFileManager.defaultManager attributesOfItemAtPath:path1
error:NULL];
NSDictionary<NSFileAttributeKey, id> *path2Attributes = [NSFileManager.defaultManager attributesOfItemAtPath:path2
error:NULL];
NSDate *path1Date = path1Attributes[NSFileCreationDate];
NSDate *path2Date = path2Attributes[NSFileCreationDate];
return [path1Date compare:path2Date];
}
}
}];
}
self.childPaths = childPaths;
}
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Javier Soto on 7/26/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <UIKit/UIKit.h>
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Javier Soto on 7/26/14.
// Copyright (c) 2020 Flipboard. All rights reserved.
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXGlobalsEntry.h"
@@ -3,7 +3,7 @@
// FLEX
//
// Created by Tanner Bennett on 7/11/19.
// Copyright © 2019 Flipboard. All rights reserved.
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewSection.h"

Some files were not shown because too many files have changed in this diff Show More