├── .gitattributes ├── FSSwitchDataSource.h ├── FSSwitchPanel.h ├── FSSwitchState.h ├── FlipConvert.h ├── FlipConvert.xm ├── Makefile ├── postinst └── postrm /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /FSSwitchDataSource.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "FSSwitchState.h" 3 | 4 | @protocol FSSwitchDataSource 5 | @optional 6 | 7 | - (FSSwitchState)stateForSwitchIdentifier:(NSString *)switchIdentifier; 8 | // Gets the current state of the switch. 9 | // Must override if building a settings-like switch. 10 | // Return FSSwitchStateIndeterminate if switch is loading 11 | // By default returns FSSwitchStateIndeterminate 12 | 13 | - (void)applyState:(FSSwitchState)newState forSwitchIdentifier:(NSString *)switchIdentifier; 14 | // Sets the new state of the switch 15 | // Must override if building a settings-like switch. 16 | // By default calls through to applyActionForSwitchIdentifier: if newState is different from the current state 17 | 18 | - (void)applyActionForSwitchIdentifier:(NSString *)switchIdentifier; 19 | // Runs the default action for the switch. 20 | // Must override if building an action-like switch. 21 | // By default calls through to applyState:forSwitchIdentifier: if state is not indeterminate 22 | 23 | - (NSString *)titleForSwitchIdentifier:(NSString *)switchIdentifier; 24 | // Returns the localized title for the switch. 25 | // By default reads the CFBundleDisplayName out of the switch's bundle. 26 | 27 | - (BOOL)shouldShowSwitchIdentifier:(NSString *)switchIdentifier; 28 | // Returns wether the switch should be shown. 29 | // By default returns YES or the value from GraphicsServices for the capability specified in the "required-capability-key" of the switch's bundle 30 | // E.g. You would detect if the device has the required capability (3G, flash etc) 31 | 32 | - (id)glyphImageDescriptorOfState:(FSSwitchState)switchState size:(CGFloat)size scale:(CGFloat)scale forSwitchIdentifier:(NSString *)switchIdentifier; 33 | // Provide an image descriptor that best displays at the requested size and scale 34 | // By default looks through the bundle to find a glyph image 35 | 36 | - (NSBundle *)bundleForSwitchIdentifier:(NSString *)switchIdentifier; 37 | // Provides a bundle to look for localizations/images in 38 | // By default returns the bundle for the current class 39 | 40 | - (void)switchWasRegisteredForIdentifier:(NSString *)switchIdentifier; 41 | // Called when switch is first registered 42 | 43 | - (void)switchWasUnregisteredForIdentifier:(NSString *)switchIdentifier; 44 | // Called when switch is unregistered 45 | 46 | - (BOOL)hasAlternateActionForSwitchIdentifier:(NSString *)switchIdentifier; 47 | // Gets whether the switch supports an alternate or "hold" action 48 | // By default queries if switch responds to applyAlternateActionForSwitchIdentifier: or if it has a "alternate-action-url" key set 49 | 50 | - (void)applyAlternateActionForSwitchIdentifier:(NSString *)switchIdentifier; 51 | // Applies the alternate or "hold" action 52 | // By default launches the URL stored in the "alternate-action-url" key of the switch's bundle 53 | 54 | @end -------------------------------------------------------------------------------- /FSSwitchPanel.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "FSSwitchState.h" 3 | 4 | @interface FSSwitchPanel : NSObject 5 | 6 | + (FSSwitchPanel *)sharedPanel; 7 | 8 | @property (nonatomic, readonly, copy) NSArray *switchIdentifiers; 9 | // Returns a list of identifying all switches installed on the device 10 | 11 | - (UIColor *)primaryColorForSwitchIdentifier:(NSString *)switchIdentifier; 12 | 13 | - (NSString *)titleForSwitchIdentifier:(NSString *)switchIdentifier; 14 | // Returns the localized title for a specific switch 15 | 16 | - (UIButton *)buttonForSwitchIdentifier:(NSString *)switchIdentifier usingTemplate:(NSBundle *)templateBundle; 17 | // Returns a UIButton for a specific switch 18 | // The button automatically updates its style based on the user interaction and switch state changes, applies the standard action when pressed, and applies the alternate action when held 19 | 20 | - (UIImage *)imageOfSwitchState:(FSSwitchState)state controlState:(UIControlState)controlState forSwitchIdentifier:(NSString *)switchIdentifier usingTemplate:(NSBundle *)templateBundle; 21 | - (UIImage *)imageOfSwitchState:(FSSwitchState)state controlState:(UIControlState)controlState scale:(CGFloat)scale forSwitchIdentifier:(NSString *)switchIdentifier usingTemplate:(NSBundle *)templateBundle; 22 | // Returns an image representing how a specific switch would look in a particular state when styled with the provided template 23 | 24 | - (id)glyphImageDescriptorOfState:(FSSwitchState)switchState size:(CGFloat)size scale:(CGFloat)scale forSwitchIdentifier:(NSString *)switchIdentifier; 25 | // Returns the raw glyph identifier as retrieved from the backing FSSwitch instance 26 | 27 | - (FSSwitchState)stateForSwitchIdentifier:(NSString *)switchIdentifier; 28 | // Returns the current state of a particualr switch 29 | - (void)setState:(FSSwitchState)state forSwitchIdentifier:(NSString *)switchIdentifier; 30 | // Updates the state of a particular switch. If the switch accepts the change it will send a state change 31 | - (void)applyActionForSwitchIdentifier:(NSString *)switchIdentifier; 32 | // Applies the default action of a particular switch 33 | 34 | - (BOOL)hasAlternateActionForSwitchIdentifier:(NSString *)switchIdentifier; 35 | // Queries whether a switch supports an alternate action. This is often triggered by a hold gesture 36 | - (void)applyAlternateActionForSwitchIdentifier:(NSString *)switchIdentifier; 37 | // Apply the alternate action of a particular switch 38 | 39 | - (void)openURLAsAlternateAction:(NSURL *)url; 40 | // Helper method to open a particular URL as if it were launched from an alternate action 41 | 42 | @end 43 | 44 | @protocol FSSwitchDataSource; 45 | 46 | @interface FSSwitchPanel (SpringBoard) 47 | - (void)registerDataSource:(id)dataSource forSwitchIdentifier:(NSString *)switchIdentifier; 48 | // Registers a switch implementation for a specific identifier. Bundlee in /Library/Switches will have their principal class automatically loaded 49 | - (void)unregisterSwitchIdentifier:(NSString *)switchIdentifier; 50 | // Unregisters a switch 51 | - (void)stateDidChangeForSwitchIdentifier:(NSString *)switchIdentifier; 52 | // Informs the system when a switch changes its state. This will trigger any switch buttons to update their style 53 | @end 54 | 55 | extern NSString * const FSSwitchPanelSwitchesChangedNotification; 56 | 57 | extern NSString * const FSSwitchPanelSwitchStateChangedNotification; 58 | extern NSString * const FSSwitchPanelSwitchIdentifierKey; 59 | 60 | extern NSString * const FSSwitchPanelSwitchWillOpenURLNotification; 61 | -------------------------------------------------------------------------------- /FSSwitchState.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | typedef enum { 4 | FSSwitchStateOff = 0, 5 | FSSwitchStateOn = 1, 6 | FSSwitchStateIndeterminate = -1 7 | } FSSwitchState; 8 | 9 | extern NSString *NSStringFromFSSwitchState(FSSwitchState state); 10 | extern FSSwitchState FSSwitchStateFromNSString(NSString *stateString); 11 | -------------------------------------------------------------------------------- /FlipConvert.h: -------------------------------------------------------------------------------- 1 | #import "FSSwitchDataSource.h" 2 | #import "FSSwitchPanel.h" 3 | #import "FSSwitchState.h" 4 | 5 | @class CCUIContentModuleContext, CCUIToggleViewController, CCUICAPackageDescription; 6 | @interface CCUIToggleModule : NSObject { 7 | 8 | CCUIToggleViewController* _viewController; 9 | CCUIContentModuleContext* _contentModuleContext; 10 | CCUICAPackageDescription* _glyphPackageDescription; 11 | 12 | } 13 | 14 | @property (nonatomic,retain) CCUIContentModuleContext * contentModuleContext; //@synthesize contentModuleContext=_contentModuleContext - In the implementation block 15 | @property (assign,getter=isSelected,nonatomic) BOOL selected; 16 | @property (nonatomic,copy,readonly) UIImage * iconGlyph; 17 | @property (nonatomic,copy,readonly) UIImage * selectedIconGlyph; 18 | @property (nonatomic,copy,readonly) UIColor * selectedColor; 19 | @property (nonatomic,copy,readonly) CCUICAPackageDescription * glyphPackageDescription; //@synthesize glyphPackageDescription=_glyphPackageDescription - In the implementation block 20 | @property (nonatomic,copy,readonly) NSString * glyphState; 21 | @property (readonly) unsigned long long hash; 22 | @property (readonly) Class superclass; 23 | @property (copy,readonly) NSString * description; 24 | @property (copy,readonly) NSString * debugDescription; 25 | @property (nonatomic,readonly) UIViewController* contentViewController; 26 | @property (nonatomic,readonly) UIViewController * backgroundViewController; 27 | -(BOOL)isSelected; 28 | -(void)setSelected:(BOOL)arg1 ; 29 | -(UIViewController*)contentViewController; 30 | -(CCUICAPackageDescription *)glyphPackageDescription; 31 | -(NSString *)glyphState; 32 | -(void)reconfigureView; 33 | -(UIImage *)iconGlyph; 34 | -(UIImage *)selectedIconGlyph; 35 | -(id)glyphPackage; 36 | -(CCUIContentModuleContext *)contentModuleContext; 37 | -(void)setContentModuleContext:(CCUIContentModuleContext *)arg1 ; 38 | -(void)refreshState; 39 | -(UIColor *)selectedColor; 40 | @end 41 | 42 | @interface FlipConvertLongPressGestureRecognizer : UILongPressGestureRecognizer 43 | @end 44 | 45 | @interface FlipConvert_PlaceHolder : CCUIToggleModule 46 | @property (nonatomic,retain) NSString * flipConvert_id; 47 | @end -------------------------------------------------------------------------------- /FlipConvert.xm: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import "FlipConvert.h" 5 | 6 | #define NSLog(...) 7 | 8 | NSMutableDictionary* allocates_forBunbdle() 9 | { 10 | static __strong NSMutableDictionary* intanceDic; 11 | if(!intanceDic) { 12 | intanceDic = [[NSMutableDictionary alloc] init]; 13 | } 14 | return intanceDic; 15 | } 16 | 17 | static void setValueWithId(NSString* identifier, NSString* key, id value) 18 | { 19 | NSMutableDictionary* dicIden = [allocates_forBunbdle()[identifier]?:@{} mutableCopy]; 20 | dicIden[key] = value; 21 | allocates_forBunbdle()[identifier] = dicIden; 22 | } 23 | 24 | static id getValueWithId(NSString* identifier, NSString* key) 25 | { 26 | NSDictionary* dicKey = allocates_forBunbdle()[identifier]; 27 | if(dicKey) { 28 | return dicKey[key]; 29 | } 30 | return nil; 31 | } 32 | 33 | @interface UIImage () 34 | + (UIImage *)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle; 35 | @end 36 | 37 | static CGFloat AspectScaleFit(CGSize sourceSize, CGRect destRect) 38 | { 39 | CGSize destSize = destRect.size; 40 | CGFloat scaleW = destSize.width / sourceSize.width; 41 | CGFloat scaleH = destSize.height / sourceSize.height; 42 | return fmin(scaleW, scaleH); 43 | } 44 | static CGRect RectAroundCenter(CGPoint center, CGSize size) 45 | { 46 | CGFloat halfWidth = size.width / 2.0f; 47 | CGFloat halfHeight = size.height / 2.0f; 48 | return CGRectMake(center.x - halfWidth, center.y - halfHeight, size.width, size.height); 49 | } 50 | static CGRect RectByFittingRect(CGRect sourceRect, CGRect destinationRect) 51 | { 52 | CGFloat aspect = AspectScaleFit(sourceRect.size, destinationRect); 53 | CGSize targetSize = CGSizeMake(sourceRect.size.width * aspect, sourceRect.size.height * aspect); 54 | CGPoint center = CGPointMake(CGRectGetMidX(destinationRect), CGRectGetMidY(destinationRect)); 55 | return RectAroundCenter(center, targetSize); 56 | } 57 | static void DrawPDFPageInRect(CGPDFPageRef pageRef, CGRect destinationRect) 58 | { 59 | CGContextRef context = UIGraphicsGetCurrentContext(); 60 | if(context == NULL) { 61 | return; 62 | } 63 | CGContextSaveGState(context); 64 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 65 | CGAffineTransform transform = CGAffineTransformIdentity; 66 | transform = CGAffineTransformScale(transform, 1.0f, -1.0f); 67 | transform = CGAffineTransformTranslate(transform, 0.0f, -image.size.height); 68 | CGContextConcatCTM(context, transform); 69 | CGRect d = CGRectApplyAffineTransform(destinationRect, transform); 70 | CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox); 71 | CGFloat drawingAspect = AspectScaleFit(pageRect.size, d); 72 | CGRect drawingRect = RectByFittingRect(pageRect, d); 73 | CGContextTranslateCTM(context, drawingRect.origin.x, drawingRect.origin.y); 74 | CGContextScaleCTM(context, drawingAspect, drawingAspect); 75 | CGContextDrawPDFPage(context, pageRef); 76 | CGContextRestoreGState(context); 77 | } 78 | static UIImage *ImageFromPDFFileFlipConvert(NSString *pdfPath, CGSize targetSize, BOOL transparent) 79 | { 80 | CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:pdfPath]); 81 | if (pdfRef == NULL) { 82 | return nil; 83 | } 84 | UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0); 85 | if(!transparent) { 86 | [[UIColor lightGrayColor] setFill]; 87 | UIRectFill(CGRectMake(0, 0, targetSize.width, targetSize.height)); 88 | } 89 | CGPDFPageRef pageRef = CGPDFDocumentGetPage(pdfRef, 1); 90 | DrawPDFPageInRect(pageRef, (CGRect){.size = targetSize}); 91 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 92 | UIGraphicsEndImageContext(); 93 | CGPDFDocumentRelease(pdfRef); 94 | return image; 95 | } 96 | 97 | 98 | @implementation FlipConvertLongPressGestureRecognizer 99 | @end 100 | 101 | @implementation FlipConvert_PlaceHolder 102 | @synthesize flipConvert_id; 103 | - (BOOL)isSelected 104 | { 105 | return ([[%c(FSSwitchPanel) sharedPanel] stateForSwitchIdentifier:flipConvert_id]==FSSwitchStateOn); 106 | } 107 | - (UIColor *)selectedColor 108 | { 109 | return [[%c(FSSwitchPanel) sharedPanel] primaryColorForSwitchIdentifier:flipConvert_id]?:[UIColor lightGrayColor]; 110 | } 111 | - (void)setSelected:(BOOL)selected 112 | { 113 | [[%c(FSSwitchPanel) sharedPanel] setState:(FSSwitchState)selected forSwitchIdentifier:flipConvert_id]; 114 | //[[%c(FSSwitchPanel) sharedPanel] applyActionForSwitchIdentifier:flipConvert_id]; 115 | [super refreshState]; 116 | } 117 | - (void)longPress:(FlipConvertLongPressGestureRecognizer *)recognizer 118 | { 119 | if(recognizer.state == UIGestureRecognizerStateBegan) { 120 | if([[%c(FSSwitchPanel) sharedPanel] hasAlternateActionForSwitchIdentifier:flipConvert_id]) { 121 | [[%c(FSSwitchPanel) sharedPanel] applyAlternateActionForSwitchIdentifier:flipConvert_id]; 122 | [super refreshState]; 123 | } 124 | } 125 | } 126 | -(UIImage *)iconGlyph 127 | { 128 | UIViewController* selfViewCon = [self respondsToSelector:@selector(contentViewController)]?self.contentViewController:nil; 129 | if(selfViewCon) { 130 | FlipConvertLongPressGestureRecognizer* longTap = [[FlipConvertLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; 131 | [longTap setNumberOfTapsRequired:0]; 132 | [longTap setMinimumPressDuration:0.5f]; 133 | [longTap setDelegate:self]; 134 | for(UIGestureRecognizer *recognizer in selfViewCon.view.gestureRecognizers) { 135 | if(recognizer&&[recognizer isKindOfClass:%c(FlipConvertLongPressGestureRecognizer)]) { 136 | [selfViewCon.view removeGestureRecognizer:recognizer]; 137 | } 138 | } 139 | [selfViewCon.view addGestureRecognizer:longTap]; 140 | } 141 | return [UIImage imageNamed:@"Icon-off" inBundle:[NSBundle bundleWithPath:getValueWithId(flipConvert_id, @"BundlePathRep")]]; 142 | } 143 | -(UIImage *)selectedIconGlyph 144 | { 145 | return [UIImage imageNamed:@"Icon-on" inBundle:[NSBundle bundleWithPath:getValueWithId(flipConvert_id, @"BundlePathRep")]]; 146 | } 147 | @end 148 | 149 | 150 | id initMethodIMP(id self, SEL _cmd) 151 | { 152 | objc_super superInit = {self, [self superclass]}; 153 | id initSuper = nil; 154 | NSString* classSt = [NSString stringWithFormat:@"%s", class_getName([self class])]; 155 | for(NSString* idNow in [allocates_forBunbdle() allKeys]) { 156 | NSString* repSt = getValueWithId(idNow, @"NSPrincipalClassRep"); 157 | if(repSt && [repSt isEqualToString:classSt]) { 158 | initSuper = getValueWithId(idNow, @"ClassRepAlloc"); 159 | if(!initSuper) { 160 | initSuper = objc_msgSendSuper(&superInit, _cmd); 161 | } 162 | setValueWithId(idNow, @"ClassRepAlloc", initSuper); 163 | ((FlipConvert_PlaceHolder*)initSuper).flipConvert_id = idNow; 164 | break; 165 | } 166 | } 167 | if(!initSuper) { 168 | initSuper = objc_msgSendSuper(&superInit, _cmd); 169 | } 170 | return initSuper; 171 | } 172 | 173 | static void alloc_class_with_Name(const char * nameClass) 174 | { 175 | Class newClass = objc_allocateClassPair([FlipConvert_PlaceHolder class], nameClass, 0); 176 | class_addMethod(newClass, @selector(init), (IMP)initMethodIMP, "@"); 177 | objc_registerClassPair(newClass); 178 | } 179 | 180 | static NSString* getPortedPathFromBundlePath(NSString* bundlePath) 181 | { 182 | return [@"/Library/ControlCenter/Bundles/" stringByAppendingPathComponent:[[[bundlePath lastPathComponent] stringByDeletingPathExtension] stringByAppendingString:@"_FlipConvert.bundle"]]; 183 | } 184 | 185 | static void allocForSwitchBundlePath(NSString* bundlePath) 186 | { 187 | NSDictionary* infoPlist = [[NSDictionary alloc] initWithContentsOfFile:[bundlePath stringByAppendingPathComponent:@"Info.plist"]]?:@{}; 188 | 189 | NSString* identifier = infoPlist[@"CFBundleIdentifier"]; 190 | 191 | NSString* executable = infoPlist[@"CFBundleExecutable"]?:infoPlist[@"CFBundleDisplayName"]?:@"executable"; 192 | NSString* principal_class = infoPlist[@"NSPrincipalClass"]; 193 | 194 | [[NSBundle bundleWithPath:bundlePath] load]; 195 | 196 | NSString* classRep = [NSString stringWithFormat:@"%@_%@", principal_class?:identifier, @"FlipConvert"]; 197 | setValueWithId(identifier, @"NSPrincipalClassRep", classRep); 198 | setValueWithId(identifier, @"CFBundleExecutable", executable); 199 | setValueWithId(identifier, @"BundlePath", bundlePath); 200 | setValueWithId(identifier, @"BundlePathRep", getPortedPathFromBundlePath(bundlePath)); 201 | 202 | alloc_class_with_Name(classRep.UTF8String); 203 | } 204 | 205 | 206 | NSMutableArray* bundlePathToMakeImage() 207 | { 208 | static __strong NSMutableArray* intanceArr; 209 | if(!intanceArr) { 210 | intanceArr = [[NSMutableArray alloc] init]; 211 | } 212 | return intanceArr; 213 | } 214 | 215 | 216 | static void bundlePathMakeImageNow() 217 | { 218 | BOOL needRespring = NO; 219 | for(NSString* bundlePath in bundlePathToMakeImage()) { 220 | NSString* portPath = getPortedPathFromBundlePath(bundlePath); 221 | if(access([portPath stringByAppendingPathComponent:@"Icon-on@2x.png"].UTF8String, F_OK) != 0) { 222 | NSString* glyphPDFOn = nil; 223 | if(access([bundlePath stringByAppendingPathComponent:@"glyph-modern-on.pdf"].UTF8String, F_OK) == 0) { 224 | glyphPDFOn = [bundlePath stringByAppendingPathComponent:@"glyph-modern-on.pdf"]; 225 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph-modern.pdf"].UTF8String, F_OK) == 0) { 226 | glyphPDFOn = [bundlePath stringByAppendingPathComponent:@"glyph-modern.pdf"]; 227 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph-on.pdf"].UTF8String, F_OK) == 0) { 228 | glyphPDFOn = [bundlePath stringByAppendingPathComponent:@"glyph-on.pdf"]; 229 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph.pdf"].UTF8String, F_OK) == 0) { 230 | glyphPDFOn = [bundlePath stringByAppendingPathComponent:@"glyph.pdf"]; 231 | } 232 | if(glyphPDFOn) { 233 | NSData* size_48x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOn, CGSizeMake(32, 32), YES)); // 48 234 | NSData* size_72x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOn, CGSizeMake(40, 40), YES)); // 72 235 | 236 | [size_48x writeToFile:[portPath stringByAppendingPathComponent:@"Icon-on@2x.png"] atomically:YES]; 237 | [size_72x writeToFile:[portPath stringByAppendingPathComponent:@"Icon-on@3x.png"] atomically:YES]; 238 | 239 | NSData* _size_48x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOn, CGSizeMake(32, 32), NO)); // 48 240 | NSData* _size_72x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOn, CGSizeMake(40, 40), NO)); // 72 241 | 242 | [_size_48x writeToFile:[portPath stringByAppendingPathComponent:@"SettingsIcon@2x.png"] atomically:YES]; 243 | [_size_72x writeToFile:[portPath stringByAppendingPathComponent:@"SettingsIcon@3x.png"] atomically:YES]; 244 | 245 | needRespring = YES; 246 | } 247 | NSString* glyphPDFOff = nil; 248 | if(access([bundlePath stringByAppendingPathComponent:@"glyph-modern-off.pdf"].UTF8String, F_OK) == 0) { 249 | glyphPDFOff = [bundlePath stringByAppendingPathComponent:@"glyph-modern-off.pdf"]; 250 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph-modern.pdf"].UTF8String, F_OK) == 0) { 251 | glyphPDFOff = [bundlePath stringByAppendingPathComponent:@"glyph-modern.pdf"]; 252 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph-off.pdf"].UTF8String, F_OK) == 0) { 253 | glyphPDFOff = [bundlePath stringByAppendingPathComponent:@"glyph-off.pdf"]; 254 | } else if(access([bundlePath stringByAppendingPathComponent:@"glyph.pdf"].UTF8String, F_OK) == 0) { 255 | glyphPDFOff = [bundlePath stringByAppendingPathComponent:@"glyph.pdf"]; 256 | } 257 | if(glyphPDFOff) { 258 | NSData* size_48x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOff, CGSizeMake(32, 32), YES)); // 48 259 | NSData* size_72x = UIImagePNGRepresentation(ImageFromPDFFileFlipConvert(glyphPDFOff, CGSizeMake(40, 40), YES)); // 72 260 | 261 | [size_48x writeToFile:[portPath stringByAppendingPathComponent:@"Icon-off@2x.png"] atomically:YES]; 262 | [size_72x writeToFile:[portPath stringByAppendingPathComponent:@"Icon-off@3x.png"] atomically:YES]; 263 | 264 | needRespring = YES; 265 | } 266 | } 267 | } 268 | if(needRespring) { 269 | system("killall SpringBoard"); 270 | } 271 | } 272 | 273 | 274 | static void port_bundle(NSString* bundlePath) 275 | { 276 | NSString* portPath = getPortedPathFromBundlePath(bundlePath); 277 | 278 | if(access(portPath.UTF8String, F_OK) == 0) { 279 | return; 280 | } 281 | 282 | system([NSString stringWithFormat:@"mkdir -p \"%@\"", portPath].UTF8String); 283 | system([NSString stringWithFormat:@"echo \"Ported\" >\"%@\"", [portPath stringByAppendingPathComponent:@"flag_ported_flipconvert"]].UTF8String); 284 | 285 | NSDictionary* infoOrigPlist = [[NSDictionary alloc] initWithContentsOfFile:[bundlePath stringByAppendingPathComponent:@"Info.plist"]]?:@{}; 286 | 287 | NSLog(@"infoOrigPlist[%@]: %@", [bundlePath stringByAppendingPathComponent:@"Info.plist"], infoOrigPlist); 288 | 289 | NSString* executableName = infoOrigPlist[@"CFBundleExecutable"]?:infoOrigPlist[@"CFBundleDisplayName"]?:@"executable"; 290 | 291 | system([NSString stringWithFormat:@"ln -s \"%@\" \"%@\"", @"/Library/MobileSubstrate/DynamicLibraries/z_FlipConvert.dylib", [portPath stringByAppendingPathComponent:executableName]].UTF8String); 292 | 293 | NSMutableDictionary* infoMut = [infoOrigPlist?:@{} mutableCopy]; 294 | infoMut[@"CFBundleIdentifier"] = infoOrigPlist[@"CFBundleIdentifier"];//[NSString stringWithFormat:@"%@_%@", @"FlipConvert", infoOrigPlist[@"CFBundleIdentifier"]]; 295 | 296 | infoMut[@"CFBundleExecutable"] = executableName; 297 | infoMut[@"CFBundleName"] = infoOrigPlist[@"CFBundleName"]?:executableName; 298 | 299 | infoMut[@"CFBundleDisplayName"] = infoOrigPlist[@"CFBundleDisplayName"]?:infoMut[@"CFBundleName"]; 300 | 301 | infoMut[@"NSPrincipalClass"] = [NSString stringWithFormat:@"%@_%@", infoOrigPlist[@"NSPrincipalClass"]?:infoMut[@"CFBundleIdentifier"], @"FlipConvert"]; 302 | 303 | infoMut[@"CFBundleDevelopmentRegion"] = @"English"; 304 | infoMut[@"CFBundleInfoDictionaryVersion"] = @"6.0"; 305 | infoMut[@"CFBundlePackageType"] = @"BNDL"; 306 | infoMut[@"CFBundleShortVersionString"] = @"1.0.0"; 307 | infoMut[@"CFBundleSignature"] = @"????"; 308 | infoMut[@"CFBundleVersion"] = @"1.0"; 309 | infoMut[@"DTPlatformName"] = @"iphoneos"; 310 | infoMut[@"MinimumOSVersion"] = @"3.0"; 311 | infoMut[@"CFBundleSupportedPlatforms"] = @[@"iPhoneOS"]; 312 | infoMut[@"UIDeviceFamily"] = @[@(1), @(2),]; 313 | 314 | [infoMut writeToFile:[portPath stringByAppendingPathComponent:@"Info.plist"] atomically:YES]; 315 | 316 | 317 | [bundlePathToMakeImage() addObject:bundlePath]; 318 | } 319 | 320 | %hook SpringBoard 321 | - (void)applicationDidFinishLaunching:(id)application 322 | { 323 | %orig; 324 | bundlePathMakeImageNow(); 325 | } 326 | %end 327 | 328 | __attribute__((constructor)) static void initialize_() 329 | { 330 | dlopen("/usr/lib/libflipswitch.dylib", RTLD_GLOBAL); 331 | dlopen("/Library/Flipswitch/libFlipswitchSpringBoard.dylib", RTLD_GLOBAL); 332 | 333 | %init; 334 | 335 | [[NSNotificationCenter defaultCenter] addObserverForName:@"FSSwitchPanelSwitchStateChangedNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { 336 | if(note) { 337 | NSDictionary* userD = [note userInfo]; 338 | NSString* idChange = userD[@"switchIdentifier"]; 339 | if(idChange) { 340 | FlipConvert_PlaceHolder* instaRep = getValueWithId(idChange, @"ClassRepAlloc"); 341 | if(instaRep) { 342 | [instaRep refreshState]; 343 | } 344 | } 345 | } 346 | }]; 347 | 348 | NSArray* fileBundles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Library/Switches/" error:nil]?:@[]; 349 | for(NSString* FileNow in fileBundles) { 350 | NSString* pathFile = [@"/Library/Switches/" stringByAppendingPathComponent:FileNow]; 351 | port_bundle(pathFile); 352 | allocForSwitchBundlePath(pathFile); 353 | } 354 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include theos/makefiles/common.mk 2 | 3 | TWEAK_NAME = z_FlipConvert 4 | z_FlipConvert_FILES = /mnt/d/codes/flipconvert/FlipConvert.xm 5 | z_FlipConvert_FRAMEWORKS = CydiaSubstrate Foundation UIKit CoreGraphics QuartzCore CoreImage CoreFoundation 6 | z_FlipConvert_PRIVATE_FRAMEWORKS = ControlCenterUIKit 7 | 8 | z_FlipConvert_LDFLAGS = -Wl,-segalign,4000 9 | 10 | export ARCHS = arm64 11 | z_FlipConvert_ARCHS = arm64 12 | 13 | include $(THEOS_MAKE_PATH)/tweak.mk 14 | 15 | 16 | all:: 17 | -------------------------------------------------------------------------------- /postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p /Library/ControlCenter/ 3 | mkdir -p /Library/ControlCenter/Bundles/ 4 | chown 0:0 /Library/ControlCenter/ 5 | chown 0:0 /Library/ControlCenter/Bundles/ 6 | chmod 777 /Library/ControlCenter/ 7 | chmod 777 /Library/ControlCenter/Bundles/ 8 | exit 0; -------------------------------------------------------------------------------- /postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | arrBundles=(/Library/ControlCenter/Bundles/*) 3 | for ((i=0; i<${#arrBundles[@]}; i++)); do 4 | if [ -f ${arrBundles[$i]}/flag_ported_flipconvert ]; then 5 | rm -rf ${arrBundles[$i]} 6 | fi 7 | done 8 | exit 0; --------------------------------------------------------------------------------