Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ff4dccb
Add GitHub Actions build workflow
ChrisGleich1AufsMaul Jun 22, 2026
02dabcc
Expose file browser header for framework module
ChrisGleich1AufsMaul Jun 22, 2026
23544d3
Upload FLEX framework artifact from CI
ChrisGleich1AufsMaul Jun 22, 2026
1687092
Add Theos tweak package workflow
ChrisGleich1AufsMaul Jun 22, 2026
8dad04c
Allow FLEX deprecation warnings in tweak build
ChrisGleich1AufsMaul Jun 22, 2026
3bc15d8
Relax warnings for Theos tweak build
ChrisGleich1AufsMaul Jun 22, 2026
7e69ec4
Make CI independent of simulator devices
ChrisGleich1AufsMaul Jun 22, 2026
652a233
Upload injectable FLEX loader dylib
ChrisGleich1AufsMaul Jun 22, 2026
d40f46b
Use Node 24 compatible GitHub Actions
ChrisGleich1AufsMaul Jun 22, 2026
2bea8b2
Guard heap object class names
ChrisGleich1AufsMaul Jun 22, 2026
e017688
Improve toolbar contrast over app content
ChrisGleich1AufsMaul Jun 22, 2026
59b2e85
AI-based recommendation engine for FLEX, providing suggestions and in…
ChrisGleich1AufsMaul Jun 25, 2026
bc16fa3
workflow updated
ChrisGleich1AufsMaul Jun 25, 2026
69c1e3f
workflow: file renamed
ChrisGleich1AufsMaul Jun 25, 2026
fc655c5
Falscher Import-Pfad korrigiert
ChrisGleich1AufsMaul Jun 25, 2026
4a2aa4b
Update FLEX.yml
ChrisGleich1AufsMaul Jun 25, 2026
6a8e301
fix: Build error in GitHub Actions workflow for FLEXRecommendation an…
ChrisGleich1AufsMaul Jun 25, 2026
3c4fad0
fix: error: missing context for method declaration
ChrisGleich1AufsMaul Jun 25, 2026
d182ce6
changes
ChrisGleich1AufsMaul Jun 26, 2026
8740652
fix FLEX build errors
ChrisGleich1AufsMaul Jun 26, 2026
57d772a
Fix FLEXRecommendationEngine.m build errors in GitHub Actions.
ChrisGleich1AufsMaul Jun 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/FLEX.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Build

on:
push:
branches:
- main
- master
- codex/flex-mit-github-actions-kompilieren
pull_request:
workflow_dispatch:

jobs:
xcode:
name: Xcode build and tests
runs-on: macos-15

env:
DERIVED_DATA_PATH: build/DerivedData

steps:
- name: Check out repository
uses: actions/checkout@v5

- 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' \
-derivedDataPath "$DERIVED_DATA_PATH" \
CODE_SIGNING_ALLOWED=NO
- name: Upload FLEX framework
uses: actions/upload-artifact@v6
with:
name: FLEX-framework-debug-iphonesimulator
path: ${{ env.DERIVED_DATA_PATH }}/Build/Products/Debug-iphonesimulator/FLEX.framework
if-no-files-found: error

- name: Build FLEX tests
run: |
xcodebuild build-for-testing \
-project FLEX.xcodeproj \
-scheme FLEXTests \
-configuration Debug \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
-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@v5

- name: Install Theos
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:
name: FLEXLoader-dylib
path: Tweak/artifacts/FLEXLoader.dylib
if-no-files-found: error

- name: Upload FLEX Loader tweak
uses: actions/upload-artifact@v6
with:
name: FLEXLoader-tweak
path: Tweak/packages/*.deb
if-no-files-found: error
11 changes: 10 additions & 1 deletion Classes/GlobalStateExplorers/FLEXLiveObjectsController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -76,8 +80,13 @@ - (void)reloadTableData {
NSMutableDictionary<NSString *, NSNumber *> *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];
}
Expand Down
25 changes: 25 additions & 0 deletions Classes/ObjectExplorers/FLEXRecommendation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// FLEXRecommendation.h
// FLEX
//
// Created by [Your Team] on 2025-06-26.
// Copyright © 2020 FLEX Team. All rights reserved.
//

#import <Foundation/Foundation.h>

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
25 changes: 25 additions & 0 deletions Classes/ObjectExplorers/FLEXRecommendation.m
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions Classes/ObjectExplorers/FLEXRecommendationEngine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// FLEXRecommendationEngine.h
// FLEX
//
// Created by [Your Team] on 2025-06-26.
// Copyright © 2020 FLEX Team. All rights reserved.
//

#import <Foundation/Foundation.h>
#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<FLEXRecommendation *> *)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<FLEXTableViewSection *> *)customSections
forObject:(id)object;

@end

NS_ASSUME_NONNULL_END
141 changes: 141 additions & 0 deletions Classes/ObjectExplorers/FLEXRecommendationEngine.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//
// 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<FLEXRecommendation *> *)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<FLEXRecommendation *> *)generateUIButtonRecommendations:(id)object type:(NSString *)type {
NSMutableArray<FLEXRecommendation *> *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<FLEXRecommendation *> *)generateUIViewRecommendations:(id)object type:(NSString *)type {
NSMutableArray<FLEXRecommendation *> *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<FLEXRecommendation *> *)generateUIViewControllerRecommendations:(id)object type:(NSString *)type {
NSMutableArray<FLEXRecommendation *> *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<FLEXRecommendation *> *)generateGenericRecommendations:(id)object type:(NSString *)type count:(NSUInteger)maxCount {
NSMutableArray<FLEXRecommendation *> *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<FLEXTableViewSection *> *)customSections forObject:(id)object {
FLEXRecommendationEngine *engine = [[FLEXRecommendationEngine alloc] init];
NSArray<FLEXRecommendation *> *recs = [engine suggestionsForObject:object context:nil];

for (FLEXRecommendation *rec in recs) {
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 = ^(__kindof UIViewController *host) {
[[FLEXManager sharedManager] showExplorerForObject:rec.relevantObject];
};
[customSections addObject:section];
}
}

@end

NS_ASSUME_NONNULL_END
9 changes: 6 additions & 3 deletions Classes/Toolbar/FLEXExplorerToolbar.m
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,20 @@ - (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];
}

// Drag handle
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];

Expand Down Expand Up @@ -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];
}
Expand All @@ -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];

Expand Down
Loading