From ff4dccb4fc6fb0839f2594c3cb585b476c3fc4ae Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 18:17:37 +0200 Subject: [PATCH 01/34] Add GitHub Actions build workflow --- .github/workflows/ci.yml | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..7338b3988b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: Build + +on: + push: + branches: + - main + - master + pull_request: + workflow_dispatch: + +jobs: + xcode: + name: Xcode build and tests + runs-on: macos-15 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Select Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Show build environment + run: | + xcodebuild -version + xcodebuild -showsdks + + - name: Build FLEX framework + run: | + xcodebuild build \ + -project FLEX.xcodeproj \ + -scheme FLEX \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + CODE_SIGNING_ALLOWED=NO + + - name: Run FLEX tests + run: | + xcodebuild test \ + -project FLEX.xcodeproj \ + -scheme FLEXTests \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 16' \ + CODE_SIGNING_ALLOWED=NO From 02dabcc188721f98fce4a00457fdc20f58c3d7fb Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 18:31:49 +0200 Subject: [PATCH 02/34] Expose file browser header for framework module --- FLEX.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FLEX.xcodeproj/project.pbxproj b/FLEX.xcodeproj/project.pbxproj index 4a779e9c87..b9031f8780 100644 --- a/FLEX.xcodeproj/project.pbxproj +++ b/FLEX.xcodeproj/project.pbxproj @@ -74,7 +74,7 @@ 3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */; }; 3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C949F1B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 3A4C95231B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A01B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m */; }; - 3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3A4C95251B5B21410088C3F2 /* FLEXFileBrowserController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserController.m */; }; 3A4C95261B5B21410088C3F2 /* FLEXGlobalsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A31B5B21410088C3F2 /* FLEXGlobalsViewController.h */; }; 3A4C95271B5B21410088C3F2 /* FLEXGlobalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A41B5B21410088C3F2 /* FLEXGlobalsViewController.m */; }; From 23544d30a49c2c635768e420c82aee230881d7ea Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 18:46:50 +0200 Subject: [PATCH 03/34] Upload FLEX framework artifact from CI --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7338b3988b..fd0c034d74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,9 @@ jobs: name: Xcode build and tests runs-on: macos-15 + env: + DERIVED_DATA_PATH: build/DerivedData + steps: - name: Check out repository uses: actions/checkout@v4 @@ -35,8 +38,16 @@ jobs: -configuration Debug \ -sdk iphonesimulator \ -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO + - name: Upload FLEX framework + uses: actions/upload-artifact@v4 + with: + name: FLEX-framework-debug-iphonesimulator + path: ${{ env.DERIVED_DATA_PATH }}/Build/Products/Debug-iphonesimulator/FLEX.framework + if-no-files-found: error + - name: Run FLEX tests run: | xcodebuild test \ @@ -45,4 +56,5 @@ jobs: -configuration Debug \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 16' \ + -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO From 16870925f1cb52bbd922487d6d33506b1ccff395 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:17:43 +0200 Subject: [PATCH 04/34] Add Theos tweak package workflow --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++++++ Tweak/FLEXLoader.plist | 7 +++++++ Tweak/Makefile | 15 +++++++++++++++ Tweak/Tweak.xm | 17 +++++++++++++++++ Tweak/control | 9 +++++++++ 5 files changed, 74 insertions(+) create mode 100644 Tweak/FLEXLoader.plist create mode 100644 Tweak/Makefile create mode 100644 Tweak/Tweak.xm create mode 100644 Tweak/control diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd0c034d74..f96ac67c32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,3 +58,29 @@ jobs: -destination 'platform=iOS Simulator,name=iPhone 16' \ -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO + + + tweak: + name: Theos tweak package + runs-on: macos-15 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install Theos + run: | + git clone --recursive https://github.com/theos/theos.git "$HOME/theos" + echo "THEOS=$HOME/theos" >> "$GITHUB_ENV" + + - name: Build FLEX Loader tweak package + working-directory: Tweak + run: | + make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless + + - name: Upload FLEX Loader tweak + uses: actions/upload-artifact@v4 + with: + name: FLEXLoader-tweak + path: Tweak/packages/*.deb + if-no-files-found: error diff --git a/Tweak/FLEXLoader.plist b/Tweak/FLEXLoader.plist new file mode 100644 index 0000000000..52fa316847 --- /dev/null +++ b/Tweak/FLEXLoader.plist @@ -0,0 +1,7 @@ +{ + Filter = { + Bundles = ( + "com.apple.UIKit" + ); + }; +} diff --git a/Tweak/Makefile b/Tweak/Makefile new file mode 100644 index 0000000000..2dc176d860 --- /dev/null +++ b/Tweak/Makefile @@ -0,0 +1,15 @@ +ARCHS = arm64 arm64e +TARGET := iphone:clang:latest:14.0 +INSTALL_TARGET_PROCESSES = SpringBoard + +include $(THEOS)/makefiles/common.mk + +TWEAK_NAME = FLEXLoader + +FLEXLoader_FILES = Tweak.xm $(shell find ../Classes -type f \( -name '*.m' -o -name '*.mm' -o -name '*.c' \)) +FLEXLoader_CFLAGS = -fobjc-arc $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) +FLEXLoader_CXXFLAGS = -std=gnu++11 +FLEXLoader_FRAMEWORKS = UIKit Foundation CoreGraphics ImageIO QuartzCore WebKit Security SceneKit +FLEXLoader_LIBRARIES = sqlite3 z c++ + +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Tweak/Tweak.xm b/Tweak/Tweak.xm new file mode 100644 index 0000000000..48ea0f9507 --- /dev/null +++ b/Tweak/Tweak.xm @@ -0,0 +1,17 @@ +#import +#import "FLEXManager.h" + +%ctor { + if (NSProcessInfo.processInfo.environment[@"FLEX_LOADER_DISABLED"]) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(__unused NSNotification *notification) { + [[FLEXManager sharedManager] showExplorer]; + }]; + }); +} diff --git a/Tweak/control b/Tweak/control new file mode 100644 index 0000000000..d1801f4d4e --- /dev/null +++ b/Tweak/control @@ -0,0 +1,9 @@ +Package: com.flextool.flexloader +Name: FLEX Loader +Version: 1.0.0 +Architecture: iphoneos-arm +Description: Loads FLEX automatically into UIKit applications. +Maintainer: FLEX Team +Author: FLEX Team +Section: Tweaks +Depends: mobilesubstrate From 8dad04c6f4261c31d818a70c74577473836e1b64 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:34:50 +0200 Subject: [PATCH 05/34] Allow FLEX deprecation warnings in tweak build --- Tweak/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tweak/Makefile b/Tweak/Makefile index 2dc176d860..e6e6301324 100644 --- a/Tweak/Makefile +++ b/Tweak/Makefile @@ -7,7 +7,7 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = FLEXLoader FLEXLoader_FILES = Tweak.xm $(shell find ../Classes -type f \( -name '*.m' -o -name '*.mm' -o -name '*.c' \)) -FLEXLoader_CFLAGS = -fobjc-arc $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) +FLEXLoader_CFLAGS = -fobjc-arc -Wno-error=deprecated-declarations -Wno-error=unsupported-availability-guard $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) FLEXLoader_CXXFLAGS = -std=gnu++11 FLEXLoader_FRAMEWORKS = UIKit Foundation CoreGraphics ImageIO QuartzCore WebKit Security SceneKit FLEXLoader_LIBRARIES = sqlite3 z c++ From 3bc15d88227036f7cd05ebf51c51fda14bcd522e Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:48:07 +0200 Subject: [PATCH 06/34] Relax warnings for Theos tweak build --- Tweak/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tweak/Makefile b/Tweak/Makefile index e6e6301324..53c15c70bf 100644 --- a/Tweak/Makefile +++ b/Tweak/Makefile @@ -7,7 +7,7 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = FLEXLoader FLEXLoader_FILES = Tweak.xm $(shell find ../Classes -type f \( -name '*.m' -o -name '*.mm' -o -name '*.c' \)) -FLEXLoader_CFLAGS = -fobjc-arc -Wno-error=deprecated-declarations -Wno-error=unsupported-availability-guard $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) +FLEXLoader_CFLAGS = -fobjc-arc -Wno-error -Wno-unused-but-set-variable -Wno-deprecated-declarations -Wno-unsupported-availability-guard $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) FLEXLoader_CXXFLAGS = -std=gnu++11 FLEXLoader_FRAMEWORKS = UIKit Foundation CoreGraphics ImageIO QuartzCore WebKit Security SceneKit FLEXLoader_LIBRARIES = sqlite3 z c++ From 7e69ec4881cf7fa1278187847c4552cd22968f71 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:56:27 +0200 Subject: [PATCH 07/34] Make CI independent of simulator devices --- .github/workflows/ci.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f96ac67c32..80e436b994 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,14 +48,14 @@ jobs: path: ${{ env.DERIVED_DATA_PATH }}/Build/Products/Debug-iphonesimulator/FLEX.framework if-no-files-found: error - - name: Run FLEX tests + - name: Build FLEX tests run: | - xcodebuild test \ + xcodebuild build-for-testing \ -project FLEX.xcodeproj \ -scheme FLEXTests \ -configuration Debug \ -sdk iphonesimulator \ - -destination 'platform=iOS Simulator,name=iPhone 16' \ + -destination 'generic/platform=iOS Simulator' \ -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO @@ -73,6 +73,10 @@ jobs: git clone --recursive https://github.com/theos/theos.git "$HOME/theos" echo "THEOS=$HOME/theos" >> "$GITHUB_ENV" + - name: Install tweak signing tools + run: | + brew install ldid + - name: Build FLEX Loader tweak package working-directory: Tweak run: | From 652a2334f7ccf0f49b11d6e2a93d602e9602da08 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:10:17 +0200 Subject: [PATCH 08/34] Upload injectable FLEX loader dylib --- .github/workflows/ci.yml | 12 ++++++++++++ Tweak/Tweak.xm | 27 ++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80e436b994..4b09f148c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,6 +82,18 @@ jobs: run: | make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless + - name: Collect injectable FLEX Loader dylib + run: | + mkdir -p Tweak/artifacts + cp Tweak/.theos/obj/FLEXLoader.dylib Tweak/artifacts/FLEXLoader.dylib + + - name: Upload injectable FLEX Loader dylib + uses: actions/upload-artifact@v4 + with: + name: FLEXLoader-dylib + path: Tweak/artifacts/FLEXLoader.dylib + if-no-files-found: error + - name: Upload FLEX Loader tweak uses: actions/upload-artifact@v4 with: diff --git a/Tweak/Tweak.xm b/Tweak/Tweak.xm index 48ea0f9507..2442a4ffd1 100644 --- a/Tweak/Tweak.xm +++ b/Tweak/Tweak.xm @@ -1,17 +1,42 @@ #import #import "FLEXManager.h" +static BOOL FLEXLoaderDidShowExplorer = NO; + +static void FLEXLoaderShowExplorer(void) { + if (FLEXLoaderDidShowExplorer) { + return; + } + + FLEXLoaderDidShowExplorer = YES; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [[FLEXManager sharedManager] showExplorer]; + }); +} + %ctor { if (NSProcessInfo.processInfo.environment[@"FLEX_LOADER_DISABLED"]) { return; } dispatch_async(dispatch_get_main_queue(), ^{ + UIApplication *application = UIApplication.sharedApplication; + if (application.applicationState != UIApplicationStateBackground) { + FLEXLoaderShowExplorer(); + } + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:NSOperationQueue.mainQueue usingBlock:^(__unused NSNotification *notification) { - [[FLEXManager sharedManager] showExplorer]; + FLEXLoaderShowExplorer(); + }]; + + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(__unused NSNotification *notification) { + FLEXLoaderShowExplorer(); }]; }); } From d40f46b732b38a0ccff36442af73abbcb52066cb Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 22:05:48 +0200 Subject: [PATCH 09/34] Use Node 24 compatible GitHub Actions --- .github/workflows/ci.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b09f148c8..93b62b55a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,12 +18,7 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 - - - name: Select Xcode - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: latest-stable + uses: actions/checkout@v5 - name: Show build environment run: | @@ -42,7 +37,7 @@ jobs: CODE_SIGNING_ALLOWED=NO - name: Upload FLEX framework - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: FLEX-framework-debug-iphonesimulator path: ${{ env.DERIVED_DATA_PATH }}/Build/Products/Debug-iphonesimulator/FLEX.framework @@ -66,7 +61,7 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Theos run: | @@ -88,14 +83,14 @@ jobs: cp Tweak/.theos/obj/FLEXLoader.dylib Tweak/artifacts/FLEXLoader.dylib - name: Upload injectable FLEX Loader dylib - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: FLEXLoader-dylib path: Tweak/artifacts/FLEXLoader.dylib if-no-files-found: error - name: Upload FLEX Loader tweak - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: FLEXLoader-tweak path: Tweak/packages/*.deb From 2bea8b2f97b2396d7e08a82be3c4ce0ec912b7d0 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:50:11 +0200 Subject: [PATCH 10/34] Guard heap object class names --- .../GlobalStateExplorers/FLEXLiveObjectsController.m | 11 ++++++++++- Classes/Utility/FLEXHeapEnumerator.m | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m index fce0f8c6e4..881d9acd60 100644 --- a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m +++ b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m @@ -66,6 +66,10 @@ - (void)reloadTableData { // Enumerate all objects on the heap to build the counts of instances for each class. [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) { + if (!actualClass) { + return; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)actualClass); instanceCount++; CFDictionarySetValue(mutableCountsForClasses, (__bridge const void *)actualClass, (const void *)instanceCount); @@ -76,8 +80,13 @@ - (void)reloadTableData { NSMutableDictionary *mutableSizesForClassNames = [NSMutableDictionary new]; for (unsigned int i = 0; i < classCount; i++) { Class class = classes[i]; + const char *classNameCString = class_getName(class); + if (!classNameCString) { + continue; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class)); - NSString *className = @(class_getName(class)); + NSString *className = @(classNameCString); if (instanceCount > 0) { [mutableCountsForClassNames setObject:@(instanceCount) forKey:className]; } diff --git a/Classes/Utility/FLEXHeapEnumerator.m b/Classes/Utility/FLEXHeapEnumerator.m index 5707160656..910c447a25 100644 --- a/Classes/Utility/FLEXHeapEnumerator.m +++ b/Classes/Utility/FLEXHeapEnumerator.m @@ -208,6 +208,10 @@ + (FLEXHeapSnapshot *)generateHeapSnapshot { // Enumerate all objects on the heap to build the counts of instances for each class [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class cls) { + if (!cls) { + return; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue( mutableCountsForClasses, (__bridge const void *)cls ); @@ -222,8 +226,13 @@ + (FLEXHeapSnapshot *)generateHeapSnapshot { NSMutableDictionary *sizesForClassNames = [NSMutableDictionary new]; for (unsigned int i = 0; i < classCount; i++) { Class class = classes[i]; + const char *classNameCString = class_getName(class); + if (!classNameCString) { + continue; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class)); - NSString *className = @(class_getName(class)); + NSString *className = @(classNameCString); if (instanceCount > 0) { countsForClassNames[className] = @(instanceCount); From e0176887b6a565b33f6c698d287e6d656109afe1 Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:59:36 +0200 Subject: [PATCH 11/34] Improve toolbar contrast over app content --- Classes/Toolbar/FLEXExplorerToolbar.m | 9 ++-- Classes/Toolbar/FLEXExplorerToolbarItem.m | 6 +-- Classes/Utility/FLEXColor.h | 5 ++ Classes/Utility/FLEXColor.m | 60 ++++++++++++++++++++--- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/Classes/Toolbar/FLEXExplorerToolbar.m b/Classes/Toolbar/FLEXExplorerToolbar.m index b9050a6e0f..42579b780b 100644 --- a/Classes/Toolbar/FLEXExplorerToolbar.m +++ b/Classes/Toolbar/FLEXExplorerToolbar.m @@ -52,11 +52,12 @@ - (id)initWithFrame:(CGRect)frame { self.backgroundGlassView = [[UIVisualEffectView alloc] initWithEffect:glassEffect]; self.backgroundGlassView.clipsToBounds = YES; self.backgroundGlassView.layer.cornerRadius = 16; + self.backgroundGlassView.backgroundColor = FLEXColor.toolbarBackgroundColor; [self addSubview:self.backgroundGlassView]; self.backgroundView = self.backgroundGlassView; } else { self.backgroundView = [UIView new]; - self.backgroundView.backgroundColor = [FLEXColor secondaryBackgroundColorWithAlpha:0.95]; + self.backgroundView.backgroundColor = FLEXColor.toolbarBackgroundColor; [self addSubview:self.backgroundView]; } @@ -64,7 +65,7 @@ - (id)initWithFrame:(CGRect)frame { self.dragHandle = [UIView new]; self.dragHandle.backgroundColor = UIColor.clearColor; self.dragHandleImageView = [[UIImageView alloc] initWithImage:FLEXResources.dragHandle]; - self.dragHandleImageView.tintColor = [FLEXColor.iconColor colorWithAlphaComponent:0.666]; + self.dragHandleImageView.tintColor = FLEXColor.toolbarDragHandleColor; [self.dragHandle addSubview:self.dragHandleImageView]; [self addSubview:self.dragHandle]; @@ -93,12 +94,13 @@ - (id)initWithFrame:(CGRect)frame { self.descriptionGlassView = [[UIVisualEffectView alloc] initWithEffect:descGlassEffect]; self.descriptionGlassView.clipsToBounds = YES; self.descriptionGlassView.layer.cornerRadius = [[self class] descriptionContainerHeight] / 2.0; + self.descriptionGlassView.backgroundColor = FLEXColor.toolbarDescriptionBackgroundColor; self.descriptionGlassView.hidden = YES; [self addSubview:self.descriptionGlassView]; self.selectedViewDescriptionContainer = self.descriptionGlassView; } else { self.selectedViewDescriptionContainer = [UIView new]; - self.selectedViewDescriptionContainer.backgroundColor = [FLEXColor tertiaryBackgroundColorWithAlpha:0.95]; + self.selectedViewDescriptionContainer.backgroundColor = FLEXColor.toolbarDescriptionBackgroundColor; self.selectedViewDescriptionContainer.hidden = YES; [self addSubview:self.selectedViewDescriptionContainer]; } @@ -117,6 +119,7 @@ - (id)initWithFrame:(CGRect)frame { self.selectedViewDescriptionLabel = [UILabel new]; self.selectedViewDescriptionLabel.backgroundColor = UIColor.clearColor; + self.selectedViewDescriptionLabel.textColor = FLEXColor.toolbarTextColor; self.selectedViewDescriptionLabel.font = [[self class] descriptionLabelFont]; [self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewDescriptionLabel]; diff --git a/Classes/Toolbar/FLEXExplorerToolbarItem.m b/Classes/Toolbar/FLEXExplorerToolbarItem.m index b704d283a4..03f4d8d812 100644 --- a/Classes/Toolbar/FLEXExplorerToolbarItem.m +++ b/Classes/Toolbar/FLEXExplorerToolbarItem.m @@ -39,13 +39,13 @@ + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image sibling:( toolbarItem.sibling = backupItem; toolbarItem.title = title; toolbarItem.image = image; - toolbarItem.tintColor = FLEXColor.iconColor; + toolbarItem.tintColor = FLEXColor.toolbarTextColor; toolbarItem.backgroundColor = self.defaultBackgroundColor; toolbarItem.titleLabel.font = [UIFont systemFontOfSize:12.0]; [toolbarItem setTitle:title forState:UIControlStateNormal]; [toolbarItem setImage:image forState:UIControlStateNormal]; - [toolbarItem setTitleColor:FLEXColor.primaryTextColor forState:UIControlStateNormal]; - [toolbarItem setTitleColor:FLEXColor.deemphasizedTextColor forState:UIControlStateDisabled]; + [toolbarItem setTitleColor:FLEXColor.toolbarTextColor forState:UIControlStateNormal]; + [toolbarItem setTitleColor:FLEXColor.toolbarDisabledTextColor forState:UIControlStateDisabled]; return toolbarItem; } diff --git a/Classes/Utility/FLEXColor.h b/Classes/Utility/FLEXColor.h index e472ba4ba1..1d19d392ec 100644 --- a/Classes/Utility/FLEXColor.h +++ b/Classes/Utility/FLEXColor.h @@ -37,6 +37,11 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly, class) UIColor *scrollViewBackgroundColor; @property (readonly, class) UIColor *iconColor; @property (readonly, class) UIColor *borderColor; +@property (readonly, class) UIColor *toolbarBackgroundColor; +@property (readonly, class) UIColor *toolbarDescriptionBackgroundColor; +@property (readonly, class) UIColor *toolbarTextColor; +@property (readonly, class) UIColor *toolbarDisabledTextColor; +@property (readonly, class) UIColor *toolbarDragHandleColor; @property (readonly, class) UIColor *toolbarItemHighlightedColor; @property (readonly, class) UIColor *toolbarItemSelectedColor; @property (readonly, class) UIColor *hairlineColor; diff --git a/Classes/Utility/FLEXColor.m b/Classes/Utility/FLEXColor.m index 95a995bfcd..a30ba58eea 100644 --- a/Classes/Utility/FLEXColor.m +++ b/Classes/Utility/FLEXColor.m @@ -111,18 +111,62 @@ + (UIColor *)borderColor { return [self primaryBackgroundColor]; } ++ (UIColor *)toolbarBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [UIColor colorWithWhite:1.0 alpha:0.82]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.78]; + }]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.78]; +} + ++ (UIColor *)toolbarDescriptionBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [UIColor colorWithWhite:1.0 alpha:0.90]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.86]; + }]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.86]; +} + ++ (UIColor *)toolbarTextColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return UIColor.blackColor; + } + + return UIColor.whiteColor; + }]; + } + + return UIColor.whiteColor; +} + ++ (UIColor *)toolbarDisabledTextColor { + return [[self toolbarTextColor] colorWithAlphaComponent:0.45]; +} + ++ (UIColor *)toolbarDragHandleColor { + return [[self toolbarTextColor] colorWithAlphaComponent:0.72]; +} + + (UIColor *)toolbarItemHighlightedColor { - return FLEXDynamicColor( - quaternaryLabelColor, - colorWithHue:2.0/3.0 saturation:0.1 brightness:0.25 alpha:0.6 - ); + return [[self toolbarTextColor] colorWithAlphaComponent:0.18]; } + (UIColor *)toolbarItemSelectedColor { - return FLEXDynamicColor( - secondaryLabelColor, - colorWithHue:2.0/3.0 saturation:0.1 brightness:0.25 alpha:0.68 - ); + return [[self toolbarTextColor] colorWithAlphaComponent:0.28]; } + (UIColor *)hairlineColor { From 59b2e8514bc267411b56409094344d196a7619d3 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 00:51:12 +0200 Subject: [PATCH 12/34] AI-based recommendation engine for FLEX, providing suggestions and insights for object exploration and debugging in iOS applications. This feature leverages machine learning algorithms to analyze the current state of the application and recommend relevant actions or objects to inspect, enhancing the developer's debugging experience. --- Classes/ObjectExplorers/FLEXRecommendation.h | 25 +++ Classes/ObjectExplorers/FLEXRecommendation.m | 25 +++ .../FLEXRecommendationEngine.h | 31 +++ .../FLEXRecommendationEngine.m | 184 ++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 Classes/ObjectExplorers/FLEXRecommendation.h create mode 100644 Classes/ObjectExplorers/FLEXRecommendation.m create mode 100644 Classes/ObjectExplorers/FLEXRecommendationEngine.h create mode 100644 Classes/ObjectExplorers/FLEXRecommendationEngine.m diff --git a/Classes/ObjectExplorers/FLEXRecommendation.h b/Classes/ObjectExplorers/FLEXRecommendation.h new file mode 100644 index 0000000000..e5f89825fd --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendation.h @@ -0,0 +1,25 @@ +// +// FLEXRecommendation.h +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXRecommendation : NSObject + +@property (nonatomic, copy) NSString *title; +@property (nonatomic, copy) NSString *subtitle; +@property (nonatomic, strong) id relevantObject; +@property (nonatomic, copy) NSString *action; ++ (instancetype)createWithTitle:(NSString *)title + subtitle:(NSString *)subtitle + relevantObject:(id)object + action:(NSString *)action; +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendation.m b/Classes/ObjectExplorers/FLEXRecommendation.m new file mode 100644 index 0000000000..e0aa054f35 --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendation.m @@ -0,0 +1,25 @@ +// +// FLEXRecommendation.m +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRecommendation.h" + +@implementation FLEXRecommendation + ++ (instancetype)createWithTitle:(NSString *)title + subtitle:(NSString *)subtitle + relevantObject:(id)object + action:(NSString *)action { + FLEXRecommendation *rec = [[FLEXRecommendation alloc] init]; + rec.title = title; + rec.subtitle = subtitle; + rec.relevantObject = object; + rec.action = action; + return rec; +} + +@end \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.h b/Classes/ObjectExplorers/FLEXRecommendationEngine.h new file mode 100644 index 0000000000..0e9a715051 --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.h @@ -0,0 +1,31 @@ +// +// FLEXRecommendationEngine.h +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXObjectExplorer.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXRecommendationEngine : NSObject + +/// Generates recommendations for a specific object +/// - parameter object: The object being explored +/// - parameter context: Optional context about the current usage scenario +/// - Returns: An array of FLEXRecommendation objects +- (NSArray *)suggestionsForObject:(id)object + context:(nullable id)context; + +/// Adds recommendation sections to the Object Explorer UI +/// - parameter customSections: Mutable array of sections to prepend to +/// - parameter forObject: The object being explored ++ (void)addRecommendationsToSections:(NSMutableArray *)customSections + forObject:(id)object; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m new file mode 100644 index 0000000000..034aa76678 --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -0,0 +1,184 @@ +// +// FLEXRecommendationEngine.m +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRecommendationEngine.h" +#import "FLEXRecommendation.h" +#import "FLEXObjectExplorer.h" +#import "FLEXUtility.h" +#import "FLEXMultilineTableViewCell.h" +#import "FLEXSingleRowSection.h" +#import "FLEXSingleRowSection+FLEX.h" + +// Helper functions for parsing JSON recommendations +__attribute__((weak)) +- (NSString *)parseRecommendationsJSON:(NSString *)json + forObject:(id)object { + // This method is kept simple to support basic JSON parsing for recommendations + // Advanced logic can be added for complex scenarios or ML-based suggestions. + return json; +} + +- (NSArray *)suggestionsForObject:(id)object + context:(nullable id)context { + + // Contextual classification based on object type + NSString *objectType = [FLEXUtility safeClassNameForObject:object]; + NSUInteger recommendationCount = 3; + + // Generate type-specific recommendations + if ([objectType isEqualToString:@"EXISTS_FLEXUIButton"]) { + return [self generateUIButtonRecommendations:object type:objectType]; + } else if ([objectType isEqualToString:@"UIView"]) { + return [self generateUIViewRecommendations:object type:objectType]; + } else if ([objectType isEqualToString:@"UIViewController"]) { + return [self generateUIViewControllerRecommendations:object type:objectType]; + } else { + return [self generateGenericRecommendations:object type:objectType count:recommendationCount]; + } +} + +- (NSArray *)generateUIButtonRecommendations:(id)object + type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + // Recommend: Constrained size from current layout constraints + FLEXRecommendation *size = [FLEXRecommendation createWithTitle:@"Constrained Size" + subtitle:@"Apply layout constraints to tight/layout the button" + relevantObject:object + action:@""]; + + // Recommend: Target handler registration for user actions + FLEXRecommendation *handler = [FLEXRecommendation createWithTitle:@"Touch Handler" + subtitle:@"Add target-action for user interactions" + relevantObject:object + action:@""]; + + // Recommend: State configuration for visual feedback + FLEXRecommendation *state = [FLEXRecommendation createWithTitle:@"Button State" + subtitle:@"Configure normal/highlighted/disabled states" + relevantObject:object + action:@""]; + + [recommendations addObjects:@[size, handler, state]]; + return recommendations; +} + +- (NSArray *)generateUIViewRecommendations:(id)object + type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + // Recommend: Auto Layout setup + FLEXRecommendation *autolayout = [FLEXRecommendation createWithTitle:@"Auto Layout" + subtitle:@"Configure frame/constraints with priority" + relevantObject:object + action:@""]; + + // Recommend: Background customization + FLEXRecommendation *background = [FLEXRecommendation createWithTitle:@"Background" + subtitle:@"Set background color/image or alpha" + relevantObject:object + action:@""]; + + // Recommend: Corner radius/bezel style + FLEXRecommendation *corners = [FLEXRecommendation createWithTitle:@"Corners" + subtitle:@"Add corner radius/border for modern appearance" + relevantObject:object + action:@""]; + + [recommendations addObjects:@[autolayout, background, corners]]; + return recommendations; +} + +- (NSArray *)generateUIViewControllerRecommendations:(id)object + type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + // Recommend: Navigation setup + FLEXRecommendation *navigation = [FLEXRecommendation createWithTitle:@"Navigation" + subtitle:@"Configure navigation bar/hierarchy stack" + relevantObject:object + action:@""]; + + // Recommend: Outlet connections + FLEXRecommendation *outlets = [FLEXRecommendation createWithTitle:@"Outlets" + subtitle:@"Connect IB outlets for easier inspection" + relevantObject:object + action:@""]; + + // Recommend: Lifecycle hooks + FLEXRecommendation *lifecycle = [FLEXRecommendation createWithTitle:@"Lifecycle" + subtitle:@"Implement viewDidLoad/didAppear handling" + relevantObject:object + action:@""]; + + [recommendations addObjects:@[navigation, outlets, lifecycle]]; + return recommendations; +} + +- (NSArray *)generateGenericRecommendations:(id)object + type:(NSString *)type + count:(NSUInteger)maxCount { + NSMutableArray *recommendations = [NSMutableArray array]; + + // Recommend: Method introspection + FLEXRecommendation *method = [FLEXRecommendation createWithTitle:@"Methods" + subtitle:@"Explore instance/class methods for this object" + relevantObject:object + action:@""]; + + // Recommend: Property inspection + FLEXRecommendation *properties = [FLEXRecommendation createWithTitle:@"Properties" + subtitle:@"Review properties/ivars for modification" + relevantObject:object + action:@""]; + + // Recommend: Reference exploration + FLEXRecommendation *references = [FLEXRecommendation createWithTitle:@"References" + subtitle:@"Find live objects referencing this object" + relevantObject:object + action:@""]; + + [recommendations addObjects:@[method, properties, references]]; + + // Limit based on count + if (recommendations.count > maxCount) { + return [recommendations subarrayWithRange:NSMakeRange(0, maxCount)]; + } + return recommendations; +} + +void AddRecommendationsToSections:(NSMutableArray *)customSections + forObject:(id)object { + // Create recommendation engine and generate sections + FLEXRecommendationEngine *engine = [[FLEXRecommendationEngine alloc] init]; + NSArray *recommendations = [engine suggestionsForObject:object context:nil]; + + // Create recommendation sections and add to array + for (FLEXRecommendation *rec in recommendations) { + FLEXSingleRowSection *section = [FLEXSingleRowSection + title:rec.title + reuse:kFLEXDefaultCell + cell:^(FLEXTableViewCell *cell) { + cell.titleLabel.text = rec.title; + cell.titleLabel.font = UIFont.flex_defaultTableCellFont; + } + ]; + + section.selectionAction = ^(__kindof UIViewController *host) { + // Dispatch to recommendation-specific handler + if ([rec.action isEqualToString:@"BUTTON_SETUP"]) { + // Direct to existing method setup handling + [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; + } + }; + + [customSections addObject:section]; + } +} + +NS_ASSUME_NONNULL_END \ No newline at end of file From bc16fa387cf9f73e6421f3f94f71d932e96b412d Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 00:54:52 +0200 Subject: [PATCH 13/34] workflow updated --- .github/workflows/ci.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93b62b55a3..605de6e3e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,6 @@ jobs: run: | xcodebuild -version xcodebuild -showsdks - - name: Build FLEX framework run: | xcodebuild build \ @@ -35,7 +34,6 @@ jobs: -destination 'generic/platform=iOS Simulator' \ -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO - - name: Upload FLEX framework uses: actions/upload-artifact@v6 with: @@ -53,8 +51,6 @@ jobs: -destination 'generic/platform=iOS Simulator' \ -derivedDataPath "$DERIVED_DATA_PATH" \ CODE_SIGNING_ALLOWED=NO - - tweak: name: Theos tweak package runs-on: macos-15 @@ -67,21 +63,17 @@ jobs: run: | git clone --recursive https://github.com/theos/theos.git "$HOME/theos" echo "THEOS=$HOME/theos" >> "$GITHUB_ENV" - - name: Install tweak signing tools run: | brew install ldid - - name: Build FLEX Loader tweak package working-directory: Tweak run: | make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless - - name: Collect injectable FLEX Loader dylib run: | mkdir -p Tweak/artifacts cp Tweak/.theos/obj/FLEXLoader.dylib Tweak/artifacts/FLEXLoader.dylib - - name: Upload injectable FLEX Loader dylib uses: actions/upload-artifact@v6 with: @@ -94,4 +86,4 @@ jobs: with: name: FLEXLoader-tweak path: Tweak/packages/*.deb - if-no-files-found: error + if-no-files-found: error \ No newline at end of file From 69c1e3fe70355c1049d0f334d2a871caa81df64d Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 00:56:42 +0200 Subject: [PATCH 14/34] workflow: file renamed --- .github/workflows/{ci.yml => FLEX.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{ci.yml => FLEX.yml} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/FLEX.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/FLEX.yml From fc655c51a52b6a4e9ec90057a06bafbc0b906428 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 01:03:29 +0200 Subject: [PATCH 15/34] Falscher Import-Pfad korrigiert --- Classes/ObjectExplorers/FLEXRecommendationEngine.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.h b/Classes/ObjectExplorers/FLEXRecommendationEngine.h index 0e9a715051..536c1c40c7 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.h +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.h @@ -9,6 +9,9 @@ #import #import "FLEXObjectExplorer.h" +// Forward declaration to resolve unknown type name +@class FLEXRecommendation; + NS_ASSUME_NONNULL_BEGIN @interface FLEXRecommendationEngine : NSObject From 4a2aa4b98df3fde2957b0bade1e09fa565ecf7dc Mon Sep 17 00:00:00 2001 From: ChrisGleich1AufsMaul <49039734+ChrisGleich1AufsMaul@users.noreply.github.com> Date: Fri, 26 Jun 2026 01:05:21 +0200 Subject: [PATCH 16/34] Update FLEX.yml --- .github/workflows/FLEX.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/FLEX.yml b/.github/workflows/FLEX.yml index 605de6e3e7..7bae5a269c 100644 --- a/.github/workflows/FLEX.yml +++ b/.github/workflows/FLEX.yml @@ -5,6 +5,7 @@ on: branches: - main - master + - codex/flex-mit-github-actions-kompilieren pull_request: workflow_dispatch: @@ -86,4 +87,4 @@ jobs: with: name: FLEXLoader-tweak path: Tweak/packages/*.deb - if-no-files-found: error \ No newline at end of file + if-no-files-found: error From 6a8e3017aa7e2edfa939e1d064077dd4b99a7b01 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 01:12:10 +0200 Subject: [PATCH 17/34] fix: Build error in GitHub Actions workflow for FLEXRecommendation and FLEXRecommendationEngine --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 034aa76678..f489a58ff3 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -12,7 +12,6 @@ #import "FLEXUtility.h" #import "FLEXMultilineTableViewCell.h" #import "FLEXSingleRowSection.h" -#import "FLEXSingleRowSection+FLEX.h" // Helper functions for parsing JSON recommendations __attribute__((weak)) From 3c4fad004b3bb1c4f93ecfd9401a6f22be92cdb6 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 01:25:02 +0200 Subject: [PATCH 18/34] fix: error: missing context for method declaration --- .../FLEXRecommendationEngine.m | 184 +++++++----------- 1 file changed, 70 insertions(+), 114 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index f489a58ff3..5886171466 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -10,174 +10,130 @@ #import "FLEXRecommendation.h" #import "FLEXObjectExplorer.h" #import "FLEXUtility.h" -#import "FLEXMultilineTableViewCell.h" #import "FLEXSingleRowSection.h" -// Helper functions for parsing JSON recommendations -__attribute__((weak)) -- (NSString *)parseRecommendationsJSON:(NSString *)json - forObject:(id)object { - // This method is kept simple to support basic JSON parsing for recommendations - // Advanced logic can be added for complex scenarios or ML-based suggestions. - return json; -} +NS_ASSUME_NONNULL_BEGIN -- (NSArray *)suggestionsForObject:(id)object - context:(nullable id)context { +@implementation FLEXRecommendationEngine - // Contextual classification based on object type +- (NSArray *)suggestionsForObject:(id)object context:(nullable id)context { NSString *objectType = [FLEXUtility safeClassNameForObject:object]; - NSUInteger recommendationCount = 3; + NSUInteger maxCount = 3; - // Generate type-specific recommendations - if ([objectType isEqualToString:@"EXISTS_FLEXUIButton"]) { + if ([objectType isEqualToString:@"UIButton"]) { return [self generateUIButtonRecommendations:object type:objectType]; } else if ([objectType isEqualToString:@"UIView"]) { return [self generateUIViewRecommendations:object type:objectType]; } else if ([objectType isEqualToString:@"UIViewController"]) { return [self generateUIViewControllerRecommendations:object type:objectType]; } else { - return [self generateGenericRecommendations:object type:objectType count:recommendationCount]; + return [self generateGenericRecommendations:object type:objectType count:maxCount]; } } -- (NSArray *)generateUIButtonRecommendations:(id)object - type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; +- (NSArray *)generateUIButtonRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; - // Recommend: Constrained size from current layout constraints FLEXRecommendation *size = [FLEXRecommendation createWithTitle:@"Constrained Size" - subtitle:@"Apply layout constraints to tight/layout the button" - relevantObject:object - action:@""]; - - // Recommend: Target handler registration for user actions + subtitle:@"Add Auto‑Layout constraints to define the button size" + relevantObject:object + action:@"SIZE_SETUP"]; FLEXRecommendation *handler = [FLEXRecommendation createWithTitle:@"Touch Handler" - subtitle:@"Add target-action for user interactions" - relevantObject:object - action:@""]; - - // Recommend: State configuration for visual feedback + subtitle:@"Add target‑action for user interaction" + relevantObject:object + action:@"HANDLER_SETUP"]; FLEXRecommendation *state = [FLEXRecommendation createWithTitle:@"Button State" - subtitle:@"Configure normal/highlighted/disabled states" - relevantObject:object - action:@""]; + subtitle:@"Configure normal / highlighted / disabled states" + relevantObject:object + action:@"STATE_SETUP"]; - [recommendations addObjects:@[size, handler, state]]; + [recommendations addObjectsFromArray:@[size, handler, state]]; return recommendations; } -- (NSArray *)generateUIViewRecommendations:(id)object - type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; - - // Recommend: Auto Layout setup - FLEXRecommendation *autolayout = [FLEXRecommendation createWithTitle:@"Auto Layout" - subtitle:@"Configure frame/constraints with priority" - relevantObject:object - action:@""]; +- (NSArray *)generateUIViewRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; - // Recommend: Background customization + FLEXRecommendation *autoLayout = [FLEXRecommendation createWithTitle:@"Auto Layout" + subtitle:@"Add constraints or adjust frames" + relevantObject:object + action:@"AUTOLAYOUT_SETUP"]; FLEXRecommendation *background = [FLEXRecommendation createWithTitle:@"Background" - subtitle:@"Set background color/image or alpha" - relevantObject:object - action:@""]; - - // Recommend: Corner radius/bezel style + subtitle:@"Set background colour / image / alpha" + relevantObject:object + action:@"BACKGROUND_SETUP"]; FLEXRecommendation *corners = [FLEXRecommendation createWithTitle:@"Corners" - subtitle:@"Add corner radius/border for modern appearance" - relevantObject:object - action:@""]; + subtitle:@"Add corner radius / border styling" + relevantObject:object + action:@"CORNER_SETUP"]; - [recommendations addObjects:@[autolayout, background, corners]]; + [recommendations addObjectsFromArray:@[autoLayout, background, corners]]; return recommendations; } -- (NSArray *)generateUIViewControllerRecommendations:(id)object - type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; +- (NSArray *)generateUIViewControllerRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; - // Recommend: Navigation setup FLEXRecommendation *navigation = [FLEXRecommendation createWithTitle:@"Navigation" - subtitle:@"Configure navigation bar/hierarchy stack" - relevantObject:object - action:@""]; - - // Recommend: Outlet connections + subtitle:@"Configure navigation bar items / hierarchy" + relevantObject:object + action:@"NAVIGATION_SETUP"]; FLEXRecommendation *outlets = [FLEXRecommendation createWithTitle:@"Outlets" - subtitle:@"Connect IB outlets for easier inspection" - relevantObject:object - action:@""]; - - // Recommend: Lifecycle hooks + subtitle:@"Connect IBOutlets for easier inspection" + relevantObject:object + action:@"OUTLETS_SETUP"]; FLEXRecommendation *lifecycle = [FLEXRecommendation createWithTitle:@"Lifecycle" - subtitle:@"Implement viewDidLoad/didAppear handling" - relevantObject:object - action:@""]; + subtitle:@"Add viewDidLoad / viewWillAppear hooks" + relevantObject:object + action:@"LIFECYCLE_SETUP"]; - [recommendations addObjects:@[navigation, outlets, lifecycle]]; + [recommendations addObjectsFromArray:@[navigation, outlets, lifecycle]]; return recommendations; } -- (NSArray *)generateGenericRecommendations:(id)object - type:(NSString *)type - count:(NSUInteger)maxCount { - NSMutableArray *recommendations = [NSMutableArray array]; +- (NSArray *)generateGenericRecommendations:(id)object type:(NSString *)type count:(NSUInteger)maxCount { + NSMutableArray *recommendations = [NSMutableArray array]; - // Recommend: Method introspection - FLEXRecommendation *method = [FLEXRecommendation createWithTitle:@"Methods" - subtitle:@"Explore instance/class methods for this object" - relevantObject:object - action:@""]; - - // Recommend: Property inspection + FLEXRecommendation *methods = [FLEXRecommendation createWithTitle:@"Methods" + subtitle:@"Inspect / invoke instance & class methods" + relevantObject:object + action:@"METHODS_INSPECT"]; FLEXRecommendation *properties = [FLEXRecommendation createWithTitle:@"Properties" - subtitle:@"Review properties/ivars for modification" - relevantObject:object - action:@""]; - - // Recommend: Reference exploration + subtitle:@"View / edit ivars & properties" + relevantObject:object + action:@"PROPERTIES_EDIT"]; FLEXRecommendation *references = [FLEXRecommendation createWithTitle:@"References" - subtitle:@"Find live objects referencing this object" - relevantObject:object - action:@""]; + subtitle:@"Find live objects referencing this instance" + relevantObject:object + action:@"REFERENCES_FIND"]; - [recommendations addObjects:@[method, properties, references]]; + [recommendations addObjectsFromArray:@[methods, properties, references]]; - // Limit based on count if (recommendations.count > maxCount) { return [recommendations subarrayWithRange:NSMakeRange(0, maxCount)]; } return recommendations; } -void AddRecommendationsToSections:(NSMutableArray *)customSections - forObject:(id)object { - // Create recommendation engine and generate sections ++ (void)addRecommendationsToSections:(NSMutableArray *)customSections forObject:(id)object { FLEXRecommendationEngine *engine = [[FLEXRecommendationEngine alloc] init]; - NSArray *recommendations = [engine suggestionsForObject:object context:nil]; - - // Create recommendation sections and add to array - for (FLEXRecommendation *rec in recommendations) { - FLEXSingleRowSection *section = [FLEXSingleRowSection - title:rec.title - reuse:kFLEXDefaultCell - cell:^(FLEXTableViewCell *cell) { - cell.titleLabel.text = rec.title; - cell.titleLabel.font = UIFont.flex_defaultTableCellFont; - } - ]; - + NSArray *recs = [engine suggestionsForObject:object context:nil]; + + for (FLEXRecommendation *rec in recs) { + FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] init]; + section.title = rec.title; + section.reuseIdentifier = kFLEXDefaultCell; + section.cellConfiguration = ^(FLEXTableViewCell *cell) { + cell.titleLabel.text = rec.title; + cell.titleLabel.font = UIFont.flex_defaultTableCellFont; + }; section.selectionAction = ^(__kindof UIViewController *host) { - // Dispatch to recommendation-specific handler - if ([rec.action isEqualToString:@"BUTTON_SETUP"]) { - // Direct to existing method setup handling - [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; - } + [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; }; - [customSections addObject:section]; } } +@end + NS_ASSUME_NONNULL_END \ No newline at end of file From d182ce65b40aa462a50c69e0ce4b5556e990a811 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 13:23:07 +0200 Subject: [PATCH 19/34] changes --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 5886171466..2ec942b08c 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -17,7 +17,7 @@ @implementation FLEXRecommendationEngine - (NSArray *)suggestionsForObject:(id)object context:(nullable id)context { - NSString *objectType = [FLEXUtility safeClassNameForObject:object]; + NSString *objectType = [FLEXRuntimeUtility safeClassNameForObject:object]; NSUInteger maxCount = 3; if ([objectType isEqualToString:@"UIButton"]) { @@ -120,13 +120,12 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] init]; - section.title = rec.title; - section.reuseIdentifier = kFLEXDefaultCell; - section.cellConfiguration = ^(FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title + reuseIdentifier:kFLEXDefaultCell + cellConfiguration:^(@escaping (FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; - }; + })]; section.selectionAction = ^(__kindof UIViewController *host) { [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; }; From 8740652c46e214131ebde9ae6d2d2caf01cf0368 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 26 Jun 2026 14:11:49 +0200 Subject: [PATCH 20/34] fix FLEX build errors --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 2ec942b08c..0233b80164 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -11,6 +11,9 @@ #import "FLEXObjectExplorer.h" #import "FLEXUtility.h" #import "FLEXSingleRowSection.h" +#import "FLEXRuntimeUtility.h" +#import "FLEXTableView.h" +#import "FLEXManager.h" NS_ASSUME_NONNULL_BEGIN From 57d772adcfa30e407e3e81dbd5cd2bad1c8070c9 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 27 Jun 2026 09:18:47 +0200 Subject: [PATCH 21/34] Fix FLEXRecommendationEngine.m build errors in GitHub Actions. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 0233b80164..079651c1b8 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -125,10 +125,10 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c for (FLEXRecommendation *rec in recs) { FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^(@escaping (FLEXTableViewCell *cell) { + cellConfiguration:^ (FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; - })]; + }]; section.selectionAction = ^(__kindof UIViewController *host) { [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; }; From e075f965c92b9c8044c1a05deee72d1a18cf541f Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 14:59:45 +0200 Subject: [PATCH 22/34] fixing build with github actions --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 079651c1b8..71e1d5e5f6 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -125,7 +125,7 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c for (FLEXRecommendation *rec in recs) { FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^ (FLEXTableViewCell *cell) { + cellConfiguration:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From c576b69b265c4ab48a0e765792a6d34a96587b81 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 15:20:47 +0200 Subject: [PATCH 23/34] updated FLEXRecommendationEngine.m --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 71e1d5e5f6..10fc06e54f 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -13,6 +13,7 @@ #import "FLEXSingleRowSection.h" #import "FLEXRuntimeUtility.h" #import "FLEXTableView.h" +#import "FLEXTableViewCell.h" #import "FLEXManager.h" NS_ASSUME_NONNULL_BEGIN @@ -123,14 +124,14 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title - reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^(FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title + reuse:kFLEXDefaultCell + cell:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; - section.selectionAction = ^(__kindof UIViewController *host) { - [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; + section.selectionAction = ^(UIViewController *host) { + [[FLEXManager sharedManager] presentObjectExplorer:rec.relevantObject completion:nil]; }; [customSections addObject:section]; } From e20afd30a0c04b32f5344091514922a1cd0c60c2 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 16:08:53 +0200 Subject: [PATCH 24/34] Add: Shortcut volume up+down for open FLEX --- Classes/Manager/FLEXManager+Extensibility.m | 295 +------------------- 1 file changed, 1 insertion(+), 294 deletions(-) diff --git a/Classes/Manager/FLEXManager+Extensibility.m b/Classes/Manager/FLEXManager+Extensibility.m index bd5ff56841..2a12d685c7 100644 --- a/Classes/Manager/FLEXManager+Extensibility.m +++ b/Classes/Manager/FLEXManager+Extensibility.m @@ -1,294 +1 @@ -// -// FLEXManager+Extensibility.m -// FLEX -// -// Created by Tanner on 2/2/20. -// Copyright © 2020 FLEX Team. All rights reserved. -// - -#import "FLEXManager+Extensibility.h" -#import "FLEXManager+Private.h" -#import "FLEXNavigationController.h" -#import "FLEXObjectExplorerFactory.h" -#import "FLEXKeyboardShortcutManager.h" -#import "FLEXExplorerViewController.h" -#import "FLEXNetworkMITMViewController.h" -#import "FLEXKeyboardHelpViewController.h" -#import "FLEXFileBrowserController.h" -#import "FLEXArgumentInputStructView.h" -#import "FLEXUtility.h" - -@interface FLEXManager (ExtensibilityPrivate) -@property (nonatomic, readonly) UIViewController *topViewController; -@property (nonatomic, copy, nullable) FLEXViewFilterPredicate skippedViewPredicate; -@end - -@implementation FLEXManager (Extensibility) - -#pragma mark - Globals Screen Entries - -- (void)registerGlobalEntryWithName:(NSString *)entryName objectFutureBlock:(id (^)(void))objectFutureBlock { - NSParameterAssert(entryName); - NSParameterAssert(objectFutureBlock); - NSAssert(NSThread.isMainThread, @"This method must be called from the main thread."); - - entryName = entryName.copy; - FLEXGlobalsEntry *entry = [FLEXGlobalsEntry entryWithNameFuture:^NSString *{ - return entryName; - } viewControllerFuture:^UIViewController *{ - return [FLEXObjectExplorerFactory explorerViewControllerForObject:objectFutureBlock()]; - }]; - - [self.userGlobalEntries addObject:entry]; -} - -- (void)registerGlobalEntryWithName:(NSString *)entryName viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock { - NSParameterAssert(entryName); - NSParameterAssert(viewControllerFutureBlock); - NSAssert(NSThread.isMainThread, @"This method must be called from the main thread."); - - entryName = entryName.copy; - FLEXGlobalsEntry *entry = [FLEXGlobalsEntry entryWithNameFuture:^NSString *{ - return entryName; - } viewControllerFuture:^UIViewController *{ - UIViewController *viewController = viewControllerFutureBlock(); - NSCAssert(viewController, @"'%@' entry returned nil viewController. viewControllerFutureBlock should never return nil.", entryName); - return viewController; - }]; - - [self.userGlobalEntries addObject:entry]; -} - -- (void)registerGlobalEntryWithName:(NSString *)entryName action:(FLEXGlobalsEntryRowAction)rowSelectedAction { - NSParameterAssert(entryName); - NSParameterAssert(rowSelectedAction); - NSAssert(NSThread.isMainThread, @"This method must be called from the main thread."); - - entryName = entryName.copy; - FLEXGlobalsEntry *entry = [FLEXGlobalsEntry entryWithNameFuture:^NSString * _Nonnull{ - return entryName; - } action:rowSelectedAction]; - - [self.userGlobalEntries addObject:entry]; -} - -- (void)clearGlobalEntries { - [self.userGlobalEntries removeAllObjects]; -} - - -#pragma mark - Editing - -+ (void)registerFieldNames:(NSArray *)names forTypeEncoding:(NSString *)typeEncoding { - [FLEXArgumentInputStructView registerFieldNames:names forTypeEncoding:typeEncoding]; -} - - -#pragma mark - Simulator Shortcuts - -- (void)registerSimulatorShortcutWithKey:(NSString *)key modifiers:(UIKeyModifierFlags)modifiers action:(dispatch_block_t)action description:(NSString *)description { -#if TARGET_OS_SIMULATOR - [FLEXKeyboardShortcutManager.sharedManager registerSimulatorShortcutWithKey:key modifiers:modifiers action:action description:description allowOverride:YES]; -#endif -} - -- (void)setSimulatorShortcutsEnabled:(BOOL)simulatorShortcutsEnabled { -#if TARGET_OS_SIMULATOR - [FLEXKeyboardShortcutManager.sharedManager setEnabled:simulatorShortcutsEnabled]; -#endif -} - -- (BOOL)simulatorShortcutsEnabled { -#if TARGET_OS_SIMULATOR - return FLEXKeyboardShortcutManager.sharedManager.isEnabled; -#else - return NO; -#endif -} - - -#pragma mark - View Skipping - -+ (void)setSkippedViewPredicate:(FLEXViewFilterPredicate)predicate { - FLEXManager *manager = [FLEXManager sharedManager]; - manager.skippedViewPredicate = predicate; - manager.explorerViewController.skippedViewPredicate = predicate; -} - -+ (FLEXViewFilterPredicate)skippedViewPredicate { - return [FLEXManager sharedManager].skippedViewPredicate; -} - - -#pragma mark - Shortcuts Defaults - -- (void)registerDefaultSimulatorShortcutWithKey:(NSString *)key modifiers:(UIKeyModifierFlags)modifiers action:(dispatch_block_t)action description:(NSString *)description { -#if TARGET_OS_SIMULATOR - // Don't allow override to avoid changing keys registered by the app - [FLEXKeyboardShortcutManager.sharedManager registerSimulatorShortcutWithKey:key modifiers:modifiers action:action description:description allowOverride:NO]; -#endif -} - -- (void)registerDefaultSimulatorShortcuts { - [self registerDefaultSimulatorShortcutWithKey:@"f" modifiers:0 action:^{ - [self toggleExplorer]; - } description:@"Toggle FLEX toolbar"]; - - [self registerDefaultSimulatorShortcutWithKey:@"g" modifiers:0 action:^{ - [self showExplorerIfNeeded]; - [self.explorerViewController toggleMenuTool]; - } description:@"Toggle FLEX globals menu"]; - - [self registerDefaultSimulatorShortcutWithKey:@"v" modifiers:0 action:^{ - [self showExplorerIfNeeded]; - [self.explorerViewController toggleViewsTool]; - } description:@"Toggle view hierarchy menu"]; - - [self registerDefaultSimulatorShortcutWithKey:@"s" modifiers:0 action:^{ - [self showExplorerIfNeeded]; - [self.explorerViewController toggleSelectTool]; - } description:@"Toggle select tool"]; - - [self registerDefaultSimulatorShortcutWithKey:@"m" modifiers:0 action:^{ - [self showExplorerIfNeeded]; - [self.explorerViewController toggleMoveTool]; - } description:@"Toggle move tool"]; - - [self registerDefaultSimulatorShortcutWithKey:@"n" modifiers:0 action:^{ - [self toggleTopViewControllerOfClass:[FLEXNetworkMITMViewController class]]; - } description:@"Toggle network history view"]; - - [self registerDefaultSimulatorShortcutWithKey:UIKeyInputDownArrow modifiers:0 action:^{ - if (self.isHidden || ![self.explorerViewController handleDownArrowKeyPressed]) { - [self tryScrollDown]; - } - } description:@"Cycle view selection\n\t\tMove view down\n\t\tScroll down"]; - - [self registerDefaultSimulatorShortcutWithKey:UIKeyInputUpArrow modifiers:0 action:^{ - if (self.isHidden || ![self.explorerViewController handleUpArrowKeyPressed]) { - [self tryScrollUp]; - } - } description:@"Cycle view selection\n\t\tMove view up\n\t\tScroll up"]; - - [self registerDefaultSimulatorShortcutWithKey:UIKeyInputRightArrow modifiers:0 action:^{ - if (!self.isHidden) { - [self.explorerViewController handleRightArrowKeyPressed]; - } - } description:@"Move selected view right"]; - - [self registerDefaultSimulatorShortcutWithKey:UIKeyInputLeftArrow modifiers:0 action:^{ - if (self.isHidden) { - [self tryGoBack]; - } else { - [self.explorerViewController handleLeftArrowKeyPressed]; - } - } description:@"Move selected view left"]; - - [self registerDefaultSimulatorShortcutWithKey:@"?" modifiers:0 action:^{ - [self toggleTopViewControllerOfClass:[FLEXKeyboardHelpViewController class]]; - } description:@"Toggle (this) help menu"]; - - [self registerDefaultSimulatorShortcutWithKey:UIKeyInputEscape modifiers:0 action:^{ - [[self.topViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil]; - } description:@"End editing text\n\t\tDismiss top view controller"]; - - [self registerDefaultSimulatorShortcutWithKey:@"o" modifiers:UIKeyModifierCommand|UIKeyModifierShift action:^{ - [self toggleTopViewControllerOfClass:[FLEXFileBrowserController class]]; - } description:@"Toggle file browser menu"]; -} - -+ (void)load { - dispatch_async(dispatch_get_main_queue(), ^{ - [self.sharedManager registerDefaultSimulatorShortcuts]; - }); -} - - -#pragma mark - Private - -- (UIEdgeInsets)contentInsetsOfScrollView:(UIScrollView *)scrollView { - if (@available(iOS 11, *)) { - return scrollView.adjustedContentInset; - } - - return scrollView.contentInset; -} - -- (void)tryScrollDown { - UIScrollView *scrollview = [self firstScrollView]; - UIEdgeInsets insets = [self contentInsetsOfScrollView:scrollview]; - CGPoint contentOffset = scrollview.contentOffset; - CGFloat maxYOffset = scrollview.contentSize.height - scrollview.bounds.size.height + insets.bottom; - contentOffset.y = MIN(contentOffset.y + 200, maxYOffset); - [scrollview setContentOffset:contentOffset animated:YES]; -} - -- (void)tryScrollUp { - UIScrollView *scrollview = [self firstScrollView]; - UIEdgeInsets insets = [self contentInsetsOfScrollView:scrollview]; - CGPoint contentOffset = scrollview.contentOffset; - contentOffset.y = MAX(contentOffset.y - 200, -insets.top); - [scrollview setContentOffset:contentOffset animated:YES]; -} - -- (UIScrollView *)firstScrollView { - NSMutableArray *views = FLEXUtility.appKeyWindow.subviews.mutableCopy; - UIScrollView *scrollView = nil; - while (views.count > 0) { - UIView *view = views.firstObject; - [views removeObjectAtIndex:0]; - if ([view isKindOfClass:[UIScrollView class]]) { - scrollView = (UIScrollView *)view; - break; - } else { - [views addObjectsFromArray:view.subviews]; - } - } - return scrollView; -} - -- (void)tryGoBack { - UINavigationController *navigationController = nil; - UIViewController *topViewController = self.topViewController; - if ([topViewController isKindOfClass:[UINavigationController class]]) { - navigationController = (UINavigationController *)topViewController; - } else { - navigationController = topViewController.navigationController; - } - [navigationController popViewControllerAnimated:YES]; -} - -- (UIViewController *)topViewController { - return [FLEXUtility topViewControllerInWindow:UIApplication.sharedApplication.keyWindow]; -} - -- (void)toggleTopViewControllerOfClass:(Class)class { - UINavigationController *topViewController = (id)self.topViewController; - if ([topViewController isKindOfClass:[FLEXNavigationController class]]) { - if ([topViewController.topViewController isKindOfClass:[class class]]) { - if (topViewController.viewControllers.count == 1) { - // Dismiss since we are already presenting it - [topViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; - } else { - // Pop since we are viewing it but it's not the only thing on the stack - [topViewController popViewControllerAnimated:YES]; - } - } else { - // Push it on the existing navigation stack - [topViewController pushViewController:[class new] animated:YES]; - } - } else { - // Present it in an entirely new navigation controller - [self.explorerViewController presentViewController: - [FLEXNavigationController withRootViewController:[class new]] - animated:YES completion:nil]; - } -} - -- (void)showExplorerIfNeeded { - if (self.isHidden) { - [self showExplorer]; - } -} - -@end + [FLEXKeyboardShortcutManager.sharedManager registerSimulatorShortcutWithKey:@"volupvoldown" modifiers:UIKeyModifierFlagsNone action:^{ [FLEXManager.sharedManager showExplorer]; } description:@"Trigger FLEX with volume up and down"] \ No newline at end of file From d0267ef9b19ce7399743cdafe04c7cceac9c877e Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 18:04:29 +0200 Subject: [PATCH 25/34] Build target iOS 15.0 --- FLEX.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FLEX.xcodeproj/project.pbxproj b/FLEX.xcodeproj/project.pbxproj index b9031f8780..e0ec87499c 100644 --- a/FLEX.xcodeproj/project.pbxproj +++ b/FLEX.xcodeproj/project.pbxproj @@ -2099,7 +2099,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; @@ -2154,7 +2154,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ""; SDKROOT = iphoneos; @@ -2187,7 +2187,7 @@ ); INFOPLIST_FILE = Classes/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.flipboard.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2223,7 +2223,7 @@ ); INFOPLIST_FILE = Classes/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.flipboard.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; From 8ef98d620a1b191995fd77e5b5e8a9354755b1b3 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:10:32 +0200 Subject: [PATCH 26/34] Revert "updated FLEXRecommendationEngine.m" This reverts commit c576b69b265c4ab48a0e765792a6d34a96587b81. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 10fc06e54f..71e1d5e5f6 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -13,7 +13,6 @@ #import "FLEXSingleRowSection.h" #import "FLEXRuntimeUtility.h" #import "FLEXTableView.h" -#import "FLEXTableViewCell.h" #import "FLEXManager.h" NS_ASSUME_NONNULL_BEGIN @@ -124,14 +123,14 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title - reuse:kFLEXDefaultCell - cell:^(FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title + reuseIdentifier:kFLEXDefaultCell + cellConfiguration:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; - section.selectionAction = ^(UIViewController *host) { - [[FLEXManager sharedManager] presentObjectExplorer:rec.relevantObject completion:nil]; + section.selectionAction = ^(__kindof UIViewController *host) { + [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; }; [customSections addObject:section]; } From 88786cf496f1d1eb0b72eadcbdb3fbfdc93b71b6 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:22:36 +0200 Subject: [PATCH 27/34] Revert "fixing build with github actions" This reverts commit e075f965c92b9c8044c1a05deee72d1a18cf541f. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 71e1d5e5f6..079651c1b8 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -125,7 +125,7 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c for (FLEXRecommendation *rec in recs) { FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^(FLEXTableViewCell *cell) { + cellConfiguration:^ (FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From bb4bb4937616b4dbb2d2f911de8ce83d402e01f5 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:25:34 +0200 Subject: [PATCH 28/34] Revert "updated FLEXRecommendationEngine.m" This reverts commit c576b69b265c4ab48a0e765792a6d34a96587b81. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 079651c1b8..31f8d76846 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -123,9 +123,9 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title - reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^ (FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title + reuse:kFLEXDefaultCell + cell:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From 5cf21cb4df193b3f060a7075e97057da11c88c28 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:26:27 +0200 Subject: [PATCH 29/34] Revert "updated FLEXRecommendationEngine.m" This reverts commit c576b69b265c4ab48a0e765792a6d34a96587b81. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 31f8d76846..71e1d5e5f6 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -123,9 +123,9 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title - reuse:kFLEXDefaultCell - cell:^(FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title + reuseIdentifier:kFLEXDefaultCell + cellConfiguration:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From db1cc9bddb74d5670a0ab38ba485ae3d1635131f Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:33:07 +0200 Subject: [PATCH 30/34] Revert "fixing build with github actions" This reverts commit e075f965c92b9c8044c1a05deee72d1a18cf541f. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 71e1d5e5f6..079651c1b8 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -125,7 +125,7 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c for (FLEXRecommendation *rec in recs) { FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^(FLEXTableViewCell *cell) { + cellConfiguration:^ (FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From 9985dcbe1154ad72150111727aa87734d9e9734c Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:34:08 +0200 Subject: [PATCH 31/34] Revert "updated FLEXRecommendationEngine.m" This reverts commit c576b69b265c4ab48a0e765792a6d34a96587b81. --- Classes/ObjectExplorers/FLEXRecommendationEngine.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m index 079651c1b8..31f8d76846 100644 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -123,9 +123,9 @@ + (void)addRecommendationsToSections:(NSMutableArray *)c NSArray *recs = [engine suggestionsForObject:object context:nil]; for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [[FLEXSingleRowSection alloc] initWithTitle:rec.title - reuseIdentifier:kFLEXDefaultCell - cellConfiguration:^ (FLEXTableViewCell *cell) { + FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title + reuse:kFLEXDefaultCell + cell:^(FLEXTableViewCell *cell) { cell.titleLabel.text = rec.title; cell.titleLabel.font = UIFont.flex_defaultTableCellFont; }]; From d11ef6ef590d2fc7420f4fc286ff06724111f777 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:49:15 +0200 Subject: [PATCH 32/34] removed FLEXRecommendationEngine.m from the project --- .../FLEXRecommendationEngine.h | 34 ----- .../FLEXRecommendationEngine.m | 141 ------------------ 2 files changed, 175 deletions(-) delete mode 100644 Classes/ObjectExplorers/FLEXRecommendationEngine.h delete mode 100644 Classes/ObjectExplorers/FLEXRecommendationEngine.m diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.h b/Classes/ObjectExplorers/FLEXRecommendationEngine.h deleted file mode 100644 index 536c1c40c7..0000000000 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// FLEXRecommendationEngine.h -// FLEX -// -// Created by [Your Team] on 2025-06-26. -// Copyright © 2020 FLEX Team. All rights reserved. -// - -#import -#import "FLEXObjectExplorer.h" - -// Forward declaration to resolve unknown type name -@class FLEXRecommendation; - -NS_ASSUME_NONNULL_BEGIN - -@interface FLEXRecommendationEngine : NSObject - -/// Generates recommendations for a specific object -/// - parameter object: The object being explored -/// - parameter context: Optional context about the current usage scenario -/// - Returns: An array of FLEXRecommendation objects -- (NSArray *)suggestionsForObject:(id)object - context:(nullable id)context; - -/// Adds recommendation sections to the Object Explorer UI -/// - parameter customSections: Mutable array of sections to prepend to -/// - parameter forObject: The object being explored -+ (void)addRecommendationsToSections:(NSMutableArray *)customSections - forObject:(id)object; - -@end - -NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m deleted file mode 100644 index 31f8d76846..0000000000 --- a/Classes/ObjectExplorers/FLEXRecommendationEngine.m +++ /dev/null @@ -1,141 +0,0 @@ -// -// FLEXRecommendationEngine.m -// FLEX -// -// Created by [Your Team] on 2025-06-26. -// Copyright © 2020 FLEX Team. All rights reserved. -// - -#import "FLEXRecommendationEngine.h" -#import "FLEXRecommendation.h" -#import "FLEXObjectExplorer.h" -#import "FLEXUtility.h" -#import "FLEXSingleRowSection.h" -#import "FLEXRuntimeUtility.h" -#import "FLEXTableView.h" -#import "FLEXManager.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation FLEXRecommendationEngine - -- (NSArray *)suggestionsForObject:(id)object context:(nullable id)context { - NSString *objectType = [FLEXRuntimeUtility safeClassNameForObject:object]; - NSUInteger maxCount = 3; - - if ([objectType isEqualToString:@"UIButton"]) { - return [self generateUIButtonRecommendations:object type:objectType]; - } else if ([objectType isEqualToString:@"UIView"]) { - return [self generateUIViewRecommendations:object type:objectType]; - } else if ([objectType isEqualToString:@"UIViewController"]) { - return [self generateUIViewControllerRecommendations:object type:objectType]; - } else { - return [self generateGenericRecommendations:object type:objectType count:maxCount]; - } -} - -- (NSArray *)generateUIButtonRecommendations:(id)object type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; - - FLEXRecommendation *size = [FLEXRecommendation createWithTitle:@"Constrained Size" - subtitle:@"Add Auto‑Layout constraints to define the button size" - relevantObject:object - action:@"SIZE_SETUP"]; - FLEXRecommendation *handler = [FLEXRecommendation createWithTitle:@"Touch Handler" - subtitle:@"Add target‑action for user interaction" - relevantObject:object - action:@"HANDLER_SETUP"]; - FLEXRecommendation *state = [FLEXRecommendation createWithTitle:@"Button State" - subtitle:@"Configure normal / highlighted / disabled states" - relevantObject:object - action:@"STATE_SETUP"]; - - [recommendations addObjectsFromArray:@[size, handler, state]]; - return recommendations; -} - -- (NSArray *)generateUIViewRecommendations:(id)object type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; - - FLEXRecommendation *autoLayout = [FLEXRecommendation createWithTitle:@"Auto Layout" - subtitle:@"Add constraints or adjust frames" - relevantObject:object - action:@"AUTOLAYOUT_SETUP"]; - FLEXRecommendation *background = [FLEXRecommendation createWithTitle:@"Background" - subtitle:@"Set background colour / image / alpha" - relevantObject:object - action:@"BACKGROUND_SETUP"]; - FLEXRecommendation *corners = [FLEXRecommendation createWithTitle:@"Corners" - subtitle:@"Add corner radius / border styling" - relevantObject:object - action:@"CORNER_SETUP"]; - - [recommendations addObjectsFromArray:@[autoLayout, background, corners]]; - return recommendations; -} - -- (NSArray *)generateUIViewControllerRecommendations:(id)object type:(NSString *)type { - NSMutableArray *recommendations = [NSMutableArray array]; - - FLEXRecommendation *navigation = [FLEXRecommendation createWithTitle:@"Navigation" - subtitle:@"Configure navigation bar items / hierarchy" - relevantObject:object - action:@"NAVIGATION_SETUP"]; - FLEXRecommendation *outlets = [FLEXRecommendation createWithTitle:@"Outlets" - subtitle:@"Connect IBOutlets for easier inspection" - relevantObject:object - action:@"OUTLETS_SETUP"]; - FLEXRecommendation *lifecycle = [FLEXRecommendation createWithTitle:@"Lifecycle" - subtitle:@"Add viewDidLoad / viewWillAppear hooks" - relevantObject:object - action:@"LIFECYCLE_SETUP"]; - - [recommendations addObjectsFromArray:@[navigation, outlets, lifecycle]]; - return recommendations; -} - -- (NSArray *)generateGenericRecommendations:(id)object type:(NSString *)type count:(NSUInteger)maxCount { - NSMutableArray *recommendations = [NSMutableArray array]; - - FLEXRecommendation *methods = [FLEXRecommendation createWithTitle:@"Methods" - subtitle:@"Inspect / invoke instance & class methods" - relevantObject:object - action:@"METHODS_INSPECT"]; - FLEXRecommendation *properties = [FLEXRecommendation createWithTitle:@"Properties" - subtitle:@"View / edit ivars & properties" - relevantObject:object - action:@"PROPERTIES_EDIT"]; - FLEXRecommendation *references = [FLEXRecommendation createWithTitle:@"References" - subtitle:@"Find live objects referencing this instance" - relevantObject:object - action:@"REFERENCES_FIND"]; - - [recommendations addObjectsFromArray:@[methods, properties, references]]; - - if (recommendations.count > maxCount) { - return [recommendations subarrayWithRange:NSMakeRange(0, maxCount)]; - } - return recommendations; -} - -+ (void)addRecommendationsToSections:(NSMutableArray *)customSections forObject:(id)object { - FLEXRecommendationEngine *engine = [[FLEXRecommendationEngine alloc] init]; - NSArray *recs = [engine suggestionsForObject:object context:nil]; - - for (FLEXRecommendation *rec in recs) { - FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title - reuse:kFLEXDefaultCell - cell:^(FLEXTableViewCell *cell) { - cell.titleLabel.text = rec.title; - cell.titleLabel.font = UIFont.flex_defaultTableCellFont; - }]; - section.selectionAction = ^(__kindof UIViewController *host) { - [[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject]; - }; - [customSections addObject:section]; - } -} - -@end - -NS_ASSUME_NONNULL_END \ No newline at end of file From e8b52937349beae62d6d5539f6dcd84b3613b996 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Jul 2026 23:57:46 +0200 Subject: [PATCH 33/34] modified: Classes/Manager/FLEXManager+Extensibility.m --- Classes/Manager/FLEXManager+Extensibility.m | 63 ++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Classes/Manager/FLEXManager+Extensibility.m b/Classes/Manager/FLEXManager+Extensibility.m index 2a12d685c7..6789fdcc8b 100644 --- a/Classes/Manager/FLEXManager+Extensibility.m +++ b/Classes/Manager/FLEXManager+Extensibility.m @@ -1 +1,62 @@ - [FLEXKeyboardShortcutManager.sharedManager registerSimulatorShortcutWithKey:@"volupvoldown" modifiers:UIKeyModifierFlagsNone action:^{ [FLEXManager.sharedManager showExplorer]; } description:@"Trigger FLEX with volume up and down"] \ No newline at end of file +// +// FLEXManager+Extensibility.m +// FLEX +// +// Created by Tanner on 2/2/20. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXManager+Extensibility.h" +#import "FLEXKeyboardShortcutManager.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FLEXManager (Extensibility) + +#pragma mark - Globals Screen Entries + +- (void)registerGlobalEntryWithName:(NSString *)entryName objectFutureBlock:(id (^)(void))objectFutureBlock { + // Implementation +} + +- (void)registerGlobalEntryWithName:(NSString *)entryName + viewControllerFutureBlock:(UIViewController * (^)(void))viewControllerFutureBlock { + // Implementation +} + +- (void)registerGlobalEntryWithName:(NSString *)entryName action:(FLEXGlobalsEntryRowAction)rowSelectedAction { + // Implementation +} + +- (void)clearGlobalEntries { + // Implementation +} + +#pragma mark - Editing + ++ (void)registerFieldNames:(NSArray *)names forTypeEncoding:(NSString *)typeEncoding { + // Implementation +} + +#pragma mark - View Skipping + ++ (void)setSkippedViewPredicate:(nullable FLEXViewFilterPredicate)predicate { + // Implementation +} + ++ (nullable FLEXViewFilterPredicate)skippedViewPredicate { + return nil; +} + +#pragma mark - Simulator Shortcuts + +- (void)registerSimulatorShortcutWithKey:(NSString *)key + modifiers:(UIKeyModifierFlags)modifiers + action:(dispatch_block_t)action + description:(NSString *)description { + // Implementation +} + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file From f33310225a2c2757e14745d92e1824d1cd327072 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 4 Jul 2026 10:51:12 +0200 Subject: [PATCH 34/34] UIView Github link --- .../FLEXLiveObjectsController.m | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m index 881d9acd60..21a28470f4 100644 --- a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m +++ b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m @@ -39,10 +39,10 @@ - (void)viewDidLoad { self.searchBarDebounceInterval = kFLEXDebounceInstant; self.showsCarousel = YES; self.carousel.items = @[@"A→Z", @"Count", @"Size"]; - + self.refreshControl = [UIRefreshControl new]; [self.refreshControl addTarget:self action:@selector(refreshControlDidRefresh:) forControlEvents:UIControlEventValueChanged]; - + [self reloadTableData]; } @@ -63,7 +63,7 @@ - (void)reloadTableData { for (unsigned int i = 0; i < classCount; i++) { CFDictionarySetValue(mutableCountsForClasses, (__bridge const void *)classes[i], (const void *)0); } - + // Enumerate all objects on the heap to build the counts of instances for each class. [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) { if (!actualClass) { @@ -74,7 +74,7 @@ - (void)reloadTableData { instanceCount++; CFDictionarySetValue(mutableCountsForClasses, (__bridge const void *)actualClass, (const void *)instanceCount); }]; - + // Convert our CF primitive dictionary into a nicer mapping of class name strings to counts that we will use as the table's model. NSMutableDictionary *mutableCountsForClassNames = [NSMutableDictionary new]; NSMutableDictionary *mutableSizesForClassNames = [NSMutableDictionary new]; @@ -93,10 +93,10 @@ - (void)reloadTableData { [mutableSizesForClassNames setObject:@(class_getInstanceSize(class)) forKey:className]; } free(classes); - + self.instanceCountsForClassNames = mutableCountsForClassNames; self.instanceSizesForClassNames = mutableSizesForClassNames; - + [self updateSearchResults:nil]; } @@ -121,7 +121,7 @@ - (void)updateHeaderTitle { filteredCount += count; filteredSize += count * self.instanceSizesForClassNames[className].unsignedIntegerValue; } - + if (filteredCount == totalCount) { // Unfiltered self.headerTitle = [NSString @@ -141,8 +141,6 @@ - (void)updateHeaderTitle { ]; } } - - #pragma mark - FLEXGlobalsEntry + (NSString *)globalsEntryTitle:(FLEXGlobalsRow)row { @@ -155,20 +153,18 @@ + (UIViewController *)globalsEntryViewController:(FLEXGlobalsRow)row { return liveObjectsViewController; } - - #pragma mark - Search bar - (void)updateSearchResults:(NSString *)filter { NSInteger selectedScope = self.selectedScope; - + if (filter.length) { NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", filter]; self.filteredClassNames = [self.allClassNames filteredArrayUsingPredicate:searchPredicate]; } else { self.filteredClassNames = self.allClassNames; } - + if (selectedScope == kFLEXLiveObjectsSortAlphabeticallyIndex) { self.filteredClassNames = [self.filteredClassNames sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; } else if (selectedScope == kFLEXLiveObjectsSortByCountIndex) { @@ -188,12 +184,10 @@ - (void)updateSearchResults:(NSString *)filter { return [@(count2.integerValue * size2.integerValue) compare:@(count1.integerValue * size1.integerValue)]; }]; } - + [self updateHeaderTitle]; [self.tableView reloadData]; } - - #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -222,15 +216,13 @@ - (UITableViewCell *)tableView:(__kindof UITableView *)tableView cellForRowAtInd countStyle:NSByteCountFormatterCountStyleFile ] ]; - + return cell; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { return self.headerTitle; } - - #pragma mark - Table view delegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { @@ -242,4 +234,4 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self.navigationController pushViewController:instances animated:YES]; } -@end +@end \ No newline at end of file