Compare commits

..

175 Commits

Author SHA1 Message Date
Tanner Bennett cf1c33a400 Gotta have this 2023-01-17 03:16:52 -08:00
Tanner Bennett 4bc797458a Hope this works!
Fix imports
2023-01-17 03:16:52 -08:00
Tanner Bennett 09570e3598 Update paths constructor code 2023-01-17 03:16:46 -08:00
Tanner Bennett 89d07a14e1 Add wip bazel support
Sigh
2023-01-17 02:41:17 -08:00
Emil Pedersen 1bbf8dbea1 Locale aware animation speed parsing (#642) 2022-12-09 03:33:07 -06:00
Tanner Bennett 343eba92b6 Finally fix the order of these buttons 2022-12-05 18:09:13 -06:00
Tanner Bennett d6232baf03 Give user opportunity to edit bad queries 2022-12-05 18:09:13 -06:00
Tanner Bennett 9808b89d6d Enable preferred actions with FLEXAlert 2022-12-05 17:55:40 -06:00
Asif de1cbfae4a Fix response body not in cache issue (#640) 2022-11-29 20:34:19 -08:00
Tanner Bennett b036fb18a5 Make class sizes only populate instansiated classes 2022-11-29 16:52:29 -06:00
Tanner Bennett c6ed5098cf Xcode 14 upgrade check 2022-11-22 04:02:40 -06:00
Tanner Bennett d7283cd22d Add FLEXHeapSnapshot 2022-11-22 04:02:14 -06:00
Tanner Bennett 785e181d75 Move subclassesOfClassWithName: to FLEXRuntimeUtility 2022-11-22 04:02:07 -06:00
Tanner Bennett dd66f46a7b Add docs to some APIs 2022-11-22 04:01:28 -06:00
Tanner Bennett 55bae8b53e Make some new headers public; fix #636 2022-11-22 03:14:39 -06:00
Tanner Bennett 5edca3fdad Update Reflex dependency URL; fix #617 2022-11-22 02:56:50 -06:00
Tanner Bennett 9bc319a38e Refine FLEXWindow level; fix #541 2022-11-22 02:47:03 -06:00
Tanner Bennett deac628b06 None of these should be optional 2022-11-04 21:19:16 -05:00
Tanner Bennett 8e44d88c36 Remove social_media_url 2022-10-30 03:09:14 -05:00
Tanner Bennett 73e4a712e8 Refine shouldReceiveTouchAtWindowPoint: logic 2022-10-20 12:50:48 -05:00
Tanner Bennett 9e1f60b2f4 "Recent" button should be disabled in presentation 2022-10-20 12:50:48 -05:00
Tanner Bennett 3c385143ee Use half sheet on iOS 15+ 2022-10-20 12:50:48 -05:00
Tanner Bennett e0acf59d06 Bump version; no longer using semantic versioning
Now versioned using `marketing-year-month`
2022-10-20 12:41:01 -05:00
Tanner Bennett f00af28418 Big brain refactor 2022-10-20 12:29:21 -05:00
Tanner Bennett 2bd809ae6c Xcode 14 2022-10-20 12:29:21 -05:00
Tanner Bennett 003b8f88e8 Add FLEXObjectRef.debugDescription 2022-10-20 12:29:21 -05:00
Tanner Bennett 5e780e6d0c Fix UIButton selection view on iOS 16 2022-10-20 12:29:21 -05:00
Tanner Bennett 17ea4976c1 Fix potential retain cycle 2022-10-10 23:10:51 -04:00
Tanner Bennett fbda722f11 Fix bug in supportedInterfaceOrientations 2022-10-09 02:39:44 -04:00
Iulian Onofrei b351b788d5 Fix error-prone FLEX exclusion from release instruction (#630) 2022-10-07 11:39:45 -04:00
Tanner Bennett a195840b67 I don't think this actually fixes anything but oh well 2022-10-06 23:01:31 -04:00
Tanner Bennett 9b946dda5d Fix crash when deleting last blacklisted host 2022-10-06 23:00:47 -04:00
Tanner Bennett 806cdc6acb Compatibility fix for new version of Theos 2022-10-06 00:13:10 -04:00
Tanner Bennett aadfc69f01 Add FLEXWindowShortcuts to project 2022-10-06 00:07:01 -04:00
Tanner Bennett 6e0135d4a0 Fix #627 2022-10-01 15:32:23 -05:00
Tanner Bennett 2599a1eb0d dogs.realm was not being included in example app 2022-10-01 15:32:23 -05:00
AnthoPak c96df6d35c Allow changing UIWindow's animation speed (#629) 2022-09-26 17:20:15 -05:00
Tanner Bennett fff3059099 Use keyboard WILL show events 🚀🚀🚀 2022-09-21 19:32:30 -05:00
Tanner Bennett 4bee6d17bc Silence some totally valid availability warnings 2022-09-21 19:26:43 -05:00
Tanner Bennett 3d8a12027b Ignore SPM build folder 2022-09-21 19:26:43 -05:00
Natheer bc96542856 Move FLEX out of the way of the keyboard (#623) 2022-09-21 19:02:01 -05:00
Jerry.Qiushi 24526a6a0a Podspec: update xcconfig to pod_target_xcconfig (#626) 2022-09-21 17:20:04 -05:00
Pierre-Yves B d33d909fa0 Add missing NSDateFormatter extension to SPM headers (#616) 2022-08-31 15:29:41 -05:00
Chaoshuai Lü 0a9db69419 Use queue instead of self.queue in FLEXNetworkRecorder.m 2022-08-30 11:58:56 -07:00
Tanner Bennett 2db78c3bef APNS: hook correct UNUNCenterDelegate method 2022-08-27 16:37:04 -05:00
Sergo Beruashvili 1b91bc963e Call missing websocket completion (#609)
Co-authored-by: Sergo Beruashvili <sergo.beruashvili@daimler.com>
2022-08-10 02:45:23 -07:00
Enrique Garcia 56d90748cb Fix Xcode 14 SPM warning related to iOS 11 support (#610) 2022-07-31 15:25:59 -05:00
Tanner Bennett 9997721e0a Display the device token as bytes, and tap to copy 2022-07-25 17:45:06 -05:00
Tanner Bennett bedbd0b8c8 FLEXAlert: shortcut to present a temporary alert 2022-07-25 17:44:50 -05:00
Tanner Bennett cb64c88c59 Polish notification hooks
They'll crash if the method is unimplemented; I forgot these methods are all optional
2022-07-25 17:28:16 -05:00
Tanner Bennett be733c30cb Use summary instead of description for remote notifs 2022-07-25 01:51:33 -05:00
Tanner Bennett e46d26034b Flatten intendations in descriptions 2022-07-25 01:51:19 -05:00
Tanner Bennett 3809ece1f9 Distinguish between remote and user notifications
Also change how we get app delegate class
2022-07-24 23:55:52 -05:00
Tanner Bennett b2410750fd Wrap NSDateFormatter 2022-07-24 23:55:52 -05:00
Tanner Bennett 72ccd007b3 APNS: hook Swift UIApplicationMain shim as well 2022-07-24 23:55:52 -05:00
helloworld 4375f1a67f Fix iOS 16 _statusBarWindow crash (#607)
Co-authored-by: ClownFish <15800960640@163.com>
2022-07-05 22:56:00 -05:00
Tanner Bennett 393a43754c Misc 2022-07-02 02:20:26 -05:00
Tanner Bennett b56d6f6d33 Add FLEXAPNSViewController for viewing push notifs 2022-07-02 02:20:26 -05:00
Tanner Bennett 0d985b504b Add auto keyword 2022-07-02 02:20:26 -05:00
Tanner Bennett 148890914d Add nullability specifiers to FLEXSingleRowSection 2022-06-27 18:39:49 -05:00
Tanner Bennett c734ad16e5 Just a lil something for the demo app 2022-06-27 18:39:25 -05:00
Tanner Bennett ac6301437b SPM project: _MSSafeMode env var 2022-06-27 18:39:07 -05:00
Tanner Bennett b45c655ba2 Hopefully fix #574 2022-06-27 18:38:05 -05:00
Tanner Bennett 83fe11210e Fix crash in FLEXFirebaseSetDataInfo 2022-06-12 01:26:42 -05:00
Tanner Bennett e80e3bb5b7 Add API to push explorer on any UINavigationController 2022-05-26 21:31:49 -05:00
Tanner Bennett 833b8e7534 Add APIs to programmatically present …
- an object explorer
- an arbitrary view controller

from FLEXManager
2022-05-26 14:45:18 -05:00
Tanner Bennett 56e8693c41 Add NSPhotoLibraryUsageDescription to example 2022-05-26 14:20:05 -05:00
Tanner Bennett 49eeb28464 Don't load tweaks when debugging the example app 2022-05-26 14:19:55 -05:00
Tanner Bennett a24d752313 Fix UIActivityViewController dismissing presenter 2022-05-26 14:19:35 -05:00
Tanner Bennett 643523a779 Add FLEXActivityViewController 2022-05-26 14:19:15 -05:00
Tanner Bennett 65744675db Fix tabs not being closed in some instances 2022-05-26 12:53:29 -05:00
Chaoshuai Lü f994346919 Match Availability versions for FLEXTableViewSection 2022-05-12 13:46:05 -07:00
Chaoshuai Lü a7a8b8e33e Fix warnings
* Fix -Wobjc-signed-char-bool-implicit-int-conversion in FLEXSwiftInternal
* Fix -Wparentheses
2022-05-11 23:19:37 -05:00
Tanner Bennett f254720408 Display dlopen errors 2022-04-27 23:45:32 -05:00
Tanner Bennett e6fd5ed24e Fix bug in new FLEXMirror usage 2022-04-27 13:45:42 -05:00
Tanner Bennett d13f263492 Update SPM example deps 2022-04-27 13:45:42 -05:00
Tanner Bennett ba36647398 Enable displaying ivar names for custom struct types
FLEXMetadataExtras.h
2022-04-27 13:45:42 -05:00
Tanner Bennett 9d97533649 Make CommitDetails a struct to demo Reflex 2022-04-27 13:45:42 -05:00
Tanner Bennett 96b13e66b6 Podspec: gnu++11 2022-04-27 13:45:42 -05:00
Tanner Bennett 9712a4c869 Delete modulemap 2022-04-27 13:45:42 -05:00
Tanner Bennett 8f9956308f Use Reflex instead of FLEX in SPM project 2022-04-27 13:45:42 -05:00
Tanner Bennett 69e88acbee Initialize FLEXObjectExplorer.reflexAvailable 2022-04-27 13:45:42 -05:00
Tanner Bennett 07587986df Use Reflex and FLEXMirror 2022-04-27 13:45:42 -05:00
Tanner Bennett e6641a5f9d Add FLEXSwiftInternal to check if object from Swift 2022-04-27 13:45:42 -05:00
Tanner Bennett 111fb6c9e6 Modernize FLEXMirror
Differentiate between class and instance props/methods
2022-04-27 13:45:42 -05:00
Tanner Bennett 995e7eadbe Add (unused) libflex modulemap file
For my own use case, I dynamically link FLEX, so I need to build Reflex using libflex.tbd as well as this modulemap file.
2022-04-27 13:45:42 -05:00
Tanner Bennett ac50a6d36b Bump version 2022-04-27 13:45:41 -05:00
Tanner Bennett af40ce0909 Fix annoying divider color in editor screens 2022-04-27 13:43:40 -05:00
matrush fb2a33876e Add FLEXTableRowDataViewController for viewing DB rows 2022-04-24 16:30:43 -07:00
Tanner Bennett a42efe17a1 Use host instead of self here 2022-04-24 16:30:43 -07:00
Tanner Bennett 4bc2d1c7a9 Shorten some line lengths 2022-04-24 14:48:47 -07:00
weiminghuaa c7ebecfcb3 Re-filter system log when new messages arrive 2022-04-24 14:48:47 -07:00
weiminghuaa 208f0a31e4 Pin seach bar in system log 2022-04-24 14:48:47 -07:00
Tanner Bennett 2aeb34a67e Cherry pick #592 2022-04-24 16:23:15 -05:00
Tanner Bennett 39f16bd039 Make properties atomic in hopes of resolving #574 2022-04-24 16:23:00 -05:00
Tanner Bennett eea681d6c5 Consolidate duplicate code 2022-04-24 16:22:08 -05:00
Tanner Bennett a8768da4b9 Fix crash where FIRDocumentSnapshot response is nil 2022-04-24 16:15:34 -05:00
Tanner Bennett 4f6fd29d38 Clean up FLEXMITMDataSource interface 2022-04-23 18:45:24 -05:00
Canius Chu ba9cb43b6a Fix compile errors and warnings (#597)
* Update INSTALL_PATH
* Update run path
* Add FLEXFirebaseTransaction.mm into project which break in commit: d2e0db8773
* Fix header imports
* Rollback LD_RUNPATH_SEARCH_PATHS
2022-04-23 18:12:17 -05:00
Tanner Bennett 3af6da8554 Format _manuallyDeactivateSearchOnDisappear 2022-04-23 18:12:17 -05:00
Chaoshuai Lü 6c21395ac8 Fix self.allTransactions race condition in FLEXMITMDataSource
There is a crash caused by this because of race condition. Here we can simply make a copy of the transaction and it will be used and released properly even within the block.
2022-03-30 20:55:19 -07:00
Chaoshuai Lü 456fda31cd Add fallback column query support when PRAGMA table_info is not working (#573)
* Add fallback column queries support when PRAGMA table_info is not working

* Switch to check columnCount instead of rowsAffected

* Use SELECT * FROM pragma_table_info('%@')

Fallback to SELECT * FROM table where 0=1

Co-authored-by: Tanner Bennett <tannerbennett@me.com>
2022-03-30 20:23:55 -07:00
Chaoshuai Lü 9fc8735925 Check rowIDs instead of rowIDs.count to validate input 2022-03-30 23:16:07 -04:00
Tanner Bennett 9683acbe4f Ignore workspace files 2022-03-28 20:55:31 -07:00
Tanner Bennett 86a1cc9324 Remove DEVELOPMENT_TEAM 2022-03-28 20:55:15 -07:00
Tanner Bennett 88b14b3a92 Escape text for webview on a background thread 2022-03-28 20:54:34 -07:00
Tanner Bennett b9cd2682a7 Clean up web vc file 2022-03-28 20:43:48 -07:00
Nick Holub 64d1534fae Add accessibilityIdentifier and accessibilityLabel to views properties 2022-03-22 15:53:57 -07:00
Chaoshuai Lü 8318902826 Fix -Wobjc-signed-char-bool-implicit-int-conversion issue in FLEXNavigationController
This should be checked explicitly to shut up the warning.
2022-03-08 03:16:34 -08:00
Chaoshuai Lu a7f41fe5fc Mark some firebase related functions as static to avoid warnings 2022-03-03 03:14:38 -06:00
Tanner Bennett 2983649cdb Show descriptions of complex FIRQuery objects 2021-12-25 03:27:58 -06:00
Tanner Bennett d2e0db8773 Move FLEXFirebaseTransaction to own file 2021-12-24 22:03:55 -06:00
Tanner Bennett fd98070166 Fix #499, thank you @zhaogyrain 2021-12-24 19:41:52 -06:00
Hossam Ghareeb 4a9fd00eda Add option to copy row as CSV
This will make it easier to insert a new row
2021-12-24 19:35:53 -06:00
Tanner Bennett 97205fc808 Fix bug in rowid selection
`SELECT rowid` returns rowids corresponding to rows in a different order than `SELECT *`. We will now order the rowids in ascending order to match the order of `SELECT *`.

Previously, the mismatched order would mean deleting a row in the UI might delete a different row.
2021-12-24 19:32:01 -06:00
Tanner Bennett 0cffe72a8f Add more assertions to FLEXTableContentVC 2021-12-24 19:32:01 -06:00
Tanner Bennett d5ab2ee916 Revise copy for FLEXTableContentVC add row screen 2021-12-24 19:32:01 -06:00
Tanner Bennett 90c9a48694 Only allow deleting rows if we have a table name 2021-12-24 19:32:01 -06:00
Tanner Bennett 0222c682a0 Improve FLEXTableContentVC toolbar button logic
Only allow adding rows or deleting rows if we have a table name
2021-12-24 19:32:01 -06:00
Tanner Bennett 1e6f6ee110 Clean up FLEXTableContentVC initializers 2021-12-24 19:32:01 -06:00
Hossam Ghareeb 00d6b348f0 Adding an option to add a row in DB table
Added a new toolbar button to insert a new row. Tapping on the button will show an alert to write the values as a comma separated string which will be added in an INSERT statement to be executed.
2021-12-24 19:32:01 -06:00
Tanner Bennett 5404f37d0f Remember the last selected network observer tab 2021-12-24 19:30:18 -06:00
Tanner Bennett 1e539c7129 Pin network history search bar
This works around an ugly visual glitch that happens when the segmented control is visible
2021-12-24 19:30:18 -06:00
Tanner Bennett ca1b202949 For now, just show the transaction object directly 2021-12-24 19:30:18 -06:00
Tanner Bennett 62220a9a65 Record Firebase document creation 2021-12-24 19:30:18 -06:00
Tanner Bennett 02730c6c86 Allow clearing only filtered requests 2021-12-24 19:30:18 -06:00
Tanner Bennett 68789fbe1d Allow filtering Firebase requests with push/pull 2021-12-24 19:30:18 -06:00
Tanner Bennett b4261f8647 Add description for Firebase transaction "push" type 2021-12-24 19:30:18 -06:00
Tanner Bennett 94bf4eac2a Record "push" Firebase network transaction types 2021-12-23 01:35:17 -06:00
Tanner Bennett bed52392e5 Add new Firebase network transaction types 2021-12-23 01:35:17 -06:00
Tanner Bennett c4891840bd Wrap some method names 2021-12-23 01:35:17 -06:00
Tanner Bennett 9720227ac7 Fix logic in network observer mode property 2021-12-23 01:35:17 -06:00
Tanner Bennett 74622aaf10 Initial work for Firebase 2021-12-23 01:35:17 -06:00
Tanner Bennett 0cb5ad8453 Restore -Wno-deprecated-declarations 2021-12-23 01:35:09 -06:00
Chaoshuai Lu def68eae48 Remove unneeded edgesForExtendedLayout setting
Update FLEXTableContentViewController.m

Remove empty lines/spaces changes
2021-12-05 15:29:30 -08:00
Tanner Bennett ffa658c49b Make a bunch of stuff private that should be private 2021-11-18 18:42:04 -06:00
Tanner Bennett 6066de480f FLEXMacros should be public 2021-11-18 18:20:59 -06:00
Tanner Bennett 0fd7dfa002 SPM: clear Headers folder when running script 2021-11-18 17:50:44 -06:00
Tanner Bennett 60403e614d Ignore Classes/Headers in VS Code search 2021-11-18 17:49:03 -06:00
skytoup fa7db997bd Fix realm database viewer crash 2021-11-16 17:34:11 -08:00
Tanner Bennett d15e72c681 Separate example projects for SPM and Cocoapods 2021-11-14 01:01:24 -06:00
Rafael Fernández 4f1ff7784d Add SPM usage in README, close #482 2021-11-14 00:56:24 -06:00
Tanner Bennett 8129a034e3 Clean up Package.swift 2021-11-14 00:56:24 -06:00
Tanner Bennett 838db6954b Add cxx standard setting 2021-11-14 00:56:24 -06:00
Tanner Bennett 5b3d3af99c Update package.swift 2021-11-14 00:56:24 -06:00
Tanner Bennett 2f9f266493 Update import format 2021-11-14 00:56:24 -06:00
Tanner Bennett 9d94979d08 Exclude LICENSE.md 2021-11-14 00:56:24 -06:00
Tanner Bennett 19b83f4404 headerSearchPath 2021-11-14 00:56:24 -06:00
Tanner Bennett 2b13378d98 Remove unsafe flags 😑 2021-11-14 00:56:24 -06:00
Tanner Bennett 4ae9d41104 Add header references 2021-11-14 00:56:24 -06:00
Tanner Bennett 1490170eb4 Add Package.swift, add script to generate headers
Update script
2021-11-14 00:56:24 -06:00
Tanner Bennett cd695ed106 Bump version 2021-11-14 00:53:41 -06:00
Tanner Bennett 69c1719159 Remove redundant/unused methods in arginputfactory 2021-11-14 00:39:44 -06:00
Tanner Bennett 4019518bf5 Fix #564
entry->log_message.format appears to be garbage on iOS 15, and it doesn't look like it is ever really used in practice anyway, as far as I can tell. Thanks @matrush for pointing this out!
2021-11-14 00:39:44 -06:00
Matt Robinson 3fd8e7c77d Fix CLANG_WARN_STRICT_PROTOTYPES/-Wstrict-prototypes issues
This allows `FLEX` to be linked statically to a binary that has `-Wstrict-prototypes` enabled (for example in CocoaPods without `use_frameworks!`.

Changes:
- Apply `void` to all the empty function/block declarations that don't take arguments.
- Apply `SEL`/`UIImage *` to the others that actually take arguments.
- Remove `CLANG_WARN_STRICT_PROTOTYPES = NO` since the default is enabled.
2021-11-14 00:39:44 -06:00
Tanner Bennett 99c3bcb8c5 Remove init exceptions from flex meta classes 2021-11-14 00:39:44 -06:00
Tanner Bennett b587e96e70 Make FLEXMirror protocol 2021-11-14 00:39:43 -06:00
Tanner Bennett ef8f0a303e Add missing nullability to metadata types 2021-11-14 00:36:52 -06:00
Tanner Bennett cfb1e4caab Add NS_SWIFT_NAME to some enums; does not work
Left it commented out. The enums just disappear for some reason?
2021-11-04 19:11:18 -05:00
daniel 2411c331cd Added a dynamic background color to the WebViewControllers response (Depending on being in Light/Dark mode. See this gist for an example: https://gist.githubusercontent.com/dlevi309/e4d48556836b26125e95cbd82d32a9de/raw/d01112d6e0734db11fa74e2fdb0a1330ddcf82a2/dynamicPage.html) 2021-10-27 13:45:33 -05:00
Tanner Bennett fd4b38f46d Fix bug in tab-close logic 2021-10-26 14:43:20 -05:00
Chaoshuai Lu 269e31894c Remove NSParameterAssert check in closeTab method 2021-10-25 18:24:50 -07:00
Tanner Bennett 2f2da50aed Fix potential crash in FLEXPointerIsReadable
vm_read allocates heap memory, this was intended to be an allocation-free check. Some apps may run out of memory in this code path.
2021-10-20 15:21:26 -05:00
Tanner Bennett d87779212c Add data property to FIRDocumentSnapshot at runtime 2021-10-17 17:33:23 -05:00
Tanner Bennett 5db6a12c6e project.pbxcproj formatting? 2021-10-17 17:33:02 -05:00
Tanner Bennett 6d0f776102 Add a FLEXHeapEnumerator test
Ensure we can spoof an object that is found by FLEXHeapEnumerator and also later prove it isn't a real object
2021-10-17 17:32:09 -05:00
Tanner Bennett 6c83ddc2c7 Refactor FLEXHeapEnumerator and FLEXObjectRef
Move logic that was in FLEXLiveObjectsController into FLEXHeapEnumerator. Also adjust FLEXObjectRef initializers to reflect the type of reference you want to hold to the object. FLEXObjectRef now supports unsafe_unretained and retained references.
2021-10-17 17:31:12 -05:00
Tanner Bennett b510d24e13 Improve FLEXPointerIsValidObjcObject
Compare allocation size to expected instance size
2021-10-17 17:28:59 -05:00
Tanner Bennett 6cdf2e61dc Fix websocket activity not being cleared 2021-10-14 00:28:49 -05:00
Tanner Bennett 9b0ed83ff5 Remove old commented out code 2021-10-13 23:41:13 -05:00
Tanner Bennett dbe1b93f48 Add network observer flag to our NSUserDefaults category 2021-10-13 18:45:52 -05:00
Tanner Bennett 06444f1576 Clean up some comments 2021-10-11 20:21:37 -05:00
Tanner Bennett 9bbf1d0d48 Refactor FLEXNetworkTransaction
Add FLEXURLTransaction to differentiate between NSURL-API-related transactions and other transactions, such as lower level protocols or Firebase ;)
2021-10-11 20:11:04 -05:00
Tanner Bennett 0562f15cd0 Fix incoming WS messages not showing correct details 2021-10-11 20:09:58 -05:00
Tanner Bennett eb63c91481 Send example WS message 2021-10-11 20:09:40 -05:00
394 changed files with 5543 additions and 1612 deletions
+3
View File
@@ -20,3 +20,6 @@ DerivedData
/Example/Pods
Podfile.lock
IDEWorkspaceChecks.plist
*.xcworkspace
.build
bazel-*
+5
View File
@@ -0,0 +1,5 @@
{
"search.exclude": {
"Classes/Headers": true
}
}
+51
View File
@@ -0,0 +1,51 @@
FLEX_PUBLIC_HDRS = glob([
"Classes/*.h",
"Classes/Manager/*.h",
"Classes/Toolbar/*.h",
"Classes/Core/**/*.h",
"Classes/Utility/Runtime/Objc/**/*.h",
"Classes/Utility/Runtime/Objc/*.h",
"Classes/ObjectExplorers/**/*.h",
"Classes/Editing/**/*.h",
"Classes/GlobalStateExplorers/**/*.h",
"Classes/Utility/Categories/*.h",
], [
"**/FLEX.h"
], allow_empty = False
) + [
"Classes/Utility/FLEXMacros.h",
"Classes/Utility/FLEXAlert.h",
"Classes/Utility/FLEXResources.h",
"Classes/Utility/FLEXHeapEnumerator.h"
]
objc_library(
name = "FLEX",
module_name = "FLEX",
hdrs = FLEX_PUBLIC_HDRS,
srcs = glob([
"Classes/**/*.m",
"Classes/**/*.mm",
"Classes/**/*.c",
"Classes/**/*.h"
], FLEX_PUBLIC_HDRS, allow_empty = False),
sdk_dylibs = [
"libz",
"libsqlite3"
],
sdk_frameworks = [
"Foundation",
"UIKit",
"CoreGraphics",
"ImageIO",
"QuartzCore",
"WebKit",
"Security",
"SceneKit"
],
copts = [
"-Wno-deprecated-declarations",
"-Wno-unsupported-availability-guard"
],
visibility = ["//visibility:public"]
)
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
#import "Classes/Headers/FLEXTableViewController.h"
#pragma mark - FLEXTableViewFiltering
@protocol FLEXTableViewFiltering <FLEXSearchResultsUpdating>
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
#import "FLEXTableViewSection.h"
#import "NSArray+FLEX.h"
#import "FLEXMacros.h"
#import "Classes/Headers/FLEXFilteringTableViewController.h"
#import "Classes/Headers/FLEXTableViewSection.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/FLEXMacros.h"
@interface FLEXFilteringTableViewController ()
@@ -74,7 +74,7 @@
#pragma mark - Search
- (void)updateSearchResults:(NSString *)newText {
NSArray *(^filter)() = ^NSArray *{
NSArray *(^filter)(void) = ^NSArray *{
self.filterText = newText;
// Sections will adjust data based on this property
@@ -16,4 +16,13 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface UINavigationController (FLEXObjectExploring)
/// Push an object explorer view controller onto the navigation stack
- (void)pushExplorerForObject:(id)object;
/// Push an object explorer view controller onto the navigation stack
- (void)pushExplorerForObject:(id)object animated:(BOOL)animated;
@end
NS_ASSUME_NONNULL_END
@@ -6,9 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXNavigationController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXTabList.h"
#import "Classes/Headers/FLEXNavigationController.h"
#import "Classes/ExplorerInterface/FLEXExplorerViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabList.h"
@interface UINavigationController (Private) <UIGestureRecognizerDelegate>
- (void)_gestureRecognizedInteractiveHide:(UIGestureRecognizer *)sender;
@@ -28,7 +29,8 @@
@implementation FLEXNavigationController
+ (instancetype)withRootViewController:(UIViewController *)rootVC {
return [[self alloc] initWithRootViewController:rootVC];
FLEXNavigationController *nav = [[self alloc] initWithRootViewController:rootVC];
return nav;
}
- (void)viewDidLoad {
@@ -65,6 +67,17 @@
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (@available(iOS 15.0, *)) {
UISheetPresentationController *presenter = self.sheetPresentationController;
presenter.detents = @[
UISheetPresentationControllerDetent.mediumDetent,
UISheetPresentationControllerDetent.largeDetent,
];
presenter.prefersScrollingExpandsWhenScrolledToEdge = NO;
presenter.selectedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
presenter.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
}
if (self.beingPresented && !self.didSetupPendingDismissButtons) {
for (UIViewController *vc in self.viewControllers) {
[self addNavigationBarItemsToViewController:vc.navigationItem];
@@ -93,15 +106,25 @@
[self addNavigationBarItemsToViewController:viewController.navigationItem];
}
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
// Workaround for UIActivityViewController trying to dismiss us for some reason
if (![self.viewControllers.lastObject.presentedViewController isKindOfClass:UIActivityViewController.self]) {
[super dismissViewControllerAnimated:flag completion:completion];
}
}
- (void)dismissAnimated {
// Tabs are only closed if the done button is pressed; this
// allows you to leave a tab open by dragging down to dismiss
[FLEXTabList.sharedList closeTab:self];
if ([self.presentingViewController isKindOfClass:[FLEXExplorerViewController class]]) {
[FLEXTabList.sharedList closeTab:self];
}
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)canShowToolbar {
return self.topViewController.toolbarItems.count;
return self.topViewController.toolbarItems.count > 0;
}
- (void)addNavigationBarItemsToViewController:(UINavigationItem *)navigationItem {
@@ -191,3 +214,18 @@
}
@end
@implementation UINavigationController (FLEXObjectExploring)
- (void)pushExplorerForObject:(id)object {
[self pushExplorerForObject:object animated:YES];
}
- (void)pushExplorerForObject:(id)object animated:(BOOL)animated {
UIViewController *explorer = [FLEXObjectExplorerFactory explorerViewControllerForObject:object];
if (explorer) {
[self pushViewController:explorer animated:animated];
}
}
@end
@@ -7,7 +7,7 @@
//
#import <UIKit/UIKit.h>
#import "FLEXTableView.h"
#import "Classes/Headers/FLEXTableView.h"
@class FLEXScopeCarousel, FLEXWindow, FLEXTableViewSection;
typedef CGFloat FLEXDebounceInterval;
@@ -6,15 +6,15 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXBookmarksViewController.h"
#import "FLEXTabsViewController.h"
#import "FLEXScopeCarousel.h"
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "FLEXResources.h"
#import "UIBarButtonItem+FLEX.h"
#import "Classes/Headers/FLEXTableViewController.h"
#import "Classes/ExplorerInterface/FLEXExplorerViewController.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabsViewController.h"
#import "Classes/Core/Views/Carousel/FLEXScopeCarousel.h"
#import "Classes/Headers/FLEXTableView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXResources.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
#import <objc/runtime.h>
@interface Block : NSObject
@@ -66,9 +66,9 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
_searchBarDebounceInterval = kFLEXDebounceFast;
_showSearchBarInitially = YES;
_style = style;
_manuallyDeactivateSearchOnDisappear = ({
NSProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11;
});
_manuallyDeactivateSearchOnDisappear = (
NSProcessInfo.processInfo.operatingSystemVersion.majorVersion < 11
);
// We will be our own search delegate if we implement this method
if ([self respondsToSelector:@selector(updateSearchResults:)]) {
@@ -559,7 +559,7 @@ static UITextField *kDummyTextField = nil;
[self.debounceTimer invalidate];
NSString *text = searchController.searchBar.text;
void (^updateSearchResults)() = ^{
void (^updateSearchResults)(void) = ^{
if (self.searchResultsUpdater) {
[self.searchResultsUpdater updateSearchResults:text];
} else {
+9 -5
View File
@@ -6,7 +6,9 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewSection.h"
#import "Classes/Headers/FLEXTableViewSection.h"
NS_ASSUME_NONNULL_BEGIN
/// A section providing a specific single row.
///
@@ -16,13 +18,15 @@
@interface FLEXSingleRowSection : FLEXTableViewSection
/// @param reuseIdentifier if nil, kFLEXDefaultCell is used.
+ (instancetype)title:(NSString *)sectionTitle
reuse:(NSString *)reuseIdentifier
+ (instancetype)title:(nullable NSString *)sectionTitle
reuse:(nullable NSString *)reuseIdentifier
cell:(void(^)(__kindof UITableViewCell *cell))cellConfiguration;
@property (nonatomic) UIViewController *pushOnSelection;
@property (nonatomic) void (^selectionAction)(UIViewController *host);
@property (nullable, nonatomic) UIViewController *pushOnSelection;
@property (nullable, nonatomic) void (^selectionAction)(UIViewController *host);
/// Called to determine whether the single row should display itself or not.
@property (nonatomic) BOOL (^filterMatcher)(NSString *filterText);
@end
NS_ASSUME_NONNULL_END
+4 -2
View File
@@ -6,8 +6,8 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSingleRowSection.h"
#import "FLEXTableView.h"
#import "Classes/Headers/FLEXSingleRowSection.h"
#import "Classes/Headers/FLEXTableView.h"
@interface FLEXSingleRowSection ()
@property (nonatomic, readonly) NSString *reuseIdentifier;
@@ -30,6 +30,8 @@
- (id)initWithTitle:(NSString *)sectionTitle
reuse:(NSString *)reuseIdentifier
cell:(void (^)(__kindof UITableViewCell *))cellConfiguration {
NSParameterAssert(cellConfiguration);
self = [super init];
if (self) {
_title = sectionTitle;
+1 -1
View File
@@ -7,7 +7,7 @@
//
#import <UIKit/UIKit.h>
#import "NSArray+FLEX.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
@class FLEXTableView;
NS_ASSUME_NONNULL_BEGIN
+5 -5
View File
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewSection.h"
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "UIMenu+FLEX.h"
#import "Classes/Headers/FLEXTableViewSection.h"
#import "Classes/Headers/FLEXTableView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/Categories/UIMenu+FLEX.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincomplete-implementation"
@@ -79,7 +79,7 @@
return @"";
}
- (NSArray<UIMenuElement *> *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13)) {
- (NSArray<UIMenuElement *> *)menuItemsForRow:(NSInteger)row sender:(UIViewController *)sender API_AVAILABLE(ios(13.0)) {
NSArray<NSString *> *copyItems = [self copyMenuItemsForRow:row];
NSAssert(copyItems.count % 2 == 0, @"copyMenuItemsForRow: should return an even list");
@@ -6,9 +6,9 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCarouselCell.h"
#import "FLEXColor.h"
#import "UIView+FLEX_Layout.h"
#import "Classes/Core/Views/Carousel/FLEXCarouselCell.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/Categories/Private/UIView+FLEX_Layout.h"
@interface FLEXCarouselCell ()
@property (nonatomic, readonly) UILabel *titleLabel;
@@ -6,11 +6,11 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXScopeCarousel.h"
#import "FLEXCarouselCell.h"
#import "FLEXColor.h"
#import "FLEXMacros.h"
#import "UIView+FLEX_Layout.h"
#import "Classes/Core/Views/Carousel/FLEXScopeCarousel.h"
#import "Classes/Core/Views/Carousel/FLEXCarouselCell.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/FLEXMacros.h"
#import "Classes/Utility/Categories/Private/UIView+FLEX_Layout.h"
const CGFloat kCarouselItemSpacing = 0;
NSString * const kCarouselCellReuseIdentifier = @"kCarouselCellReuseIdentifier";
+1 -1
View File
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXMultilineTableViewCell.h"
#import "Classes/Headers/FLEXMultilineTableViewCell.h"
NS_ASSUME_NONNULL_BEGIN
+2 -2
View File
@@ -6,8 +6,8 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCodeFontCell.h"
#import "UIFont+FLEX.h"
#import "Classes/Headers/FLEXCodeFontCell.h"
#import "Classes/Utility/Categories/UIFont+FLEX.h"
@implementation FLEXCodeFontCell
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
#import "Classes/Headers/FLEXTableViewCell.h"
@interface FLEXKeyValueTableViewCell : FLEXTableViewCell
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXKeyValueTableViewCell.h"
#import "Classes/Headers/FLEXKeyValueTableViewCell.h"
@implementation FLEXKeyValueTableViewCell
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
#import "Classes/Headers/FLEXTableViewCell.h"
/// A cell with both labels set to be multi-line capable.
@interface FLEXMultilineTableViewCell : FLEXTableViewCell
@@ -6,9 +6,9 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXMultilineTableViewCell.h"
#import "UIView+FLEX_Layout.h"
#import "FLEXUtility.h"
#import "Classes/Headers/FLEXMultilineTableViewCell.h"
#import "Classes/Utility/Categories/Private/UIView+FLEX_Layout.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXMultilineTableViewCell ()
@property (nonatomic, readonly) UILabel *_titleLabel;
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
#import "Classes/Headers/FLEXTableViewCell.h"
/// A cell initialized with \c UITableViewCellStyleSubtitle
@interface FLEXSubtitleTableViewCell : FLEXTableViewCell
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSubtitleTableViewCell.h"
#import "Classes/Headers/FLEXSubtitleTableViewCell.h"
@implementation FLEXSubtitleTableViewCell
+4 -4
View File
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewCell.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "FLEXTableView.h"
#import "Classes/Headers/FLEXTableViewCell.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Headers/FLEXTableView.h"
@interface UITableView (Internal)
// Exists at least since iOS 5
+6 -6
View File
@@ -6,12 +6,12 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "FLEXSubtitleTableViewCell.h"
#import "FLEXMultilineTableViewCell.h"
#import "FLEXKeyValueTableViewCell.h"
#import "FLEXCodeFontCell.h"
#import "Classes/Headers/FLEXTableView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Headers/FLEXSubtitleTableViewCell.h"
#import "Classes/Headers/FLEXMultilineTableViewCell.h"
#import "Classes/Headers/FLEXKeyValueTableViewCell.h"
#import "Classes/Headers/FLEXCodeFontCell.h"
FLEXTableViewCellReuseIdentifier const kFLEXDefaultCell = @"kFLEXDefaultCell";
FLEXTableViewCellReuseIdentifier const kFLEXDetailCell = @"kFLEXDetailCell";
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputColorView : FLEXArgumentInputView
@@ -6,9 +6,9 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputColorView.h"
#import "FLEXUtility.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@protocol FLEXColorComponentInputViewDelegate;
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputDateView : FLEXArgumentInputView
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputDateView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@interface FLEXArgumentInputDateView ()
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputFontView : FLEXArgumentInputView
@@ -6,10 +6,10 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputFontView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXArgumentInputFontsPickerView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.h"
@interface FLEXArgumentInputFontView ()
@@ -6,7 +6,7 @@
// Copyright (c) 2014年 f. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
@interface FLEXArgumentInputFontsPickerView : FLEXArgumentInputTextView <UIPickerViewDataSource, UIPickerViewDelegate>
@end
@@ -6,8 +6,8 @@
// Copyright (c) 2014 f. All rights reserved.
//
#import "FLEXArgumentInputFontsPickerView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontsPickerView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@interface FLEXArgumentInputFontsPickerView ()
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
@interface FLEXArgumentInputNotSupportedView : FLEXArgumentInputTextView
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputNotSupportedView.h"
#import "FLEXColor.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.h"
#import "Classes/Utility/FLEXColor.h"
@implementation FLEXArgumentInputNotSupportedView
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
@interface FLEXArgumentInputNumberView : FLEXArgumentInputTextView
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputNumberView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@implementation FLEXArgumentInputNumberView
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
@interface FLEXArgumentInputObjectView : FLEXArgumentInputTextView
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputObjectView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
static const CGFloat kSegmentInputMargin = 10;
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputTextView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
@interface FLEXArgumentInputStringView : FLEXArgumentInputTextView
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputStringView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@implementation FLEXArgumentInputStringView
@@ -6,8 +6,11 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputStructView : FLEXArgumentInputView
/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;
@end
@@ -6,10 +6,10 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputStructView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXTypeEncodingParser.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Utility/Runtime/Objc/FLEXTypeEncodingParser.h"
@interface FLEXArgumentInputStructView ()
@@ -19,6 +19,41 @@
@implementation FLEXArgumentInputStructView
static NSMutableDictionary<NSString *, NSArray<NSString *> *> *structFieldNameRegistrar = nil;
+ (void)initialize {
if (self == [FLEXArgumentInputStructView class]) {
structFieldNameRegistrar = [NSMutableDictionary new];
[self registerDefaultFieldNames];
}
}
+ (void)registerDefaultFieldNames {
NSDictionary *defaults = @{
@(@encode(CGRect)): @[@"CGPoint origin", @"CGSize size"],
@(@encode(CGPoint)): @[@"CGFloat x", @"CGFloat y"],
@(@encode(CGSize)): @[@"CGFloat width", @"CGFloat height"],
@(@encode(CGVector)): @[@"CGFloat dx", @"CGFloat dy"],
@(@encode(UIEdgeInsets)): @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"],
@(@encode(UIOffset)): @[@"CGFloat horizontal", @"CGFloat vertical"],
@(@encode(NSRange)): @[@"NSUInteger location", @"NSUInteger length"],
@(@encode(CATransform3D)): @[@"CGFloat m11", @"CGFloat m12", @"CGFloat m13", @"CGFloat m14",
@"CGFloat m21", @"CGFloat m22", @"CGFloat m23", @"CGFloat m24",
@"CGFloat m31", @"CGFloat m32", @"CGFloat m33", @"CGFloat m34",
@"CGFloat m41", @"CGFloat m42", @"CGFloat m43", @"CGFloat m44"],
@(@encode(CGAffineTransform)): @[@"CGFloat a", @"CGFloat b",
@"CGFloat c", @"CGFloat d",
@"CGFloat tx", @"CGFloat ty"],
};
[structFieldNameRegistrar addEntriesFromDictionary:defaults];
if (@available(iOS 11.0, *)) {
structFieldNameRegistrar[@(@encode(NSDirectionalEdgeInsets))] = @[
@"CGFloat top", @"CGFloat leading", @"CGFloat bottom", @"CGFloat trailing"
];
}
}
- (instancetype)initWithArgumentTypeEncoding:(const char *)typeEncoding {
self = [super initWithArgumentTypeEncoding:typeEncoding];
if (self) {
@@ -181,40 +216,13 @@
return NO;
}
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
NSParameterAssert(typeEncoding); NSParameterAssert(names);
structFieldNameRegistrar[typeEncoding] = names;
}
+ (NSArray<NSString *> *)customFieldTitlesForTypeEncoding:(const char *)typeEncoding {
NSArray<NSString *> *customTitles = nil;
if (strcmp(typeEncoding, @encode(CGRect)) == 0) {
customTitles = @[@"CGPoint origin", @"CGSize size"];
} else if (strcmp(typeEncoding, @encode(CGPoint)) == 0) {
customTitles = @[@"CGFloat x", @"CGFloat y"];
} else if (strcmp(typeEncoding, @encode(CGSize)) == 0) {
customTitles = @[@"CGFloat width", @"CGFloat height"];
} else if (strcmp(typeEncoding, @encode(CGVector)) == 0) {
customTitles = @[@"CGFloat dx", @"CGFloat dy"];
} else if (strcmp(typeEncoding, @encode(UIEdgeInsets)) == 0) {
customTitles = @[@"CGFloat top", @"CGFloat left", @"CGFloat bottom", @"CGFloat right"];
} else if (strcmp(typeEncoding, @encode(UIOffset)) == 0) {
customTitles = @[@"CGFloat horizontal", @"CGFloat vertical"];
} else if (strcmp(typeEncoding, @encode(NSRange)) == 0) {
customTitles = @[@"NSUInteger location", @"NSUInteger length"];
} else if (strcmp(typeEncoding, @encode(CATransform3D)) == 0) {
customTitles = @[@"CGFloat m11", @"CGFloat m12", @"CGFloat m13", @"CGFloat m14",
@"CGFloat m21", @"CGFloat m22", @"CGFloat m23", @"CGFloat m24",
@"CGFloat m31", @"CGFloat m32", @"CGFloat m33", @"CGFloat m34",
@"CGFloat m41", @"CGFloat m42", @"CGFloat m43", @"CGFloat m44"];
} else if (strcmp(typeEncoding, @encode(CGAffineTransform)) == 0) {
customTitles = @[@"CGFloat a", @"CGFloat b",
@"CGFloat c", @"CGFloat d",
@"CGFloat tx", @"CGFloat ty"];
} else {
if (@available(iOS 11.0, *)) {
if (strcmp(typeEncoding, @encode(NSDirectionalEdgeInsets)) == 0) {
customTitles = @[@"CGFloat top", @"CGFloat leading",
@"CGFloat bottom", @"CGFloat trailing"];
}
}
}
return customTitles;
return structFieldNameRegistrar[@(typeEncoding)];
}
@end
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputSwitchView : FLEXArgumentInputView
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputSwitchView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.h"
@interface FLEXArgumentInputSwitchView ()
@@ -6,7 +6,7 @@
//
//
#import "FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
@interface FLEXArgumentInputTextView : FLEXArgumentInputView <UITextViewDelegate>
@@ -6,9 +6,9 @@
//
//
#import "FLEXColor.h"
#import "FLEXArgumentInputTextView.h"
#import "FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputTextView.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXArgumentInputTextView ()
@@ -6,9 +6,9 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXArgumentInputView.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
@interface FLEXArgumentInputView ()
@@ -7,7 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "FLEXArgumentInputSwitchView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.h"
@interface FLEXArgumentInputViewFactory : NSObject
@@ -21,4 +21,7 @@
/// Useful when deciding whether to edit or explore a property, ivar, or NSUserDefaults value.
+ (BOOL)canEditFieldWithTypeEncoding:(const char *)typeEncoding currentValue:(id)currentValue;
/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding;
@end
+17 -12
View File
@@ -6,18 +6,18 @@
//
//
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputObjectView.h"
#import "FLEXArgumentInputNumberView.h"
#import "FLEXArgumentInputSwitchView.h"
#import "FLEXArgumentInputStructView.h"
#import "FLEXArgumentInputNotSupportedView.h"
#import "FLEXArgumentInputStringView.h"
#import "FLEXArgumentInputFontView.h"
#import "FLEXArgumentInputColorView.h"
#import "FLEXArgumentInputDateView.h"
#import "FLEXRuntimeUtility.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputObjectView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputSwitchView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStructView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputNotSupportedView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputStringView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputFontView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputColorView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputDateView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
@implementation FLEXArgumentInputViewFactory
@@ -67,4 +67,9 @@
return [self argumentInputViewSubclassForTypeEncoding:typeEncoding currentValue:currentValue] != nil;
}
/// Enable displaying ivar names for custom struct types
+ (void)registerFieldNames:(NSArray<NSString *> *)names forTypeEncoding:(NSString *)typeEncoding {
[FLEXArgumentInputStructView registerFieldNames:names forTypeEncoding:typeEncoding];
}
@end
@@ -6,13 +6,13 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorViewController.h"
#import "Classes/Editing/FLEXFieldEditorViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface FLEXDefaultEditorViewController : FLEXVariableEditorViewController
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit;
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit;
+ (BOOL)canEditDefaultWithValue:(nullable id)currentValue;
@@ -6,11 +6,11 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXDefaultEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "Classes/Editing/FLEXDefaultEditorViewController.h"
#import "Classes/Editing/FLEXFieldEditorView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
@interface FLEXDefaultEditorViewController ()
@@ -21,7 +21,7 @@
@implementation FLEXDefaultEditorViewController
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)())onCommit {
+ (instancetype)target:(NSUserDefaults *)defaults key:(NSString *)key commitHandler:(void(^_Nullable)(void))onCommit {
FLEXDefaultEditorViewController *editor = [self target:defaults data:key commitHandler:onCommit];
editor.title = @"Edit Default";
return editor;
+5 -4
View File
@@ -6,9 +6,10 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorView.h"
#import "FLEXArgumentInputView.h"
#import "FLEXUtility.h"
#import "Classes/Editing/FLEXFieldEditorView.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
@interface FLEXFieldEditorView ()
@@ -122,7 +123,7 @@
}
+ (UIColor *)dividerColor {
return UIColor.lightGrayColor;
return FLEXColor.tertiaryBackgroundColor;
}
+ (CGFloat)horizontalPadding {
@@ -6,18 +6,18 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXVariableEditorViewController.h"
#import "FLEXProperty.h"
#import "FLEXIvar.h"
#import "Classes/Editing/FLEXVariableEditorViewController.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.h"
NS_ASSUME_NONNULL_BEGIN
@interface FLEXFieldEditorViewController : FLEXVariableEditorViewController
/// @return nil if the property is readonly or if the type is unsupported
+ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)())onCommit;
+ (nullable instancetype)target:(id)target property:(FLEXProperty *)property commitHandler:(void(^_Nullable)(void))onCommit;
/// @return nil if the ivar type is unsupported
+ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)())onCommit;
+ (nullable instancetype)target:(id)target ivar:(FLEXIvar *)ivar commitHandler:(void(^_Nullable)(void))onCommit;
/// Subclasses can change the button title via the \c title property
@property (nonatomic, readonly) UIBarButtonItem *getterButton;
+29 -25
View File
@@ -6,17 +6,19 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFieldEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXPropertyAttributes.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "UIBarButtonItem+FLEX.h"
#import "Classes/Editing/FLEXFieldEditorViewController.h"
#import "Classes/Editing/FLEXFieldEditorView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMetadataExtras.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
@interface FLEXFieldEditorViewController () <FLEXArgumentInputViewDelegate>
@property (nonatomic, readonly) id<FLEXMetadataAuxiliaryInfo> auxiliaryInfoProvider;
@property (nonatomic) FLEXProperty *property;
@property (nonatomic) FLEXIvar *ivar;
@@ -30,19 +32,14 @@
#pragma mark - Initialization
+ (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;
}
+ (instancetype)target:(id)target property:(nonnull FLEXProperty *)property commitHandler:(void(^)(void))onCommit {
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 commitHandler:(void(^_Nullable)())onCommit {
+ (instancetype)target:(id)target ivar:(nonnull FLEXIvar *)ivar commitHandler:(void(^)(void))onCommit {
FLEXFieldEditorViewController *editor = [self target:target data:ivar commitHandler:onCommit];
editor.title = [@"Ivar: " stringByAppendingString:ivar.name];
editor.ivar = ivar;
@@ -66,6 +63,8 @@
self.toolbarItems = @[
UIBarButtonItem.flex_flexibleSpace, self.getterButton, self.actionButton
];
[self registerAuxiliaryInfo];
// Configure input view
self.fieldEditorView.fieldDescription = self.fieldDescription;
@@ -127,6 +126,17 @@
#pragma mark - Private
- (void)registerAuxiliaryInfo {
// This is how Reflex will get Swift struct field names into the editor at runtime
NSDictionary<NSString *, NSArray *> *labels = [self.auxiliaryInfoProvider
auxiliaryInfoForKey:FLEXAuxiliarynfoKeyFieldLabels
];
for (NSString *type in labels) {
[FLEXArgumentInputViewFactory registerFieldNames:labels[type] forTypeEncoding:type];
}
}
- (id)currentValue {
if (self.property) {
return [self.property getValue:self.target];
@@ -135,6 +145,10 @@
}
}
- (id<FLEXMetadataAuxiliaryInfo>)auxiliaryInfoProvider {
return self.ivar ?: self.property;
}
- (const FLEXTypeEncoding *)typeEncoding {
if (self.property) {
return self.property.attributes.typeEncoding.UTF8String;
@@ -151,14 +165,4 @@
}
}
+ (BOOL)canEditProperty:(FLEXProperty *)property onObject:(id)object currentValue:(id)value {
const FLEXTypeEncoding *typeEncoding = property.attributes.typeEncoding.UTF8String;
BOOL canEditType = [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:typeEncoding currentValue:value];
return canEditType && [object respondsToSelector:property.likelySetter];
}
+ (BOOL)canEditIvar:(Ivar)ivar currentValue:(id)value {
return [FLEXArgumentInputViewFactory canEditFieldWithTypeEncoding:ivar_getTypeEncoding(ivar) currentValue:value];
}
@end
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXVariableEditorViewController.h"
#import "FLEXMethod.h"
#import "Classes/Editing/FLEXVariableEditorViewController.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.h"
@interface FLEXMethodCallingViewController : FLEXVariableEditorViewController
@@ -6,14 +6,14 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXMethodCallingViewController.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXFieldEditorView.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXObjectExplorerViewController.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXUtility.h"
#import "Classes/Editing/FLEXMethodCallingViewController.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Editing/FLEXFieldEditorView.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXObjectExplorerViewController.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXMethodCallingViewController ()
@property (nonatomic, readonly) FLEXMethod *method;
@@ -21,17 +21,17 @@ NS_ASSUME_NONNULL_BEGIN
@protected
id _target;
_Nullable id _data;
void (^_Nullable _commitHandler)();
void (^_Nullable _commitHandler)(void);
}
/// @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;
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))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;
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit;
@property (nonatomic, readonly) id target;
@@ -6,16 +6,16 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXColor.h"
#import "FLEXVariableEditorViewController.h"
#import "FLEXFieldEditorView.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXArgumentInputView.h"
#import "FLEXArgumentInputViewFactory.h"
#import "FLEXObjectExplorerViewController.h"
#import "UIBarButtonItem+FLEX.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Editing/FLEXVariableEditorViewController.h"
#import "Classes/Editing/FLEXFieldEditorView.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Editing/ArgumentInputViews/FLEXArgumentInputView.h"
#import "Classes/Editing/FLEXArgumentInputViewFactory.h"
#import "Classes/Headers/FLEXObjectExplorerViewController.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
@interface FLEXVariableEditorViewController () <UIScrollViewDelegate>
@property (nonatomic) UIScrollView *scrollView;
@@ -25,11 +25,11 @@
#pragma mark - Initialization
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
+ (instancetype)target:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
return [[self alloc] initWithTarget:target data:data commitHandler:onCommit];
}
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)())onCommit {
- (id)initWithTarget:(id)target data:(nullable id)data commitHandler:(void(^_Nullable)(void))onCommit {
self = [super init];
if (self) {
_target = target;
@@ -37,7 +37,7 @@
_commitHandler = onCommit;
[NSNotificationCenter.defaultCenter
addObserver:self selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil
name:UIKeyboardWillShowNotification object:nil
];
[NSNotificationCenter.defaultCenter
addObserver:self selector:@selector(keyboardWillHide:)
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXBookmarkManager.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.h"
static NSMutableArray *kFLEXBookmarkManagerBookmarks = nil;
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
#import "Classes/Headers/FLEXTableViewController.h"
NS_ASSUME_NONNULL_BEGIN
@@ -6,16 +6,16 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXBookmarksViewController.h"
#import "FLEXExplorerViewController.h"
#import "FLEXNavigationController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXBookmarkManager.h"
#import "UIBarButtonItem+FLEX.h"
#import "FLEXColor.h"
#import "FLEXUtility.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXTableView.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.h"
#import "Classes/ExplorerInterface/FLEXExplorerViewController.h"
#import "Classes/Headers/FLEXNavigationController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Headers/FLEXTableView.h"
@interface FLEXBookmarksViewController ()
@property (nonatomic, copy) NSArray *bookmarks;
@@ -6,7 +6,7 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXExplorerToolbar.h"
#import "Classes/Headers/FLEXExplorerToolbar.h"
@class FLEXWindow;
@protocol FLEXExplorerViewControllerDelegate;
@@ -6,21 +6,21 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXExplorerViewController.h"
#import "FLEXExplorerToolbarItem.h"
#import "FLEXUtility.h"
#import "FLEXWindow.h"
#import "FLEXTabList.h"
#import "FLEXNavigationController.h"
#import "FLEXHierarchyViewController.h"
#import "FLEXGlobalsViewController.h"
#import "FLEXObjectExplorerViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXNetworkMITMViewController.h"
#import "FLEXTabsViewController.h"
#import "FLEXWindowManagerController.h"
#import "FLEXViewControllersViewController.h"
#import "NSUserDefaults+FLEX.h"
#import "Classes/ExplorerInterface/FLEXExplorerViewController.h"
#import "Classes/Headers/FLEXExplorerToolbarItem.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/ExplorerInterface/FLEXWindow.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabList.h"
#import "Classes/Headers/FLEXNavigationController.h"
#import "Classes/ViewHierarchy/FLEXHierarchyViewController.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.h"
#import "Classes/Headers/FLEXObjectExplorerViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Network/FLEXNetworkMITMViewController.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabsViewController.h"
#import "Classes/ExplorerInterface/FLEXWindowManagerController.h"
#import "Classes/ExplorerInterface/FLEXViewControllersViewController.h"
#import "Classes/Utility/Categories/NSUserDefaults+FLEX.h"
typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
FLEXExplorerModeDefault,
@@ -129,6 +129,14 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
if (@available(iOS 10.0, *)) {
_selectionFBG = [UISelectionFeedbackGenerator new];
}
// Observe keyboard to move self out of the way
[NSNotificationCenter.defaultCenter
addObserver:self
selector:@selector(keyboardShown:)
name:UIKeyboardWillShowNotification
object:nil
];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -162,7 +170,10 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
UIViewController *viewControllerToAsk = [self viewControllerForRotationAndOrientation];
UIInterfaceOrientationMask supportedOrientations = FLEXUtility.infoPlistSupportedInterfaceOrientationsMask;
if (viewControllerToAsk && ![viewControllerToAsk isKindOfClass:[self class]]) {
// We check its class by name because using isKindOfClass will fail for the same class defined
// twice in the runtime; and the goal here is to avoid calling -supportedInterfaceOrientations
// recursively when I'm inspecting FLEX with itself from a tweak dylib
if (viewControllerToAsk && ![NSStringFromClass([viewControllerToAsk class]) hasPrefix:@"FLEX"]) {
supportedOrientations = [viewControllerToAsk supportedInterfaceOrientations];
}
@@ -375,6 +386,21 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
return [self.view convertRect:frameInWindow fromView:nil];
}
- (void)keyboardShown:(NSNotification *)notif {
CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect toolbarFrame = self.explorerToolbar.frame;
if (CGRectGetMinY(keyboardFrame) < CGRectGetMaxY(toolbarFrame)) {
toolbarFrame.origin.y = keyboardFrame.origin.y - toolbarFrame.size.height;
// Subtract a little more, to ignore accessory input views
toolbarFrame.origin.y -= 50;
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.5
options:UIViewAnimationOptionCurveEaseOut animations:^{
[self updateToolbarPositionWithUnconstrainedFrame:toolbarFrame];
} completion:nil];
}
}
#pragma mark - Toolbar Buttons
@@ -403,8 +429,12 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
}
- (UIWindow *)statusWindow {
NSString *statusBarString = [NSString stringWithFormat:@"%@arWindow", @"_statusB"];
return [UIApplication.sharedApplication valueForKey:statusBarString];
if (!@available(iOS 16, *)) {
NSString *statusBarString = [NSString stringWithFormat:@"%@arWindow", @"_statusB"];
return [UIApplication.sharedApplication valueForKey:statusBarString];
}
return nil;
}
- (void)recentButtonTapped:(FLEXExplorerToolbarItem *)sender {
@@ -436,7 +466,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
toolbar.moveItem.selected = self.currentMode == FLEXExplorerModeMove;
// Recent only enabled when we have a last active tab
toolbar.recentItem.enabled = FLEXTabList.sharedList.activeTab != nil;
if (!self.presentedViewController) {
toolbar.recentItem.enabled = FLEXTabList.sharedList.activeTab != nil;
} else {
toolbar.recentItem.enabled = NO;
}
}
@@ -460,17 +494,12 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
initWithTarget:self action:@selector(handleToolbarDetailsTapGesture:)
];
[toolbar.selectedViewDescriptionContainer addGestureRecognizer:self.detailsTapGR];
// Swipe gestures for selecting deeper / higher views at a point
UIPanGestureRecognizer *leftSwipe = [[UIPanGestureRecognizer alloc]
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:@selector(handleChangeViewAtPointGesture:)
];
// 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:panGesture];
// Long press gesture to present tabs manager
[toolbar.globalsItem addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
@@ -823,31 +852,34 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
#pragma mark - Touch Handling
- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates {
BOOL shouldReceiveTouch = NO;
CGPoint pointInLocalCoordinates = [self.view convertPoint:pointInWindowCoordinates fromView:nil];
// Always if it's on the toolbar
if (CGRectContainsPoint(self.explorerToolbar.frame, pointInLocalCoordinates)) {
shouldReceiveTouch = YES;
// If we have a modal presented, is it in the modal?
if (self.presentedViewController) {
UIView *presentedView = self.presentedViewController.view;
CGPoint pipvc = [presentedView convertPoint:pointInLocalCoordinates fromView:self.view];
UIView *hit = [presentedView hitTest:pipvc withEvent:nil];
if (hit != nil) {
return YES;
}
}
// Always if we're in selection mode
if (!shouldReceiveTouch && self.currentMode == FLEXExplorerModeSelect) {
shouldReceiveTouch = YES;
if (self.currentMode == FLEXExplorerModeSelect) {
return YES;
}
// Always in move mode too
if (!shouldReceiveTouch && self.currentMode == FLEXExplorerModeMove) {
shouldReceiveTouch = YES;
if (self.currentMode == FLEXExplorerModeMove) {
return YES;
}
// Always if we have a modal presented
if (!shouldReceiveTouch && self.presentedViewController) {
shouldReceiveTouch = YES;
// Always if it's on the toolbar
if (CGRectContainsPoint(self.explorerToolbar.frame, pointInLocalCoordinates)) {
return YES;
}
return shouldReceiveTouch;
return NO;
}
@@ -893,8 +925,14 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
// up in case we start replacing them again in the future
self.appMenuItems = UIMenuController.sharedMenuController.menuItems;
[self updateButtonStates];
// Show the view controller
[super presentViewController:toPresent animated:animated completion:completion];
[super presentViewController:toPresent animated:animated completion:^{
[self updateButtonStates];
if (completion) completion();
}];
}
- (void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion {
@@ -915,7 +953,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
[self updateButtonStates];
[super dismissViewControllerAnimated:animated completion:completion];
[super dismissViewControllerAnimated:animated completion:^{
[self updateButtonStates];
if (completion) completion();
}];
}
- (BOOL)wantsWindowToBecomeKey {
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
#import "Classes/Headers/FLEXFilteringTableViewController.h"
NS_ASSUME_NONNULL_BEGIN
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXViewControllersViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXMutableListSection.h"
#import "FLEXUtility.h"
#import "Classes/ExplorerInterface/FLEXViewControllersViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXViewControllersViewController ()
@property (nonatomic, readonly) FLEXMutableListSection *section;
+4 -9
View File
@@ -6,8 +6,8 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import "FLEXWindow.h"
#import "FLEXUtility.h"
#import "Classes/ExplorerInterface/FLEXWindow.h"
#import "Classes/Utility/FLEXUtility.h"
#import <objc/runtime.h>
@implementation FLEXWindow
@@ -18,18 +18,13 @@
// Some apps have windows at UIWindowLevelStatusBar + n.
// If we make the window level too high, we block out UIAlertViews.
// There's a balance between staying above the app's windows and staying below alerts.
// UIWindowLevelStatusBar + 100 seems to hit that balance.
self.windowLevel = UIWindowLevelStatusBar + 100.0;
self.windowLevel = UIWindowLevelAlert - 1;
}
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
BOOL pointInside = NO;
if ([self.eventDelegate shouldHandleTouchAtPoint:point]) {
pointInside = [super pointInside:point withEvent:event];
}
return pointInside;
return [self.eventDelegate shouldHandleTouchAtPoint:point];
}
- (BOOL)shouldAffectStatusBarAppearance {
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
#import "Classes/Headers/FLEXTableViewController.h"
NS_ASSUME_NONNULL_BEGIN
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXWindowManagerController.h"
#import "FLEXManager+Private.h"
#import "FLEXUtility.h"
#import "FLEXObjectExplorerFactory.h"
#import "Classes/ExplorerInterface/FLEXWindowManagerController.h"
#import "Classes/Manager/Private/FLEXManager+Private.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
@interface FLEXWindowManagerController ()
@property (nonatomic) UIWindow *keyWindow;
@@ -72,7 +72,7 @@
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)showRevertOrDismissAlert:(void(^)())revertBlock {
- (void)showRevertOrDismissAlert:(void(^)(void))revertBlock {
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
[self reloadData];
[self.tableView reloadData];
+14 -4
View File
@@ -6,8 +6,8 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTabList.h"
#import "FLEXUtility.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabList.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXTabList () {
NSMutableArray *_openTabs;
@@ -80,10 +80,20 @@
- (void)closeTab:(UINavigationController *)tab {
NSParameterAssert(tab);
NSParameterAssert([self.openTabs containsObject:tab]);
NSInteger idx = [self.openTabs indexOfObject:tab];
if (idx != NSNotFound) {
[self closeTabAtIndex:idx];
}
[self closeTabAtIndex:idx];
// Not sure how this is possible, but it happens sometimes
if (self.activeTab == tab) {
[self chooseNewActiveTab];
}
// It is possible for an object explorer to form a retain cycle
// with its own navigation controller; clearing the view controllers
// manually when closing a tab breaks the cycle
tab.viewControllers = @[];
}
- (void)closeTabAtIndex:(NSInteger)idx {
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTableViewController.h"
#import "Classes/Headers/FLEXTableViewController.h"
@interface FLEXTabsViewController : FLEXTableViewController
@@ -6,17 +6,17 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXTabsViewController.h"
#import "FLEXNavigationController.h"
#import "FLEXTabList.h"
#import "FLEXBookmarkManager.h"
#import "FLEXTableView.h"
#import "FLEXUtility.h"
#import "FLEXColor.h"
#import "UIBarButtonItem+FLEX.h"
#import "FLEXExplorerViewController.h"
#import "FLEXGlobalsViewController.h"
#import "FLEXBookmarksViewController.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabsViewController.h"
#import "Classes/Headers/FLEXNavigationController.h"
#import "Classes/ExplorerInterface/Tabs/FLEXTabList.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarkManager.h"
#import "Classes/Headers/FLEXTableView.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
#import "Classes/ExplorerInterface/FLEXExplorerViewController.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.h"
#import "Classes/ExplorerInterface/Bookmarks/FLEXBookmarksViewController.h"
@interface FLEXTabsViewController ()
@property (nonatomic, copy) NSArray<UINavigationController *> *openTabs;
+12 -13
View File
@@ -6,17 +6,16 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
#import "Classes/Utility/Categories/CALayer+FLEX.h"
#import "Classes/Utility/Categories/UIFont+FLEX.h"
#import "Classes/Utility/Categories/UIGestureRecognizer+Blocks.h"
#import "Classes/Utility/Categories/UIPasteboard+FLEX.h"
#import "Classes/Utility/Categories/UIMenu+FLEX.h"
#import "Classes/Utility/Categories/UITextField+Range.h"
#import <FLEX/UIBarButtonItem+FLEX.h>
#import <FLEX/CALayer+FLEX.h>
#import <FLEX/UIFont+FLEX.h>
#import <FLEX/UIGestureRecognizer+Blocks.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/NSUserDefaults+FLEX.h>
#import <FLEX/NSTimer+FLEX.h>
#import "Classes/Utility/Categories/NSObject+FLEX_Reflection.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/Categories/NSUserDefaults+FLEX.h"
#import "Classes/Utility/Categories/NSTimer+FLEX.h"
#import "Classes/Utility/Categories/NSDateFormatter+FLEX.h"
+11 -12
View File
@@ -6,18 +6,17 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXFilteringTableViewController.h>
#import <FLEX/FLEXNavigationController.h>
#import <FLEX/FLEXTableViewController.h>
#import <FLEX/FLEXTableView.h>
#import "Classes/Headers/FLEXFilteringTableViewController.h"
#import "Classes/Headers/FLEXNavigationController.h"
#import "Classes/Headers/FLEXTableViewController.h"
#import "Classes/Headers/FLEXTableView.h"
#import <FLEX/FLEXSingleRowSection.h>
#import <FLEX/FLEXTableViewSection.h>
#import "Classes/Headers/FLEXSingleRowSection.h"
#import "Classes/Headers/FLEXTableViewSection.h"
#import <FLEX/FLEXCodeFontCell.h>
#import <FLEX/FLEXSubtitleTableViewCell.h>
#import <FLEX/FLEXTableViewCell.h>
#import <FLEX/FLEXMultilineTableViewCell.h>
#import <FLEX/FLEXKeyValueTableViewCell.h>
#import "Classes/Headers/FLEXCodeFontCell.h"
#import "Classes/Headers/FLEXSubtitleTableViewCell.h"
#import "Classes/Headers/FLEXTableViewCell.h"
#import "Classes/Headers/FLEXMultilineTableViewCell.h"
#import "Classes/Headers/FLEXKeyValueTableViewCell.h"
#import <FLEX/FLEXScopeCarousel.h>
+11 -19
View File
@@ -6,25 +6,17 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXObjectExplorerFactory.h>
#import <FLEX/FLEXObjectExplorerViewController.h>
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXObjectExplorerViewController.h"
#import <FLEX/FLEXObjectExplorer.h>
#import "Classes/Headers/FLEXObjectExplorer.h"
#import <FLEX/FLEXShortcut.h>
#import <FLEX/FLEXShortcutsFactory+Defaults.h>
#import <FLEX/FLEXShortcutsSection.h>
#import <FLEX/FLEXBlockShortcuts.h>
#import <FLEX/FLEXBundleShortcuts.h>
#import <FLEX/FLEXClassShortcuts.h>
#import <FLEX/FLEXImageShortcuts.h>
#import <FLEX/FLEXLayerShortcuts.h>
#import <FLEX/FLEXViewControllerShortcuts.h>
#import <FLEX/FLEXViewShortcuts.h>
#import "Classes/Headers/FLEXShortcut.h"
#import "Classes/Headers/FLEXShortcutsSection.h"
#import <FLEX/FLEXCollectionContentSection.h>
#import <FLEX/FLEXColorPreviewSection.h>
#import <FLEX/FLEXDefaultsContentSection.h>
#import <FLEX/FLEXMetadataSection.h>
#import <FLEX/FLEXMutableListSection.h>
#import <FLEX/FLEXObjectInfoSection.h>
#import "Classes/Headers/FLEXCollectionContentSection.h"
#import "Classes/Headers/FLEXColorPreviewSection.h"
#import "Classes/Headers/FLEXDefaultsContentSection.h"
#import "Classes/Headers/FLEXMetadataSection.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Headers/FLEXObjectInfoSection.h"
+17 -15
View File
@@ -6,20 +6,22 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXObjcInternal.h>
#import <FLEX/FLEXRuntimeSafety.h>
#import <FLEX/FLEXBlockDescription.h>
#import <FLEX/FLEXTypeEncodingParser.h>
#import "Classes/Utility/Runtime/Objc/FLEXObjcInternal.h"
#import "Classes/Utility/Runtime/Objc/FLEXSwiftInternal.h"
#import "Classes/Utility/Runtime/Objc/FLEXRuntimeSafety.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXBlockDescription.h"
#import "Classes/Utility/Runtime/Objc/FLEXTypeEncodingParser.h"
#import <FLEX/FLEXMirror.h>
#import <FLEX/FLEXProtocol.h>
#import <FLEX/FLEXProperty.h>
#import <FLEX/FLEXIvar.h>
#import <FLEX/FLEXMethodBase.h>
#import <FLEX/FLEXMethod.h>
#import <FLEX/FLEXPropertyAttributes.h>
#import <FLEX/FLEXRuntime+Compare.h>
#import <FLEX/FLEXRuntime+UIKitHelpers.h>
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMirror.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMethodBase.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h"
#import "Classes/Utility/Categories/FLEXRuntime+Compare.h"
#import "Classes/Utility/Categories/FLEXRuntime+UIKitHelpers.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXMetadataExtras.h"
#import <FLEX/FLEXProtocolBuilder.h>
#import <FLEX/FLEXClassBuilder.h>
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXProtocolBuilder.h"
#import "Classes/Utility/Runtime/Objc/Reflection/FLEXClassBuilder.h"
+14 -12
View File
@@ -7,18 +7,20 @@
// Copyright (c) 2020 FLEX Team. All rights reserved.
//
#import <FLEX/FLEXManager.h>
#import <FLEX/FLEXManager+Extensibility.h>
#import <FLEX/FLEXManager+Networking.h>
#import "Classes/Headers/FLEXManager.h"
#import "Classes/Headers/FLEXManager+Extensibility.h"
#import "Classes/Headers/FLEXManager+Networking.h"
#import <FLEX/FLEXExplorerToolbar.h>
#import <FLEX/FLEXExplorerToolbarItem.h>
#import <FLEX/FLEXGlobalsEntry.h>
#import "Classes/Headers/FLEXExplorerToolbar.h"
#import "Classes/Headers/FLEXExplorerToolbarItem.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
#import <FLEX/FLEX-Core.h>
#import <FLEX/FLEX-Runtime.h>
#import <FLEX/FLEX-Categories.h>
#import <FLEX/FLEX-ObjectExploring.h>
#import "Classes/Headers/FLEX-Core.h"
#import "Classes/Headers/FLEX-Runtime.h"
#import "Classes/Headers/FLEX-Categories.h"
#import "Classes/Headers/FLEX-ObjectExploring.h"
#import <FLEX/FLEXAlert.h>
#import <FLEX/FLEXResources.h>
#import "Classes/Utility/FLEXMacros.h"
#import "Classes/Utility/FLEXAlert.h"
#import "Classes/Utility/FLEXResources.h"
#import "Classes/Utility/FLEXHeapEnumerator.h"
@@ -6,11 +6,11 @@
// Copyright © 2015 f. All rights reserved.
//
#import "FLEXDBQueryRowCell.h"
#import "FLEXMultiColumnTableView.h"
#import "NSArray+FLEX.h"
#import "UIFont+FLEX.h"
#import "FLEXColor.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/Categories/UIFont+FLEX.h"
#import "Classes/Utility/FLEXColor.h"
NSString * const kFLEXDBQueryRowCellReuse = @"kFLEXDBQueryRowCellReuse";
@@ -12,7 +12,7 @@
// which Flying Meat Inc. licenses this file to you.
#import <Foundation/Foundation.h>
#import "FLEXSQLResult.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.h"
/// Conformers should automatically open and close the database
@protocol FLEXDatabaseManager <NSObject>
@@ -7,7 +7,7 @@
//
#import <UIKit/UIKit.h>
#import "FLEXTableColumnHeader.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h"
@class FLEXMultiColumnTableView;
@@ -6,11 +6,11 @@
// Copyright © 2015 Peng Tao. All rights reserved.
//
#import "FLEXMultiColumnTableView.h"
#import "FLEXDBQueryRowCell.h"
#import "FLEXTableLeftCell.h"
#import "NSArray+FLEX.h"
#import "FLEXColor.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDBQueryRowCell.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/FLEXColor.h"
@interface FLEXMultiColumnTableView () <
UITableViewDataSource, UITableViewDelegate,
@@ -7,7 +7,7 @@
//
#import <Foundation/Foundation.h>
#import "FLEXDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h"
@interface FLEXRealmDatabaseManager : NSObject <FLEXDatabaseManager>
@@ -6,15 +6,15 @@
// Copyright © 2016 Realm. All rights reserved.
//
#import "FLEXRealmDatabaseManager.h"
#import "NSArray+FLEX.h"
#import "FLEXSQLResult.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.h"
#if __has_include(<Realm/Realm.h>)
#import <Realm/Realm.h>
#import <Realm/RLMRealm_Dynamic.h>
#else
#import "FLEXRealmDefines.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDefines.h"
#endif
@interface FLEXRealmDatabaseManager ()
@@ -6,14 +6,14 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXSQLResult.h"
#import "NSArray+FLEX.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
@implementation FLEXSQLResult
@synthesize keyedRows = _keyedRows;
+ (instancetype)message:(NSString *)message {
return [[self alloc] initWithmessage:message columns:nil rows:nil];
return [[self alloc] initWithMessage:message columns:nil rows:nil];
}
+ (instancetype)error:(NSString *)message {
@@ -23,12 +23,12 @@
}
+ (instancetype)columns:(NSArray<NSString *> *)columnNames rows:(NSArray<NSArray<NSString *> *> *)rowData {
return [[self alloc] initWithmessage:nil columns:columnNames rows:rowData];
return [[self alloc] initWithMessage:nil columns:columnNames rows:rowData];
}
- (id)initWithmessage:(NSString *)message columns:(NSArray *)columns rows:(NSArray<NSArray *> *)rows {
- (instancetype)initWithMessage:(NSString *)message columns:(NSArray<NSString *> *)columns rows:(NSArray<NSArray<NSString *> *> *)rows {
NSParameterAssert(message || (columns && rows));
NSParameterAssert(columns.count == rows.firstObject.count);
NSParameterAssert(rows.count == 0 || columns.count == rows.firstObject.count);
self = [super init];
if (self) {
@@ -12,8 +12,8 @@
// which Flying Meat Inc. licenses this file to you.
#import <Foundation/Foundation.h>
#import "FLEXDatabaseManager.h"
#import "FLEXSQLResult.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLResult.h"
@interface FLEXSQLiteDatabaseManager : NSObject <FLEXDatabaseManager>
@@ -6,13 +6,16 @@
// Copyright © 2015 Peng Tao. All rights reserved.
//
#import "FLEXSQLiteDatabaseManager.h"
#import "FLEXManager.h"
#import "NSArray+FLEX.h"
#import "FLEXRuntimeConstants.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.h"
#import "Classes/Headers/FLEXManager.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/Runtime/Objc/FLEXRuntimeConstants.h"
#import <sqlite3.h>
static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
#define kQuery(name, str) static NSString * const QUERY_##name = str
kQuery(TABLENAMES, @"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name");
kQuery(ROWIDS, @"SELECT rowid FROM \"%@\" ORDER BY rowid ASC");
@interface FLEXSQLiteDatabaseManager ()
@property (nonatomic) sqlite3 *db;
@@ -107,7 +110,19 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
- (NSArray<NSString *> *)queryAllColumnsOfTable:(NSString *)tableName {
NSString *sql = [NSString stringWithFormat:@"PRAGMA table_info('%@')",tableName];
FLEXSQLResult *results = [self executeStatement:sql];
// https://github.com/FLEXTool/FLEX/issues/554
if (!results.keyedRows.count) {
sql = [NSString stringWithFormat:@"SELECT * FROM pragma_table_info('%@')", tableName];
results = [self executeStatement:sql];
// Fallback to empty query
if (!results.keyedRows.count) {
sql = [NSString stringWithFormat:@"SELECT * FROM \"%@\" where 0=1", tableName];
return [self executeStatement:sql].columns ?: @[];
}
}
return [results.keyedRows flex_mapped:^id(NSDictionary *column, NSUInteger idx) {
return column[@"name"];
}] ?: @[];
@@ -119,7 +134,7 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
}
- (NSArray<NSString *> *)queryRowIDsInTable:(NSString *)tableName {
NSString *command = [NSString stringWithFormat:@"SELECT rowid FROM \"%@\"", tableName];
NSString *command = [NSString stringWithFormat:QUERY_ROWIDS, tableName];
NSArray<NSArray<NSString *> *> *data = [self executeStatement:command].rows ?: @[];
return [data flex_mapped:^id(NSArray<NSString *> *obj, NSUInteger idx) {
@@ -146,7 +161,7 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
return self.lastResult;
}
// Grab columns
// Grab columns (columnCount will be 0 for insert/update/delete)
int columnCount = sqlite3_column_count(pstmt);
NSArray<NSString *> *columns = [NSArray flex_forEachUpTo:columnCount map:^id(NSUInteger i) {
return @(sqlite3_column_name(pstmt, (int)i));
@@ -164,8 +179,9 @@ static NSString * const QUERY_TABLENAMES = @"SELECT name FROM sqlite_master WHER
}
if (status == SQLITE_DONE) {
if (rows.count) {
// We selected some rows
// columnCount will be 0 for insert/update/delete
if (rows.count || columnCount > 0) {
// We executed a SELECT query
result = _lastResult = [FLEXSQLResult columns:columns rows:rows];
} else {
// We executed a query like INSERT, UDPATE, or DELETE
@@ -6,10 +6,10 @@
// Copyright © 2015 f. All rights reserved.
//
#import "FLEXTableColumnHeader.h"
#import "FLEXColor.h"
#import "UIFont+FLEX.h"
#import "FLEXUtility.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableColumnHeader.h"
#import "Classes/Utility/FLEXColor.h"
#import "Classes/Utility/Categories/UIFont+FLEX.h"
#import "Classes/Utility/FLEXUtility.h"
static const CGFloat kMargin = 5;
static const CGFloat kArrowWidth = 20;
@@ -7,19 +7,29 @@
//
#import <UIKit/UIKit.h>
#import "FLEXDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h"
NS_ASSUME_NONNULL_BEGIN
@interface FLEXTableContentViewController : UIViewController
/// Display a table with the given columns, rows, and name.
/// Display a mutable table with the given columns, rows, and name.
///
/// @param columnNames self explanatory.
/// @param rowData an array of rows, where each row is an array of column data.
/// @param rowIDs an array of stringy row IDs. Required for deleting rows.
/// @param tableName an optional name of the table being viewed, if any. Enables adding rows.
/// @param databaseManager an optional manager to allow modifying the table.
/// Required for deleting rows. Required for adding rows if \c tableName is supplied.
+ (instancetype)columns:(NSArray<NSString *> *)columnNames
rows:(NSArray<NSArray<NSString *> *> *)rowData
rowIDs:(nullable NSArray<NSString *> *)rowIds
rowIDs:(NSArray<NSString *> *)rowIDs
tableName:(NSString *)tableName
database:(nullable id<FLEXDatabaseManager>)databaseManager;
database:(id<FLEXDatabaseManager>)databaseManager;
/// Display an immutable table with the given columns and rows.
+ (instancetype)columns:(NSArray<NSString *> *)columnNames
rows:(NSArray<NSArray<NSString *> *> *)rowData;
@end
@@ -6,11 +6,12 @@
// Copyright © 2015 Peng Tao. All rights reserved.
//
#import "FLEXTableContentViewController.h"
#import "FLEXMultiColumnTableView.h"
#import "FLEXWebViewController.h"
#import "FLEXUtility.h"
#import "UIBarButtonItem+FLEX.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableRowDataViewController.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXMultiColumnTableView.h"
#import "Classes/GlobalStateExplorers/FLEXWebViewController.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
@interface FLEXTableContentViewController () <
FLEXMultiColumnTableViewDataSource, FLEXMultiColumnTableViewDelegate
@@ -21,6 +22,8 @@
@property (nonatomic, nullable) NSMutableArray<NSString *> *rowIDs;
@property (nonatomic, readonly, nullable) id<FLEXDatabaseManager> databaseManager;
@property (nonatomic, readonly) BOOL canRefresh;
@property (nonatomic) FLEXMultiColumnTableView *multiColumnView;
@end
@@ -28,16 +31,43 @@
+ (instancetype)columns:(NSArray<NSString *> *)columnNames
rows:(NSArray<NSArray<NSString *> *> *)rowData
rowIDs:(nullable NSArray<NSString *> *)rowIDs
rowIDs:(NSArray<NSString *> *)rowIDs
tableName:(NSString *)tableName
database:(nullable id<FLEXDatabaseManager>)databaseManager {
FLEXTableContentViewController *controller = [self new];
controller->_columns = columnNames.copy;
controller->_rows = rowData.mutableCopy;
controller->_rowIDs = rowIDs.mutableCopy;
controller->_tableName = tableName.copy;
controller->_databaseManager = databaseManager;
return controller;
database:(id<FLEXDatabaseManager>)databaseManager {
return [[self alloc]
initWithColumns:columnNames
rows:rowData
rowIDs:rowIDs
tableName:tableName
database:databaseManager
];
}
+ (instancetype)columns:(NSArray<NSString *> *)cols
rows:(NSArray<NSArray<NSString *> *> *)rowData {
return [[self alloc] initWithColumns:cols rows:rowData rowIDs:nil tableName:nil database:nil];
}
- (instancetype)initWithColumns:(NSArray<NSString *> *)columnNames
rows:(NSArray<NSArray<NSString *> *> *)rowData
rowIDs:(nullable NSArray<NSString *> *)rowIDs
tableName:(nullable NSString *)tableName
database:(nullable id<FLEXDatabaseManager>)databaseManager {
// Must supply all optional parameters as one, or none
BOOL all = rowIDs && tableName && databaseManager;
BOOL none = !rowIDs && !tableName && !databaseManager;
NSParameterAssert(all || none);
self = [super init];
if (self) {
self->_columns = columnNames.copy;
self->_rows = rowData.mutableCopy;
self->_rowIDs = rowIDs.mutableCopy;
self->_tableName = tableName.copy;
self->_databaseManager = databaseManager;
}
return self;
}
- (void)loadView {
@@ -49,7 +79,6 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.title = self.tableName;
self.edgesForExtendedLayout = UIRectEdgeNone;
[self.multiColumnView reloadData];
[self setupToolbarItems];
}
@@ -67,6 +96,10 @@
return _multiColumnView;
}
- (BOOL)canRefresh {
return self.databaseManager && self.tableName;
}
#pragma mark MultiColumnTableView DataSource
- (NSInteger)numberOfColumnsInTableView:(FLEXMultiColumnTableView *)tableView {
@@ -122,6 +155,10 @@
return [NSString stringWithFormat:@"%@:\n%@", self.columns[idx], field];
}];
NSArray<NSString *> *values = [self.rows[row] flex_mapped:^id(NSString *value, NSUInteger idx) {
return [NSString stringWithFormat:@"'%@'", value];
}];
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title([@"Row " stringByAppendingString:@(row).stringValue]);
NSString *message = [fields componentsJoinedByString:@"\n\n"];
@@ -129,10 +166,19 @@
make.button(@"Copy").handler(^(NSArray<NSString *> *strings) {
UIPasteboard.generalPasteboard.string = message;
});
make.button(@"Copy as CSV").handler(^(NSArray<NSString *> *strings) {
UIPasteboard.generalPasteboard.string = [values componentsJoinedByString:@", "];
});
make.button(@"Focus on Row").handler(^(NSArray<NSString *> *strings) {
UIViewController *focusedRow = [FLEXTableRowDataViewController
rows:[NSDictionary dictionaryWithObjects:self.rows[row] forKeys:self.columns]
];
[self.navigationController pushViewController:focusedRow animated:YES];
});
// Option to delete row
BOOL hasRowID = self.rows.count && row < self.rows.count;
if (hasRowID) {
if (hasRowID && self.canRefresh) {
make.button(@"Delete").destructiveStyle().handler(^(NSArray<NSString *> *strings) {
NSString *deleteRow = [NSString stringWithFormat:
@"DELETE FROM %@ WHERE rowid = %@",
@@ -142,9 +188,7 @@
[self executeStatementAndShowResult:deleteRow completion:^(BOOL success) {
// Remove deleted row and reload view
if (success) {
[self.rowIDs removeObjectAtIndex:row];
[self.rows removeObjectAtIndex:row];
[self.multiColumnView reloadData];
[self reloadTableDataFromDB];
}
}];
});
@@ -216,14 +260,24 @@
return;
}
UIBarButtonItem *trashButton = [FLEXBarButtonItemSystem(Trash, self, @selector(trashPressed))
flex_withTintColor:UIColor.redColor
UIBarButtonItem *trashButton = FLEXBarButtonItemSystem(Trash, self, @selector(trashPressed));
UIBarButtonItem *addButton = FLEXBarButtonItemSystem(Add, self, @selector(addPressed));
// Only allow adding rows or deleting rows if we have a table name
trashButton.enabled = self.canRefresh;
addButton.enabled = self.canRefresh;
self.toolbarItems = @[
UIBarButtonItem.flex_flexibleSpace,
addButton,
UIBarButtonItem.flex_flexibleSpace,
[trashButton flex_withTintColor:UIColor.redColor],
];
trashButton.enabled = self.databaseManager && self.rows.count;
self.toolbarItems = @[UIBarButtonItem.flex_flexibleSpace, trashButton];
}
- (void)trashPressed {
NSParameterAssert(self.tableName);
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Delete All Rows");
make.message(@"All rows in this table will be permanently deleted.\nDo you want to proceed?");
@@ -241,9 +295,35 @@
} showFrom:self];
}
- (void)addPressed {
NSParameterAssert(self.tableName);
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Add a New Row");
make.message(@"Comma separate values to use in an INSERT statement.\n\n");
make.message(@"INSERT INTO [table] VALUES (your_input)");
make.textField(@"5, 'John Smith', 14,...");
make.button(@"Insert").handler(^(NSArray<NSString *> *strings) {
NSString *statement = [NSString stringWithFormat:
@"INSERT INTO %@ VALUES (%@)", self.tableName, strings[0]
];
[self executeStatementAndShowResult:statement completion:^(BOOL success) {
if (success) {
[self reloadTableDataFromDB];
}
}];
});
make.button(@"Cancel").cancelStyle();
} showFrom:self];
}
#pragma mark - Helpers
- (void)executeStatementAndShowResult:(NSString *)statement completion:(void (^_Nullable)(BOOL success))completion {
- (void)executeStatementAndShowResult:(NSString *)statement
completion:(void (^_Nullable)(BOOL success))completion {
NSParameterAssert(self.databaseManager);
FLEXSQLResult *result = [self.databaseManager executeStatement:statement];
[FLEXAlert makeAlert:^(FLEXAlert *make) {
@@ -260,5 +340,20 @@
} showFrom:self];
}
- (void)reloadTableDataFromDB {
if (!self.canRefresh) {
return;
}
NSArray<NSArray *> *rows = [self.databaseManager queryAllDataInTable:self.tableName];
NSArray<NSString *> *rowIDs = nil;
if ([self.databaseManager respondsToSelector:@selector(queryRowIDsInTable:)]) {
rowIDs = [self.databaseManager queryRowIDsInTable:self.tableName];
}
self.rows = rows.mutableCopy;
self.rowIDs = rowIDs.mutableCopy;
[self.multiColumnView reloadData];
}
@end
@@ -6,7 +6,7 @@
// Copyright © 2015 f. All rights reserved.
//
#import "FLEXTableLeftCell.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableLeftCell.h"
@implementation FLEXTableLeftCell
@@ -6,7 +6,7 @@
// Copyright © 2015年 Peng Tao. All rights reserved.
//
#import "FLEXFilteringTableViewController.h"
#import "Classes/Headers/FLEXFilteringTableViewController.h"
@interface FLEXTableListViewController : FLEXFilteringTableViewController
@@ -6,15 +6,15 @@
// Copyright © 2015 Peng Tao. All rights reserved.
//
#import "FLEXTableListViewController.h"
#import "FLEXDatabaseManager.h"
#import "FLEXSQLiteDatabaseManager.h"
#import "FLEXRealmDatabaseManager.h"
#import "FLEXTableContentViewController.h"
#import "FLEXMutableListSection.h"
#import "NSArray+FLEX.h"
#import "FLEXAlert.h"
#import "FLEXMacros.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableListViewController.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXSQLiteDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXRealmDatabaseManager.h"
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableContentViewController.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Utility/Categories/NSArray+FLEX.h"
#import "Classes/Utility/FLEXAlert.h"
#import "Classes/Utility/FLEXMacros.h"
@interface FLEXTableListViewController ()
@property (nonatomic, readonly) id<FLEXDatabaseManager> dbm;
@@ -71,7 +71,10 @@
self.tables.selectionHandler = ^(FLEXTableListViewController *host, NSString *tableName) {
NSArray *rows = [host.dbm queryAllDataInTable:tableName];
NSArray *columns = [host.dbm queryAllColumnsOfTable:tableName];
NSArray *rowIDs = [host.dbm queryRowIDsInTable:tableName];
NSArray *rowIDs = nil;
if ([host.dbm respondsToSelector:@selector(queryRowIDsInTable:)]) {
rowIDs = [host.dbm queryRowIDsInTable:tableName];
}
UIViewController *resultsScreen = [FLEXTableContentViewController
columns:columns rows:rows rowIDs:rowIDs tableName:tableName database:host.dbm
];
@@ -90,19 +93,40 @@
}
- (void)queryButtonPressed {
[self showQueryInput:nil];
}
- (void)showQueryInput:(NSString *)prefillQuery {
FLEXSQLiteDatabaseManager *database = self.dbm;
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Execute an SQL query");
make.textField(nil);
make.configuredTextField(^(UITextField *textField) {
textField.text = prefillQuery;
});
make.button(@"Run").handler(^(NSArray<NSString *> *strings) {
FLEXSQLResult *result = [database executeStatement:strings[0]];
NSString *query = strings[0];
FLEXSQLResult *result = [database executeStatement:query];
if (result.message) {
[FLEXAlert showAlert:@"Message" message:result.message from:self];
// Allow users to edit their last query if it had an error
if ([result.message containsString:@"error"]) {
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Error").message(result.message);
make.button(@"Edit Query").preferred().handler(^(NSArray<NSString *> *_) {
// Show query editor again with our last input
[self showQueryInput:query];
});
make.button(@"Cancel").cancelStyle();
} showFrom:self];
} else {
[FLEXAlert showAlert:@"Message" message:result.message from:self];
}
} else {
UIViewController *resultsScreen = [FLEXTableContentViewController
columns:result.columns rows:result.rows rowIDs:nil tableName:@"" database:nil
columns:result.columns rows:result.rows
];
[self.navigationController pushViewController:resultsScreen animated:YES];
@@ -0,0 +1,14 @@
//
// FLEXTableRowDataViewController.h
// FLEX
//
// Created by Chaoshuai Lu on 7/8/20.
//
#import "Classes/Headers/FLEXFilteringTableViewController.h"
@interface FLEXTableRowDataViewController : FLEXFilteringTableViewController
+ (instancetype)rows:(NSDictionary<NSString *, id> *)rowData;
@end
@@ -0,0 +1,54 @@
//
// FLEXTableRowDataViewController.m
// FLEX
//
// Created by Chaoshuai Lu on 7/8/20.
//
#import "Classes/GlobalStateExplorers/DatabaseBrowser/FLEXTableRowDataViewController.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Utility/FLEXAlert.h"
@interface FLEXTableRowDataViewController ()
@property (nonatomic) NSDictionary<NSString *, NSString *> *rowsByColumn;
@end
@implementation FLEXTableRowDataViewController
#pragma mark - Initialization
+ (instancetype)rows:(NSDictionary<NSString *, id> *)rowData {
FLEXTableRowDataViewController *controller = [self new];
controller.rowsByColumn = rowData;
return controller;
}
#pragma mark - Overrides
- (NSArray<FLEXTableViewSection *> *)makeSections {
NSDictionary<NSString *, NSString *> *rowsByColumn = self.rowsByColumn;
FLEXMutableListSection<NSString *> *section = [FLEXMutableListSection list:self.rowsByColumn.allKeys
cellConfiguration:^(UITableViewCell *cell, NSString *column, NSInteger row) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = column;
cell.detailTextLabel.text = rowsByColumn[column].description;
} filterMatcher:^BOOL(NSString *filterText, NSString *column) {
return [column localizedCaseInsensitiveContainsString:filterText] ||
[rowsByColumn[column] localizedCaseInsensitiveContainsString:filterText];
}
];
section.selectionHandler = ^(UIViewController *host, NSString *column) {
UIPasteboard.generalPasteboard.string = rowsByColumn[column].description;
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Column Copied to Clipboard");
make.message(rowsByColumn[column].description);
make.button(@"Dismiss").cancelStyle();
} showFrom:host];
};
return @[section];
}
@end
@@ -0,0 +1,14 @@
//
// FLEXAPNSViewController.h
// FLEX
//
// Created by Tanner Bennett on 6/28/22.
// Copyright © 2022 FLEX Team. All rights reserved.
//
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
#import "Classes/Headers/FLEXFilteringTableViewController.h"
@interface FLEXAPNSViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
@end
@@ -0,0 +1,372 @@
//
// FLEXAPNSViewController.m
// FLEX
//
// Created by Tanner Bennett on 6/28/22.
// Copyright © 2022 FLEX Team. All rights reserved.
//
#import "Classes/GlobalStateExplorers/FLEXAPNSViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Headers/FLEXSingleRowSection.h"
#import "Classes/Utility/Categories/NSUserDefaults+FLEX.h"
#import "Classes/Utility/Categories/UIBarButtonItem+FLEX.h"
#import "Classes/Utility/Categories/NSDateFormatter+FLEX.h"
#import "Classes/Utility/FLEXResources.h"
#import "Classes/Utility/FLEXUtility.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Utility/Runtime/flex_fishhook.h"
#import <dlfcn.h>
#import <UserNotifications/UserNotifications.h>
#define orig(method, ...) if (orig_##method) { orig_##method(__VA_ARGS__); }
#define method_lookup(__selector, __cls, __return, ...) \
([__cls instancesRespondToSelector:__selector] ? \
(__return(*)(__VA_ARGS__))class_getMethodImplementation(__cls, __selector) : nil)
@interface FLEXAPNSViewController ()
@property (nonatomic, readonly, class) Class appDelegateClass;
@property (nonatomic, class) NSData *deviceToken;
@property (nonatomic, class) NSError *registrationError;
@property (nonatomic, readonly, class) NSString *deviceTokenString;
@property (nonatomic, readonly, class) NSMutableArray<NSDictionary *> *remoteNotifications;
@property (nonatomic, readonly, class) NSMutableArray<UNNotification *> *userNotifications API_AVAILABLE(ios(10.0));
@property (nonatomic) FLEXSingleRowSection *deviceToken;
@property (nonatomic) FLEXMutableListSection<NSDictionary *> *remoteNotifications;
@property (nonatomic) FLEXMutableListSection<UNNotification *> *userNotifications API_AVAILABLE(ios(10.0));
@end
@implementation FLEXAPNSViewController
#pragma mark Swizzles
/// Hook User Notifications related methods on the app delegate
/// and UNUserNotificationCenter delegate classes
+ (void)load { FLEX_EXIT_IF_NO_CTORS()
if (!NSUserDefaults.standardUserDefaults.flex_enableAPNSCapture) {
return;
}
////
// App Delegate //
////
// Hook UIApplication to intercept app delegate
Class uiapp = UIApplication.self;
auto orig_uiapp_setDelegate = (void(*)(id, SEL, id))class_getMethodImplementation(
uiapp, @selector(setDelegate:)
);
IMP uiapp_setDelegate = imp_implementationWithBlock(^(id _, id delegate) {
[self hookAppDelegateClass:[delegate class]];
orig_uiapp_setDelegate(_, @selector(setDelegate:), delegate);
});
class_replaceMethod(
uiapp,
@selector(setDelegate:),
uiapp_setDelegate,
"v@:@"
);
////
// UNUserNotificationCenter Delegate //
////
if (@available(iOS 10.0, *)) {
Class unusernc = UNUserNotificationCenter.self;
auto orig_unusernc_setDelegate = (void(*)(id, SEL, id))class_getMethodImplementation(
unusernc, @selector(setDelegate:)
);
IMP unusernc_setDelegate = imp_implementationWithBlock(^(id _, id delegate) {
[self hookUNUserNotificationCenterDelegateClass:[delegate class]];
orig_unusernc_setDelegate(_, @selector(setDelegate:), delegate);
});
class_replaceMethod(
unusernc,
@selector(setDelegate:),
unusernc_setDelegate,
"v@:@"
);
}
}
+ (void)hookAppDelegateClass:(Class)appDelegate {
// Abort if we already hooked something
if (_appDelegateClass) {
return;
}
_appDelegateClass = appDelegate;
// Better documentation for what's happening is in hookUNUserNotificationCenterDelegateClass: below
auto types_didRegisterForRemoteNotificationsWithDeviceToken = "v@:@@";
auto types_didFailToRegisterForRemoteNotificationsWithError = "v@:@@";
auto types_didReceiveRemoteNotification = "v@:@@@?";
auto sel_didRegisterForRemoteNotifications = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);
auto sel_didFailToRegisterForRemoteNotifs = @selector(application:didFailToRegisterForRemoteNotificationsWithError:);
auto sel_didReceiveRemoteNotification = @selector(application:didReceiveRemoteNotification:fetchCompletionHandler:);
auto orig_didRegisterForRemoteNotificationsWithDeviceToken = method_lookup(
sel_didRegisterForRemoteNotifications, appDelegate, void, id, SEL, id, id);
auto orig_didFailToRegisterForRemoteNotificationsWithError = method_lookup(
sel_didFailToRegisterForRemoteNotifs, appDelegate, void, id, SEL, id, id);
auto orig_didReceiveRemoteNotification = method_lookup(
sel_didReceiveRemoteNotification, appDelegate, void, id, SEL, id, id, id);
IMP didRegisterForRemoteNotificationsWithDeviceToken = imp_implementationWithBlock(^(id _, id app, NSData *token) {
self.deviceToken = token;
orig(didRegisterForRemoteNotificationsWithDeviceToken, _, nil, app, token);
});
IMP didFailToRegisterForRemoteNotificationsWithError = imp_implementationWithBlock(^(id _, id app, NSError *error) {
self.registrationError = error;
orig(didFailToRegisterForRemoteNotificationsWithError, _, nil, app, error);
});
IMP didReceiveRemoteNotification = imp_implementationWithBlock(^(id _, id app, NSDictionary *payload, id handler) {
// TODO: notify when new notifications are added
[self.remoteNotifications addObject:payload];
orig(didReceiveRemoteNotification, _, nil, app, payload, handler);
});
class_replaceMethod(
appDelegate,
sel_didRegisterForRemoteNotifications,
didRegisterForRemoteNotificationsWithDeviceToken,
types_didRegisterForRemoteNotificationsWithDeviceToken
);
class_replaceMethod(
appDelegate,
sel_didFailToRegisterForRemoteNotifs,
didFailToRegisterForRemoteNotificationsWithError,
types_didFailToRegisterForRemoteNotificationsWithError
);
class_replaceMethod(
appDelegate,
sel_didReceiveRemoteNotification,
didReceiveRemoteNotification,
types_didReceiveRemoteNotification
);
}
+ (void)hookUNUserNotificationCenterDelegateClass:(Class)delegate API_AVAILABLE(ios(10.0)) {
// Selector
auto sel_didReceiveNotification =
@selector(userNotificationCenter:willPresentNotification:withCompletionHandler:);
// Original implementation (or nil if unimplemented)
auto orig_didReceiveNotification = method_lookup(
sel_didReceiveNotification, delegate, void, id, SEL, id, id, id);
// Our hook (ignores self and other unneeded parameters)
IMP didReceiveNotification = imp_implementationWithBlock(^(id _, id __, UNNotification *notification, id ___) {
[self.userNotifications addObject:notification];
// This macro is a no-op if there is no original implementation
orig(didReceiveNotification, _, nil, __, notification, ___);
});
// Set the hook
class_replaceMethod(
delegate,
sel_didReceiveNotification,
didReceiveNotification,
"v@:@@@?"
);
}
#pragma mark Class Properties
static Class _appDelegateClass = nil;
+ (Class)appDelegateClass {
return _appDelegateClass;
}
static NSData *_apnsDeviceToken = nil;
+ (NSData *)deviceToken {
return _apnsDeviceToken;
}
+ (void)setDeviceToken:(NSData *)deviceToken {
_apnsDeviceToken = deviceToken;
}
+ (NSString *)deviceTokenString {
static NSString *_deviceTokenString = nil;
if (!_deviceTokenString && self.deviceToken) {
NSData *token = self.deviceToken;
NSUInteger capacity = token.length * 2;
NSMutableString *tokenString = [NSMutableString stringWithCapacity:capacity];
const UInt8 *tokenData = token.bytes;
for (NSUInteger idx = 0; idx < token.length; ++idx) {
[tokenString appendFormat:@"%02X", (int)tokenData[idx]];
}
_deviceTokenString = tokenString;
}
return _deviceTokenString;
}
static NSError *_apnsRegistrationError = nil;
+ (NSError *)registrationError {
return _apnsRegistrationError;
}
+ (void)setRegistrationError:(NSError *)error {
_apnsRegistrationError = error;
}
+ (NSMutableArray<NSDictionary *> *)userNotifications {
static NSMutableArray *_userNotifications = nil;
if (!_userNotifications) {
_userNotifications = [NSMutableArray new];
}
return _userNotifications;
}
+ (NSMutableArray<NSDictionary *> *)remoteNotifications {
static NSMutableArray *_remoteNotifications = nil;
if (!_remoteNotifications) {
_remoteNotifications = [NSMutableArray new];
}
return _remoteNotifications;
}
#pragma mark Instance stuff
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Push Notifications";
self.refreshControl = [UIRefreshControl new];
[self.refreshControl addTarget:self action:@selector(reloadData) forControlEvents:UIControlEventValueChanged];
[self addToolbarItems:@[
[UIBarButtonItem
flex_itemWithImage:FLEXResources.gearIcon
target:self
action:@selector(settingsButtonTapped)
],
]];
}
- (NSArray<FLEXTableViewSection *> *)makeSections {
self.deviceToken = [FLEXSingleRowSection title:@"APNS Device Token" reuse:nil cell:^(UITableViewCell *cell) {
NSString *tokenString = FLEXAPNSViewController.deviceTokenString;
if (tokenString) {
cell.textLabel.text = tokenString;
cell.textLabel.numberOfLines = 0;
}
else if (!NSUserDefaults.standardUserDefaults.flex_enableAPNSCapture) {
cell.textLabel.text = @"APNS capture disabled";
}
else {
cell.textLabel.text = @"Not yet registered";
}
}];
self.deviceToken.selectionAction = ^(UIViewController *host) {
UIPasteboard.generalPasteboard.string = FLEXAPNSViewController.deviceTokenString;
[FLEXAlert showQuickAlert:@"Copied to Clipboard" from:host];
};
// Remote Notifications //
self.remoteNotifications = [FLEXMutableListSection list:FLEXAPNSViewController.remoteNotifications
cellConfiguration:^(UITableViewCell *cell, NSDictionary *notif, NSInteger row) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// TODO: date received
cell.detailTextLabel.text = [FLEXRuntimeUtility summaryForObject:notif];
}
filterMatcher:^BOOL(NSString *filterText, NSDictionary *notif) {
return [notif.description localizedCaseInsensitiveContainsString:filterText];
}
];
self.remoteNotifications.customTitle = @"Remote Notifications";
self.remoteNotifications.selectionHandler = ^(UIViewController *host, NSDictionary *notif) {
[host.navigationController pushViewController:[
FLEXObjectExplorerFactory explorerViewControllerForObject:notif
] animated:YES];
};
// User Notifications //
if (@available(iOS 10.0, *)) {
self.userNotifications = [FLEXMutableListSection list:FLEXAPNSViewController.userNotifications
cellConfiguration:^(UITableViewCell *cell, UNNotification *notif, NSInteger row) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Subtitle is 'subtitle \n date'
NSString *dateString = [NSDateFormatter flex_stringFrom:notif.date format:FLEXDateFormatPreciseClock];
NSString *subtitle = notif.request.content.subtitle;
subtitle = subtitle ? [NSString stringWithFormat:@"%@\n%@", subtitle, dateString] : dateString;
cell.textLabel.text = notif.request.content.title;
cell.detailTextLabel.text = subtitle;
}
filterMatcher:^BOOL(NSString *filterText, NSDictionary *notif) {
return [notif.description localizedCaseInsensitiveContainsString:filterText];
}
];
self.userNotifications.customTitle = @"Push Notifications";
self.userNotifications.selectionHandler = ^(UIViewController *host, UNNotification *notif) {
[host.navigationController pushViewController:[
FLEXObjectExplorerFactory explorerViewControllerForObject:notif.request
] animated:YES];
};
return @[self.deviceToken, self.remoteNotifications, self.userNotifications];
}
else {
return @[self.deviceToken, self.remoteNotifications];
}
}
- (void)reloadData {
[self.refreshControl endRefreshing];
self.remoteNotifications.customTitle = [NSString stringWithFormat:
@"%@ notifications", @(self.remoteNotifications.filteredList.count)
];
[super reloadData];
}
- (void)settingsButtonTapped {
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
BOOL enabled = defaults.flex_enableAPNSCapture;
NSString *apnsToggle = enabled ? @"Disable Capture" : @"Enable Capture";
[FLEXAlert makeAlert:^(FLEXAlert *make) {
make.title(@"Settings")
.message(@"Enable or disable the capture of push notifications.\n\n")
.message(@"This will hook UIApplicationMain on launch until it is disabled, ")
.message(@"and swizzle some app delegate methods. Restart the app for changes to take effect.");
make.button(apnsToggle).destructiveStyle().handler(^(NSArray<NSString *> *strings) {
[defaults flex_toggleBoolForKey:kFLEXDefaultsAPNSCaptureEnabledKey];
});
make.button(@"Dismiss").cancelStyle();
} showFrom:self];
}
#pragma mark - FLEXGlobalsEntry
+ (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row {
return @"📌 Push Notifications";
}
+ (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row {
return [self new];
}
@end
@@ -6,7 +6,7 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXGlobalsEntry.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
@interface FLEXAddressExplorerCoordinator : NSObject <FLEXGlobalsEntry>
@@ -6,12 +6,12 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXAddressExplorerCoordinator.h"
#import "FLEXGlobalsViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXObjectExplorerViewController.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "Classes/GlobalStateExplorers/FLEXAddressExplorerCoordinator.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXObjectExplorerViewController.h"
#import "Classes/Utility/Runtime/FLEXRuntimeUtility.h"
#import "Classes/Utility/FLEXUtility.h"
@interface UITableViewController (FLEXAddressExploration)
- (void)deselectSelectedRow;
@@ -6,8 +6,8 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXGlobalsEntry.h"
#import "FLEXFilteringTableViewController.h"
#import "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
#import "Classes/Headers/FLEXFilteringTableViewController.h"
@interface FLEXCookiesViewController : FLEXFilteringTableViewController <FLEXGlobalsEntry>
@@ -6,10 +6,10 @@
// Copyright © 2020 FLEX Team. All rights reserved.
//
#import "FLEXCookiesViewController.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXMutableListSection.h"
#import "FLEXUtility.h"
#import "Classes/GlobalStateExplorers/FLEXCookiesViewController.h"
#import "Classes/Headers/FLEXObjectExplorerFactory.h"
#import "Classes/Headers/FLEXMutableListSection.h"
#import "Classes/Utility/FLEXUtility.h"
@interface FLEXCookiesViewController ()
@property (nonatomic, readonly) FLEXMutableListSection<NSHTTPCookie *> *cookies;
@@ -26,6 +26,14 @@
self.title = @"Cookies";
}
- (NSString *)headerTitle {
return self.cookies.title;
}
- (void)setHeaderTitle:(NSString *)headerTitle {
self.cookies.customTitle = headerTitle;
}
- (NSArray<FLEXTableViewSection *> *)makeSections {
NSSortDescriptor *nameSortDescriptor = [[NSSortDescriptor alloc]
initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)

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