diff --git a/Anemone.h b/Anemone.h deleted file mode 100644 index 1a781b5..0000000 --- a/Anemone.h +++ /dev/null @@ -1,22 +0,0 @@ -// From: slack logs -// Usage to get icon badge: -// -// @interface SBIconBadgeView -// + (SBIconAccessoryImage *)_checkoutBackgroundImage; -// @end -// -// [UIImage imageNamed:@"SBBadgeBG.png"] -// -// Notes: -// Can convert to UIColor with +[UIColor colorWithPatternImage:] -// Needs tested. Heard bad reports about colorWithPatternImage: and memory usage -// - -@interface ANEMSettingsManager : NSObject { - NSArray *_themeSettings; -} -+ (instancetype)sharedManager; -- (NSArray *)themeSettings; -@end - -#define HAS_ANEMONE (objc_getClass("ANEMSettingsManager") != nil) diff --git a/Asphaleia.h b/Asphaleia.h new file mode 100644 index 0000000..46607bb --- /dev/null +++ b/Asphaleia.h @@ -0,0 +1,49 @@ +#import + +typedef NS_ENUM(NSInteger, ASAuthenticationAlertType) { + ASAuthenticationAlertAppArranging, + ASAuthenticationAlertSwitcher, + ASAuthenticationAlertSpotlight, + ASAuthenticationAlertPowerDown, + ASAuthenticationAlertControlCentre, + ASAuthenticationAlertControlPanel, + ASAuthenticationAlertDynamicSelection, + ASAuthenticationAlertPhotos, + ASAuthenticationAlertSettingsPanel, + ASAuthenticationAlertFlipswitch +}; + +typedef NS_ENUM(NSInteger, ASAuthenticationType) { + ASAuthenticationItem, + ASAuthenticationFunction, + ASAuthenticationSecurityMod +}; + +typedef void (^ASCommonAuthenticationHandler) (BOOL wasCancelled); + +@interface ASCommon : NSObject { + ASCommonAuthenticationHandler authHandler; +} ++ (instancetype)sharedInstance; +- (BOOL)displayingAuthAlert; +- (BOOL)authenticateAppWithDisplayIdentifier:(NSString *)appIdentifier customMessage:(NSString *)customMessage dismissedHandler:(ASCommonAuthenticationHandler)handler; +- (BOOL)authenticateFunction:(ASAuthenticationAlertType)alertType dismissedHandler:(ASCommonAuthenticationHandler)handler; + +@end + +#define LOAD_ASPHALEIA if ([NSFileManager.defaultManager fileExistsAtPath:@"/usr/lib/libasphaleiaui.dylib"]) dlopen("/usr/lib/libasphaleiaui.dylib", RTLD_LAZY); + +#define HAS_ASPHALEIA (objc_getClass("ASCommon") != nil) +#define IF_ASPHALEIA if (HAS_ASPHALEIA) + +#define ASPHALEIA_AUTHENTICATE_APP(ident, success, failure_) \ + BOOL isAppProtected = [[objc_getClass("ASCommon") sharedInstance] authenticateAppWithDisplayIdentifier:ident customMessage:nil dismissedHandler:^(BOOL wasCancelled) { \ + if (!wasCancelled) { \ + success(); \ + } else { \ + failure_(); \ + } \ + }]; \ + if (!isAppProtected) { \ + success(); \ + } diff --git a/Asphaleia2.h b/Asphaleia2.h deleted file mode 100644 index 3b69d4f..0000000 --- a/Asphaleia2.h +++ /dev/null @@ -1,43 +0,0 @@ -#import - -// https://gist.github.com/evilGoldfish/49753c4aa247b727453e - -typedef NS_ENUM(NSInteger, ASAuthenticationAlertType) { - ASAuthenticationAlertAppArranging, - ASAuthenticationAlertSwitcher, - ASAuthenticationAlertSpotlight, - ASAuthenticationAlertPowerDown, - ASAuthenticationAlertControlCentre, - ASAuthenticationAlertControlPanel, - ASAuthenticationAlertPhotos, - ASAuthenticationAlertSettingsPanel, - ASAuthenticationAlertFlipswitch -}; - -typedef void (^ASCommonAuthenticationHandler) (BOOL wasCancelled); - -@interface ASCommon : NSObject { - ASCommonAuthenticationHandler authHandler; -} -+(instancetype)sharedInstance; --(UIAlertView *)currentAuthAlert; --(BOOL)authenticateAppWithDisplayIdentifier:(NSString *)appIdentifier customMessage:(NSString *)customMessage dismissedHandler:(ASCommonAuthenticationHandler)handler; --(BOOL)authenticateFunction:(ASAuthenticationAlertType)alertType dismissedHandler:(ASCommonAuthenticationHandler)handler; - -@end - -#define LOAD_ASPHALEIA if ([NSFileManager.defaultManager fileExistsAtPath:@"/usr/lib/libasphaleiaui.dylib"]) dlopen("/usr/lib/libasphaleiaui.dylib", RTLD_LAZY); - -#define HAS_ASPHALEIA2 (objc_getClass("ASCommon") != nil) -#define IF_ASPHALEIA2 if (HAS_ASPHALEIA2) - -#define ASPHALEIA2_AUTHENTICATE_APP(ident, success, failure_) \ - BOOL isAppProtected = [[objc_getClass("ASCommon") sharedInstance] authenticateAppWithDisplayIdentifier:ident customMessage:nil dismissedHandler:^(BOOL wasCancelled) { \ - if (!wasCancelled) \ - success(); \ - else \ - failure_(); \ - }]; \ - if (!isAppProtected) { \ - success(); \ - } \ No newline at end of file diff --git a/Backgrounding/BackgroundModeTogglerActivator.xm b/Backgrounding/BackgroundModeTogglerActivator.xm index 44e5c24..426f7e1 100644 --- a/Backgrounding/BackgroundModeTogglerActivator.xm +++ b/Backgrounding/BackgroundModeTogglerActivator.xm @@ -1,65 +1,52 @@ #import +#import "UIAlertController+Window.h" #import "RABackgrounder.h" #import "RASettings.h" -@interface RAActivatorBackgrounderToggleModeListener : NSObject +@interface RAActivatorBackgrounderToggleModeListener : NSObject @end static RAActivatorBackgrounderToggleModeListener *sharedInstance$RAActivatorBackgrounderToggleModeListener; @implementation RAActivatorBackgrounderToggleModeListener -- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event -{ - SBApplication *app = [UIApplication sharedApplication]._accessibilityFrontMostApplication; +- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event { + SBApplication *app = [UIApplication sharedApplication]._accessibilityFrontMostApplication; - if (!app) - return; + if (!app) { + return; + } - NSString *friendlyCurrentBackgroundMode = FriendlyNameForBackgroundMode((RABackgroundMode)[RABackgrounder.sharedInstance backgroundModeForIdentifier:app.bundleIdentifier]); + BOOL dismissApp = [[%c(RASettings) sharedInstance] exitAppAfterUsingActivatorAction]; - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"MULTIPLEXER") message:[NSString stringWithFormat:LOCALIZE(@"BACKGROUNDER_POPUP_SWITCHER_TEXT"),app.displayName,friendlyCurrentBackgroundMode] delegate:self cancelButtonTitle:LOCALIZE(@"CANCEL") otherButtonTitles:LOCALIZE(@"FORCE_FOREGROUND"), LOCALIZE(@"NATIVE"), LOCALIZE(@"SUSPEND_IMMEDIATELY"), LOCALIZE(@"DISABLE"), nil]; + NSString *friendlyCurrentBackgroundMode = FriendlyNameForBackgroundMode((RABackgroundMode)[RABackgrounder.sharedInstance backgroundModeForIdentifier:app.bundleIdentifier]); - [alert show]; -} + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"MULTIPLEXER") message:[NSString stringWithFormat:LOCALIZE(@"BACKGROUNDER_POPUP_SWITCHER_TEXT"),app.displayName,friendlyCurrentBackgroundMode] preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:LOCALIZE(@"FORCE_FOREGROUND") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:app andCloseForegroundApp:dismissApp]; + }]]; + + [alert addAction:[UIAlertAction actionWithTitle:LOCALIZE(@"NATIVE") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeNative forApplication:app andCloseForegroundApp:dismissApp]; + }]]; -- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - SBApplication *app = UIApplication.sharedApplication._accessibilityFrontMostApplication; - if (!app) - return; + [alert addAction:[UIAlertAction actionWithTitle:LOCALIZE(@"SUSPEND_IMMEDIATELY") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeSuspendImmediately forApplication:app andCloseForegroundApp:dismissApp]; + }]]; - BOOL dismissApp = [[%c(RASettings) sharedInstance] exitAppAfterUsingActivatorAction]; + [alert addAction:[UIAlertAction actionWithTitle:LOCALIZE(@"DISABLE") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeForceNone forApplication:app andCloseForegroundApp:dismissApp]; + }]]; - if (buttonIndex == [alertView cancelButtonIndex]) - { - return; - } - if (buttonIndex == 1) - { - // Force foreground - [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:app andCloseForegroundApp:dismissApp]; - } - else if (buttonIndex == 2) - { - // Native - [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeNative forApplication:app andCloseForegroundApp:dismissApp]; - } - else if (buttonIndex == 3) - { - [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeSuspendImmediately forApplication:app andCloseForegroundApp:dismissApp]; - } - else// if (buttonIndex == 3) - { - [RABackgrounder.sharedInstance temporarilyApplyBackgroundingMode:RABackgroundModeForceNone forApplication:app andCloseForegroundApp:dismissApp]; - } + [alert addAction:[UIAlertAction actionWithTitle:LOCALIZE(@"CANCEL") style:UIAlertActionStyleDefault handler:nil]]; + + [alert show]; } @end -%ctor -{ - if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.springboard"]) - { - sharedInstance$RAActivatorBackgrounderToggleModeListener = [[RAActivatorBackgrounderToggleModeListener alloc] init]; - [[%c(LAActivator) sharedInstance] registerListener:sharedInstance$RAActivatorBackgrounderToggleModeListener forName:@"com.efrederickson.reachapp.backgrounder.togglemode"]; - } -} \ No newline at end of file +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance$RAActivatorBackgrounderToggleModeListener = [[RAActivatorBackgrounderToggleModeListener alloc] init]; + [[%c(LAActivator) sharedInstance] registerListener:sharedInstance$RAActivatorBackgrounderToggleModeListener forName:@"com.efrederickson.reachapp.backgrounder.togglemode"]; +} diff --git a/Backgrounding/IconIndicator.xm b/Backgrounding/IconIndicator.xm index 2981f19..6c72e0a 100644 --- a/Backgrounding/IconIndicator.xm +++ b/Backgrounding/IconIndicator.xm @@ -3,7 +3,7 @@ #import #import #import "ColorBadges.h" -#import "Anemone.h" +#import NSMutableDictionary *indicatorStateDict = [[[NSMutableDictionary alloc] init] retain]; #define SET_INFO_(x, y) indicatorStateDict[x] = [NSNumber numberWithInt:y] @@ -12,68 +12,70 @@ NSMutableDictionary *indicatorStateDict = [[[NSMutableDictionary alloc] init] re #define GET_INFO (self.icon && self.icon.application ? GET_INFO_(self.icon.application.bundleIdentifier) : RAIconIndicatorViewInfoNone) -NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) -{ +NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) { NSString *ret = @""; - if (info & RAIconIndicatorViewInfoNone) + if (info & RAIconIndicatorViewInfoNone) { return nil; + } - if ([[%c(RASettings) sharedInstance] showNativeStateIconIndicators] && (info & RAIconIndicatorViewInfoNative)) + if ([[%c(RASettings) sharedInstance] showNativeStateIconIndicators] && (info & RAIconIndicatorViewInfoNative)) { ret = [ret stringByAppendingString:@"N"]; - - if (info & RAIconIndicatorViewInfoForced) + } + + if (info & RAIconIndicatorViewInfoForced) { ret = [ret stringByAppendingString:@"F"]; + } //if (info & RAIconIndicatorViewInfoForceDeath) // [ret appendString:@"D"]; - if (info & RAIconIndicatorViewInfoSuspendImmediately) + if (info & RAIconIndicatorViewInfoSuspendImmediately) { ret = [ret stringByAppendingString:@"ll"]; - - if (info & RAIconIndicatorViewInfoUnkillable) + } + + if (info & RAIconIndicatorViewInfoUnkillable) { ret = [ret stringByAppendingString:@"U"]; + } - if (info & RAIconIndicatorViewInfoUnlimitedBackgroundTime) + if (info & RAIconIndicatorViewInfoUnlimitedBackgroundTime) { ret = [ret stringByAppendingString:@"∞"]; + } return ret; } %hook SBIconView -%new -(void) RA_updateIndicatorView:(RAIconIndicatorViewInfo)info -{ +%property (nonatomic, assign) BOOL RA_isIconIndicatorInhibited; +%new - (void)RA_updateIndicatorView:(RAIconIndicatorViewInfo)info { @autoreleasepool { - if (info == RAIconIndicatorViewInfoTemporarilyInhibit || info == RAIconIndicatorViewInfoInhibit) - { + if (info == RAIconIndicatorViewInfoTemporarilyInhibit || info == RAIconIndicatorViewInfoInhibit) { [[self viewWithTag:9962] removeFromSuperview]; [self RA_setIsIconIndicatorInhibited:YES]; - if (info == RAIconIndicatorViewInfoTemporarilyInhibit) - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + if (info == RAIconIndicatorViewInfoTemporarilyInhibit) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [self RA_setIsIconIndicatorInhibited:NO showAgainImmediately:NO]; }); + } return; - } - else if (info == RAIconIndicatorViewInfoUninhibit) - { + } else if (info == RAIconIndicatorViewInfoUninhibit) { [self RA_setIsIconIndicatorInhibited:NO showAgainImmediately:NO]; } NSString *text = stringFromIndicatorInfo(info); if ( - [self RA_isIconIndicatorInhibited] || - (text == nil || text.length == 0) || // OR info == RAIconIndicatorViewInfoNone - (self.icon == nil || self.icon.application == nil || self.icon.application.isRunning == NO || ![RABackgrounder.sharedInstance shouldShowIndicatorForIdentifier:self.icon.application.bundleIdentifier]) || - [[%c(RASettings) sharedInstance] backgrounderEnabled] == NO) + [self RA_isIconIndicatorInhibited] || + (!text || text.length == 0) || // OR info == RAIconIndicatorViewInfoNone + (!self.icon || !self.icon.application || !self.icon.application.isRunning || ![RABackgrounder.sharedInstance shouldShowIndicatorForIdentifier:self.icon.application.bundleIdentifier]) || + ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { [[self viewWithTag:9962] removeFromSuperview]; return; } UILabel *badge = (UILabel*)[self viewWithTag:9962]; - if (!badge) - { + if (!badge) { badge = [[[UILabel alloc] init] retain]; badge.tag = 9962; @@ -85,47 +87,40 @@ NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) badge.backgroundColor = GET_COLORBADGES_COLOR(self.icon, THEMED(backgroundingIndicatorBackgroundColor)); //badge.textColor = GET_ACCEPTABLE_TEXT_COLOR(badge.backgroundColor, THEMED(backgroundingIndicatorTextColor)); - if (HAS_COLORBADGES && [%c(ColorBadges) isEnabled]) - { + if (HAS_COLORBADGES && [%c(ColorBadges) isEnabled]) { int bgColor = RGBFromUIColor(badge.backgroundColor); int txtColor = RGBFromUIColor(THEMED(backgroundingIndicatorTextColor)); - if ([%c(ColorBadges) isDarkColor:bgColor]) - { + if ([%c(ColorBadges) isDarkColor:bgColor]) { // dark color - if ([%c(ColorBadges) isDarkColor:txtColor]) - { + if ([%c(ColorBadges) isDarkColor:txtColor]) { // dark + dark badge.textColor = [UIColor whiteColor]; - } - else - { + } else { // dark + light badge.textColor = THEMED(backgroundingIndicatorTextColor); } - } - else - { + } else { // light color - if ([%c(ColorBadges) isDarkColor:txtColor]) - { + if ([%c(ColorBadges) isDarkColor:txtColor]) { // light + dark badge.textColor = THEMED(backgroundingIndicatorTextColor); - } - else - { + } else { //light + light badge.textColor = [UIColor blackColor]; } } - } - else - { + + if ([%c(ColorBadges) areBordersEnabled]) { + badge.layer.borderColor = badge.textColor.CGColor; + badge.layer.borderWidth = 1.0; + } + } else { badge.textColor = THEMED(backgroundingIndicatorTextColor); } + UIImage *bgImage = [%c(SBIconBadgeView) _checkoutBackgroundImage]; - if (HAS_ANEMONE && [[[%c(ANEMSettingsManager) sharedManager] themeSettings] containsObject:@"ModernBadges"]) - { + if (%c(ANEMSettingsManager) && [[[%c(ANEMSettingsManager) sharedManager] themeSettings] containsObject:@"ModernBadges"]) { badge.backgroundColor = [UIColor colorWithPatternImage:bgImage]; } @@ -137,13 +132,11 @@ NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) badge.layer.cornerRadius = MAX(badge.frame.size.width, badge.frame.size.height) / 2.0; } - if (HAS_ANEMONE && [[[%c(ANEMSettingsManager) sharedManager] themeSettings] containsObject:@"ModernBadges"]) - { + if (%c(ANEMSettingsManager) && [[[%c(ANEMSettingsManager) sharedManager] themeSettings] containsObject:@"ModernBadges"]) { UIImageView *textImageView = (UIImageView*)[badge viewWithTag:42]; - if (!textImageView) - { - CGFloat padding = [objc_getClass("SBIconBadgeView") _textPadding]; - + if (!textImageView) { + CGFloat padding = [%c(SBIconBadgeView) _textPadding]; + textImageView = [[UIImageView alloc] initWithFrame:CGRectMake(padding, padding, badge.frame.size.width - (padding * 2.0), badge.frame.size.height - (padding * 2.0))]; textImageView.center = CGPointMake((badge.frame.size.width / 2.0) + [%c(SBIconBadgeView) _textOffset].x, (badge.frame.size.height / 2.0) + [%c(SBIconBadgeView) _textOffset].y); textImageView.tag = 42; @@ -152,39 +145,34 @@ NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) UIImage *textImage = [%c(SBIconBadgeView) _checkoutImageForText:text highlighted:NO]; textImageView.image = textImage; - } - else + } else { [badge performSelectorOnMainThread:@selector(setText:) withObject:text waitUntilDone:YES]; + } SET_INFO(info); } } -%new -(void) RA_updateIndicatorViewWithExistingInfo -{ +%new - (void)RA_updateIndicatorViewWithExistingInfo { //if ([self viewWithTag:9962]) - [self RA_updateIndicatorView:GET_INFO]; + [self RA_updateIndicatorView:GET_INFO]; } -%new -(void) RA_setIsIconIndicatorInhibited:(BOOL)value -{ +%new - (void)RA_setIsIconIndicatorInhibited:(BOOL)value { [self RA_setIsIconIndicatorInhibited:value showAgainImmediately:YES]; } -%new -(void) RA_setIsIconIndicatorInhibited:(BOOL)value showAgainImmediately:(BOOL)value2 -{ - objc_setAssociatedObject(self, @selector(RA_isIconIndicatorInhibited), value ? (id)kCFBooleanTrue : (id)kCFBooleanFalse, OBJC_ASSOCIATION_ASSIGN); - if (value2 || value == YES) - [self RA_updateIndicatorViewWithExistingInfo]; +%new - (void)RA_setIsIconIndicatorInhibited:(BOOL)value showAgainImmediately:(BOOL)value2 { + self.RA_isIconIndicatorInhibited = value; + if (value2 || value) { + [self RA_updateIndicatorViewWithExistingInfo]; + } } --(void) dealloc -{ - if (self) - { +- (void)dealloc { + if (self) { UIView *view = [self viewWithTag:9962]; - if (view) - { + if (view) { [view removeFromSuperview]; } } @@ -192,31 +180,21 @@ NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) %orig; } -%new -(BOOL) RA_isIconIndicatorInhibited -{ - return [objc_getAssociatedObject(self, @selector(RA_isIconIndicatorInhibited)) boolValue]; -} - --(void) layoutSubviews -{ - %orig; +- (void)layoutSubviews { + %orig; - //if ([self viewWithTag:9962] == nil) - // this is back in, again, to try to fix "Smartclose badges show randomly in the app switcher for random applications even though I only have one app smart closed" + //if ([self viewWithTag:9962] == nil) + // this is back in, again, to try to fix "Smartclose badges show randomly in the app switcher for random applications even though I only have one app smart closed" // [self RA_updateIndicatorView:GET_INFO]; } -- (void)setIsEditing:(_Bool)arg1 animated:(_Bool)arg2 -{ +- (void)setIsEditing:(_Bool)arg1 animated:(_Bool)arg2 { %orig; - if (arg1) - { + if (arg1) { // inhibit icon indicator [self RA_setIsIconIndicatorInhibited:YES]; - } - else - { + } else { [self RA_setIsIconIndicatorInhibited:NO]; } } @@ -225,127 +203,72 @@ NSString *stringFromIndicatorInfo(RAIconIndicatorViewInfo info) NSMutableDictionary *lsbitems = [[[NSMutableDictionary alloc] init] retain]; %hook SBApplication - -/* - -TODO: fix this crash - -Last Exception Backtrace: -0 CoreFoundation 0x273cefea 0x272c7000 + 0x107fea // __exceptionPreprocess + 0x7a -1 libobjc.A.dylib 0x35a72c86 0x35a6c000 + 0x6c86 // objc_exception_throw + 0x22 -2 CoreFoundation 0x273d4404 0x272c7000 + 0x10d404 // -[NSObject(NSObject) doesNotRecognizeSelector:] + 0xb8 -3 + ReachApp.dylib 0x0665540a 0x065d7000 + 0x7e40a // Logos hook for -[NSObject(_ungrouped) doesNotRecognizeSelector:](NSObject*, objc_selector*, objc_selector) + 0x1b2 -4 CoreFoundation 0x273d2322 0x272c7000 + 0x10b322 // ___forwarding___ + 0x2c6 -5 CoreFoundation 0x27301e74 0x272c7000 + 0x3ae74 // _CF_forwarding_prep_0 + 0x14 -6 + ReachAppBackgrounding.dylib 0x0644a252 0x06442000 + 0x8252 // Logos hook for -[SBApplication(_ungrouped) RA_addStatusBarIconForSelfIfOneDoesNotExist](SBApplication*, objc_selector*) + 0x76 -7 + ReachAppBackgrounding.dylib 0x0644a8b6 0x06442000 + 0x88b6 // Logos hook for -[SBApplication(_ungrouped) setApplicationState:](SBApplication*, objc_selector*, unsigned int) + 0x156 -8 libdispatch.dylib 0x360032de 0x36002000 + 0x12de // _dispatch_call_block_and_release + 0x6 -9 libdispatch.dylib 0x360032ca 0x36002000 + 0x12ca // _dispatch_client_callout + 0x12 -10 libdispatch.dylib 0x36006d2a 0x36002000 + 0x4d2a // _dispatch_main_queue_callback_4CF + 0x52e -11 CoreFoundation 0x27394604 0x272c7000 + 0xcd604 // __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 0x4 -12 CoreFoundation 0x27392d04 0x272c7000 + 0xcbd04 // __CFRunLoopRun + 0x5e4 -13 CoreFoundation 0x272df1fc 0x272c7000 + 0x181fc // CFRunLoopRunSpecific + 0x1d8 -14 CoreFoundation 0x272df00e 0x272c7000 + 0x1800e // CFRunLoopRunInMode + 0x66 -15 GraphicsServices 0x2edb01fc 0x2eda7000 + 0x91fc // GSEventRunModal + 0x84 -16 UIKit 0x2aaaba04 0x2aa3c000 + 0x6fa04 // UIApplicationMain + 0x59c -17 + FolderCloser.dylib 0x06337fe8 0x06337000 + 0xfe8 // my_UIApplicationMainX + 0x140 -18 SpringBoard (*) 0x0007f296 0x00077000 + 0x8296 // 0x00007ae8 + 0x7ae -19 libdyld.dylib 0x36024aaa 0x36023000 + 0x1aaa // tlv_initializer + 0x2 - -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] doesNotRecognizeSelector: selector 'objectForKey:' on class '__NSCFString' (image: /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation) -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] Obtained 10 stack frames: -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 0 ReachApp.dylib 0x06655379 _ZL59_logos_method$_ungrouped$NSObject$doesNotRecognizeSelector$P8NSObjectP13objc_selectorS1_ + 288 -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 1 CoreFoundation 0x273d2327 + 714 -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 2 CoreFoundation 0x27301e78 _CF_forwarding_prep_0 + 24 -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 3 ReachAppBackgrounding.dylib 0x0644a257 _ZL82_logos_method$_ungrouped$SBApplication$RA_addStatusBarIconForSelfIfOneDoesNotExistP13SBApplicationP13objc_selector + 122 -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 4 ReachAppBackgrounding.dylib 0x0644a8bb _ZL59_logos_method$_ungrouped$SBApplication$setApplicationState$P13SBApplicationP13objc_selectorj + 346 -Tue Sep 8 12:44:18 2015: SpringBoard (com.apple.springboard): [ReachApp] 5 libdispatch.dylib 0x360032e3 + 10 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): [ReachApp] 6 libdispatch.dylib 0x360032cf + 22 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): [ReachApp] 7 libdispatch.dylib 0x36006d2f _dispatch_main_queue_callback_4CF + 1330 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): [ReachApp] 8 CoreFoundation 0x27394609 + 8 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): [ReachApp] 9 CoreFoundation 0x27392d09 + 1512 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): -[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x1d50e650 -Tue Sep 8 12:44:19 2015: SpringBoard (com.apple.springboard): *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x1d50e650' -*** First throw call stack: -(0x273cefef 0x35a72c8b 0x273d4409 0x665540f 0x273d2327 0x27301e78 0x644a257 0x644a8bb 0x360032e3 0x360032cf 0x36006d2f 0x27394609 0x27392d09 0x272df201 0x272df013 0x2edb0201 0x2aaaba09 0x6337fec 0x7f29b 0x36024aaf) - -FIXED?: Forgot to -retain the dictionary. (It was autoreleased i believe?) - -*/ -%new -(void) RA_addStatusBarIconForSelfIfOneDoesNotExist -{ +%new - (void)RA_addStatusBarIconForSelfIfOneDoesNotExist { #if DEBUG - if ([lsbitems respondsToSelector:@selector(objectForKey:)] == NO) - { - NSLog(@"[ReachApp] ERROR: lsbitems is not NSDictionary it is %s", class_getName(lsbitems.class)); + if (![lsbitems respondsToSelector:@selector(objectForKey:)]) { + LogError(@"ERROR: lsbitems is not NSDictionary it is %s", class_getName(lsbitems.class)); //@throw [NSException exceptionWithName:@"OH POOP" reason:@"Expected NSDictionary" userInfo:nil]; } #endif - if (objc_getClass("LSStatusBarItem") && [lsbitems objectForKey:self.bundleIdentifier] == nil && [RABackgrounder.sharedInstance shouldShowStatusBarIconForIdentifier:self.bundleIdentifier]) - { - if ([[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] containsObject:self.bundleIdentifier]) - { + BOOL homescreenMapCheck = [%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)] && [[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] containsObject:self.bundleIdentifier]; + BOOL homescreenIconViewMapCheck = [[[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] visibleIconIdentifiers] containsObject:self.bundleIdentifier]; + + if (%c(LSStatusBarItem) && ![lsbitems objectForKey:self.bundleIdentifier] && [RABackgrounder.sharedInstance shouldShowStatusBarIconForIdentifier:self.bundleIdentifier]) { + if (homescreenMapCheck || homescreenIconViewMapCheck) { RAIconIndicatorViewInfo info = [RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:self.bundleIdentifier]; BOOL native = (info & RAIconIndicatorViewInfoNative); - if ((info & RAIconIndicatorViewInfoNone) == 0 && (native == NO || [[%c(RASettings) sharedInstance] shouldShowStatusBarNativeIcons])) - { - LSStatusBarItem *item = [[%c(LSStatusBarItem) alloc] initWithIdentifier:[NSString stringWithFormat:@"multiplexer-%@",self.bundleIdentifier] alignment:StatusBarAlignmentLeft]; - if ([item customViewClass] == nil) - item.customViewClass = @"RAAppIconStatusBarIconView"; - item.imageName = [NSString stringWithFormat:@"multiplexer-%@",self.bundleIdentifier]; - lsbitems[self.bundleIdentifier] = item; - } - } + if ((info & RAIconIndicatorViewInfoNone) == 0 && (!native || [[%c(RASettings) sharedInstance] shouldShowStatusBarNativeIcons])) { + LSStatusBarItem *item = [[%c(LSStatusBarItem) alloc] initWithIdentifier:[NSString stringWithFormat:@"multiplexer-%@",self.bundleIdentifier] alignment:StatusBarAlignmentLeft]; + if (![item customViewClass]) { + item.customViewClass = @"RAAppIconStatusBarIconView"; + } + item.imageName = [NSString stringWithFormat:@"multiplexer-%@",self.bundleIdentifier]; + lsbitems[self.bundleIdentifier] = item; + } + } } } -- (void)setApplicationState:(unsigned int)arg1 -{ - %orig; - - if (self.isRunning == NO) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:RAIconIndicatorViewInfoNone]; - //SET_INFO_(self.bundleIdentifier, RAIconIndicatorViewInfoNone); - [lsbitems removeObjectForKey:self.bundleIdentifier]; - } - else - { - if ([self respondsToSelector:@selector(RA_addStatusBarIconForSelfIfOneDoesNotExist)]) - [self performSelector:@selector(RA_addStatusBarIconForSelfIfOneDoesNotExist)]; +- (void)setApplicationState:(unsigned int)arg1 { + %orig; + + if (!self.isRunning) { + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:RAIconIndicatorViewInfoNone]; + //SET_INFO_(self.bundleIdentifier, RAIconIndicatorViewInfoNone); + [lsbitems removeObjectForKey:self.bundleIdentifier]; + } else { + if ([self respondsToSelector:@selector(RA_addStatusBarIconForSelfIfOneDoesNotExist)]) { + [self performSelector:@selector(RA_addStatusBarIconForSelfIfOneDoesNotExist)]; + } [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:self.bundleIdentifier]]; SET_INFO_(self.bundleIdentifier, [RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:self.bundleIdentifier]); - } + } } -%new +(void) RA_clearAllStatusBarIcons -{ +%new + (void)RA_clearAllStatusBarIcons { [lsbitems removeAllObjects]; } -- (void)didAnimateActivation -{ +- (void)didAnimateActivation { //[RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:RAIconIndicatorViewInfoUninhibit]; [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:RAIconIndicatorViewInfoTemporarilyInhibit]; %orig; } -- (void)willAnimateActivation -{ +- (void)willAnimateActivation { [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:RAIconIndicatorViewInfoInhibit]; %orig; } %end %hook SBIconViewMap -- (id) _iconViewForIcon:(unsafe_id)arg1 -{ - SBIconView *iconView = %orig; +- (id)_iconViewForIcon:(unsafe_id)arg1 { + SBIconView *iconView = %orig; - [iconView RA_updateIndicatorViewWithExistingInfo]; - return iconView; + [iconView RA_updateIndicatorViewWithExistingInfo]; + return iconView; } %end @@ -357,24 +280,23 @@ FIXED?: Forgot to -retain the dictionary. (It was autoreleased i believe?) @interface UIStatusBarCustomItem : UIStatusBarItem @end -inline NSString *getAppNameFromIndicatorName(NSString *indicatorName) -{ +inline NSString *getAppNameFromIndicatorName(NSString *indicatorName) { return [indicatorName substringFromIndex:(@"multiplexer-").length]; } %subclass RAAppIconStatusBarIconView : UIStatusBarCustomItemView --(id) contentsImage -{ +- (id)contentsImage { UIImage *img = [ALApplicationList.sharedApplicationList iconOfSize:15 forDisplayIdentifier:getAppNameFromIndicatorName(self.item.indicatorName)]; - return [_UILegibilityImageSet imageFromImage:img withShadowImage:img]; + return [_UILegibilityImageSet imageFromImage:img withShadowImage:img]; +} + +- (CGFloat)standardPadding { + return 4; } --(CGFloat) standardPadding { return 4; } %end %hook UIStatusBarCustomItem --(NSUInteger) leftOrder -{ - if ([self.indicatorName hasPrefix:@"multiplexer-"]) - { +- (NSUInteger)leftOrder { + if ([self.indicatorName hasPrefix:@"multiplexer-"]) { return 7; // Shows just after vpn, before the loading/sync indicator } return %orig; @@ -382,10 +304,8 @@ inline NSString *getAppNameFromIndicatorName(NSString *indicatorName) %end %end -%ctor -{ - if ([%c(RASettings) isLibStatusBarInstalled]) - { +%ctor { + if ([%c(RASettings) isLibStatusBarInstalled]) { %init(libstatusbar); } %init; diff --git a/Backgrounding/Makefile b/Backgrounding/Makefile index 70ef84a..d16212c 100644 --- a/Backgrounding/Makefile +++ b/Backgrounding/Makefile @@ -1,8 +1,7 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../ -I../Theming/ -CFLAGS += -fno-objc-arc -LDFLAGS += -Wl,-segalign,4000 +CFLAGS = -I../ -I../Theming/ -O2 +CFLAGS += -fobjc-arc include $(THEOS)/makefiles/common.mk @@ -11,6 +10,9 @@ ReachAppBackgrounding_FILES = $(wildcard *.xm) $(wildcard *.mm) $(wildcard *.m) ReachAppBackgrounding_FRAMEWORKS = UIKit CoreGraphics ReachAppBackgrounding_LIBRARIES = applist +IconIndicator.xm_CFLAGS = -fno-objc-arc +SpringBoard_UIAppCustomBackgroundModes.xm_CFLAGS = -fno-objc-arc + include $(THEOS_MAKE_PATH)/tweak.mk after-install:: diff --git a/Backgrounding/RABackgrounder.h b/Backgrounding/RABackgrounder.h index 8602c15..de6d707 100644 --- a/Backgrounding/RABackgrounder.h +++ b/Backgrounding/RABackgrounder.h @@ -1,56 +1,56 @@ #import "headers.h" -enum RABackgroundMode { - RABackgroundModeNative = 1, - RABackgroundModeForceNativeForOldApps = 2, - RABackgroundModeForcedForeground = 3, - RABackgroundModeForceNone = 4, - RABackgroundModeSuspendImmediately = 5, - RABackgroundModeUnlimitedBackgroundingTime = 6, +typedef NS_ENUM(NSInteger, RABackgroundMode) { + RABackgroundModeNative = 1, + RABackgroundModeForceNativeForOldApps = 2, + RABackgroundModeForcedForeground = 3, + RABackgroundModeForceNone = 4, + RABackgroundModeSuspendImmediately = 5, + RABackgroundModeUnlimitedBackgroundingTime = 6, }; -enum RAIconIndicatorViewInfo { - RAIconIndicatorViewInfoNone = 0, - RAIconIndicatorViewInfoNative = 1, - RAIconIndicatorViewInfoForced = 2, - RAIconIndicatorViewInfoSuspendImmediately = 4, +typedef NS_ENUM(NSInteger, RAIconIndicatorViewInfo) { + RAIconIndicatorViewInfoNone = 0, + RAIconIndicatorViewInfoNative = 1, + RAIconIndicatorViewInfoForced = 2, + RAIconIndicatorViewInfoSuspendImmediately = 4, - RAIconIndicatorViewInfoUnkillable = 8, - RAIconIndicatorViewInfoForceDeath = 16, + RAIconIndicatorViewInfoUnkillable = 8, + RAIconIndicatorViewInfoForceDeath = 16, - RAIconIndicatorViewInfoUnlimitedBackgroundTime = 32, + RAIconIndicatorViewInfoUnlimitedBackgroundTime = 32, - RAIconIndicatorViewInfoTemporarilyInhibit = 1024, - RAIconIndicatorViewInfoInhibit = 2048, - RAIconIndicatorViewInfoUninhibit = 4096, + RAIconIndicatorViewInfoTemporarilyInhibit = 1024, + RAIconIndicatorViewInfoInhibit = 2048, + RAIconIndicatorViewInfoUninhibit = 4096, }; NSString *FriendlyNameForBackgroundMode(RABackgroundMode mode); @interface RABackgrounder : NSObject -+(id) sharedInstance; ++ (instancetype) sharedInstance; --(BOOL) shouldAutoLaunchApplication:(NSString*)identifier; --(BOOL) shouldAutoRelaunchApplication:(NSString*)identifier; +- (BOOL)shouldAutoLaunchApplication:(NSString*)identifier; +- (BOOL)shouldAutoRelaunchApplication:(NSString*)identifier; --(BOOL) shouldKeepInForeground:(NSString*)identifier; --(BOOL) shouldSuspendImmediately:(NSString*)identifier; +- (BOOL)shouldKeepInForeground:(NSString*)identifier; +- (BOOL)shouldSuspendImmediately:(NSString*)identifier; --(BOOL) killProcessOnExit:(NSString*)identifier; --(BOOL) shouldRemoveFromSwitcherWhenKilledOnExit:(NSString*)identifier; --(BOOL) preventKillingOfIdentifier:(NSString*)identifier; --(NSInteger) backgroundModeForIdentifier:(NSString*)identifier; --(BOOL) hasUnlimitedBackgroundTime:(NSString*)identifier; +- (BOOL)killProcessOnExit:(NSString*)identifier; +- (BOOL)shouldRemoveFromSwitcherWhenKilledOnExit:(NSString*)identifier; +- (BOOL)preventKillingOfIdentifier:(NSString*)identifier; +- (NSInteger)backgroundModeForIdentifier:(NSString*)identifier; +- (BOOL)hasUnlimitedBackgroundTime:(NSString*)identifier; --(void) temporarilyApplyBackgroundingMode:(RABackgroundMode)mode forApplication:(SBApplication*)app andCloseForegroundApp:(BOOL)close; --(void) queueRemoveTemporaryOverrideForIdentifier:(NSString*)identifier; --(void) removeTemporaryOverrideForIdentifier:(NSString*)identifier; +- (void)temporarilyApplyBackgroundingMode:(RABackgroundMode)mode forApplication:(SBApplication*)app andCloseForegroundApp:(BOOL)close; +- (void)queueRemoveTemporaryOverrideForIdentifier:(NSString*)identifier; +- (void)removeTemporaryOverrideForIdentifier:(NSString*)identifier; --(NSInteger) application:(NSString*)identifier overrideBackgroundMode:(NSString*)mode; +- (NSInteger)application:(NSString*)identifier overrideBackgroundMode:(NSString*)mode; --(RAIconIndicatorViewInfo) allAggregatedIndicatorInfoForIdentifier:(NSString*)identifier; --(void) updateIconIndicatorForIdentifier:(NSString*)identifier withInfo:(RAIconIndicatorViewInfo)info; --(BOOL) shouldShowIndicatorForIdentifier:(NSString*)identifier; --(BOOL) shouldShowStatusBarIconForIdentifier:(NSString*)identifier; -@end \ No newline at end of file +- (RAIconIndicatorViewInfo)allAggregatedIndicatorInfoForIdentifier:(NSString*)identifier; +- (void)updateIconIndicatorForIdentifier:(NSString*)identifier withInfo:(RAIconIndicatorViewInfo)info; +- (BOOL)shouldShowIndicatorForIdentifier:(NSString*)identifier; +- (BOOL)shouldShowStatusBarIconForIdentifier:(NSString*)identifier; +@end diff --git a/Backgrounding/RABackgrounder.xm b/Backgrounding/RABackgrounder.xm index bc3839a..06c89cf 100644 --- a/Backgrounding/RABackgrounder.xm +++ b/Backgrounding/RABackgrounder.xm @@ -1,10 +1,9 @@ #import "RABackgrounder.h" #import "RASettings.h" +#import "Multiplexer.h" -NSString *FriendlyNameForBackgroundMode(RABackgroundMode mode) -{ - switch (mode) - { +NSString *FriendlyNameForBackgroundMode(RABackgroundMode mode) { + switch (mode) { case RABackgroundModeNative: return LOCALIZE(@"NATIVE"); case RABackgroundModeForcedForeground: @@ -24,205 +23,204 @@ NSMutableDictionary *temporaryOverrides = [NSMutableDictionary dictionary]; NSMutableDictionary *temporaryShouldPop = [NSMutableDictionary dictionary]; @implementation RABackgrounder -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE(RABackgrounder); } --(BOOL) shouldAutoLaunchApplication:(NSString*)identifier -{ - if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) return NO; - +- (BOOL)shouldAutoLaunchApplication:(NSString*)identifier { + if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { + return NO; + } + NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"enabled"] ? [dict[@"enabled"] boolValue] : NO; - return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && ([dict objectForKey:@"autoLaunch"] == nil ? NO : [dict[@"autoLaunch"] boolValue]); + return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && (![dict objectForKey:@"autoLaunch"] ? NO : [dict[@"autoLaunch"] boolValue]); } --(BOOL) shouldAutoRelaunchApplication:(NSString*)identifier -{ - if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) return NO; - +- (BOOL)shouldAutoRelaunchApplication:(NSString*)identifier { + if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { + return NO; + } + NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"enabled"] ? [dict[@"enabled"] boolValue] : NO; - return [self killProcessOnExit:identifier] == NO && [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && ([dict objectForKey:@"autoRelaunch"] == nil ? NO : [dict[@"autoRelaunch"] boolValue]); + return ![self killProcessOnExit:identifier] && [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && (![dict objectForKey:@"autoRelaunch"] ? NO : [dict[@"autoRelaunch"] boolValue]); } --(NSInteger) popTemporaryOverrideForApplication:(NSString*)identifier -{ - if (!identifier) return -1; - - if (![temporaryOverrides objectForKey:identifier]) +- (NSInteger)popTemporaryOverrideForApplication:(NSString*)identifier { + if (!identifier || ![temporaryOverrides objectForKey:identifier]) { return -1; + } + RABackgroundMode override = (RABackgroundMode)[temporaryOverrides[identifier] intValue]; return override; } --(void) queueRemoveTemporaryOverrideForIdentifier:(NSString*)identifier -{ - if (!identifier) return; - +- (void)queueRemoveTemporaryOverrideForIdentifier:(NSString*)identifier { + if (!identifier) { + return; + } temporaryShouldPop[identifier] = @YES; } --(void) removeTemporaryOverrideForIdentifier:(NSString*)identifier -{ - if (!identifier) return; +- (void)removeTemporaryOverrideForIdentifier:(NSString*)identifier { + if (!identifier) { + return; + } - if ([temporaryShouldPop objectForKey:identifier] != nil && [[temporaryShouldPop objectForKey:identifier] boolValue]) - { + if ([temporaryShouldPop objectForKey:identifier] && [[temporaryShouldPop objectForKey:identifier] boolValue]) { [temporaryShouldPop removeObjectForKey:identifier]; - [temporaryOverrides removeObjectForKey:identifier]; + [temporaryOverrides removeObjectForKey:identifier]; } } --(NSInteger) popTemporaryOverrideForApplication:(NSString*)identifier is:(RABackgroundMode)mode -{ +- (NSInteger)popTemporaryOverrideForApplication:(NSString*)identifier is:(RABackgroundMode)mode { NSInteger popped = [self popTemporaryOverrideForApplication:identifier]; return popped == -1 ? -1 : (popped == mode ? 1 : 0); } --(RABackgroundMode) globalBackgroundMode -{ +- (RABackgroundMode)globalBackgroundMode { return (RABackgroundMode)[(RASettings*)[%c(RASettings) sharedInstance] globalBackgroundMode]; } --(BOOL) shouldKeepInForeground:(NSString*)identifier -{ +- (BOOL)shouldKeepInForeground:(NSString*)identifier { return [self backgroundModeForIdentifier:identifier] == RABackgroundModeForcedForeground; } --(BOOL) shouldSuspendImmediately:(NSString*)identifier -{ +- (BOOL)shouldSuspendImmediately:(NSString*)identifier { return [self backgroundModeForIdentifier:identifier] == RABackgroundModeSuspendImmediately; } --(BOOL) preventKillingOfIdentifier:(NSString*)identifier -{ - if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) return NO; - +- (BOOL)preventKillingOfIdentifier:(NSString*)identifier { + if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { + return NO; + } + NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"enabled"] ? [dict[@"enabled"] boolValue] : NO; - return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && ([dict objectForKey:@"preventDeath"] == nil ? NO : [dict[@"preventDeath"] boolValue]); + return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && (![dict objectForKey:@"preventDeath"] ? NO : [dict[@"preventDeath"] boolValue]); } --(BOOL) shouldRemoveFromSwitcherWhenKilledOnExit:(NSString*)identifier -{ - if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) return NO; - +- (BOOL)shouldRemoveFromSwitcherWhenKilledOnExit:(NSString*)identifier { + if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { + return NO; + } + NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"removeFromSwitcher"] ? [dict[@"removeFromSwitcher"] boolValue] : NO; - return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && ([dict objectForKey:@"removeFromSwitcher"] == nil ? NO : [dict[@"removeFromSwitcher"] boolValue]); + return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled && (![dict objectForKey:@"removeFromSwitcher"] ? NO : [dict[@"removeFromSwitcher"] boolValue]); } --(NSInteger) backgroundModeForIdentifier:(NSString*)identifier -{ +- (NSInteger)backgroundModeForIdentifier:(NSString*)identifier { @autoreleasepool { - if (!identifier || [[%c(RASettings) sharedInstance] backgrounderEnabled] == NO) + if (!identifier || ![[%c(RASettings) sharedInstance] backgrounderEnabled]) { return RABackgroundModeNative; + } NSInteger temporaryOverride = [self popTemporaryOverrideForApplication:identifier]; - if (temporaryOverride != -1) + if (temporaryOverride != -1) { return temporaryOverride; + } #if __has_feature(objc_arc) __weak // dictionary is cached by RASettings anyway #endif NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"enabled"] ? [dict[@"enabled"] boolValue] : NO; - if (!enabled) + if (!enabled) { return [self globalBackgroundMode]; + } return [dict[@"backgroundMode"] intValue]; } } --(BOOL) hasUnlimitedBackgroundTime:(NSString*)identifier -{ +- (BOOL)hasUnlimitedBackgroundTime:(NSString*)identifier { return [self backgroundModeForIdentifier:identifier] == RABackgroundModeUnlimitedBackgroundingTime; } --(BOOL) killProcessOnExit:(NSString*)identifier -{ +- (BOOL)killProcessOnExit:(NSString*)identifier { return [self backgroundModeForIdentifier:identifier] == RABackgroundModeForceNone; } --(void) temporarilyApplyBackgroundingMode:(RABackgroundMode)mode forApplication:(SBApplication*)app andCloseForegroundApp:(BOOL)close -{ +- (void)temporarilyApplyBackgroundingMode:(RABackgroundMode)mode forApplication:(SBApplication*)app andCloseForegroundApp:(BOOL)close { temporaryOverrides[app.bundleIdentifier] = @(mode); [temporaryShouldPop removeObjectForKey:app.bundleIdentifier]; - if (close) - { - FBWorkspaceEvent *event = [objc_getClass("FBWorkspaceEvent") eventWithName:@"ActivateSpringBoard" handler:^{ - SBAppToAppWorkspaceTransaction *transaction = [[objc_getClass("SBAppExitedWorkspaceTransaction") alloc] initWithAlertManager:nil exitedApp:app]; - [transaction begin]; - }]; - [(FBWorkspaceEventQueue*)[objc_getClass("FBWorkspaceEventQueue") sharedInstance] executeOrAppendEvent:event]; + if (close) { + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBAppToAppWorkspaceTransaction *transaction = [%c(Multiplexer) createSBAppToAppWorkspaceTransactionForExitingApp:app]; + [transaction begin]; + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; } } --(NSInteger) application:(NSString*)identifier overrideBackgroundMode:(NSString*)mode -{ +- (NSInteger)application:(NSString*)identifier overrideBackgroundMode:(NSString*)mode { NSDictionary *dict = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL enabled = [dict objectForKey:@"enabled"] ? [dict[@"enabled"] boolValue] : NO; id val = dict[@"backgroundModes"][mode]; return [[%c(RASettings) sharedInstance] backgrounderEnabled] && enabled ? (val ? [val boolValue] : -1) : -1; } --(RAIconIndicatorViewInfo) allAggregatedIndicatorInfoForIdentifier:(NSString*)identifier -{ +- (RAIconIndicatorViewInfo)allAggregatedIndicatorInfoForIdentifier:(NSString*)identifier { int info = RAIconIndicatorViewInfoNone; - if ([self backgroundModeForIdentifier:identifier] == RABackgroundModeNative) + if ([self backgroundModeForIdentifier:identifier] == RABackgroundModeNative) { info |= RAIconIndicatorViewInfoNative; - else if ([self backgroundModeForIdentifier:identifier] == RABackgroundModeForcedForeground) + } else if ([self backgroundModeForIdentifier:identifier] == RABackgroundModeForcedForeground) { info |= RAIconIndicatorViewInfoForced; - else if ([self shouldSuspendImmediately:identifier]) + } else if ([self shouldSuspendImmediately:identifier]) { info |= RAIconIndicatorViewInfoSuspendImmediately; - else if ([self hasUnlimitedBackgroundTime:identifier]) + } else if ([self hasUnlimitedBackgroundTime:identifier]) { info |= RAIconIndicatorViewInfoUnlimitedBackgroundTime; + } - if ([self killProcessOnExit:identifier]) + if ([self killProcessOnExit:identifier]) { info |= RAIconIndicatorViewInfoForceDeath; + } - if ([self preventKillingOfIdentifier:identifier]) + if ([self preventKillingOfIdentifier:identifier]) { info |= RAIconIndicatorViewInfoUnkillable; + } return (RAIconIndicatorViewInfo)info; } --(void) updateIconIndicatorForIdentifier:(NSString*)identifier withInfo:(RAIconIndicatorViewInfo)info -{ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +- (void)updateIconIndicatorForIdentifier:(NSString*)identifier withInfo:(RAIconIndicatorViewInfo)info { @autoreleasepool { SBIconView *ret = nil; - if ([[[objc_getClass("SBIconViewMap") homescreenMap] iconModel] respondsToSelector:@selector(applicationIconForBundleIdentifier:)]) - { - // iOS 8.0+ - - SBIcon *icon = [[[objc_getClass("SBIconViewMap") homescreenMap] iconModel] applicationIconForBundleIdentifier:identifier]; - ret = [[objc_getClass("SBIconViewMap") homescreenMap] mappedIconViewForIcon:icon]; - } - else - { - // iOS 7.X - SBIcon *icon = [[[objc_getClass("SBIconViewMap") homescreenMap] iconModel] applicationIconForDisplayIdentifier:identifier]; - ret = [[objc_getClass("SBIconViewMap") homescreenMap] mappedIconViewForIcon:icon]; - } - - [ret RA_updateIndicatorView:info]; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + if ([[[%c(SBIconViewMap) homescreenMap] iconModel] respondsToSelector:@selector(applicationIconForBundleIdentifier:)]) { + // iOS 8.0+ + SBApplicationIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:identifier]; + ret = [[%c(SBIconViewMap) homescreenMap] mappedIconViewForIcon:icon]; + } else { + // iOS 7.X could support once all features are seperate tweaks? + SBApplicationIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForDisplayIdentifier:identifier]; + ret = [[%c(SBIconViewMap) homescreenMap] mappedIconViewForIcon:icon]; + } + } else { + SBApplicationIcon *icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:identifier]; + ret = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] mappedIconViewForIcon:icon]; + } + + [ret RA_updateIndicatorView:info]; } } +#pragma GCC diagnostic pop + --(BOOL) shouldShowIndicatorForIdentifier:(NSString*)identifier -{ +- (BOOL)shouldShowIndicatorForIdentifier:(NSString*)identifier { NSDictionary *dct = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL globalSetting = [[%c(RASettings) sharedInstance] shouldShowIconIndicatorsGlobally]; - return globalSetting ? ([dct objectForKey:@"showIndicatorOnIcon"] == nil ? YES : [dct[@"showIndicatorOnIcon"] boolValue]) : NO; + return globalSetting ? (![dct objectForKey:@"showIndicatorOnIcon"] ? YES : [dct[@"showIndicatorOnIcon"] boolValue]) : NO; } --(BOOL) shouldShowStatusBarIconForIdentifier:(NSString*)identifier -{ +- (BOOL)shouldShowStatusBarIconForIdentifier:(NSString*)identifier { NSDictionary *dct = [[%c(RASettings) sharedInstance] rawCompiledBackgrounderSettingsForIdentifier:identifier]; BOOL globalSetting = [[%c(RASettings) sharedInstance] shouldShowStatusBarIcons]; - return globalSetting ? ([dct objectForKey:@"showStatusBarIcon"] == nil ? YES : [dct[@"showStatusBarIcon"] boolValue]) : NO; + return globalSetting ? (![dct objectForKey:@"showStatusBarIcon"] ? YES : [dct[@"showStatusBarIcon"] boolValue]) : NO; } -@end \ No newline at end of file +@end diff --git a/Backgrounding/SpringBoard.xm b/Backgrounding/SpringBoard.xm index 5f26350..bf807c8 100644 --- a/Backgrounding/SpringBoard.xm +++ b/Backgrounding/SpringBoard.xm @@ -3,136 +3,132 @@ #import "RAAppSwitcherModelWrapper.h" %hook SBApplication --(BOOL) shouldAutoRelaunchAfterExit -{ - return [RABackgrounder.sharedInstance shouldAutoRelaunchApplication:self.bundleIdentifier] || %orig; +- (BOOL)shouldAutoRelaunchAfterExit { + return [RABackgrounder.sharedInstance shouldAutoRelaunchApplication:self.bundleIdentifier] || %orig; } --(BOOL) shouldAutoLaunchOnBootOrInstall -{ - return [RABackgrounder.sharedInstance shouldAutoLaunchApplication:self.bundleIdentifier] || %orig; +- (BOOL)shouldAutoLaunchOnBootOrInstall { + return [RABackgrounder.sharedInstance shouldAutoLaunchApplication:self.bundleIdentifier] || %orig; } --(BOOL) _shouldAutoLaunchOnBootOrInstall:(BOOL)arg1 -{ - return [RABackgrounder.sharedInstance shouldAutoLaunchApplication:self.bundleIdentifier] || %orig; +- (BOOL)_shouldAutoLaunchOnBootOrInstall:(BOOL)arg1 { + return [RABackgrounder.sharedInstance shouldAutoLaunchApplication:self.bundleIdentifier] || %orig; } %end // STAY IN "FOREGROUND" %hook FBUIApplicationResignActiveManager --(void) _sendResignActiveForReason:(int)arg1 toProcess:(__unsafe_unretained FBApplicationProcess*)arg2 -{ - if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg2.bundleIdentifier]) - return; +- (void)_sendResignActiveForReason:(int)arg1 toProcess:(__unsafe_unretained FBApplicationProcess*)arg2 { + if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg2.bundleIdentifier]) { + return; + } - %orig; + %orig; - if ([RABackgrounder.sharedInstance shouldSuspendImmediately:arg2.bundleIdentifier]) - { - BKSProcess *bkProcess = MSHookIvar(arg2, "_bksProcess"); - //[bkProcess _handleExpirationWarning:nil]; - [arg2 processWillExpire:bkProcess]; - } + if ([RABackgrounder.sharedInstance shouldSuspendImmediately:arg2.bundleIdentifier]) { + BKSProcess *bkProcess = MSHookIvar(arg2, "_bksProcess"); + //[bkProcess _handleExpirationWarning:nil]; + [arg2 processWillExpire:bkProcess]; + } } %end %hook FBUIApplicationSceneDeactivationManager // iOS 9 -- (BOOL)_isEligibleProcess:(__unsafe_unretained FBApplicationProcess*)arg1 -{ - if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg1.bundleIdentifier]) - return NO; +- (BOOL)_isEligibleProcess:(__unsafe_unretained FBApplicationProcess*)arg1 { + if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg1.bundleIdentifier]) { + return NO; + } - return %orig; + return %orig; } %end %hook FBSSceneImpl -- (id)_initWithQueue:(unsafe_id)arg1 callOutQueue:(unsafe_id)arg2 identifier:(unsafe_id)arg3 display:(unsafe_id)arg4 settings:(__unsafe_unretained UIMutableApplicationSceneSettings*)arg5 clientSettings:(unsafe_id)arg6 -{ - if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg3]) - { - // what? - if (!arg5) - { - UIMutableApplicationSceneSettings *fakeSettings = [[%c(UIMutableApplicationSceneSettings) alloc] init]; - arg5 = fakeSettings; - } - SET_BACKGROUNDED(arg5, NO); +- (id)_initWithQueue:(unsafe_id)arg1 callOutQueue:(unsafe_id)arg2 identifier:(unsafe_id)arg3 display:(unsafe_id)arg4 settings:(__unsafe_unretained UIMutableApplicationSceneSettings*)arg5 clientSettings:(unsafe_id)arg6 { + if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg3]) { + // what? + if (!arg5) { + UIMutableApplicationSceneSettings *fakeSettings = [[%c(UIMutableApplicationSceneSettings) alloc] init]; + arg5 = fakeSettings; } - return %orig(arg1, arg2, arg3, arg4, arg5, arg6); + SET_BACKGROUNDED(arg5, NO); + } + return %orig(arg1, arg2, arg3, arg4, arg5, arg6); +} + +- (id)initWithQueue:(id)arg1 identifier:(id)arg2 display:(id)arg3 settings:(__unsafe_unretained UIMutableApplicationSceneSettings*)arg4 clientSettings:(id)arg5 { + if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg2]) { + // what? + if (!arg4) { + UIMutableApplicationSceneSettings *fakeSettings = [[%c(UIMutableApplicationSceneSettings) alloc] init]; + arg4 = fakeSettings; + } + SET_BACKGROUNDED(arg4, NO); + } + return %orig(arg1, arg2, arg3, arg4, arg5); } %end %hook FBUIApplicationWorkspaceScene --(void) host:(__unsafe_unretained FBScene*)arg1 didUpdateSettings:(__unsafe_unretained FBSSceneSettings*)arg2 withDiff:(unsafe_id)arg3 transitionContext:(unsafe_id)arg4 completion:(unsafe_id)arg5 -{ - [RABackgrounder.sharedInstance removeTemporaryOverrideForIdentifier:arg1.identifier]; - if (arg1 && arg1.identifier && arg2 && arg1.clientProcess) // FIX: sanity check to prevent NC App crash. untested/not working. - { - if (arg2.backgrounded) - { - if ([RABackgrounder.sharedInstance killProcessOnExit:arg1.identifier]) - { - FBProcess *proc = arg1.clientProcess; - - if ([proc isKindOfClass:[%c(FBApplicationProcess) class]]) - { - FBApplicationProcess *proc2 = (FBApplicationProcess*)proc; - [proc2 killForReason:1 andReport:NO withDescription:@"ReachApp.Backgrounder.killOnExit" completion:nil]; - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:RAIconIndicatorViewInfoForceDeath]; - if ([RABackgrounder.sharedInstance shouldRemoveFromSwitcherWhenKilledOnExit:arg1.identifier]) - { - [%c(RAAppSwitcherModelWrapper) removeItemWithIdentifier:arg1.identifier]; - } - } - [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; - } - - if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg1.identifier]) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; - [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; - return; - } - else if ([RABackgrounder.sharedInstance backgroundModeForIdentifier:arg1.identifier] == RABackgroundModeNative) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; - [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; - } - else if ([RABackgrounder.sharedInstance shouldSuspendImmediately:arg1.identifier]) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; - [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; - } - } - else if ([RABackgrounder.sharedInstance shouldSuspendImmediately:arg1.identifier]) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; +- (void)host:(__unsafe_unretained FBScene*)arg1 didUpdateSettings:(__unsafe_unretained FBSSceneSettings*)arg2 withDiff:(unsafe_id)arg3 transitionContext:(unsafe_id)arg4 completion:(unsafe_id)arg5 { + if (arg1 && arg1.identifier && arg2 && arg1.clientProcess) { + if (arg2.backgrounded) { + if ([RABackgrounder.sharedInstance killProcessOnExit:arg1.identifier]) { + FBProcess *proc = arg1.clientProcess; + + if ([proc isKindOfClass:[%c(FBApplicationProcess) class]]) { + FBApplicationProcess *proc2 = (FBApplicationProcess*)proc; + [proc2 killForReason:1 andReport:NO withDescription:@"ReachApp.Backgrounder.killOnExit" completion:nil]; + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:RAIconIndicatorViewInfoForceDeath]; + if ([RABackgrounder.sharedInstance shouldRemoveFromSwitcherWhenKilledOnExit:arg1.identifier]) { + [%c(RAAppSwitcherModelWrapper) removeItemWithIdentifier:arg1.identifier]; + } } + [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; + } + + if ([RABackgrounder.sharedInstance shouldKeepInForeground:arg1.identifier]) { + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; + [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; + return; + } else if ([RABackgrounder.sharedInstance backgroundModeForIdentifier:arg1.identifier] == RABackgroundModeNative) { + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; + [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; + } else if ([RABackgrounder.sharedInstance shouldSuspendImmediately:arg1.identifier]) { + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:arg1.identifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:arg1.identifier]]; + [RABackgrounder.sharedInstance queueRemoveTemporaryOverrideForIdentifier:arg1.identifier]; + } } + } + + %orig(arg1, arg2, arg3, arg4, arg5); +} +%end - %orig(arg1, arg2, arg3, arg4, arg5); +%hook FBSceneManager +- (void)_noteSceneMovedToForeground:(FBScene*)arg1 { + if ([arg1.clientProcess isKindOfClass:[%c(FBApplicationProcess) class]]) { + [RABackgrounder.sharedInstance removeTemporaryOverrideForIdentifier:arg1.identifier]; + } + + %orig; } %end // PREVENT KILLING %hook FBApplicationProcess -- (void)killForReason:(int)arg1 andReport:(BOOL)arg2 withDescription:(unsafe_id)arg3 completion:(unsafe_id/*block*/)arg4 -{ - if ([RABackgrounder.sharedInstance preventKillingOfIdentifier:self.bundleIdentifier]) - { - [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:self.bundleIdentifier]]; - return; - } - %orig; +- (void)killForReason:(int)arg1 andReport:(BOOL)arg2 withDescription:(unsafe_id)arg3 completion:(unsafe_id/*block*/)arg4 { + if ([RABackgrounder.sharedInstance preventKillingOfIdentifier:self.bundleIdentifier]) { + [RABackgrounder.sharedInstance updateIconIndicatorForIdentifier:self.bundleIdentifier withInfo:[RABackgrounder.sharedInstance allAggregatedIndicatorInfoForIdentifier:self.bundleIdentifier]]; + return; + } + %orig; } %end -%ctor -{ - IF_SPRINGBOARD - { - %init; - } +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + %init; } diff --git a/Backgrounding/SpringBoard_UIAppCustomBackgroundModes.xm b/Backgrounding/SpringBoard_UIAppCustomBackgroundModes.xm index 50ed74d..6892a8f 100644 --- a/Backgrounding/SpringBoard_UIAppCustomBackgroundModes.xm +++ b/Backgrounding/SpringBoard_UIAppCustomBackgroundModes.xm @@ -6,55 +6,52 @@ @interface FBApplicationInfo : NSObject @property (nonatomic, copy) NSString *bundleIdentifier; --(BOOL) isExitsOnSuspend; +- (BOOL)isExitsOnSuspend; @end %hook FBApplicationInfo -- (BOOL)supportsBackgroundMode:(__unsafe_unretained NSString *)mode -{ +- (BOOL)supportsBackgroundMode:(__unsafe_unretained NSString *)mode { int override = [RABackgrounder.sharedInstance application:self.bundleIdentifier overrideBackgroundMode:mode]; - if (override == -1) - return %orig; + if (override == -1) { + return %orig; + } return override; } %end %hook BKSProcessAssertion -- (id)initWithPID:(int)arg1 flags:(unsigned int)arg2 reason:(unsigned int)arg3 name:(unsafe_id)arg4 withHandler:(unsafe_id)arg5 -{ - if ((arg3 == kProcessAssertionReasonViewServices) == NO && // whitelist this to allow share menu to work - [arg4 isEqualToString:@"Called by iOS6_iCleaner, from unknown method"] == NO && // whitelist iCleaner to prevent crash on open - [arg4 isEqualToString:@"Called by Filza_main, from -[AppDelegate applicationDidEnterBackground:]"] == NO && // Whitelist filza to prevent iOS hang (?!) - [NSBundle.mainBundle.bundleIdentifier isEqualToString:@"com.apple.springboard"] == NO) // FIXME: this is a hack that prevents SpringBoard from not starting - { - NSString *identifier = NSBundle.mainBundle.bundleIdentifier; +- (instancetype)initWithPID:(NSInteger)arg1 flags:(NSUInteger)arg2 reason:(NSUInteger)arg3 name:(NSString *)arg4 withHandler:(unsafe_id)arg5 { + if (arg3 != BKSProcessAssertionReasonViewServices && // whitelist this to allow share menu to work + ![arg4 isEqualToString:@"Called by iOS6_iCleaner, from unknown method"] && // whitelist iCleaner to prevent crash on open + ![arg4 isEqualToString:@"Called by Filza_main, from -[AppDelegate applicationDidEnterBackground:]"]) // Whitelist filza to prevent iOS hang (?!) Not sure if the springboard hack is still required + { + NSString *identifier = [NSBundle mainBundle].bundleIdentifier; - if (!identifier) - goto ORIGINAL; - - //NSLog(@"[ReachApp] BKSProcessAssertion initWithPID:'%d' flags:'%d' reason:'%d' name:'%@' withHandler:'%@' process identifier:'%@'", arg1, arg2, arg3, arg4, arg5, identifier); + if (!identifier) + goto ORIGINAL; - if ([RABackgrounder.sharedInstance shouldSuspendImmediately:identifier]) - { - if ((arg3 >= kProcessAssertionReasonAudio && arg3 <= kProcessAssertionReasonVOiP)) // In most cases arg3 == 4 (finish task) - { - //NSLog(@"[ReachApp] blocking BKSProcessAssertion"); + //LogDebug(@"BKSProcessAssertion initWithPID:'%zd' flags:'%tu' reason:'%tu' name:'%@' withHandler:'%@' process identifier:'%@'", arg1, arg2, arg3, arg4, arg5, identifier); - //if (arg5) - //{ - //void (^arg5fix)() = arg5; - //arg5fix(); - // ^^ causes crashes with share menu - //} - return nil; - } - //else if (arg3 == kProcessAssertionReasonActivation) - //{ - // arg2 = ProcessAssertionFlagAllowIdleSleep; - //} - } - } + if ([RABackgrounder.sharedInstance shouldSuspendImmediately:identifier]) { + if ((arg3 >= BKSProcessAssertionReasonAudio && arg3 <= BKSProcessAssertionReasonVOiP)) // In most cases arg3 == 4 (finish task) + { + //NSLog(@"[ReachApp] blocking BKSProcessAssertion"); + + //if (arg5) + //{ + //void (^arg5fix)() = arg5; + //arg5fix(); + // ^^ causes crashes with share menu + //} + return nil; + } + //else if (arg3 == kProcessAssertionReasonActivation) + //{ + // arg2 = ProcessAssertionFlagAllowIdleSleep; + //} + } + } ORIGINAL: - return %orig(arg1, arg2, arg3, arg4, arg5); + return %orig(arg1, arg2, arg3, arg4, arg5); } %end diff --git a/Backgrounding/UnlimitedBackgrounding.xm b/Backgrounding/UnlimitedBackgrounding.xm index 430dd71..42524c2 100644 --- a/Backgrounding/UnlimitedBackgrounding.xm +++ b/Backgrounding/UnlimitedBackgrounding.xm @@ -6,51 +6,41 @@ NSMutableDictionary *processAssertions = [NSMutableDictionary dictionary]; BKSProcessAssertion *keepAlive$temp; %hook FBUIApplicationWorkspaceScene --(void) host:(__unsafe_unretained FBScene*)arg1 didUpdateSettings:(__unsafe_unretained FBSSceneSettings*)arg2 withDiff:(unsafe_id)arg3 transitionContext:(unsafe_id)arg4 completion:(unsafe_id)arg5 -{ - if ([RABackgrounder.sharedInstance hasUnlimitedBackgroundTime:arg1.identifier] && arg2.backgrounded == YES && [processAssertions objectForKey:arg1.identifier] == nil) - { - SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:arg1.identifier]; +- (void)host:(__unsafe_unretained FBScene*)arg1 didUpdateSettings:(__unsafe_unretained FBSSceneSettings*)arg2 withDiff:(unsafe_id)arg3 transitionContext:(unsafe_id)arg4 completion:(unsafe_id)arg5 { + if ([RABackgrounder.sharedInstance hasUnlimitedBackgroundTime:arg1.identifier] && arg2.backgrounded && ![processAssertions objectForKey:arg1.identifier]) { + SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:arg1.identifier]; - keepAlive$temp = [[%c(BKSProcessAssertion) alloc] initWithPID:[app pid] - flags:(ProcessAssertionFlagPreventSuspend | ProcessAssertionFlagAllowIdleSleep | ProcessAssertionFlagPreventThrottleDownCPU | ProcessAssertionFlagWantsForegroundResourcePriority) - reason:kProcessAssertionReasonBackgroundUI - name:@"reachapp" - withHandler:^{ - NSLog(@"ReachApp: %d kept alive: %@", [app pid], [keepAlive$temp valid] ? @"TRUE" : @"FALSE"); - if (keepAlive$temp.valid) - processAssertions[arg1.identifier] = keepAlive$temp; - else - { - - } - }]; - } - %orig(arg1, arg2, arg3, arg4, arg5); + keepAlive$temp = [[%c(BKSProcessAssertion) alloc] initWithPID:[app pid] flags:(BKSProcessAssertionFlagPreventSuspend | BKSProcessAssertionFlagAllowIdleSleep | BKSProcessAssertionFlagPreventThrottleDownCPU | BKSProcessAssertionFlagWantsForegroundResourcePriority) reason:BKSProcessAssertionReasonBackgroundUI name:@"reachapp" withHandler:^{ + LogInfo(@"ReachApp: %d kept alive: %@", [app pid], [keepAlive$temp valid] ? @"TRUE" : @"FALSE"); + if (keepAlive$temp.valid) { + processAssertions[arg1.identifier] = keepAlive$temp; + } + }]; + } + %orig(arg1, arg2, arg3, arg4, arg5); } %end @interface RAUnlimitedBackgroundingAppWatcher : NSObject -+(void) load; ++ (void)load; @end RAUnlimitedBackgroundingAppWatcher *sharedInstance$RAUnlimitedBackgroundingAppWatcher; @implementation RAUnlimitedBackgroundingAppWatcher -+(void) load -{ - IF_SPRINGBOARD { - sharedInstance$RAUnlimitedBackgroundingAppWatcher = [[RAUnlimitedBackgroundingAppWatcher alloc] init]; - [[%c(RARunningAppsProvider) sharedInstance] addTarget:sharedInstance$RAUnlimitedBackgroundingAppWatcher]; - } ++ (void)load { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance$RAUnlimitedBackgroundingAppWatcher = [[RAUnlimitedBackgroundingAppWatcher alloc] init]; + [[%c(RARunningAppsProvider) sharedInstance] addTarget:sharedInstance$RAUnlimitedBackgroundingAppWatcher]; } --(void) appDidDie:(__unsafe_unretained SBApplication*)app -{ - if (/*W[RABackgrounder.sharedInstance preventKillingOfIdentifier:app.bundleIdentifier] == NO && */[processAssertions objectForKey:app.bundleIdentifier]) - { - [processAssertions[app.bundleIdentifier] invalidate]; - [processAssertions removeObjectForKey:app.bundleIdentifier]; - } +- (void)appDidDie:(__unsafe_unretained SBApplication*)app { + if (![processAssertions objectForKey:app.bundleIdentifier]) { + return; + } + [processAssertions[app.bundleIdentifier] invalidate]; + [processAssertions removeObjectForKey:app.bundleIdentifier]; } -@end \ No newline at end of file +@end diff --git a/BioLockdown.h b/BioLockdown.h index 5b0c0ff..195ff6b 100644 --- a/BioLockdown.h +++ b/BioLockdown.h @@ -3,6 +3,8 @@ @class SBApplication; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" __attribute__((visibility("hidden"))) @interface BioLockdownController : NSObject @@ -18,15 +20,14 @@ __attribute__((visibility("hidden"))) - (BOOL)authenticateForRecord:(ABRecordRef)record actionText:(NSString *)actionText completion:(dispatch_block_t)completion failure:(dispatch_block_t)failure; @end - +#pragma GCC diagnostic pop #define HAS_BIOLOCKDOWN (objc_getClass("BioLockdownController") != nil) #define IF_BIOLOCKDOWN if (HAS_BIOLOCKDOWN) #define BIOLOCKDOWN_AUTHENTICATE_APP(ident, success, failure_) \ - if ([[objc_getClass("BioLockdownController") sharedController] requiresAuthenticationForIdentifier:ident]) \ - { \ + if ([[objc_getClass("BioLockdownController") sharedController] requiresAuthenticationForIdentifier:ident]) { \ [[objc_getClass("BioLockdownController") sharedController] authenticateForIdentifier:ident actionDescription:LOCALIZE(@"BIOLOCKDOWN_AUTH_DESCRIPTION") completion:success failure:failure_]; \ - } \ - else \ - success() \ No newline at end of file + } else { \ + success(); \ + } diff --git a/ColorBadges.h b/ColorBadges.h index 805343d..567e1b3 100644 --- a/ColorBadges.h +++ b/ColorBadges.h @@ -14,6 +14,10 @@ + (BOOL)areBordersEnabled; + (BOOL)isEnabled; +// Added in ColorBadges v1.1.1. ++ (BOOL)isDarkColorOrIsAlwaysWhiteEnabled:(int)color; ++ (BOOL)isAlwaysWhiteEnabled; + // Return RGB ints. i.e. 0xRRGGBB. - (int)colorForImage:(UIImage *)image; - (int)colorForIcon:(id)icon; // Must be an SBIcon * @@ -41,19 +45,17 @@ @end */ -static inline int RGBFromUIColor(UIColor *self) -{ - CGFloat red, green, blue; - if ([self getRed:&red green:&green blue:&blue alpha:NULL]) - { - NSUInteger redInt = (NSUInteger)(red * 255 + 0.5); - NSUInteger greenInt = (NSUInteger)(green * 255 + 0.5); - NSUInteger blueInt = (NSUInteger)(blue * 255 + 0.5); +static inline int RGBFromUIColor(UIColor *self) { + CGFloat red, green, blue; + if ([self getRed:&red green:&green blue:&blue alpha:NULL]) { + NSUInteger redInt = (NSUInteger)(red * 255 + 0.5); + NSUInteger greenInt = (NSUInteger)(green * 255 + 0.5); + NSUInteger blueInt = (NSUInteger)(blue * 255 + 0.5); - return (redInt << 16) | (greenInt << 8) | blueInt; - } + return (redInt << 16) | (greenInt << 8) | blueInt; + } - return 0; + return 0; } #define HAS_COLORBADGES (objc_getClass("ColorBadges") != nil) diff --git a/DRM/Statistics.xm b/DRM/Statistics.xm index 46fc040..ca96103 100644 --- a/DRM/Statistics.xm +++ b/DRM/Statistics.xm @@ -1,32 +1,30 @@ #import "headers.h" -%ctor -{ - IF_SPRINGBOARD { - #if DEBUG - NSLog(@"[ReachApp][DRM] Not checking statistics on debug build"); - #else - dispatch_async(dispatch_get_main_queue(), ^(void){ - NSString *statsPath = @"/var/mobile/Library/Preferences/.multiplexer.stats_checked"; - if ([NSFileManager.defaultManager fileExistsAtPath:statsPath] == NO) - { - CFStringRef (*$MGCopyAnswer)(CFStringRef); +%ctor { + IF_NOT_SPRINGBOARD { + return; + } +#if DEBUG + LogInfo(@"[ReachApp][DRM] Not checking statistics on debug build"); +#else + dispatch_async(dispatch_get_main_queue(), ^(void){ + NSString *statsPath = @"/var/mobile/Library/Preferences/.multiplexer.stats_checked"; + if (![NSFileManager.defaultManager fileExistsAtPath:statsPath]) { + CFStringRef (*$MGCopyAnswer)(CFStringRef); - void *gestalt = dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_GLOBAL | RTLD_LAZY); - $MGCopyAnswer = (CFStringRef (*)(CFStringRef))dlsym(gestalt, "MGCopyAnswer"); + void *gestalt = dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_GLOBAL | RTLD_LAZY); + $MGCopyAnswer = (CFStringRef (*)(CFStringRef))dlsym(gestalt, "MGCopyAnswer"); - NSString *udid = (__bridge NSString*)$MGCopyAnswer(CFSTR("UniqueDeviceID")); - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://elijahandandrew.com/multiplexer/stats.php?udid=%@", udid]] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0]; - [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - int code = [httpResponse statusCode]; - if (error == nil && (code == 0 || code == 200)) - { - [NSFileManager.defaultManager createFileAtPath:statsPath contents:[NSData new] attributes:nil]; - } - }]; - } - }); - #endif - } -} \ No newline at end of file + NSString *udid = (__bridge NSString*)$MGCopyAnswer(CFSTR("UniqueDeviceID")); + NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://elijahandandrew.com/multiplexer/stats.php?udid=%@", udid]] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0]; + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; + int code = [httpResponse statusCode]; + if (!error && (code == 0 || code == 200)) { + [NSFileManager.defaultManager createFileAtPath:statsPath contents:[NSData new] attributes:nil]; + } + }]; + } + }); +#endif +} diff --git a/Debugging/Core.xm b/Debugging/Core.xm index 1d8a770..e733810 100644 --- a/Debugging/Core.xm +++ b/Debugging/Core.xm @@ -7,28 +7,16 @@ #import "headers.h" %hook NSObject --(void)doesNotRecognizeSelector:(SEL)selector -{ - NSLog(@"[ReachApp] doesNotRecognizeSelector: selector '%@' on class '%s' (image: %s)", NSStringFromSelector(selector), class_getName(self.class), class_getImageName(self.class)); - - void *array[10]; - size_t size; - char **strings; - size_t i; - - size = backtrace (array, 10); - strings = backtrace_symbols (array, size); - - NSLog(@"[ReachApp] Obtained %zd stack frames:\n", size); +- (void)doesNotRecognizeSelector:(SEL)selector { + LogDebug(@"[ReachApp] doesNotRecognizeSelector: selector '%@' on class '%s' (image: %s)", NSStringFromSelector(selector), class_getName(self.class), class_getImageName(self.class)); - for (i = 0; i < size; i++) - { - NSLog(@"[ReachApp] %s\n", strings[i]); + NSArray *symbols = [NSThread callStackSymbols]; + LogDebug(@"[ReachApp] Obtained %zd stack frames:\n", symbols.count); + for (NSString *symbol in symbols) { + LogDebug(@"[ReachApp] %@\n", symbol); } - free(strings); - - %orig; + %orig; } %end @@ -38,7 +26,7 @@ Class hook$objc_getClass(const char *name) Class cls = orig$objc_getClass(name); if (!cls) { - NSLog(@"[ReachApp] something attempted to access nil class '%s'", name); + LogDebug(@"[ReachApp] something attempted to access nil class '%s'", name); } return cls; }*/ @@ -46,11 +34,11 @@ Class hook$objc_getClass(const char *name) %ctor { IF_SPRINGBOARD { - + // Causes cycript to not function //MSHookFunction((void*)objc_getClass, (void*)hook$objc_getClass, (void**)&orig$objc_getClass); - + %init; } - //NSLog(@"[ReachApp] %s", class_getImageName(orig$objc_getClass("RAMissionControlManager"))); + //LogDebug(@"[ReachApp] %s", class_getImageName(orig$objc_getClass("RAMissionControlManager"))); } diff --git a/GestureSupport/Hooks_iOS8.xm b/GestureSupport/Hooks_iOS8.xm index 1cef3e7..1e3b512 100644 --- a/GestureSupport/Hooks_iOS8.xm +++ b/GestureSupport/Hooks_iOS8.xm @@ -2,35 +2,34 @@ #import "RAGestureManager.h" /* -Some code modified/adapted/based off of MultitaskingGestures by HamzaSood. +Some code modified/adapted/based off of MultitaskingGestures by HamzaSood. MultitaskingGestures source code: https://github.com/hamzasood/MultitaskingGestures/ License (GPL): https://github.com/hamzasood/MultitaskingGestures/blob/master/License.md */ @interface _UIScreenEdgePanRecognizer (Velocity) --(CGPoint) RA_velocity; +- (CGPoint)RA_velocity; @end static BOOL isTracking = NO; static NSMutableSet *gestureRecognizers; UIRectEdge currentEdge; -struct VelocityData { +typedef struct { CGPoint velocity; double timestamp; CGPoint location; -}; +} VelocityData; %hook _UIScreenEdgePanRecognizer -- (void)incorporateTouchSampleAtLocation:(CGPoint)location timestamp:(double)timestamp modifier:(NSInteger)modifier interfaceOrientation:(UIInterfaceOrientation)orientation -{ +- (void)incorporateTouchSampleAtLocation:(CGPoint)location timestamp:(double)timestamp modifier:(NSInteger)modifier interfaceOrientation:(UIInterfaceOrientation)orientation { %orig; VelocityData newData; VelocityData oldData; [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&oldData]; - + // this is really quite simple, it calculates a velocity based off of // (current location - last location) / (time taken to move from last location to current location) // which effectively gives you a CGPoint of where it would end if the user continued the gesture. @@ -43,8 +42,7 @@ struct VelocityData { } %new -- (CGPoint)RA_velocity -{ +- (CGPoint)RA_velocity { VelocityData data; [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&data]; @@ -53,119 +51,101 @@ struct VelocityData { %end %hook SBHandMotionExtractor --(id) init -{ - if ((self = %orig)) - { - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer setDelegate:(id<_UIScreenEdgePanRecognizerDelegate>)self]; +- (id)init { + if ((self = %orig)) { + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer setDelegate:(id<_UIScreenEdgePanRecognizerDelegate>)self]; } - return self; + } + return self; } --(void) extractHandMotionForActiveTouches:(SBActiveTouch*) activeTouches count:(NSUInteger)count centroid:(CGPoint)centroid -{ - %orig; - dispatch_async(dispatch_get_main_queue(), ^{ - if (count > 0) { - SBActiveTouch touch = activeTouches[0]; - if (touch.type == 0) // Begin - { - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer incorporateTouchSampleAtLocation:touch.unrotatedLocation timestamp:CACurrentMediaTime() modifier:touch.modifier interfaceOrientation:touch.interfaceOrientation]; - isTracking = YES; - } - else if (isTracking) // Move - { - _UIScreenEdgePanRecognizer *targetRecognizer = nil; - - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - { - [recognizer incorporateTouchSampleAtLocation:touch.unrotatedLocation timestamp:CACurrentMediaTime() modifier:touch.modifier interfaceOrientation:touch.interfaceOrientation]; - - if (recognizer.targetEdges & currentEdge) - targetRecognizer = recognizer; - } - [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateChanged withPoint:touch.location velocity:targetRecognizer.RA_velocity forEdge:currentEdge]; - } +- (void)extractHandMotionForActiveTouches:(SBActiveTouch*) activeTouches count:(NSUInteger)count centroid:(CGPoint)centroid { + %orig; + dispatch_async(dispatch_get_main_queue(), ^{ + if (count > 0) { + SBActiveTouch touch = activeTouches[0]; + if (touch.type == 0) { //begin + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer incorporateTouchSampleAtLocation:touch.unrotatedLocation timestamp:CACurrentMediaTime() modifier:touch.modifier interfaceOrientation:touch.interfaceOrientation]; } - }); -} + isTracking = YES; + } else if (isTracking) { //move + _UIScreenEdgePanRecognizer *targetRecognizer = nil; -%new -(void) screenEdgePanRecognizerStateDidChange:(_UIScreenEdgePanRecognizer*) screenEdgePanRecognizer -{ - if (screenEdgePanRecognizer.state == UIGestureRecognizerStateBegan) - { - CGPoint location = MSHookIvar(screenEdgePanRecognizer, "_lastTouchLocation"); + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer incorporateTouchSampleAtLocation:touch.unrotatedLocation timestamp:CACurrentMediaTime() modifier:touch.modifier interfaceOrientation:touch.interfaceOrientation]; - // Adjust for the two unsupported orientations... what... - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location.x != 0 && location.y != 0)) - { - location.x = UIScreen.mainScreen.bounds.size.width - location.x; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown && (location.x != 0 && location.y != 0)) - { - location.x = UIScreen.mainScreen.bounds.size.width - location.x; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - CGFloat t = location.y; - location.y = location.x; - location.x = t; + if (recognizer.targetEdges & currentEdge) { + targetRecognizer = recognizer; + } } + [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateChanged withPoint:touch.location velocity:targetRecognizer.RA_velocity forEdge:currentEdge]; + } + } + }); +} - if ([RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateBegan withPoint:location velocity:screenEdgePanRecognizer.RA_velocity forEdge:screenEdgePanRecognizer.targetEdges]) - { - currentEdge = screenEdgePanRecognizer.targetEdges; - BKSHIDServicesCancelTouchesOnMainDisplay(); // This is needed or open apps, etc will still get touch events. For example open settings app + swipeover without this line and you can still scroll up/down through the settings - } +%new - (void)screenEdgePanRecognizerStateDidChange:(_UIScreenEdgePanRecognizer*)screenEdgePanRecognizer { + if (screenEdgePanRecognizer.state == UIGestureRecognizerStateBegan) { + CGPoint location = MSHookIvar(screenEdgePanRecognizer, "_lastTouchLocation"); + + // Adjust for the two unsupported orientations... what... + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location.x != 0 && location.y != 0)) { + location.x = UIScreen.mainScreen.bounds.size.width - location.x; + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown && (location.x != 0 && location.y != 0)) { + location.x = UIScreen.mainScreen.bounds.size.width - location.x; + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + CGFloat t = location.y; + location.y = location.x; + location.x = t; } + + if ([RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateBegan withPoint:location velocity:screenEdgePanRecognizer.RA_velocity forEdge:screenEdgePanRecognizer.targetEdges]) { + currentEdge = screenEdgePanRecognizer.targetEdges; + BKSHIDServicesCancelTouchesOnMainDisplay(); // This is needed or open apps, etc will still get touch events. For example open settings app + swipeover without this line and you can still scroll up/down through the settings + } + } } --(void) clear -{ - dispatch_async(dispatch_get_main_queue(), ^{ - if (isTracking) // Ended - { - _UIScreenEdgePanRecognizer *targetRecognizer = nil; - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - { - if (recognizer.targetEdges & currentEdge) - targetRecognizer = recognizer; - } - - [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateEnded withPoint:CGPointZero velocity:targetRecognizer.RA_velocity forEdge:currentEdge]; - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer reset]; // remove current touches it's "incorporated" - currentEdge = UIRectEdgeNone; - isTracking = NO; +- (void)clear { + dispatch_async(dispatch_get_main_queue(), ^{ + if (isTracking) { //ended + _UIScreenEdgePanRecognizer *targetRecognizer = nil; + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + if (recognizer.targetEdges & currentEdge) { + targetRecognizer = recognizer; } - }); - %orig; + } + + [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateEnded withPoint:CGPointZero velocity:targetRecognizer.RA_velocity forEdge:currentEdge]; + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer reset]; // remove current touches it's "incorporated" + } + currentEdge = UIRectEdgeNone; + isTracking = NO; + } + }); + %orig; } %end -%ctor -{ - IF_SPRINGBOARD - { - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) - return; - - class_addProtocol(objc_getClass("SBHandMotionExtractor"), @protocol(_UIScreenEdgePanRecognizerDelegate)); - - UIRectEdge edgesToWatch[] = { UIRectEdgeBottom, UIRectEdgeLeft, UIRectEdgeRight, UIRectEdgeTop }; - int edgeCount = sizeof(edgesToWatch) / sizeof(UIRectEdge); - gestureRecognizers = [[NSMutableSet alloc] initWithCapacity:edgeCount]; - for (int i = 0; i < edgeCount; i++) - { - _UIScreenEdgePanRecognizer *recognizer = [[_UIScreenEdgePanRecognizer alloc] initWithType:2]; - recognizer.targetEdges = edgesToWatch[i]; - recognizer.screenBounds = UIScreen.mainScreen.bounds; - [gestureRecognizers addObject:recognizer]; - } +%ctor { + if (IS_IOS_OR_NEWER(iOS_9_0) || !IS_SPRINGBOARD) { + return; + } - %init; - } - -} \ No newline at end of file + class_addProtocol(%c(SBHandMotionExtractor), @protocol(_UIScreenEdgePanRecognizerDelegate)); + + UIRectEdge edgesToWatch[] = { UIRectEdgeBottom, UIRectEdgeLeft, UIRectEdgeRight, UIRectEdgeTop }; + int edgeCount = sizeof(edgesToWatch) / sizeof(UIRectEdge); + gestureRecognizers = [[NSMutableSet alloc] initWithCapacity:edgeCount]; + for (int i = 0; i < edgeCount; i++) { + _UIScreenEdgePanRecognizer *recognizer = [[_UIScreenEdgePanRecognizer alloc] initWithType:2]; + recognizer.targetEdges = edgesToWatch[i]; + recognizer.screenBounds = UIScreen.mainScreen.bounds; + [gestureRecognizers addObject:recognizer]; + } + + %init; +} diff --git a/GestureSupport/Hooks_iOS9.xm b/GestureSupport/Hooks_iOS9.xm index 250d783..24b7f0d 100644 --- a/GestureSupport/Hooks_iOS9.xm +++ b/GestureSupport/Hooks_iOS9.xm @@ -16,47 +16,45 @@ typedef void* (*clientCreatePointer)(const CFAllocatorRef); extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); @interface _UIScreenEdgePanRecognizer (Velocity) --(CGPoint) RA_velocity; +- (CGPoint)RA_velocity; @end static BOOL isTracking = NO; static NSMutableSet *gestureRecognizers; UIRectEdge currentEdge9; -struct VelocityData { +typedef struct { CGPoint velocity; double timestamp; CGPoint location; -}; +} VelocityData; %hook _UIScreenEdgePanRecognizer -- (void)incorporateTouchSampleAtLocation:(CGPoint)location timestamp:(double)timestamp modifier:(NSInteger)modifier interfaceOrientation:(UIInterfaceOrientation)orientation forceState:(int)arg5 -{ - %orig; - - VelocityData newData; - VelocityData oldData; - - [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&oldData]; - - // this is really quite simple, it calculates a velocity based off of - // (current location - last location) / (time taken to move from last location to current location) - // which effectively gives you a CGPoint of where it would end if the user continued the gesture. - CGPoint velocity = CGPointMake((location.x - oldData.location.x) / (timestamp - oldData.timestamp), (location.y - oldData.location.y) / (timestamp - oldData.timestamp)); - newData.velocity = velocity; - newData.location = location; - newData.timestamp = timestamp; - - objc_setAssociatedObject(self, @selector(RA_velocityData), [NSValue valueWithBytes:&newData objCType:@encode(VelocityData)], OBJC_ASSOCIATION_RETAIN); +- (void)incorporateTouchSampleAtLocation:(CGPoint)location timestamp:(double)timestamp modifier:(NSInteger)modifier interfaceOrientation:(UIInterfaceOrientation)orientation forceState:(int)arg5 { + %orig; + + VelocityData newData; + VelocityData oldData; + + [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&oldData]; + + // this is really quite simple, it calculates a velocity based off of + // (current location - last location) / (time taken to move from last location to current location) + // which effectively gives you a CGPoint of where it would end if the user continued the gesture. + CGPoint velocity = CGPointMake((location.x - oldData.location.x) / (timestamp - oldData.timestamp), (location.y - oldData.location.y) / (timestamp - oldData.timestamp)); + newData.velocity = velocity; + newData.location = location; + newData.timestamp = timestamp; + + objc_setAssociatedObject(self, @selector(RA_velocityData), [NSValue valueWithBytes:&newData objCType:@encode(VelocityData)], OBJC_ASSOCIATION_RETAIN); } %new -- (CGPoint)RA_velocity -{ - VelocityData data; - [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&data]; +- (CGPoint)RA_velocity { + VelocityData data; + [objc_getAssociatedObject(self, @selector(RA_velocityData)) getValue:&data]; - return data.velocity; + return data.velocity; } %end @@ -65,153 +63,138 @@ struct VelocityData { @end @implementation Hooks9$SBHandMotionExtractorReplacementByMultiplexer --(id) init -{ - if (self = [super init]) - { - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer setDelegate:(id<_UIScreenEdgePanRecognizerDelegate>)self]; +- (instancetype)init { + if (self = [super init]) { + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer setDelegate:(id<_UIScreenEdgePanRecognizerDelegate>)self]; + } + } + return self; +} + +- (void)screenEdgePanRecognizerStateDidChange:(_UIScreenEdgePanRecognizer*)screenEdgePanRecognizer { + if (screenEdgePanRecognizer.state == UIGestureRecognizerStateBegan) { + CGPoint location = MSHookIvar(screenEdgePanRecognizer, "_lastTouchLocation"); + + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location.x != 0 && location.y != 0)) { + location.x = UIScreen.mainScreen.bounds.size.width - location.x; + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown && (location.x != 0 && location.y != 0)) { + location.x = UIScreen.mainScreen.bounds.size.width - location.x; + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + CGFloat t = location.y; + location.y = location.x; + location.x = t; + } + LogDebug(@"[ReachApp] _UIScreenEdgePanRecognizer location: %@", NSStringFromCGPoint(location)); + if ([RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateBegan withPoint:location velocity:screenEdgePanRecognizer.RA_velocity forEdge:screenEdgePanRecognizer.targetEdges]) { + currentEdge9 = screenEdgePanRecognizer.targetEdges; + BKSHIDServicesCancelTouchesOnMainDisplay(); // This is needed or open apps, etc will still get touch events. For example open settings app + swipeover without this line and you can still scroll up/down through the settings } - return self; + } } +@end --(void) screenEdgePanRecognizerStateDidChange:(_UIScreenEdgePanRecognizer*) screenEdgePanRecognizer -{ - if (screenEdgePanRecognizer.state == UIGestureRecognizerStateBegan) - { - CGPoint location = MSHookIvar(screenEdgePanRecognizer, "_lastTouchLocation"); +void touch_event(void *target, void *refcon, IOHIDServiceRef service, IOHIDEventRef event) { + if (IOHIDEventGetType(event) == kIOHIDEventTypeDigitizer) { + NSArray *children = (__bridge NSArray *)IOHIDEventGetChildren(event); + if ([children count] == 1) { + float density = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerDensity); - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location.x != 0 && location.y != 0)) - { - location.x = UIScreen.mainScreen.bounds.size.width - location.x; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown && (location.x != 0 && location.y != 0)) - { - location.x = UIScreen.mainScreen.bounds.size.width - location.x; + float x = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerX) * UIScreen.mainScreen._referenceBounds.size.width; + float y = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerY) * UIScreen.mainScreen._referenceBounds.size.height; + CGPoint location = (CGPoint) { x, y }; + + UIInterfaceOrientation interfaceOrientation = GET_STATUSBAR_ORIENTATION; + + float rotatedX = x; + float rotatedY = y; + + if (interfaceOrientation == UIInterfaceOrientationLandscapeRight) { + rotatedX = y; + rotatedY = UIScreen.mainScreen.bounds.size.height - x; + } else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) { + rotatedX = UIScreen.mainScreen._referenceBounds.size.height - y; + rotatedY = x; + } + + CGPoint rotatedLocation = (CGPoint) { rotatedX, rotatedY }; + + LogInfo(@"[ReachApp] (%f, %d) %@ -> %@", density, isTracking, NSStringFromCGPoint(location), NSStringFromCGPoint(rotatedLocation)); + + if (!isTracking) { + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer incorporateTouchSampleAtLocation:location timestamp:CACurrentMediaTime() modifier:1 interfaceOrientation:interfaceOrientation forceState:0]; } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - CGFloat t = location.y; - location.y = location.x; - location.x = t; + isTracking = YES; + } else if (density == 0 && isTracking) { + _UIScreenEdgePanRecognizer *targetRecognizer = nil; + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + if (recognizer.targetEdges & currentEdge9) { + targetRecognizer = recognizer; + } } - NSLog(@"[ReachApp] _UIScreenEdgePanRecognizer location: %@", NSStringFromCGPoint(location)); - if ([RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateBegan withPoint:location velocity:screenEdgePanRecognizer.RA_velocity forEdge:screenEdgePanRecognizer.targetEdges]) - { - currentEdge9 = screenEdgePanRecognizer.targetEdges; - BKSHIDServicesCancelTouchesOnMainDisplay(); // This is needed or open apps, etc will still get touch events. For example open settings app + swipeover without this line and you can still scroll up/down through the settings + + [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateEnded withPoint:CGPointZero velocity:targetRecognizer.RA_velocity forEdge:currentEdge9]; + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer reset]; // remove current touches it's "incorporated" } - } -} -@end + currentEdge9 = UIRectEdgeNone; + isTracking = NO; -void touch_event(void *target, void *refcon, IOHIDServiceRef service, IOHIDEventRef event) -{ - if (IOHIDEventGetType(event) == kIOHIDEventTypeDigitizer) - { - NSArray *children = (__bridge NSArray *)IOHIDEventGetChildren(event); - if ([children count] == 1) - { - float density = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerDensity); - - float x = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerX) * UIScreen.mainScreen._referenceBounds.size.width; - float y = IOHIDEventGetFloatValue((__bridge __IOHIDEvent *)children[0], (IOHIDEventField)kIOHIDEventFieldDigitizerY) * UIScreen.mainScreen._referenceBounds.size.height; - CGPoint location = (CGPoint) { x, y }; - - UIInterfaceOrientation interfaceOrientation = GET_STATUSBAR_ORIENTATION; - - float rotatedX = x; - float rotatedY = y; - - if (interfaceOrientation == UIInterfaceOrientationLandscapeRight) - { - rotatedX = y; - rotatedY = UIScreen.mainScreen.bounds.size.height - x; - } - else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) - { - rotatedX = UIScreen.mainScreen._referenceBounds.size.height - y; - rotatedY = x; - } - - CGPoint rotatedLocation = (CGPoint) { rotatedX, rotatedY }; - - NSLog(@"[ReachApp] (%f, %d) %@ -> %@", density, isTracking, NSStringFromCGPoint(location), NSStringFromCGPoint(rotatedLocation)); - - if (isTracking == NO) - { - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer incorporateTouchSampleAtLocation:location timestamp:CACurrentMediaTime() modifier:1 interfaceOrientation:interfaceOrientation forceState:0]; - isTracking = YES; - } - else if (density == 0 && isTracking) - { - _UIScreenEdgePanRecognizer *targetRecognizer = nil; - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - { - if (recognizer.targetEdges & currentEdge9) - targetRecognizer = recognizer; - } - - [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateEnded withPoint:CGPointZero velocity:targetRecognizer.RA_velocity forEdge:currentEdge9]; - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - [recognizer reset]; // remove current touches it's "incorporated" - currentEdge9 = UIRectEdgeNone; - isTracking = NO; - - NSLog(@"[ReachApp] touch ended."); - } - else - { - _UIScreenEdgePanRecognizer *targetRecognizer = nil; - - for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) - { - [recognizer incorporateTouchSampleAtLocation:location timestamp:CACurrentMediaTime() modifier:1 interfaceOrientation:interfaceOrientation forceState:0]; - - if (recognizer.targetEdges & currentEdge9) - targetRecognizer = recognizer; - } - [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateChanged withPoint:rotatedLocation velocity:targetRecognizer.RA_velocity forEdge:currentEdge9]; - } + LogInfo(@"[ReachApp] touch ended."); + } else { + _UIScreenEdgePanRecognizer *targetRecognizer = nil; + for (_UIScreenEdgePanRecognizer *recognizer in gestureRecognizers) { + [recognizer incorporateTouchSampleAtLocation:location timestamp:CACurrentMediaTime() modifier:1 interfaceOrientation:interfaceOrientation forceState:0]; + + if (recognizer.targetEdges & currentEdge9) { + targetRecognizer = recognizer; + } } + [RAGestureManager.sharedInstance handleMovementOrStateUpdate:UIGestureRecognizerStateChanged withPoint:rotatedLocation velocity:targetRecognizer.RA_velocity forEdge:currentEdge9]; + } } + } } __strong id __static$Hooks9$SBHandMotionExtractorReplacementByMultiplexer; -%ctor -{ - - IF_SPRINGBOARD - { - if (SYSTEM_VERSION_LESS_THAN(@"9.0")) - return; - - clientCreatePointer clientCreate; - void *handle = dlopen(0, 9); - *(void**)(&clientCreate) = dlsym(handle,"IOHIDEventSystemClientCreate"); - IOHIDEventSystemClientRef hidEventSystem = (__IOHIDEventSystemClient *)clientCreate(kCFAllocatorDefault); - IOHIDEventSystemClientScheduleWithRunLoop(hidEventSystem, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - IOHIDEventSystemClientRegisterEventCallback(hidEventSystem, (IOHIDEventSystemClientEventCallback)touch_event, NULL, NULL); - - class_addProtocol(objc_getClass("Hooks9$SBHandMotionExtractorReplacementByMultiplexer"), @protocol(_UIScreenEdgePanRecognizerDelegate)); - - UIRectEdge edgesToWatch[] = { UIRectEdgeBottom, UIRectEdgeLeft, UIRectEdgeRight, UIRectEdgeTop }; - int edgeCount = sizeof(edgesToWatch) / sizeof(UIRectEdge); - gestureRecognizers = [[NSMutableSet alloc] initWithCapacity:edgeCount]; - for (int i = 0; i < edgeCount; i++) - { - _UIScreenEdgePanRecognizer *recognizer = [[_UIScreenEdgePanRecognizer alloc] initWithType:2]; - recognizer.targetEdges = edgesToWatch[i]; - recognizer.screenBounds = UIScreen.mainScreen.bounds; - [gestureRecognizers addObject:recognizer]; - } +%ctor { + if (IS_IOS_OR_OLDER(iOS_8_4) || !IS_SPRINGBOARD) { + return; + } - %init; + LogDebug(@"start of ctor"); - __static$Hooks9$SBHandMotionExtractorReplacementByMultiplexer = [[Hooks9$SBHandMotionExtractorReplacementByMultiplexer alloc] init]; - } - -} \ No newline at end of file + clientCreatePointer clientCreate; + void *handle = dlopen(0, 9); + *(void**)(&clientCreate) = dlsym(handle,"IOHIDEventSystemClientCreate"); + IOHIDEventSystemClientRef hidEventSystem = (__IOHIDEventSystemClient *)clientCreate(kCFAllocatorDefault); + IOHIDEventSystemClientScheduleWithRunLoop(hidEventSystem, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDEventSystemClientRegisterEventCallback(hidEventSystem, (IOHIDEventSystemClientEventCallback)touch_event, NULL, NULL); + + LogDebug(@"did iokit stuff") + + class_addProtocol(%c(Hooks9$SBHandMotionExtractorReplacementByMultiplexer), @protocol(_UIScreenEdgePanRecognizerDelegate)); + + LogDebug(@"added protocol"); + + UIRectEdge edgesToWatch[] = { UIRectEdgeBottom, UIRectEdgeLeft, UIRectEdgeRight, UIRectEdgeTop }; + int edgeCount = sizeof(edgesToWatch) / sizeof(UIRectEdge); + gestureRecognizers = [[NSMutableSet alloc] initWithCapacity:edgeCount]; + for (int i = 0; i < edgeCount; i++) { + _UIScreenEdgePanRecognizer *recognizer = [[_UIScreenEdgePanRecognizer alloc] initWithType:2]; + recognizer.targetEdges = edgesToWatch[i]; + recognizer.screenBounds = UIScreen.mainScreen._referenceBounds; + [gestureRecognizers addObject:recognizer]; + } + + LogDebug(@"added gestureRecognizers") + + %init; + + LogDebug(@"inited ctor"); + + __static$Hooks9$SBHandMotionExtractorReplacementByMultiplexer = [[Hooks9$SBHandMotionExtractorReplacementByMultiplexer alloc] init]; +} diff --git a/GestureSupport/RAGestureCallback.h b/GestureSupport/RAGestureCallback.h index 507d679..0b23d7f 100644 --- a/GestureSupport/RAGestureCallback.h +++ b/GestureSupport/RAGestureCallback.h @@ -9,6 +9,6 @@ @property (nonatomic) UIRectEdge screenEdge; @property (nonatomic) NSUInteger priority; -@property (nonatomic, retain) NSString *identifier; +@property (nonatomic, copy) NSString *identifier; -@end \ No newline at end of file +@end diff --git a/GestureSupport/RAGestureManager.h b/GestureSupport/RAGestureManager.h index f5a449f..a8ef218 100644 --- a/GestureSupport/RAGestureManager.h +++ b/GestureSupport/RAGestureManager.h @@ -2,17 +2,17 @@ @class RAGestureCallback; -typedef enum { +typedef NS_ENUM(NSInteger, RAGestureCallbackResult) { RAGestureCallbackResultSuccessAndContinue, RAGestureCallbackResultFailure, RAGestureCallbackResultSuccessAndStop, RAGestureCallbackResultSuccess = RAGestureCallbackResultSuccessAndContinue, -} RAGestureCallbackResult; +}; @protocol RAGestureCallbackProtocol --(BOOL) RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity; --(RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; +- (BOOL)RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity; +- (RAGestureCallbackResult)RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; @end typedef BOOL(^RAGestureConditionBlock)(CGPoint location, CGPoint velocity); @@ -26,20 +26,20 @@ const NSUInteger RAGesturePriorityDefault = RAGesturePriorityLow; NSMutableArray *gestures; NSMutableDictionary *ignoredAreas; } -+(id) sharedInstance; - --(void) addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority; --(void) addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier; --(void) addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier; --(void) addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority; --(void) addGesture:(RAGestureCallback*)callback; --(void) removeGestureWithIdentifier:(NSString*)identifier; - --(BOOL) canHandleMovementWithPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; --(BOOL) handleMovementOrStateUpdate:(UIGestureRecognizerState)state withPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; - --(void) ignoreSwipesBeginningInRect:(CGRect)area forIdentifier:(NSString*)identifier; --(void) stopIgnoringSwipesForIdentifier:(NSString*)identifier; --(void) ignoreSwipesBeginningOnSide:(UIRectEdge)side aboveYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier; --(void) ignoreSwipesBeginningOnSide:(UIRectEdge)side belowYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier; -@end \ No newline at end of file ++ (instancetype)sharedInstance; + +- (void)addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority; +- (void)addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier; +- (void)addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier; +- (void)addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority; +- (void)addGesture:(RAGestureCallback*)callback; +- (void)removeGestureWithIdentifier:(NSString*)identifier; + +- (BOOL)canHandleMovementWithPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; +- (BOOL)handleMovementOrStateUpdate:(UIGestureRecognizerState)state withPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge; + +- (void)ignoreSwipesBeginningInRect:(CGRect)area forIdentifier:(NSString*)identifier; +- (void)stopIgnoringSwipesForIdentifier:(NSString*)identifier; +- (void)ignoreSwipesBeginningOnSide:(UIRectEdge)side aboveYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier; +- (void)ignoreSwipesBeginningOnSide:(UIRectEdge)side belowYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier; +@end diff --git a/GestureSupport/RAGestureManager.xm b/GestureSupport/RAGestureManager.xm index 5744a71..e29a5f8 100644 --- a/GestureSupport/RAGestureManager.xm +++ b/GestureSupport/RAGestureManager.xm @@ -4,49 +4,44 @@ #import "RAGestureCallback.h" @implementation RAGestureManager -+(id) sharedInstance -{ - SHARED_INSTANCE2(RAGestureManager, - sharedInstance->gestures = [NSMutableArray array]; ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RAGestureManager, + sharedInstance->gestures = [NSMutableArray array]; sharedInstance->ignoredAreas = [NSMutableDictionary dictionary]; ); } --(void) sortGestureRecognizers -{ +- (void)sortGestureRecognizers { [gestures sortUsingComparator:^NSComparisonResult(RAGestureCallback *a, RAGestureCallback *b) { - if (a.priority > b.priority) + if (a.priority > b.priority) { return NSOrderedAscending; - else if (a.priority < b.priority) + } else if (a.priority < b.priority) { return NSOrderedDescending; + } return NSOrderedSame; }]; } --(void) addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier -{ +- (void)addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier { [self addGestureRecognizer:callbackBlock withCondition:conditionBlock forEdge:screenEdge identifier:identifier priority:RAGesturePriorityDefault]; } --(void) addGesture:(RAGestureCallback*)callback -{ +- (void)addGesture:(RAGestureCallback*)callback { BOOL found = NO; - for (RAGestureCallback *callback_ in gestures) - if ([callback_.identifier isEqual:callback.identifier]) - { + for (RAGestureCallback *callback_ in gestures) { + if ([callback_.identifier isEqual:callback.identifier]) { found = YES; break; } + } - if (!found) - { + if (!found) { [gestures addObject:callback]; - [self sortGestureRecognizers]; + [self sortGestureRecognizers]; } } --(void) addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority -{ +- (void)addGestureRecognizer:(RAGestureCallbackBlock)callbackBlock withCondition:(RAGestureConditionBlock)conditionBlock forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority { RAGestureCallback *callback = [[RAGestureCallback alloc] init]; callback.callbackBlock = [callbackBlock copy]; callback.conditionBlock = [conditionBlock copy]; @@ -57,13 +52,11 @@ [self addGesture:callback]; } --(void) addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier -{ +- (void)addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier { [self addGestureRecognizerWithTarget:target forEdge:screenEdge identifier:identifier priority:RAGesturePriorityDefault]; } --(void) addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority -{ +- (void)addGestureRecognizerWithTarget:(NSObject*)target forEdge:(UIRectEdge)screenEdge identifier:(NSString*)identifier priority:(NSUInteger)priority { RAGestureCallback *callback = [[RAGestureCallback alloc] init]; callback.target = target; callback.screenEdge = screenEdge; @@ -73,14 +66,11 @@ [self addGesture:callback]; } --(void) removeGestureWithIdentifier:(NSString*)identifier -{ +- (void)removeGestureWithIdentifier:(NSString*)identifier { int i = 0; - while (i < gestures.count) - { + while (i < gestures.count) { RAGestureCallback *callback = [self callbackAtIndex:i]; - if ([callback.identifier isEqual:identifier]) - { + if ([callback.identifier isEqual:identifier]) { [gestures removeObjectAtIndex:i]; i--; // offset for the change } @@ -89,37 +79,33 @@ } } --(RAGestureCallback*) callbackAtIndex:(NSUInteger)index -{ +- (RAGestureCallback*)callbackAtIndex:(NSUInteger)index { RAGestureCallback *ret = gestures[index]; //[gestures[index] getValue:&ret]; return ret; } --(BOOL) canHandleMovementWithPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge -{ - for (int i = 0; i < gestures.count; i++) - { +- (BOOL)canHandleMovementWithPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { + for (int i = 0; i < gestures.count; i++) { RAGestureCallback *callback = [self callbackAtIndex:i]; - if (callback.screenEdge & edge) - { - if (callback.conditionBlock) - { - if (callback.conditionBlock(point, velocity)) + if (callback.screenEdge & edge) { + if (callback.conditionBlock) { + if (callback.conditionBlock(point, velocity)) { return YES; - } - else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_canHandle:velocity:)]) - if ([callback.target RAGestureCallback_canHandle:point velocity:velocity]) + } + } else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_canHandle:velocity:)]) { + if ([callback.target RAGestureCallback_canHandle:point velocity:velocity]) { return YES; + } + } } } return NO; } --(BOOL) handleMovementOrStateUpdate:(UIGestureRecognizerState)state withPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge -{ +- (BOOL)handleMovementOrStateUpdate:(UIGestureRecognizerState)state withPoint:(CGPoint)point velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { // If we don't do this check here, but in canHandleMovementWithPoint:forEdge:, the recognizer hooks will not begin tracking the swipe - // This is an issue if someone calls stopIgnoringSwipesForIdentifier: while a swipe is going on. + // This is an issue if someone calls stopIgnoringSwipesForIdentifier: while a swipe is going on. /*for (NSString *key in ignoredAreas.allKeys) { NSValue *value = ignoredAreas[key]; @@ -129,47 +115,46 @@ }*/ BOOL ret = NO; - for (int i = 0; i < gestures.count; i++) - { + for (int i = 0; i < gestures.count; i++) { RAGestureCallback *callback = [self callbackAtIndex:i]; NSValue *value = [ignoredAreas objectForKey:callback.identifier]; - if (value) - { + if (value) { CGRect rect = [value CGRectValue]; - if (CGRectContainsPoint(rect, point)) + if (CGRectContainsPoint(rect, point)) { continue; + } } - if (callback.screenEdge & edge) - { + if (callback.screenEdge & edge) { BOOL isThisCallbackCapable = NO; - if (callback.conditionBlock) - { - if (callback.conditionBlock(point, velocity)) + if (callback.conditionBlock) { + if (callback.conditionBlock(point, velocity)) { isThisCallbackCapable = YES; - } - else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_canHandle:velocity:)]) - if ([callback.target RAGestureCallback_canHandle:point velocity:velocity]) + } + } else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_canHandle:velocity:)]) { + if ([callback.target RAGestureCallback_canHandle:point velocity:velocity]) { isThisCallbackCapable = YES; + } + } - if (isThisCallbackCapable) - { - if (callback.callbackBlock) - { + if (isThisCallbackCapable) { + if (callback.callbackBlock) { RAGestureCallbackResult result = callback.callbackBlock(state, point, velocity); - if (result == RAGestureCallbackResultSuccessAndContinue || result == RAGestureCallbackResultSuccessAndStop) + if (result == RAGestureCallbackResultSuccessAndContinue || result == RAGestureCallbackResultSuccessAndStop) { ret = YES; - if (result == RAGestureCallbackResultSuccessAndStop) + } + if (result == RAGestureCallbackResultSuccessAndStop) { break; - } - else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_handle:withPoint:velocity:forEdge:)]) - { + } + } else if (callback.target && [callback.target respondsToSelector:@selector(RAGestureCallback_handle:withPoint:velocity:forEdge:)]) { RAGestureCallbackResult result = [callback.target RAGestureCallback_handle:state withPoint:point velocity:velocity forEdge:edge]; - if (result == RAGestureCallbackResultSuccessAndContinue || result == RAGestureCallbackResultSuccessAndStop) + if (result == RAGestureCallbackResultSuccessAndContinue || result == RAGestureCallbackResultSuccessAndStop) { ret = YES; - if (result == RAGestureCallbackResultSuccessAndStop) + } + if (result == RAGestureCallbackResultSuccessAndStop) { break; + } } } } @@ -177,28 +162,26 @@ return ret; } --(void) ignoreSwipesBeginningInRect:(CGRect)area forIdentifier:(NSString*)identifier -{ +- (void)ignoreSwipesBeginningInRect:(CGRect)area forIdentifier:(NSString*)identifier { [ignoredAreas setObject:[NSValue valueWithCGRect:area] forKey:identifier]; } --(void) stopIgnoringSwipesForIdentifier:(NSString*)identifier -{ +- (void)stopIgnoringSwipesForIdentifier:(NSString*)identifier { [ignoredAreas removeObjectForKey:identifier]; } --(void) ignoreSwipesBeginningOnSide:(UIRectEdge)side aboveYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier -{ - if (side != UIRectEdgeLeft && side != UIRectEdgeRight) +- (void)ignoreSwipesBeginningOnSide:(UIRectEdge)side aboveYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier { + if (side != UIRectEdgeLeft && side != UIRectEdgeRight) { @throw [NSException exceptionWithName:@"InvalidRectEdgeException" reason:@"Expected UIRectEdgeLeft or UIRectEdgeRight" userInfo:nil]; + } CGRect r = CGRectMake(side == UIRectEdgeLeft ? 0 : UIScreen.mainScreen.bounds.size.width / 2.0 , 0, UIScreen.mainScreen.bounds.size.width / 2.0, axis); [self ignoreSwipesBeginningInRect:r forIdentifier:identifier]; } --(void) ignoreSwipesBeginningOnSide:(UIRectEdge)side belowYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier -{ - if (side != UIRectEdgeLeft && side != UIRectEdgeRight) +-(void) ignoreSwipesBeginningOnSide:(UIRectEdge)side belowYAxis:(NSUInteger)axis forIdentifier:(NSString*)identifier { + if (side != UIRectEdgeLeft && side != UIRectEdgeRight) { @throw [NSException exceptionWithName:@"InvalidRectEdgeException" reason:@"Expected UIRectEdgeLeft or UIRectEdgeRight" userInfo:nil]; + } CGRect r = CGRectMake(side == UIRectEdgeLeft ? 0 : UIScreen.mainScreen.bounds.size.width / 2.0 , axis, UIScreen.mainScreen.bounds.size.width / 2.0, UIScreen.mainScreen.bounds.size.height - axis); [self ignoreSwipesBeginningInRect:r forIdentifier:identifier]; } diff --git a/KeyboardSupport/RAKeyboardStateListener.h b/KeyboardSupport/RAKeyboardStateListener.h index 027acbb..7ada633 100644 --- a/KeyboardSupport/RAKeyboardStateListener.h +++ b/KeyboardSupport/RAKeyboardStateListener.h @@ -1,12 +1,11 @@ #import "headers.h" @interface RAKeyboardStateListener : NSObject -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; @property (nonatomic, readonly) BOOL visible; @property (nonatomic, readonly) CGSize size; --(void) _setVisible:(BOOL)val; --(void) _setSize:(CGSize)size; +- (void)_setVisible:(BOOL)val; +- (void)_setSize:(CGSize)size; @end - diff --git a/KeyboardSupport/RAKeyboardStateListener.xm b/KeyboardSupport/RAKeyboardStateListener.xm index a6d5387..80e09c4 100644 --- a/KeyboardSupport/RAKeyboardStateListener.xm +++ b/KeyboardSupport/RAKeyboardStateListener.xm @@ -12,112 +12,112 @@ extern BOOL overrideDisableForStatusBar; BOOL isShowing = NO; @implementation RAKeyboardStateListener -+ (instancetype)sharedInstance -{ - SHARED_INSTANCE(RAKeyboardStateListener); ++ (instancetype)sharedInstance { + SHARED_INSTANCE(RAKeyboardStateListener); } -- (void)didShow:(NSNotification*)notif -{ - NSLog(@"[ReachApp] keyboard didShow"); - _visible = YES; - _size = [[notif.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; +- (void)didShow:(NSNotification*)notif { + LogDebug(@"[ReachApp] keyboard didShow"); + _visible = YES; + _size = [[notif.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; - IF_NOT_SPRINGBOARD { - CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("com.efrederickson.reachapp.keyboard.didShow"), NULL, NULL, true); - [RAMessagingClient.sharedInstance notifyServerOfKeyboardSizeUpdate:_size]; + IF_NOT_SPRINGBOARD { + CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("com.efrederickson.reachapp.keyboard.didShow"), NULL, NULL, true); + [RAMessagingClient.sharedInstance notifyServerOfKeyboardSizeUpdate:_size]; - if ([RAMessagingClient.sharedInstance shouldUseExternalKeyboard]) - { - [RAMessagingClient.sharedInstance notifyServerToShowKeyboard]; - isShowing = YES; - } + if ([RAMessagingClient.sharedInstance shouldUseExternalKeyboard]) { + [RAMessagingClient.sharedInstance notifyServerToShowKeyboard]; + isShowing = YES; } + } } -- (void)didHide -{ - NSLog(@"[ReachApp] keyboard didHide"); - _visible = NO; +- (void)didHide { + LogDebug(@"[ReachApp] keyboard didHide"); + _visible = NO; - IF_NOT_SPRINGBOARD { - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.keyboard.didHide"), NULL, NULL, true); - if ([RAMessagingClient.sharedInstance shouldUseExternalKeyboard] || isShowing) - { - isShowing = NO; - [RAMessagingClient.sharedInstance notifyServerToHideKeyboard]; - } + IF_NOT_SPRINGBOARD { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.keyboard.didHide"), NULL, NULL, true); + if ([RAMessagingClient.sharedInstance shouldUseExternalKeyboard] || isShowing) { + isShowing = NO; + [RAMessagingClient.sharedInstance notifyServerToHideKeyboard]; } + } } -- (id)init -{ - if ((self = [super init])) - { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - [center addObserver:self selector:@selector(didShow:) name:UIKeyboardDidShowNotification object:nil]; - [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil]; - [center addObserver:self selector:@selector(didHide) name:UIApplicationWillResignActiveNotification object:nil]; - } - return self; +- (instancetype)init { + self = [super init]; + if (self) { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(didShow:) name:UIKeyboardDidShowNotification object:nil]; + [center addObserver:self selector:@selector(didHide) name:UIKeyboardWillHideNotification object:nil]; + [center addObserver:self selector:@selector(didHide) name:UIApplicationWillResignActiveNotification object:nil]; + } + return self; +} + +- (void)_setVisible:(BOOL)val { + _visible = val; } --(void) _setVisible:(BOOL)val { _visible = val; } --(void) _setSize:(CGSize)size { _size = size; } +- (void)_setSize:(CGSize)size { + _size = size; +} @end -void externalKeyboardDidShow(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) -{ - [RAKeyboardStateListener.sharedInstance _setVisible:YES]; +void externalKeyboardDidShow(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + [RAKeyboardStateListener.sharedInstance _setVisible:YES]; } -void externalKeyboardDidHide(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) -{ - //NSLog(@"[ReachApp] externalKeyboardDidHide"); - [RAKeyboardStateListener.sharedInstance _setVisible:NO]; +void externalKeyboardDidHide(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + //LogDebug(@"[ReachApp] externalKeyboardDidHide"); + [RAKeyboardStateListener.sharedInstance _setVisible:NO]; } %hook UIKeyboard --(void) activate -{ - %orig; - - void (^block)() = ^{ - IF_NOT_SPRINGBOARD { - unsigned int contextID = 0; - if (objc_getClass("UIRemoteKeyboardWindow") != nil && [UIKeyboard activeKeyboard] && [[UIKeyboard activeKeyboard] window]) - contextID = [[[UIKeyboard activeKeyboard] window] _contextId]; // ((UITextEffectsWindow*)[%c(UIRemoteKeyboardWindow) remoteKeyboardWindowForScreen:UIScreen.mainScreen create:NO])._contextId; - else - contextID = UITextEffectsWindow.sharedTextEffectsWindow._contextId; - [RAMessagingClient.sharedInstance notifyServerWithKeyboardContextId:contextID]; - - #if DEBUG && NO - assert([[[UIKeyboard activeKeyboard] window] _contextId]); - assert(contextID != 0); - assert(contextID == [[[UIKeyboard activeKeyboard] window] _contextId]); - #endif - - NSLog(@"[ReachApp] c id %d", contextID); +- (void)activate { + %orig; + + void (^block)() = ^{ + IF_NOT_SPRINGBOARD { + unsigned int contextID = 0; + if (%c(UIRemoteKeyboardWindow) && [UIKeyboard activeKeyboard] && [[UIKeyboard activeKeyboard] window]) { + contextID = [[[UIKeyboard activeKeyboard] window] _contextId]; // ((UITextEffectsWindow*)[%c(UIRemoteKeyboardWindow) remoteKeyboardWindowForScreen:UIScreen.mainScreen create:NO])._contextId; + } else { + contextID = UITextEffectsWindow.sharedTextEffectsWindow._contextId; } - }; + [RAMessagingClient.sharedInstance notifyServerWithKeyboardContextId:contextID]; + + #if DEBUG && NO + assert([[[UIKeyboard activeKeyboard] window] _contextId]); + assert(contextID != 0); + assert(contextID == [[[UIKeyboard activeKeyboard] window] _contextId]); + #endif + + LogDebug(@"[ReachApp] c id %d", contextID); + } + }; - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), block); - else - block(); + if (IS_IOS_OR_NEWER(iOS_9_0)) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), block); + } else { + block(); + } +} ++ (void)initImplementationNow { + %orig; + LogDebug(@"initImplementationNow"); } %end -%ctor -{ - // Any process - [RAKeyboardStateListener sharedInstance]; +%ctor { + // Any process + [RAKeyboardStateListener sharedInstance]; - // Just SpringBoard - IF_SPRINGBOARD - { - CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, externalKeyboardDidShow, CFSTR("com.efrederickson.reachapp.keyboard.didShow"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, externalKeyboardDidHide, CFSTR("com.efrederickson.reachapp.keyboard.didHide"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - } -} \ No newline at end of file + // Just SpringBoard + IF_SPRINGBOARD { + CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, externalKeyboardDidShow, CFSTR("com.efrederickson.reachapp.keyboard.didShow"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, externalKeyboardDidHide, CFSTR("com.efrederickson.reachapp.keyboard.didHide"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + } +} diff --git a/KeyboardSupport/RAKeyboardWindow.h b/KeyboardSupport/RAKeyboardWindow.h index 366d7e2..e5db643 100644 --- a/KeyboardSupport/RAKeyboardWindow.h +++ b/KeyboardSupport/RAKeyboardWindow.h @@ -5,8 +5,8 @@ RARemoteKeyboardView *kbView; } --(void) setupForKeyboardAndShow:(NSString*)identifier; --(void) removeKeyboard; +- (void)setupForKeyboardAndShow:(NSString*)identifier; +- (void)removeKeyboard; --(unsigned int) contextId; +- (unsigned int)contextId; @end diff --git a/KeyboardSupport/RAKeyboardWindow.mm b/KeyboardSupport/RAKeyboardWindow.mm index b257e40..17ffedc 100644 --- a/KeyboardSupport/RAKeyboardWindow.mm +++ b/KeyboardSupport/RAKeyboardWindow.mm @@ -4,13 +4,13 @@ #import "RADesktopManager.h" @implementation RAKeyboardWindow --(void) setupForKeyboardAndShow:(NSString*)identifier -{ +- (void)setupForKeyboardAndShow:(NSString*)identifier { self.userInteractionEnabled = YES; self.backgroundColor = UIColor.clearColor; - - if (kbView) + + if (kbView) { [self removeKeyboard]; + } kbView = [[RARemoteKeyboardView alloc] initWithFrame:UIScreen.mainScreen.bounds]; [kbView connectToKeyboardWindowForApp:identifier]; @@ -21,12 +21,13 @@ -(void) setupForKeyboardAndShow:(NSString*)identifier [self makeKeyAndVisible]; } --(void) removeKeyboard -{ +- (void)removeKeyboard { [kbView connectToKeyboardWindowForApp:nil]; [kbView removeFromSuperview]; kbView = nil; } --(unsigned int) contextId { return kbView.layerHost.contextId; } +- (unsigned int)contextId { + return kbView.layerHost.contextId; +} @end diff --git a/KeyboardSupport/RARemoteKeyboardView.h b/KeyboardSupport/RARemoteKeyboardView.h index e5bd873..e6f6c0b 100644 --- a/KeyboardSupport/RARemoteKeyboardView.h +++ b/KeyboardSupport/RARemoteKeyboardView.h @@ -9,5 +9,5 @@ NSString *_identifier; } @property (nonatomic, retain) CALayerHost *layerHost; --(void) connectToKeyboardWindowForApp:(NSString*)identifier; +- (void)connectToKeyboardWindowForApp:(NSString*)identifier; @end diff --git a/KeyboardSupport/RARemoteKeyboardView.xm b/KeyboardSupport/RARemoteKeyboardView.xm index 3fa92b4..6f23fec 100644 --- a/KeyboardSupport/RARemoteKeyboardView.xm +++ b/KeyboardSupport/RARemoteKeyboardView.xm @@ -12,48 +12,43 @@ @implementation RARemoteKeyboardView @synthesize layerHost = _layerHost; --(void) connectToKeyboardWindowForApp:(NSString*)identifier -{ - if (!identifier) - { - self.layerHost.contextId = 0; - cancelFetchingContextId = YES; - return; - } - _identifier = identifier; - - unsigned int value = [RAMessagingServer.sharedInstance getStoredKeyboardContextIdForApp:identifier]; - self.layerHost.contextId = value; - - NSLog(@"[ReachApp] loaded keyboard view with %d", value); - if (value == 0 && cancelFetchingContextId == NO) - { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self connectToKeyboardWindowForApp:identifier]; - }); - } +- (void)connectToKeyboardWindowForApp:(NSString*)identifier { + if (!identifier) { + self.layerHost.contextId = 0; + cancelFetchingContextId = YES; + return; + } + _identifier = identifier; + + unsigned int value = [RAMessagingServer.sharedInstance getStoredKeyboardContextIdForApp:identifier]; + self.layerHost.contextId = value; + + LogDebug(@"[ReachApp] loaded keyboard view with %d", value); + if (value == 0 && !cancelFetchingContextId) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self connectToKeyboardWindowForApp:identifier]; + }); + } } --(id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { - self.userInteractionEnabled = YES; - self.layerHost = [[CALayerHost alloc] init]; - self.layerHost.anchorPoint = CGPointMake(0, 0); - if (SYSTEM_VERSION_LESS_THAN(@"9.0")) - self.layerHost.transform = CATransform3DMakeScale(1/[UIScreen mainScreen].scale, 1/[UIScreen mainScreen].scale, 1); - self.layerHost.bounds = self.bounds; - [self.layer addSublayer:self.layerHost]; - update = NO; +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.userInteractionEnabled = YES; + self.layerHost = [[CALayerHost alloc] init]; + self.layerHost.anchorPoint = CGPointMake(0, 0); + if (IS_IOS_OR_OLDER(iOS_8_4)) { + self.layerHost.transform = CATransform3DMakeScale(1/[UIScreen mainScreen].scale, 1/[UIScreen mainScreen].scale, 1); } - - return self; + self.layerHost.bounds = self.bounds; + [self.layer addSublayer:self.layerHost]; + update = NO; + } + + return self; } --(void)dealloc -{ - self.layerHost = nil; +- (void)dealloc { + self.layerHost = nil; } @end diff --git a/KeyboardSupport/RASpringBoardKeyboardActivation.h b/KeyboardSupport/RASpringBoardKeyboardActivation.h index 9a6dd03..af3384f 100644 --- a/KeyboardSupport/RASpringBoardKeyboardActivation.h +++ b/KeyboardSupport/RASpringBoardKeyboardActivation.h @@ -2,12 +2,12 @@ #import "RARunningAppsProvider.h" @interface RASpringBoardKeyboardActivation : NSObject -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; -@property (nonatomic, readonly, retain) NSString *currentIdentifier; +@property (nonatomic, readonly, copy) NSString *currentIdentifier; --(void) showKeyboardForAppWithIdentifier:(NSString*)identifier; --(void) hideKeyboard; +- (void)showKeyboardForAppWithIdentifier:(NSString*)identifier; +- (void)hideKeyboard; --(UIWindow*) keyboardWindow; +- (UIWindow*)keyboardWindow; @end diff --git a/KeyboardSupport/RASpringBoardKeyboardActivation.xm b/KeyboardSupport/RASpringBoardKeyboardActivation.xm index 2f3bd0b..b8c3c66 100644 --- a/KeyboardSupport/RASpringBoardKeyboardActivation.xm +++ b/KeyboardSupport/RASpringBoardKeyboardActivation.xm @@ -10,47 +10,43 @@ extern BOOL overrideDisableForStatusBar; RAKeyboardWindow *keyboardWindow; @implementation RASpringBoardKeyboardActivation -+(id) sharedInstance -{ - SHARED_INSTANCE2(RASpringBoardKeyboardActivation, - [RARunningAppsProvider.sharedInstance addTarget:self] - ); ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RASpringBoardKeyboardActivation, + [RARunningAppsProvider.sharedInstance addTarget:self] + ); } --(void) showKeyboardForAppWithIdentifier:(NSString*)identifier -{ - if (keyboardWindow) - { - [self hideKeyboard]; - //NSLog(@"[ReachApp] springboard cancelling - keyboardWindow exists"); - //return; - } +- (void)showKeyboardForAppWithIdentifier:(NSString*)identifier { + if (keyboardWindow) { + [self hideKeyboard]; + //NSLog(@"[ReachApp] springboard cancelling - keyboardWindow exists"); + //return; + } - NSLog(@"[ReachApp] showing kb window %@", identifier); - keyboardWindow = [[RAKeyboardWindow alloc] init]; - overrideDisableForStatusBar = YES; - [keyboardWindow setupForKeyboardAndShow:identifier]; - overrideDisableForStatusBar = NO; - _currentIdentifier = identifier; + LogDebug(@"[ReachApp] showing kb window %@", identifier); + keyboardWindow = [[RAKeyboardWindow alloc] init]; + overrideDisableForStatusBar = YES; + [keyboardWindow setupForKeyboardAndShow:identifier]; + overrideDisableForStatusBar = NO; + _currentIdentifier = identifier; } --(void) hideKeyboard -{ - NSLog(@"[ReachApp] remove kb window (%@)", _currentIdentifier); - keyboardWindow.hidden = YES; - [keyboardWindow removeKeyboard]; - keyboardWindow = nil; - _currentIdentifier = nil; +- (void)hideKeyboard { + LogDebug(@"[ReachApp] remove kb window (%@)", _currentIdentifier); + keyboardWindow.hidden = YES; + [keyboardWindow removeKeyboard]; + keyboardWindow = nil; + _currentIdentifier = nil; } --(void) appDidDie:(SBApplication*)app -{ - if ([_currentIdentifier isEqual:app.bundleIdentifier]) - [self hideKeyboard]; +- (void)appDidDie:(SBApplication*)app { + if (![_currentIdentifier isEqual:app.bundleIdentifier]) { + return; + } + [self hideKeyboard]; } --(UIWindow*) keyboardWindow -{ - return keyboardWindow; +- (UIWindow*)keyboardWindow { + return keyboardWindow; } @end diff --git a/Makefile b/Makefile index c1b30ff..a8c1bb1 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,7 @@ -DEBUG = 1 ARCHS = armv7 armv7s arm64 -CFLAGS = -I./ -Iwidgets/ -Iwidgets/Core/ -Iwidgets/Reachability/ -ISwipeOver/ -IReachability/ -IGestureSupport/ -IKeyboardSupport/ -IMissionControl/ -IWindowedMultitasking/ -INotificationCenterApp/ -IBackgrounding/ -IIntroTutorial/ -IMessaging/ -ITheming/ +CFLAGS = -I./ -Iwidgets/ -Iwidgets/Core/ -Iwidgets/Reachability/ -ISwipeOver/ -IReachability/ -IGestureSupport/ -IKeyboardSupport/ -IMissionControl/ -IWindowedMultitasking/ -INotificationCenterApp/ -IBackgrounding/ -IIntroTutorial/ -IMessaging/ -ITheming/ -O2 CFLAGS += -fobjc-arc -LDFLAGS += -Wl,-segalign,4000 -THEOS_PACKAGE_DIR_NAME = debs -TARGET = :8.0 +TARGET = iphone:9.2 include $(THEOS)/makefiles/common.mk @@ -23,18 +20,15 @@ ReachApp_FILES = Tweak.xm $(wildcard *.xm) $(wildcard *.mm) $(wildcard *.m) \ $(wildcard DRM/*.xm) $(wildcard DRM/*.mm) $(wildcard DRM/*.m) \ $(wildcard Theming/*.xm) $(wildcard Theming/*.mm) $(wildcard Theming/*.m) \ $(wildcard Debugging/*.xm) $(wildcard Debugging/*.mm) $(wildcard Debugging/*.m) - + ReachApp_FRAMEWORKS = UIKit QuartzCore CoreGraphics CoreImage ReachApp_PRIVATE_FRAMEWORKS = GraphicsServices BackBoardServices AppSupport IOKit -ReachApp_LIBRARIES = applist +ReachApp_LIBRARIES = applist rocketbootstrap include $(THEOS_MAKE_PATH)/tweak.mk after-install:: -# install.exec "killall -9 SpringBoard" -# install.exec "killall -9 Preferences" - install.exec "killall -9 backboardd" - + install.exec "killall -9 SpringBoard" SUBPROJECTS += Backgrounding SUBPROJECTS += MissionControl diff --git a/Messaging/RAMessaging.h b/Messaging/RAMessaging.h index 7ced4fa..f51dea0 100644 --- a/Messaging/RAMessaging.h +++ b/Messaging/RAMessaging.h @@ -1,15 +1,15 @@ #import -enum { +typedef NS_ENUM(NSInteger, RAMessageType) { RAMessageTypeUpdateAppData = 0, RAMessageTypeShowKeyboard, RAMessageTypeHideKeyboard, RAMessageTypeUpdateKeyboardContextId, RAMessageTypeRetrieveKeyboardContextId, -} RAMessageType; +}; -struct RAMessageAppData { +typedef struct { BOOL shouldForceSize; // Can't use CGSize because it uses CGFloats which aren't able to be transferred between 32/64bit processes (because its float in one and something else (double? i can't remember) in the other). // Also why we can't use CGFloat here @@ -21,15 +21,15 @@ struct RAMessageAppData { BOOL statusBarVisibility; BOOL shouldForceStatusBar; BOOL canHideStatusBarIfWanted; - + UIInterfaceOrientation forcedOrientation; BOOL shouldForceOrientation; - + BOOL shouldUseExternalKeyboard; BOOL isBeingHosted; // Only applies after the app has been restarted. BOOL forcePhoneMode; -}; +} RAMessageAppData; static NSString *RAMessagingUpdateAppInfoMessageName = @"updateAppInfo"; static NSString *RAMessagingShowKeyboardMessageName = @"showKeyboard"; diff --git a/Messaging/RAMessagingClient.h b/Messaging/RAMessagingClient.h index b1528c9..f9173a0 100644 --- a/Messaging/RAMessagingClient.h +++ b/Messaging/RAMessagingClient.h @@ -1,32 +1,33 @@ #import "headers.h" #import +#import #import "RAMessaging.h" @interface RAMessagingClient : NSObject { CPDistributedMessagingCenter *serverCenter; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; @property (nonatomic, readonly) RAMessageAppData currentData; @property (nonatomic) BOOL hasRecievedData; -@property (nonatomic, retain) NSString *knownFrontmostApp; +@property (nonatomic, copy) NSString *knownFrontmostApp; --(void) requestUpdateFromServer; +- (void)requestUpdateFromServer; --(void) notifyServerWithKeyboardContextId:(unsigned int)cid; --(void) notifyServerOfKeyboardSizeUpdate:(CGSize)size; --(void) notifyServerToShowKeyboard; --(void) notifyServerToHideKeyboard; --(BOOL) notifyServerToOpenURL:(NSURL*)url openInWindow:(BOOL)openWindow; --(void) notifySpringBoardOfFrontAppChangeToSelf; +- (void)notifyServerWithKeyboardContextId:(unsigned int)cid; +- (void)notifyServerOfKeyboardSizeUpdate:(CGSize)size; +- (void)notifyServerToShowKeyboard; +- (void)notifyServerToHideKeyboard; +- (BOOL)notifyServerToOpenURL:(NSURL*)url openInWindow:(BOOL)openWindow; +- (void)notifySpringBoardOfFrontAppChangeToSelf; // Methods to ease the currentData usage --(BOOL) shouldResize; --(CGSize) resizeSize; --(BOOL) shouldHideStatusBar; --(BOOL) shouldShowStatusBar; --(UIInterfaceOrientation) forcedOrientation; --(BOOL) shouldForceOrientation; --(BOOL) shouldUseExternalKeyboard; --(BOOL) isBeingHosted; -@end \ No newline at end of file +- (BOOL)shouldResize; +- (CGSize)resizeSize; +- (BOOL)shouldHideStatusBar; +- (BOOL)shouldShowStatusBar; +- (UIInterfaceOrientation)forcedOrientation; +- (BOOL)shouldForceOrientation; +- (BOOL)shouldUseExternalKeyboard; +- (BOOL)isBeingHosted; +@end diff --git a/Messaging/RAMessagingClient.xm b/Messaging/RAMessagingClient.xm index 6a79fe2..e2c1252 100644 --- a/Messaging/RAMessagingClient.xm +++ b/Messaging/RAMessagingClient.xm @@ -5,40 +5,38 @@ extern BOOL allowClosingReachabilityNatively; #define IS_PROCESS(x) (strcmp(__progname, x) == 0) -@interface RAMessagingClient () { -} - +@interface RAMessagingClient () @property (nonatomic) BOOL allowedProcess; @end @implementation RAMessagingClient @synthesize allowedProcess; -+(instancetype) sharedInstance -{ ++ (instancetype)sharedInstance { IF_SPRINGBOARD { @throw [NSException exceptionWithName:@"IsSpringBoardException" reason:@"Cannot use RAMessagingClient in SpringBoard" userInfo:nil]; } - SHARED_INSTANCE2(RAMessagingClient, + SHARED_INSTANCE2(RAMessagingClient, [sharedInstance loadMessagingCenter]; sharedInstance.hasRecievedData = NO; if ([NSBundle.mainBundle.executablePath hasPrefix:@"/Applications"] || + [NSBundle.mainBundle.executablePath hasPrefix:@"/var/stash/appsstash"] || + [NSBundle.mainBundle.executablePath hasPrefix:@"/var/containers/Bundle/Application"] || [NSBundle.mainBundle.executablePath hasPrefix:@"/private/var/db/stash"] || [NSBundle.mainBundle.executablePath hasPrefix:@"/var/mobile/Applications"] || [NSBundle.mainBundle.executablePath hasPrefix:@"/private/var/mobile/Applications"] || [NSBundle.mainBundle.executablePath hasPrefix:@"/var/mobile/Containers/Bundle/Application"] || [NSBundle.mainBundle.executablePath hasPrefix:@"/private/var/mobile/Containers/Bundle/Application"]) { - NSLog(@"[ReachApp] valid process for RAMessagingClient"); + LogDebug(@"[ReachApp] valid process for RAMessagingClient"); sharedInstance->allowedProcess = YES; } ); } --(void) loadMessagingCenter -{ +- (void)loadMessagingCenter { RAMessageAppData data; data.shouldForceSize = NO; @@ -53,78 +51,64 @@ extern BOOL allowClosingReachabilityNatively; data.shouldForceOrientation = NO; data.shouldUseExternalKeyboard = NO; data.forcePhoneMode = NO; - data.isBeingHosted = NO; + data.isBeingHosted = NO; _currentData = data; // Initialize data - serverCenter = [objc_getClass("CPDistributedMessagingCenter") centerNamed:@"com.efrederickson.reachapp.messaging.server"]; + serverCenter = [%c(CPDistributedMessagingCenter) centerNamed:@"com.efrederickson.reachapp.messaging.server"]; - void* handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY); - if (handle) - { - void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*); - rocketbootstrap_distributedmessagingcenter_apply = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); - rocketbootstrap_distributedmessagingcenter_apply(serverCenter); - dlclose(handle); - } + void* handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY); + if (handle) { + void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*) = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); + rocketbootstrap_distributedmessagingcenter_apply(serverCenter); + dlclose(handle); + } } --(void) alertUser:(NSString*)description -{ -#if DEBUG - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"MULTIPLEXER") message:description delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; -#endif +- (void)alertUser:(NSString*)description { + LogError(@"%@", description); } --(void) _requestUpdateFromServerWithTries:(int)tries -{ - /*if (!NSBundle.mainBundle.bundleIdentifier || +- (void)_requestUpdateFromServerWithTries:(int)tries { + /*if (!NSBundle.mainBundle.bundleIdentifier || IS_PROCESS("assertiond") || // Don't need to load into this anyway IS_PROCESS("searchd") || // safe-mode crash fix IS_PROCESS("gputoolsd") || // iMohkles found this crashes (no uikit) IS_PROCESS("filecoordinationd") || // ??? - IS_PROCESS("backboardd") // Backboardd uses its own messaging center for what it does. + IS_PROCESS("backboardd") // Backboardd uses its own messaging center for what it does. )*/ - if (allowedProcess == NO) - { + if (!allowedProcess) { // Anything that's not a UIApp (system app or user app) doesn't need this messaging client // Attempting to reach out will either: // 1. hang the process // 2. crash after timeout due to no UIKit (?) // 3. something else bad - // so therefore all those are simply blacklisted. simple. + // so therefore all those are simply blacklisted. simple. return; } NSDictionary *dict = @{ @"bundleIdentifier": NSBundle.mainBundle.bundleIdentifier }; NSDictionary *data = [serverCenter sendMessageAndReceiveReplyName:RAMessagingUpdateAppInfoMessageName userInfo:dict]; - if (data && [data objectForKey:@"data"] != nil) - { + if (data && [data objectForKey:@"data"]) { RAMessageAppData actualData; [data[@"data"] getBytes:&actualData length:sizeof(actualData)]; [self updateWithData:actualData]; self.hasRecievedData = YES; - } - else - { - if (tries <= 4) + } else { + if (tries <= 4) { [self _requestUpdateFromServerWithTries:tries + 1]; - else - { + } else { [self alertUser:[NSString stringWithFormat:@"App \"%@\" is unable to communicate with messaging server", [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"] ?: NSBundle.mainBundle.bundleIdentifier]]; } } } --(void) requestUpdateFromServer -{ +- (void)requestUpdateFromServer { [self _requestUpdateFromServerWithTries:0]; } --(void) updateWithData:(RAMessageAppData)data -{ +- (void)updateWithData:(RAMessageAppData)data { BOOL didStatusBarVisibilityChange = _currentData.shouldForceStatusBar != data.shouldForceStatusBar; BOOL didOrientationChange = _currentData.shouldForceOrientation != data.shouldForceOrientation; BOOL didSizingChange =_currentData.shouldForceSize != data.shouldForceSize; @@ -132,49 +116,47 @@ extern BOOL allowClosingReachabilityNatively; /* THE REAL IMPORTANT BIT */ _currentData = data; - if (didStatusBarVisibilityChange && data.shouldForceStatusBar == NO) - [UIApplication.sharedApplication RA_forceStatusBarVisibility:_currentData.statusBarVisibility orRevert:YES]; - else if (data.shouldForceStatusBar) - [UIApplication.sharedApplication RA_forceStatusBarVisibility:_currentData.statusBarVisibility orRevert:NO]; + if (didStatusBarVisibilityChange && !data.shouldForceStatusBar) { + [UIApplication.sharedApplication RA_forceStatusBarVisibility:_currentData.statusBarVisibility orRevert:YES]; + } else if (data.shouldForceStatusBar) { + [UIApplication.sharedApplication RA_forceStatusBarVisibility:_currentData.statusBarVisibility orRevert:NO]; + } - if (didSizingChange && data.shouldForceSize == NO) - [UIApplication.sharedApplication RA_updateWindowsForSizeChange:CGSizeMake(data.wantedClientWidth, data.wantedClientHeight) isReverting:YES]; - else if (data.shouldForceSize) - [UIApplication.sharedApplication RA_updateWindowsForSizeChange:CGSizeMake(data.wantedClientWidth, data.wantedClientHeight) isReverting:NO]; + if (didSizingChange && !data.shouldForceSize) { + [UIApplication.sharedApplication RA_updateWindowsForSizeChange:CGSizeMake(data.wantedClientWidth, data.wantedClientHeight) isReverting:YES]; + } else if (data.shouldForceSize) { + [UIApplication.sharedApplication RA_updateWindowsForSizeChange:CGSizeMake(data.wantedClientWidth, data.wantedClientHeight) isReverting:NO]; + } - if (didOrientationChange && data.shouldForceOrientation == NO) + if (didOrientationChange && !data.shouldForceOrientation) { [UIApplication.sharedApplication RA_forceRotationToInterfaceOrientation:data.forcedOrientation isReverting:YES]; - else if (data.shouldForceOrientation) + } else if (data.shouldForceOrientation) { [UIApplication.sharedApplication RA_forceRotationToInterfaceOrientation:data.forcedOrientation isReverting:NO]; + } allowClosingReachabilityNatively = YES; } --(void) notifyServerWithKeyboardContextId:(unsigned int)cid -{ +- (void)notifyServerWithKeyboardContextId:(unsigned int)cid { NSDictionary *dict = @{ @"contextId": @(cid), @"bundleIdentifier": NSBundle.mainBundle.bundleIdentifier }; [serverCenter sendMessageName:RAMessagingUpdateKeyboardContextIdMessageName userInfo:dict]; } --(void) notifyServerToShowKeyboard -{ +- (void)notifyServerToShowKeyboard { NSDictionary *dict = @{ @"bundleIdentifier": NSBundle.mainBundle.bundleIdentifier }; [serverCenter sendMessageName:RAMessagingShowKeyboardMessageName userInfo:dict]; } --(void) notifyServerToHideKeyboard -{ +- (void)notifyServerToHideKeyboard { [serverCenter sendMessageName:RAMessagingHideKeyboardMessageName userInfo:nil]; } --(void) notifyServerOfKeyboardSizeUpdate:(CGSize)size -{ +- (void)notifyServerOfKeyboardSizeUpdate:(CGSize)size { NSDictionary *dict = @{ @"size": NSStringFromCGSize(size) }; [serverCenter sendMessageName:RAMessagingUpdateKeyboardSizeMessageName userInfo:dict]; } --(BOOL) notifyServerToOpenURL:(NSURL*)url openInWindow:(BOOL)openWindow -{ +- (BOOL)notifyServerToOpenURL:(NSURL*)url openInWindow:(BOOL)openWindow { NSDictionary *dict = @{ @"url": url.absoluteString, @"openInWindow": @(openWindow) @@ -182,53 +164,56 @@ extern BOOL allowClosingReachabilityNatively; return [[serverCenter sendMessageAndReceiveReplyName:RAMessagingOpenURLKMessageName userInfo:dict][@"success"] boolValue]; } --(void) notifySpringBoardOfFrontAppChangeToSelf -{ +- (void)notifySpringBoardOfFrontAppChangeToSelf { NSString *ident = NSBundle.mainBundle.bundleIdentifier; - if (!ident) + if (!ident) { return; + } - if ([self isBeingHosted] && (self.knownFrontmostApp == nil || [self.knownFrontmostApp isEqual:ident] == NO)) + if ([self isBeingHosted] && (!self.knownFrontmostApp || ![self.knownFrontmostApp isEqual:ident])) { [serverCenter sendMessageName:RAMessagingChangeFrontMostAppMessageName userInfo:@{ @"bundleIdentifier": ident }]; + } } --(BOOL) shouldUseExternalKeyboard { return _currentData.shouldUseExternalKeyboard; } --(BOOL) shouldResize { return _currentData.shouldForceSize; } --(CGSize) resizeSize { return CGSizeMake(_currentData.wantedClientWidth, _currentData.wantedClientHeight); } --(BOOL) shouldHideStatusBar { return _currentData.shouldForceStatusBar && _currentData.statusBarVisibility == NO; } --(BOOL) shouldShowStatusBar { return _currentData.shouldForceStatusBar && _currentData.statusBarVisibility == YES; } --(UIInterfaceOrientation) forcedOrientation { return _currentData.forcedOrientation; } --(BOOL) shouldForceOrientation { return _currentData.shouldForceOrientation; } --(BOOL) isBeingHosted { return _currentData.isBeingHosted; } +- (BOOL)shouldUseExternalKeyboard { + return _currentData.shouldUseExternalKeyboard; +} +- (BOOL)shouldResize { + return _currentData.shouldForceSize; +} +- (CGSize)resizeSize { + return CGSizeMake(_currentData.wantedClientWidth, _currentData.wantedClientHeight); +} +- (BOOL)shouldHideStatusBar { + return _currentData.shouldForceStatusBar && !_currentData.statusBarVisibility; +} +- (BOOL)shouldShowStatusBar { + return _currentData.shouldForceStatusBar && _currentData.statusBarVisibility; +} +- (UIInterfaceOrientation)forcedOrientation { + return _currentData.forcedOrientation; +} +- (BOOL)shouldForceOrientation { + return _currentData.shouldForceOrientation; +} +- (BOOL)isBeingHosted { + return _currentData.isBeingHosted; +} @end -void reloadClientData(CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo) -{ +void reloadClientData(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { [[RAMessagingClient sharedInstance] requestUpdateFromServer]; } -void updateFrontmostApp(CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo) -{ +void updateFrontmostApp(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { RAMessagingClient.sharedInstance.knownFrontmostApp = ((__bridge NSDictionary*)userInfo)[@"bundleIdentifier"]; } -%ctor -{ +%ctor { IF_SPRINGBOARD { - - } - else - { - [RAMessagingClient sharedInstance]; - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &reloadClientData, (__bridge CFStringRef)[NSString stringWithFormat:@"com.efrederickson.reachapp.clientupdate-%@",NSBundle.mainBundle.bundleIdentifier], NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, &updateFrontmostApp, CFSTR("com.efrederickson.reachapp.frontmostAppDidUpdate"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + return; } -} \ No newline at end of file + [RAMessagingClient sharedInstance]; + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &reloadClientData, (__bridge CFStringRef)[NSString stringWithFormat:@"com.efrederickson.reachapp.clientupdate-%@",NSBundle.mainBundle.bundleIdentifier], NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, &updateFrontmostApp, CFSTR("com.efrederickson.reachapp.frontmostAppDidUpdate"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); +} diff --git a/Messaging/RAMessagingServer.h b/Messaging/RAMessagingServer.h index 353d1ac..a34a3bf 100644 --- a/Messaging/RAMessagingServer.h +++ b/Messaging/RAMessagingServer.h @@ -1,5 +1,6 @@ #import "headers.h" #import +#import #import "RAMessaging.h" @interface RAMessagingServer : NSObject { @@ -8,31 +9,31 @@ NSMutableDictionary *contextIds; NSMutableDictionary *waitingCompletions; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; --(void) loadServer; +- (void)loadServer; --(RAMessageAppData) getDataForIdentifier:(NSString*)identifier; --(void) setData:(RAMessageAppData)data forIdentifier:(NSString*)identifier; --(void) sendStoredDataToApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (RAMessageAppData)getDataForIdentifier:(NSString*)identifier; +- (void)setData:(RAMessageAppData)data forIdentifier:(NSString*)identifier; +- (void)sendStoredDataToApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) resizeApp:(NSString*)identifier toSize:(CGSize)size completion:(RAMessageCompletionCallback)callback; --(void) moveApp:(NSString*)identifier toOrigin:(CGPoint)origin completion:(RAMessageCompletionCallback)callback; --(void) endResizingApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)resizeApp:(NSString*)identifier toSize:(CGSize)size completion:(RAMessageCompletionCallback)callback; +- (void)moveApp:(NSString*)identifier toOrigin:(CGPoint)origin completion:(RAMessageCompletionCallback)callback; +- (void)endResizingApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) rotateApp:(NSString*)identifier toOrientation:(UIInterfaceOrientation)orientation completion:(RAMessageCompletionCallback)callback; --(void) unRotateApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)rotateApp:(NSString*)identifier toOrientation:(UIInterfaceOrientation)orientation completion:(RAMessageCompletionCallback)callback; +- (void)unRotateApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) forceStatusBarVisibility:(BOOL)visibility forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) unforceStatusBarVisibilityForApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)forceStatusBarVisibility:(BOOL)visibility forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)unforceStatusBarVisibilityForApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) setHosted:(BOOL)value forIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)setHosted:(BOOL)value forIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; --(void) forcePhoneMode:(BOOL)value forIdentifier:(NSString*)identifier andRelaunchApp:(BOOL)relaunch; +- (void)forcePhoneMode:(BOOL)value forIdentifier:(NSString*)identifier andRelaunchApp:(BOOL)relaunch; --(unsigned int) getStoredKeyboardContextIdForApp:(NSString*)identifier; +- (unsigned int)getStoredKeyboardContextIdForApp:(NSString*)identifier; --(void) receiveShowKeyboardForAppWithIdentifier:(NSString*)identifier; --(void) receiveHideKeyboard; --(void) setShouldUseExternalKeyboard:(BOOL)value forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; +- (void)receiveShowKeyboardForAppWithIdentifier:(NSString*)identifier; +- (void)receiveHideKeyboard; +- (void)setShouldUseExternalKeyboard:(BOOL)value forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback; @end diff --git a/Messaging/RAMessagingServer.xm b/Messaging/RAMessagingServer.xm index c182652..4322571 100644 --- a/Messaging/RAMessagingServer.xm +++ b/Messaging/RAMessagingServer.xm @@ -12,6 +12,8 @@ #import "RADesktopManager.h" #import "RAWindowSnapDataProvider.h" #import "RAHostManager.h" +#import "Multiplexer.h" +#import "UIAlertController+Window.h" extern BOOL launchNextOpenIntoWindow; @@ -21,9 +23,8 @@ extern BOOL launchNextOpenIntoWindow; @end @implementation RAMessagingServer -+(instancetype) sharedInstance -{ - SHARED_INSTANCE2(RAMessagingServer, ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RAMessagingServer, [sharedInstance loadServer]; sharedInstance->dataForApps = [NSMutableDictionary dictionary]; sharedInstance->contextIds = [NSMutableDictionary dictionary]; @@ -32,73 +33,64 @@ extern BOOL launchNextOpenIntoWindow; ); } --(void) loadServer -{ - messagingCenter = [objc_getClass("CPDistributedMessagingCenter") centerNamed:@"com.efrederickson.reachapp.messaging.server"]; - - void* handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY); - if (handle) - { - void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*); - rocketbootstrap_distributedmessagingcenter_apply = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); - rocketbootstrap_distributedmessagingcenter_apply(messagingCenter); - dlclose(handle); - } - - [messagingCenter runServerOnCurrentThread]; - - [messagingCenter registerForMessageName:RAMessagingShowKeyboardMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingHideKeyboardMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingUpdateKeyboardContextIdMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingRetrieveKeyboardContextIdMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingUpdateAppInfoMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - - [messagingCenter registerForMessageName:RAMessagingUpdateKeyboardSizeMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingOpenURLKMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - - [messagingCenter registerForMessageName:RAMessagingGetFrontMostAppInfoMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingChangeFrontMostAppMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; - - [messagingCenter registerForMessageName:RAMessagingSnapFrontMostWindowLeftMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingSnapFrontMostWindowRightMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingGoToDesktopOnTheLeftMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingGoToDesktopOnTheRightMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingMaximizeAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingAddNewDesktopMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingCloseAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; - [messagingCenter registerForMessageName:RAMessagingDetachCurrentAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; +- (void)loadServer { + messagingCenter = [%c(CPDistributedMessagingCenter) centerNamed:@"com.efrederickson.reachapp.messaging.server"]; + + void* handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY); + if (handle) { + void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*) = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); + rocketbootstrap_distributedmessagingcenter_apply(messagingCenter); + dlclose(handle); + } + + [messagingCenter runServerOnCurrentThread]; + + [messagingCenter registerForMessageName:RAMessagingShowKeyboardMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingHideKeyboardMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingUpdateKeyboardContextIdMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingRetrieveKeyboardContextIdMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingUpdateAppInfoMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + + [messagingCenter registerForMessageName:RAMessagingUpdateKeyboardSizeMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingOpenURLKMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + + [messagingCenter registerForMessageName:RAMessagingGetFrontMostAppInfoMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingChangeFrontMostAppMessageName target:self selector:@selector(handleMessageNamed:userInfo:)]; + + [messagingCenter registerForMessageName:RAMessagingSnapFrontMostWindowLeftMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingSnapFrontMostWindowRightMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingGoToDesktopOnTheLeftMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingGoToDesktopOnTheRightMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingMaximizeAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingAddNewDesktopMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingCloseAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; + [messagingCenter registerForMessageName:RAMessagingDetachCurrentAppMessageName target:self selector:@selector(handleKeyboardEvent:userInfo:)]; } --(NSDictionary*) handleMessageNamed:(NSString*)identifier userInfo:(NSDictionary*)info -{ - if ([identifier isEqual:RAMessagingShowKeyboardMessageName]) +- (NSDictionary*)handleMessageNamed:(NSString*)identifier userInfo:(NSDictionary*)info { + if ([identifier isEqual:RAMessagingShowKeyboardMessageName]) { [self receiveShowKeyboardForAppWithIdentifier:info[@"bundleIdentifier"]]; - else if ([identifier isEqual:RAMessagingHideKeyboardMessageName]) + } else if ([identifier isEqual:RAMessagingHideKeyboardMessageName]) { [self receiveHideKeyboard]; - else if ([identifier isEqual:RAMessagingUpdateKeyboardContextIdMessageName]) + } else if ([identifier isEqual:RAMessagingUpdateKeyboardContextIdMessageName]) { [self setKeyboardContextId:[info[@"contextId"] integerValue] forIdentifier:info[@"bundleIdentifier"]]; - else if ([identifier isEqual:RAMessagingRetrieveKeyboardContextIdMessageName]) + } else if ([identifier isEqual:RAMessagingRetrieveKeyboardContextIdMessageName]) { return @{ @"contextId": @([self getStoredKeyboardContextIdForApp:info[@"bundleIdentifier"]]) }; - else if ([identifier isEqual:RAMessagingUpdateKeyboardSizeMessageName]) - { + } else if ([identifier isEqual:RAMessagingUpdateKeyboardSizeMessageName]) { CGSize size = CGSizeFromString(info[@"size"]); [RAKeyboardStateListener.sharedInstance _setSize:size]; - } - else if ([identifier isEqual:RAMessagingUpdateAppInfoMessageName]) - { + } else if ([identifier isEqual:RAMessagingUpdateAppInfoMessageName]) { NSString *identifier = info[@"bundleIdentifier"]; RAMessageAppData data = [self getDataForIdentifier:identifier]; - if ([waitingCompletions objectForKey:identifier] != nil) - { + if ([waitingCompletions objectForKey:identifier]) { RAMessageCompletionCallback callback = (RAMessageCompletionCallback)waitingCompletions[identifier]; [waitingCompletions removeObjectForKey:identifier]; callback(YES); } - // Got the message, cancel the re-sender - if ([asyncHandles objectForKey:identifier] != nil) - { + // Got the message, cancel the re-sender + if ([asyncHandles objectForKey:identifier]) { struct dispatch_async_handle *handle = (struct dispatch_async_handle *)[asyncHandles[identifier] pointerValue]; dispatch_after_cancel(handle); [asyncHandles removeObjectForKey:identifier]; @@ -107,38 +99,33 @@ extern BOOL launchNextOpenIntoWindow; return @{ @"data": [NSData dataWithBytes:&data length:sizeof(data)], }; - } - else if ([identifier isEqual:RAMessagingOpenURLKMessageName]) - { + } else if ([identifier isEqual:RAMessagingOpenURLKMessageName]) { NSURL *url = [NSURL URLWithString:info[@"url"]]; BOOL openInWindow = [RASettings.sharedInstance openLinksInWindows]; // [info[@"openInWindow"] boolValue]; - if (openInWindow) + if (openInWindow) { launchNextOpenIntoWindow = YES; + } BOOL success = [UIApplication.sharedApplication openURL:url]; return @{ @"success": @(success) }; - } - else if ([identifier isEqual:RAMessagingGetFrontMostAppInfoMessageName]) - { - if (UIApplication.sharedApplication._accessibilityFrontMostApplication) + } else if ([identifier isEqual:RAMessagingGetFrontMostAppInfoMessageName]) { + if (UIApplication.sharedApplication._accessibilityFrontMostApplication) { return nil; + } RAWindowBar *window = RADesktopManager.sharedInstance.lastUsedWindow; - if (window) - { + if (window) { SBApplication *app = window.attachedView.app; - if (app.pid) + if (app.pid) { return @{ @"pid": @(app.pid), @"bundleIdentifier": app.bundleIdentifier }; + } } - } - else if ([identifier isEqual:RAMessagingChangeFrontMostAppMessageName]) - { + } else if ([identifier isEqual:RAMessagingChangeFrontMostAppMessageName]) { NSString *bundleIdentifier = info[@"bundleIdentifier"]; RAWindowBar *window = [RADesktopManager.sharedInstance windowForIdentifier:bundleIdentifier]; - if (window) - { + if (window) { RADesktopManager.sharedInstance.lastUsedWindow = window; CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("com.efrederickson.reachapp.frontmostAppDidUpdate"), NULL, (__bridge CFDictionaryRef)@{ @"bundleIdentifier": bundleIdentifier }, YES); } @@ -147,90 +134,78 @@ extern BOOL launchNextOpenIntoWindow; return nil; } --(void) handleKeyboardEvent:(NSString*)identifier userInfo:(NSDictionary*)info -{ - if ([identifier isEqual:RAMessagingDetachCurrentAppMessageName]) - { - SBApplication *topApp = [[UIApplication sharedApplication] _accessibilityFrontMostApplication]; - - if (topApp) - { - [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; - [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; - - UIView *appView = [RAHostManager systemHostViewForApplication:topApp].superview; - - [UIView animateWithDuration:0.2 animations:^{ - appView.transform = CGAffineTransformMakeScale(0.5, 0.5); - } completion:^(BOOL _) { - [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; - FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ - SBAppToAppWorkspaceTransaction *transaction = [[%c(SBAppToAppWorkspaceTransaction) alloc] initWithAlertManager:nil exitedApp:UIApplication.sharedApplication._accessibilityFrontMostApplication]; - [transaction begin]; - }]; - [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; - [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:topApp animated:YES]; - }]; - } - } - else if ([identifier isEqual:RAMessagingGoToDesktopOnTheLeftMessageName]) - { +- (void)handleKeyboardEvent:(NSString*)identifier userInfo:(NSDictionary*)info { + if ([identifier isEqual:RAMessagingDetachCurrentAppMessageName]) { + SBApplication *topApp = [[UIApplication sharedApplication] _accessibilityFrontMostApplication]; + + if (topApp) { + [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; + [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; + + UIView *appView = [RAHostManager systemHostViewForApplication:topApp].superview; + + [UIView animateWithDuration:0.2 animations:^{ + appView.transform = CGAffineTransformMakeScale(0.5, 0.5); + } completion:^(BOOL _) { + [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBDeactivationSettings *deactiveSets = [[%c(SBDeactivationSettings) alloc] init]; + [deactiveSets setFlag:YES forDeactivationSetting:20]; + [deactiveSets setFlag:NO forDeactivationSetting:2]; + [topApp _setDeactivationSettings:deactiveSets]; + + SBAppToAppWorkspaceTransaction *transaction = [Multiplexer createSBAppToAppWorkspaceTransactionForExitingApp:topApp]; + [transaction begin]; + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; + [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:topApp animated:YES]; + }]; + } + } else if ([identifier isEqual:RAMessagingGoToDesktopOnTheLeftMessageName]) { int newIndex = RADesktopManager.sharedInstance.currentDesktopIndex - 1; BOOL isValid = newIndex >= 0 && newIndex <= RADesktopManager.sharedInstance.numberOfDesktops; - if (isValid) + if (isValid) { [RADesktopManager.sharedInstance switchToDesktop:newIndex]; - } - else if ([identifier isEqual:RAMessagingGoToDesktopOnTheRightMessageName]) - { + } + } else if ([identifier isEqual:RAMessagingGoToDesktopOnTheRightMessageName]) { int newIndex = RADesktopManager.sharedInstance.currentDesktopIndex + 1; BOOL isValid = newIndex >= 0 && newIndex < RADesktopManager.sharedInstance.numberOfDesktops; if (isValid) [RADesktopManager.sharedInstance switchToDesktop:newIndex]; - } - else if ([identifier isEqual:RAMessagingAddNewDesktopMessageName]) - { + } else if ([identifier isEqual:RAMessagingAddNewDesktopMessageName]) { [RADesktopManager.sharedInstance addDesktop:YES]; } RAWindowBar *window = RADesktopManager.sharedInstance.lastUsedWindow; - if (!window) + if (!window) { return; - if ([identifier isEqual:RAMessagingSnapFrontMostWindowLeftMessageName]) - { - [RAWindowSnapDataProvider snapWindow:window toLocation:RAWindowSnapLocationGetLeftOfScreen() animated:YES]; } - else if ([identifier isEqual:RAMessagingSnapFrontMostWindowRightMessageName]) - { + if ([identifier isEqual:RAMessagingSnapFrontMostWindowLeftMessageName]) { + [RAWindowSnapDataProvider snapWindow:window toLocation:RAWindowSnapLocationGetLeftOfScreen() animated:YES]; + } else if ([identifier isEqual:RAMessagingSnapFrontMostWindowRightMessageName]) { [RAWindowSnapDataProvider snapWindow:window toLocation:RAWindowSnapLocationGetRightOfScreen() animated:YES]; - } - else if ([identifier isEqual:RAMessagingMaximizeAppMessageName]) - { + } else if ([identifier isEqual:RAMessagingMaximizeAppMessageName]) { [window maximize]; - } - else if ([identifier isEqual:RAMessagingCloseAppMessageName]) - { + } else if ([identifier isEqual:RAMessagingCloseAppMessageName]) { [window close]; } } --(void) alertUser:(NSString*)description -{ +- (void)alertUser:(NSString*)description { #if DEBUG - if ([RASettings.sharedInstance debug_showIPCMessages]) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"MULTIPLEXER") message:description delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - } + if ([RASettings.sharedInstance debug_showIPCMessages]) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"MULTIPLEXER") message:description preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; + [alert show]; + } #endif } --(RAMessageAppData) getDataForIdentifier:(NSString*)identifier -{ +- (RAMessageAppData)getDataForIdentifier:(NSString*)identifier { RAMessageAppData ret; - if ([dataForApps objectForKey:identifier] != nil) + if ([dataForApps objectForKey:identifier]) { [dataForApps[identifier] getValue:&ret]; - else - { + } else { // Initialize with some default values ret.shouldForceSize = NO; ret.wantedClientOriginX = -1; @@ -249,50 +224,44 @@ extern BOOL launchNextOpenIntoWindow; return ret; } --(void) setData:(RAMessageAppData)data forIdentifier:(NSString*)identifier -{ - if (identifier) - { - dataForApps[identifier] = [NSValue valueWithBytes:&data objCType:@encode(RAMessageAppData)]; +- (void)setData:(RAMessageAppData)data forIdentifier:(NSString*)identifier { + if (!identifier) { + return; } + dataForApps[identifier] = [NSValue valueWithBytes:&data objCType:@encode(RAMessageAppData)]; } --(void) checkIfCompletionStillExitsForIdentifierAndFailIt:(NSString*)identifier -{ - if ([waitingCompletions objectForKey:identifier] != nil) - { - // We timed out, remove the re-sender - if ([asyncHandles objectForKey:identifier] != nil) - { - struct dispatch_async_handle *handle = (struct dispatch_async_handle *)[asyncHandles[identifier] pointerValue]; - dispatch_after_cancel(handle); - [asyncHandles removeObjectForKey:identifier]; - } +- (void)checkIfCompletionStillExitsForIdentifierAndFailIt:(NSString*)identifier { + if (![waitingCompletions objectForKey:identifier]) { + return; + } + // We timed out, remove the re-sender + if ([asyncHandles objectForKey:identifier]) { + struct dispatch_async_handle *handle = (struct dispatch_async_handle *)[asyncHandles[identifier] pointerValue]; + dispatch_after_cancel(handle); + [asyncHandles removeObjectForKey:identifier]; + } - RAMessageCompletionCallback callback = (RAMessageCompletionCallback)waitingCompletions[identifier]; - [waitingCompletions removeObjectForKey:identifier]; + RAMessageCompletionCallback callback = (RAMessageCompletionCallback)waitingCompletions[identifier]; + [waitingCompletions removeObjectForKey:identifier]; - SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; - [self alertUser:[NSString stringWithFormat:@"Unable to communicate with app %@ (%@)", app.displayName, identifier]]; - callback(NO); - } + SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; + [self alertUser:[NSString stringWithFormat:@"Unable to communicate with app %@ (%@)", app.displayName, identifier]]; + callback(NO); } --(void) sendDataWithCurrentTries:(int)tries toAppWithBundleIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)sendDataWithCurrentTries:(int)tries toAppWithBundleIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; - if (!app.isRunning || [app mainScene] == nil) - { - if (tries > 4) - { + if (!app.isRunning || ![app mainScene]) { + if (tries > 4) { [self alertUser:[NSString stringWithFormat:@"Unable to communicate with app that isn't running: %@ (%@)", app.displayName, identifier]]; - if (callback) + if (callback) { callback(NO); + } return; } - if ([asyncHandles objectForKey:identifier] != nil) - { + if ([asyncHandles objectForKey:identifier]) { struct dispatch_async_handle *handle = (struct dispatch_async_handle *)[asyncHandles[identifier] pointerValue]; dispatch_after_cancel(handle); [asyncHandles removeObjectForKey:identifier]; @@ -306,11 +275,9 @@ extern BOOL launchNextOpenIntoWindow; } CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)[NSString stringWithFormat:@"com.efrederickson.reachapp.clientupdate-%@",identifier], nil, nil, YES); - - if (tries <= 4) - { - if ([asyncHandles objectForKey:identifier] != nil) - { + + if (tries <= 4) { + if ([asyncHandles objectForKey:identifier]) { struct dispatch_async_handle *handle = (struct dispatch_async_handle *)[asyncHandles[identifier] pointerValue]; dispatch_after_cancel(handle); [asyncHandles removeObjectForKey:identifier]; @@ -321,18 +288,18 @@ extern BOOL launchNextOpenIntoWindow; }); asyncHandles[identifier] = [NSValue valueWithPointer:handle]; - if ([waitingCompletions objectForKey:identifier] == nil) - { + if (![waitingCompletions objectForKey:identifier]) { //if (callback == nil) // callback = ^(BOOL _) { }; - if (callback) + if (callback) { waitingCompletions[identifier] = [callback copy]; + } } - // Reset failure checker + // Reset failure checker [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(checkIfCompletionStillExitsForIdentifierAndFailIt:) object:identifier]; [self performSelector:@selector(checkIfCompletionStillExitsForIdentifierAndFailIt:) withObject:identifier afterDelay:4]; } - + /* SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; @@ -376,16 +343,15 @@ extern BOOL launchNextOpenIntoWindow; */ } --(void) sendStoredDataToApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ - if (!identifier || identifier.length == 0) +- (void)sendStoredDataToApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { + if (!identifier || identifier.length == 0) { return; + } [self sendDataWithCurrentTries:0 toAppWithBundleIdentifier:identifier completion:callback]; } --(void) resizeApp:(NSString*)identifier toSize:(CGSize)size completion:(RAMessageCompletionCallback)callback -{ +- (void)resizeApp:(NSString*)identifier toSize:(CGSize)size completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.wantedClientWidth = size.width; data.wantedClientHeight = size.height; @@ -394,8 +360,7 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) moveApp:(NSString*)identifier toOrigin:(CGPoint)origin completion:(RAMessageCompletionCallback)callback -{ +- (void)moveApp:(NSString*)identifier toOrigin:(CGPoint)origin completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.wantedClientOriginX = (float)origin.x; data.wantedClientOriginY = (float)origin.y; @@ -404,8 +369,7 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) endResizingApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)endResizingApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; //data.wantedClientSize = CGSizeMake(-1, -1); data.shouldForceSize = NO; @@ -413,12 +377,12 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) rotateApp:(NSString*)identifier toOrientation:(UIInterfaceOrientation)orientation completion:(RAMessageCompletionCallback)callback -{ +- (void)rotateApp:(NSString*)identifier toOrientation:(UIInterfaceOrientation)orientation completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; - if (data.forcePhoneMode) + if (data.forcePhoneMode) { return; + } data.forcedOrientation = orientation; data.shouldForceOrientation = YES; @@ -426,8 +390,7 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) unRotateApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)unRotateApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.forcedOrientation = UIApplication.sharedApplication.statusBarOrientation; data.shouldForceOrientation = NO; @@ -435,8 +398,7 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) forceStatusBarVisibility:(BOOL)visibility forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)forceStatusBarVisibility:(BOOL)visibility forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.shouldForceStatusBar = YES; data.statusBarVisibility = visibility; @@ -444,70 +406,61 @@ extern BOOL launchNextOpenIntoWindow; [self sendStoredDataToApp:identifier completion:callback]; } --(void) unforceStatusBarVisibilityForApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)unforceStatusBarVisibilityForApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.shouldForceStatusBar = NO; [self setData:data forIdentifier:identifier]; [self sendStoredDataToApp:identifier completion:callback]; } --(void) setShouldUseExternalKeyboard:(BOOL)value forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)setShouldUseExternalKeyboard:(BOOL)value forApp:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.shouldUseExternalKeyboard = value; [self setData:data forIdentifier:identifier]; [self sendStoredDataToApp:identifier completion:callback]; } --(void) setHosted:(BOOL)value forIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback -{ +- (void)setHosted:(BOOL)value forIdentifier:(NSString*)identifier completion:(RAMessageCompletionCallback)callback { RAMessageAppData data = [self getDataForIdentifier:identifier]; data.isBeingHosted = value; [self setData:data forIdentifier:identifier]; [self sendStoredDataToApp:identifier completion:callback]; } --(void) forcePhoneMode:(BOOL)value forIdentifier:(NSString*)identifier andRelaunchApp:(BOOL)relaunch -{ +- (void)forcePhoneMode:(BOOL)value forIdentifier:(NSString*)identifier andRelaunchApp:(BOOL)relaunch { RAMessageAppData data = [self getDataForIdentifier:identifier]; - + data.forcePhoneMode = value; [self setData:data forIdentifier:identifier]; - - if (relaunch) - { + + if (relaunch) { [RAAppKiller killAppWithIdentifier:identifier completion:^{ [RADesktopManager.sharedInstance updateWindowSizeForApplication:identifier]; }]; } } --(void) receiveShowKeyboardForAppWithIdentifier:(NSString*)identifier -{ +- (void)receiveShowKeyboardForAppWithIdentifier:(NSString*)identifier { [RASpringBoardKeyboardActivation.sharedInstance showKeyboardForAppWithIdentifier:identifier]; } --(void) receiveHideKeyboard -{ +- (void)receiveHideKeyboard { [RASpringBoardKeyboardActivation.sharedInstance hideKeyboard]; } --(void) setKeyboardContextId:(unsigned int)id forIdentifier:(NSString*)identifier -{ - NSLog(@"[ReachApp] got c id %d", id); +- (void)setKeyboardContextId:(unsigned int)id forIdentifier:(NSString*)identifier { + LogDebug(@"[ReachApp] got c id %d", id); contextIds[identifier] = @(id); } --(unsigned int) getStoredKeyboardContextIdForApp:(NSString*)identifier -{ - return [contextIds objectForKey:identifier] != nil ? [contextIds[identifier] unsignedIntValue] : 0; +- (unsigned int)getStoredKeyboardContextIdForApp:(NSString*)identifier { + return [contextIds objectForKey:identifier] ? [contextIds[identifier] unsignedIntValue] : 0; } @end -%ctor -{ - IF_SPRINGBOARD { - [RAMessagingServer sharedInstance]; +%ctor { + IF_NOT_SPRINGBOARD { + return; } -} \ No newline at end of file + [RAMessagingServer sharedInstance]; +} diff --git a/MissionControl/ActivatorListener.xm b/MissionControl/ActivatorListener.xm index 596511e..bb9a88c 100644 --- a/MissionControl/ActivatorListener.xm +++ b/MissionControl/ActivatorListener.xm @@ -8,24 +8,25 @@ static RAActivatorListener *sharedInstance; @implementation RAActivatorListener -- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event -{ - if ([[%c(SBLockScreenManager) sharedInstance] isUILocked]) +- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event { + if ([[%c(SBLockScreenManager) sharedInstance] isUILocked]) { return; - else if ([[%c(RASettings) sharedInstance] missionControlEnabled]) - { - [RAMissionControlManager.sharedInstance toggleMissionControl:YES]; - [[[%c(SBUIController) sharedInstance] _appSwitcherController] forceDismissAnimated:NO]; + } else if ([[%c(RASettings) sharedInstance] missionControlEnabled]) { + [RAMissionControlManager.sharedInstance toggleMissionControl:YES]; + if ([%c(SBUIController) respondsToSelector:@selector(_appSwitcherController)]) { + [[[%c(SBUIController) sharedInstance] _appSwitcherController] forceDismissAnimated:NO]; + } else { + [[%c(SBMainSwitcherViewController) sharedInstance] RA_dismissSwitcherUnanimated]; + } } - [event setHandled:YES]; + [event setHandled:YES]; } @end -%ctor -{ - if ([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.springboard"]) - { - sharedInstance = [[RAActivatorListener alloc] init]; - [[%c(LAActivator) sharedInstance] registerListener:sharedInstance forName:@"com.efrederickson.reachapp.missioncontrol.activatorlistener"]; - } -} \ No newline at end of file +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance = [[RAActivatorListener alloc] init]; + [[%c(LAActivator) sharedInstance] registerListener:sharedInstance forName:@"com.efrederickson.reachapp.missioncontrol.activatorlistener"]; +} diff --git a/MissionControl/AppSwitcher.xm b/MissionControl/AppSwitcher.xm index 96443cb..8716ad3 100644 --- a/MissionControl/AppSwitcher.xm +++ b/MissionControl/AppSwitcher.xm @@ -9,114 +9,95 @@ BOOL allowMissionControlActivationFromSwitcher = YES; BOOL statusBarVisibility; BOOL willShowMissionControl = NO; +BOOL toggleOrActivate = NO; %hook SBUIController -- (void)_showNotificationsGestureBeganWithLocation:(CGPoint)arg1 -{ - if ([[[%c(SBUIController) sharedInstance] switcherWindow] isKeyWindow] && CGRectContainsPoint([[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999].frame, arg1)) +- (void)_showNotificationsGestureBeganWithLocation:(CGPoint)arg1 { + if ([[[%c(SBUIController) sharedInstance] switcherWindow] isKeyWindow] && CGRectContainsPoint([[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999].frame, arg1)) { return; + } - if ([[%c(RASettings) sharedInstance] missionControlEnabled] && self.isAppSwitcherShowing) + if ([[%c(RASettings) sharedInstance] missionControlEnabled] && self.isAppSwitcherShowing) { return; + } %orig; } -- (_Bool)_activateAppSwitcher -{ +- (_Bool)_activateAppSwitcher { statusBarVisibility = UIApplication.sharedApplication.statusBarHidden; willShowMissionControl = NO; - if ([[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC] && [[%c(RASettings) sharedInstance] missionControlEnabled]) - { - if (RAMissionControlManager.sharedInstance.isShowingMissionControl == NO) - { + if ([[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC] && [[%c(RASettings) sharedInstance] missionControlEnabled]) { + if (!RAMissionControlManager.sharedInstance.isShowingMissionControl) { [RAMissionControlManager.sharedInstance showMissionControl:YES]; - } - else - [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } else { + [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } return YES; - } - else - { - if ([RAMissionControlManager.sharedInstance isShowingMissionControl]) - { + } else { + if ([RAMissionControlManager.sharedInstance isShowingMissionControl]) { [RAMissionControlManager.sharedInstance hideMissionControl:YES]; } } BOOL s = %orig; - if (s && [[%c(RASettings) sharedInstance] missionControlEnabled] && [[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999] != nil) - { + if (s && [[%c(RASettings) sharedInstance] missionControlEnabled] && [[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999]) { [UIView animateWithDuration:0.3 animations:^{ [[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999].alpha = 1; }]; } - if (s) - { + if (s) { [[%c(RADesktopManager) sharedInstance] performSelectorOnMainThread:@selector(hideDesktop) withObject:nil waitUntilDone:NO]; //[[[%c(RADesktopManager) sharedInstance] currentDesktop] unloadApps]; } return s; } -- (void)_hideNotificationsGestureCancelled -{ +- (void)_hideNotificationsGestureCancelled { %orig; RAMissionControlManager.sharedInstance.inhibitDismissalGesture = NO; } -- (void)_hideNotificationsGestureEndedWithCompletionType:(long long)arg1 velocity:(CGPoint)arg2 -{ +- (void)_hideNotificationsGestureEndedWithCompletionType:(long long)arg1 velocity:(CGPoint)arg2 { %orig; RAMissionControlManager.sharedInstance.inhibitDismissalGesture = NO; } -- (void)_hideNotificationsGestureBegan:(CGFloat)arg1 -{ +- (void)_hideNotificationsGestureBegan:(CGFloat)arg1 { RAMissionControlManager.sharedInstance.inhibitDismissalGesture = YES; %orig; } -- (_Bool)isAppSwitcherShowing -{ +- (_Bool)isAppSwitcherShowing { return %orig || RAMissionControlManager.sharedInstance.isShowingMissionControl; } --(void) _dismissSwitcherAnimated:(_Bool)arg1 -{ - if (RAMissionControlManager.sharedInstance.isShowingMissionControl) - { +-(void) _dismissSwitcherAnimated:(_Bool)arg1 { + if (RAMissionControlManager.sharedInstance.isShowingMissionControl) { [RAMissionControlManager.sharedInstance hideMissionControl:arg1]; } - + %orig; } %end -%hook SBAppSwitcherController -// iOS 8 -- (void)switcherWillBeDismissed:(_Bool)arg1 -{ - if (willShowMissionControl == NO) - { - [[%c(RADesktopManager) sharedInstance] reshowDesktop]; - //[[[%c(RADesktopManager) sharedInstance] currentDesktop] loadApps]; +%hook SBNotificationCenterController +-(void)_showNotificationCenterGestureBeganWithGestureRecognizer:(id)arg1 { + CGPoint location = [arg1 locationInView:[[%c(SBMainSwitcherViewController) sharedInstance] view]]; + if ([[%c(RASettings) sharedInstance] missionControlEnabled] && [[%c(SBUIController) sharedInstance] isAppSwitcherShowing] && CGRectContainsPoint([[[[%c(SBMainSwitcherViewController) sharedInstance] valueForKey:@"_contentView"] contentView] viewWithTag:999].frame, location)) { + return; } - [UIView animateWithDuration:0.3 animations:^{ - [[[%c(SBUIController) sharedInstance] switcherWindow] viewWithTag:999].alpha = 0; - }]; - %orig; } +%end -// iOS 9 -- (void)_switcherWasDismissed:(_Bool)arg1 -{ - if (willShowMissionControl == NO) - { +%hook SBAppSwitcherController +// iOS 8 +- (void)switcherWillBeDismissed:(_Bool)arg1 { + if (!willShowMissionControl) { [[%c(RADesktopManager) sharedInstance] reshowDesktop]; //[[[%c(RADesktopManager) sharedInstance] currentDesktop] loadApps]; } @@ -128,8 +109,7 @@ BOOL willShowMissionControl = NO; %orig; } -- (void)switcherScroller:(id)arg1 itemTapped:(__unsafe_unretained SBDisplayLayout*)arg2 -{ +- (void)switcherScroller:(id)arg1 itemTapped:(__unsafe_unretained SBDisplayLayout*)arg2 { SBDisplayItem *item = [arg2 displayItems][0]; NSString *identifier = item.displayIdentifier; @@ -140,30 +120,27 @@ BOOL willShowMissionControl = NO; %end @interface SBAppSwitcherController () --(UIView*) view; +- (UIView*)view; @end //%hook SBAppSwitcherWindow %hook SBAppSwitcherController //-(void) addSubview:(UIView*)view -- (void)_layoutInOrientation:(long long)arg1 -{ +- (void)_layoutInOrientation:(long long)arg1 { %orig; - + UIView *view = MSHookIvar(self, "_contentView"); - if ([view viewWithTag:999] == nil && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) - { + if (![view viewWithTag:999] && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) { CGFloat width = 50, height = 30; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - { + if (IS_IPAD) { width = 60; - height = 40; + height = 40; } SBControlCenterGrabberView *grabber = [[%c(SBControlCenterGrabberView) alloc] initWithFrame:CGRectMake(0, 0, width, height)]; grabber.center = CGPointMake(view.frame.size.width / 2, 20/2); - + grabber.backgroundColor = [UIColor clearColor]; //grabber.chevronView.vibrantSettings = [%c(_SBFVibrantSettings) vibrantSettingsWithReferenceColor:UIColor.whiteColor referenceContrast:0.5 legibilitySettings:nil]; @@ -180,30 +157,26 @@ BOOL willShowMissionControl = NO; [view addSubview:grabber]; [[%c(RAGestureManager) sharedInstance] addGestureRecognizerWithTarget:(NSObject *)self forEdge:UIRectEdgeTop identifier:@"com.efrederickson.reachapp.appswitchergrabber"]; - } - else + } else { ((UIView*)[view viewWithTag:999]).center = CGPointMake(view.frame.size.width / 2, 20/2); + } } // iOS 8 --(void)viewDidAppear:(BOOL)a -{ +- (void)viewDidAppear:(BOOL)a { %orig; - UIView *view = MSHookIvar(self, "_contentView"); - if ([view viewWithTag:999] == nil && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) - { + if (![view viewWithTag:999] && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) { CGFloat width = 50, height = 30; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - { + if (IS_IPAD) { width = 60; - height = 40; + height = 40; } SBControlCenterGrabberView *grabber = [[%c(SBControlCenterGrabberView) alloc] initWithFrame:CGRectMake(0, 0, width, height)]; grabber.center = CGPointMake(view.frame.size.width / 2, 20/2); - - + + grabber.backgroundColor = [UIColor clearColor]; //grabber.chevronView.vibrantSettings = [%c(_SBFVibrantSettings) vibrantSettingsWithReferenceColor:UIColor.whiteColor referenceContrast:0.5 legibilitySettings:nil]; @@ -224,37 +197,36 @@ BOOL willShowMissionControl = NO; [view addSubview:grabber]; [[%c(RAGestureManager) sharedInstance] addGestureRecognizerWithTarget:(NSObject *)self forEdge:UIRectEdgeTop identifier:@"com.efrederickson.reachapp.appswitchergrabber"]; - } - else + } else { ((UIView*)[view viewWithTag:999]).center = CGPointMake(view.frame.size.width / 2, 20/2); + } } -%new -(BOOL) RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity -{ +%new - (BOOL)RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity { return allowMissionControlActivationFromSwitcher && [[%c(RASettings) sharedInstance] missionControlEnabled] && self.view.window.isKeyWindow; } -%new -(RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge -{ - [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureFailed)]; - [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureCancelled)]; +%new - (RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { + if ([%c(SBUIController) respondsToSelector:@selector(_showNotificationsGestureFailed)]) { + [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureFailed)]; + [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureCancelled)]; + } else { + [[%c(SBNotificationCenterController) sharedInstance] performSelector:@selector(_showNotificationCenterGestureFailed)]; + [[%c(SBNotificationCenterController) sharedInstance] performSelector:@selector(_showNotificationCenterGestureCancelled)]; + } static CGFloat origY = -1; static UIView *fakeView; UIView *view = MSHookIvar(self, "_contentView"); - if (!fakeView) - { + if (!fakeView) { UIImage *snapshot = [[%c(RASnapshotProvider) sharedInstance] storedSnapshotOfMissionControl]; - if (snapshot) - { + if (snapshot) { fakeView = [[UIImageView alloc] initWithFrame:view.frame]; ((UIImageView*)fakeView).image = snapshot; [view addSubview:fakeView]; - } - else - { + } else { fakeView = [[UIView alloc] initWithFrame:view.frame]; CGFloat width = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 4.5714; @@ -322,23 +294,21 @@ BOOL willShowMissionControl = NO; } } - if (origY == -1) - { + if (origY == -1) { CGRect f = fakeView.frame; f.origin.y = -f.size.height; fakeView.frame = f; origY = fakeView.center.y; } - if (state == UIGestureRecognizerStateChanged) + if (state == UIGestureRecognizerStateChanged) { fakeView.center = (CGPoint) { fakeView.center.x, origY + location.y }; - - if (state == UIGestureRecognizerStateEnded) - { + } + + if (state == UIGestureRecognizerStateEnded) { //NSLog(@"[ReachApp] %@ + %@ = %@ > %@", NSStringFromCGPoint(fakeView.frame.origin), NSStringFromCGPoint(velocity), @(fakeView.frame.origin.y + velocity.y), @(-(UIScreen.mainScreen.bounds.size.height / 2))); - if (fakeView.frame.origin.y + velocity.y > -(UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 2)) - { + if (fakeView.frame.origin.y + velocity.y > -(UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 2)) { willShowMissionControl = YES; CGFloat distance = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - (fakeView.frame.origin.y + fakeView.frame.size.height); CGFloat duration = MIN(distance / velocity.y, 0.3); @@ -360,9 +330,7 @@ BOOL willShowMissionControl = NO; // ((UIWindow*)[[%c(SBUIController) sharedInstance] switcherWindow]).alpha = 1; //}); }]; - } - else - { + } else { CGFloat distance = fakeView.frame.size.height + fakeView.frame.origin.y /* origin.y is less than 0 so the + is actually a - operation */; CGFloat duration = MIN(distance / velocity.y, 0.3); @@ -381,49 +349,301 @@ BOOL willShowMissionControl = NO; } %end -@interface SBAppSwitcherPageViewController : UIViewController -@end -%hook SBAppSwitcherPageViewController -- (void)_layout -{ +%hook SBSwitcherContainerView +- (void)layoutSubviews { %orig; - UIView *view = [self view]; + UIView *view = self.contentView; - if ([view viewWithTag:999] == nil && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) - { + if (![view viewWithTag:999] && ([[%c(RASettings) sharedInstance] missionControlEnabled] && ![[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC])) { CGFloat width = 50, height = 30; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - { + if (IS_IPAD) { width = 60; - height = 40; + height = 40; } - SBControlCenterGrabberView *grabber = [[%c(SBControlCenterGrabberView) alloc] initWithFrame:CGRectMake(0, 0, width, height)]; - grabber.center = CGPointMake(view.frame.size.width / 2, 20/2); - - - grabber.backgroundColor = [UIColor clearColor]; - //grabber.chevronView.vibrantSettings = [%c(_SBFVibrantSettings) vibrantSettingsWithReferenceColor:UIColor.whiteColor referenceContrast:0.5 legibilitySettings:nil]; - _UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithStyle:2060]; - blurView.frame = grabber.frame; - [grabber insertSubview:blurView atIndex:0]; + if ([%c(SBControlCenterGrabberView) class]) { + SBControlCenterGrabberView *grabber = [[%c(SBControlCenterGrabberView) alloc] initWithFrame:CGRectMake(0, 0, width, height)]; - [grabber.chevronView setState:1 animated:NO]; + grabber.center = CGPointMake(UIScreen.mainScreen.bounds.size.width / 2, 20/2); - grabber.layer.cornerRadius = 5; - //[grabber.chevronView setState:1 animated:YES]; - grabber.tag = 999; - [view addSubview:grabber]; + grabber.backgroundColor = [UIColor clearColor]; + //grabber.chevronView.vibrantSettings = [%c(_SBFVibrantSettings) vibrantSettingsWithReferenceColor:UIColor.whiteColor referenceContrast:0.5 legibilitySettings:nil]; - //[grabber.chevronView setState:1 animated:YES]; - grabber.tag = 999; - [view addSubview:grabber]; + _UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithStyle:2060]; + blurView.frame = grabber.frame; + [grabber insertSubview:blurView atIndex:0]; + + [grabber.chevronView setState:1 animated:NO]; + + grabber.layer.cornerRadius = 5; + + //[grabber.chevronView setState:1 animated:YES]; + grabber.tag = 999; + [view addSubview:grabber]; + + } else { + UIView *grabber = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)]; + + grabber.center = CGPointMake(UIScreen.mainScreen.bounds.size.width / 2, 20/2); + + _UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithStyle:2060]; + blurView.frame = grabber.frame; + blurView._blurRadius = 30; + [blurView _setCornerRadius:6]; + [blurView _applyCornerRadiusToSubviews]; + [grabber addSubview:blurView]; + SBUIChevronView *chevronView = [[%c(SBUIChevronView) alloc] initWithColor:[UIColor blackColor]]; + chevronView.frame = CGRectMake((width - 36) / 2, (height - 14) / 2, 36, 14); + [chevronView setState:1 animated:NO]; + chevronView.alpha = 0.6499; + [grabber addSubview:chevronView]; + + grabber.layer.cornerRadius = 6; + + grabber.tag = 999; + [view addSubview:grabber]; + + } [[%c(RAGestureManager) sharedInstance] addGestureRecognizerWithTarget:(NSObject *)self forEdge:UIRectEdgeTop identifier:@"com.efrederickson.reachapp.appswitchergrabber"]; + } else { + ((UIView*)[view viewWithTag:999]).center = CGPointMake(UIScreen.mainScreen.bounds.size.width / 2, 20/2); } - else - ((UIView*)[view viewWithTag:999]).center = CGPointMake(view.frame.size.width / 2, 20/2); +} + +%new - (BOOL)RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity { + return allowMissionControlActivationFromSwitcher && [[%c(RASettings) sharedInstance] missionControlEnabled] && [[%c(SBUIController) sharedInstance] isAppSwitcherShowing]; +} + +%new - (RAGestureCallbackResult)RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { + if ([%c(SBUIController) respondsToSelector:@selector(_showNotificationsGestureFailed)]) { + [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureFailed)]; + [[%c(SBUIController) sharedInstance] performSelector:@selector(_showNotificationsGestureCancelled)]; + } else { + [[%c(SBNotificationCenterController) sharedInstance] performSelector:@selector(_showNotificationCenterGestureFailed)]; + [[%c(SBNotificationCenterController) sharedInstance] performSelector:@selector(_showNotificationCenterGestureCancelled)]; + } + + static CGFloat origY = -1; + static UIView *fakeView; + UIView *view = self.contentView; + + if (!fakeView) { + UIImage *snapshot = [[%c(RASnapshotProvider) sharedInstance] storedSnapshotOfMissionControl]; + + if (snapshot) { + fakeView = [[UIImageView alloc] initWithFrame:view.frame]; + ((UIImageView*)fakeView).image = snapshot; + [view addSubview:fakeView]; + } else { + fakeView = [[UIView alloc] initWithFrame:view.frame]; + + CGFloat width = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 4.5714; + CGFloat height = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 4.36; + + _UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithStyle:1]; + blurView.frame = fakeView.frame; + [fakeView addSubview:blurView]; + + UILabel *desktopLabel, *windowedLabel, *otherLabel; + UIScrollView *desktopScrollView, *windowedAppScrollView, *otherRunningAppsScrollView; + + CGFloat x = 15; + CGFloat y = 20; + + desktopLabel = [[UILabel alloc] initWithFrame:CGRectMake(9.37, y, fakeView.frame.size.width - 20, 25)]; + desktopLabel.font = [UIFont fontWithName:@"SFUIText-Medium" size:14]; + desktopLabel.textColor = UIColor.whiteColor; + desktopLabel.text = @"Desktops"; + [fakeView addSubview:desktopLabel]; + + y = y + desktopLabel.frame.size.height; + + desktopScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y, fakeView.frame.size.width, height * 1.15)]; + desktopScrollView.backgroundColor = [UIColor.whiteColor colorWithAlphaComponent:0.3]; + + [fakeView addSubview:desktopScrollView]; + + UIButton *newDesktopButton = [[UIButton alloc] init]; + newDesktopButton.frame = CGRectMake(x, 20, width, height); + newDesktopButton.backgroundColor = [UIColor darkGrayColor]; + [newDesktopButton setTitle:@"+" forState:UIControlStateNormal]; + newDesktopButton.titleLabel.font = [UIFont systemFontOfSize:36]; + [desktopScrollView addSubview:newDesktopButton]; + + x = 15; + y = desktopScrollView.frame.origin.y + desktopScrollView.frame.size.height + 7; + + windowedLabel = [[UILabel alloc] initWithFrame:CGRectMake(9.37, y, fakeView.frame.size.width - 20, 25)]; + windowedLabel.font = [UIFont fontWithName:@"SFUIText-Medium" size:14]; + windowedLabel.textColor = UIColor.whiteColor; + windowedLabel.text = @"On This Desktop"; + [fakeView addSubview:windowedLabel]; + + windowedAppScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y + windowedLabel.frame.size.height, fakeView.frame.size.width, height * 1.15)]; + windowedAppScrollView.backgroundColor = [UIColor.whiteColor colorWithAlphaComponent:0.3]; + + [fakeView addSubview:windowedAppScrollView]; + + x = 15; + y = windowedAppScrollView.frame.origin.y + windowedAppScrollView.frame.size.height + 7; + + otherLabel = [[UILabel alloc] initWithFrame:CGRectMake(9.37, y, fakeView.frame.size.width - 20, 25)]; + otherLabel.font = [UIFont fontWithName:@"SFUIText-Medium" size:14]; + otherLabel.textColor = UIColor.whiteColor; + otherLabel.text = @"Running Elsewhere"; + [fakeView addSubview:otherLabel]; + + otherRunningAppsScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, y + otherLabel.frame.size.height, fakeView.frame.size.width, height * 1.15)]; + otherRunningAppsScrollView.backgroundColor = [UIColor.whiteColor colorWithAlphaComponent:0.3]; + + [fakeView addSubview:otherRunningAppsScrollView]; + + [view addSubview:fakeView]; + } + } + + if (origY == -1) { + CGRect f = fakeView.frame; + f.origin.y = -f.size.height; + fakeView.frame = f; + origY = fakeView.center.y; + } + + if (state == UIGestureRecognizerStateChanged) { + fakeView.center = CGPointMake(fakeView.center.x, origY + location.y); + } + + if (state == UIGestureRecognizerStateEnded) { + //NSLog(@"[ReachApp] %@ + %@ = %@ > %@", NSStringFromCGPoint(fakeView.frame.origin), NSStringFromCGPoint(velocity), @(fakeView.frame.origin.y + velocity.y), @(-(UIScreen.mainScreen.bounds.size.height / 2))); + + if (fakeView.frame.origin.y + velocity.y > -(UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 2)) { + willShowMissionControl = YES; + CGFloat distance = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - (fakeView.frame.origin.y + fakeView.frame.size.height); + CGFloat duration = MIN(distance / velocity.y, 0.3); + + //NSLog(@"[ReachApp] dist %f, dur %f", distance, duration); + + [UIView animateWithDuration:duration animations:^{ + fakeView.frame = UIScreen.mainScreen.RA_interfaceOrientedBounds; + } completion:^(BOOL _) { + //((UIWindow*)[[%c(SBUIController) sharedInstance] switcherWindow]).alpha = 0; + if ([%c(SBUIController) respondsToSelector:@selector(dismissSwitcherAnimated:)]) { + [[%c(SBUIController) sharedInstance] dismissSwitcherAnimated:NO]; + } else { + [[%c(SBMainSwitcherViewController) sharedInstance] RA_dismissSwitcherUnanimated]; + } + [RAMissionControlManager.sharedInstance showMissionControl:NO]; + [fakeView removeFromSuperview]; + fakeView = nil; + UIApplication.sharedApplication.statusBarHidden = statusBarVisibility; + // avoid status bar hiding + //dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + // ((UIWindow*)[[%c(SBUIController) sharedInstance] switcherWindow]).alpha = 1; + //}); + }]; + } else { + CGFloat distance = fakeView.frame.size.height + fakeView.frame.origin.y /* origin.y is less than 0 so the + is actually a - operation */; + CGFloat duration = MIN(distance / velocity.y, 0.3); + + //NSLog(@"[ReachApp] dist %f, dur %f", distance, duration); + + [UIView animateWithDuration:duration animations:^{ + fakeView.frame = CGRectMake(fakeView.frame.origin.x, -fakeView.frame.size.height, fakeView.frame.size.width, fakeView.frame.size.height); + } completion:^(BOOL _) { + [fakeView removeFromSuperview]; + fakeView = nil; + }]; + } + } + + return RAGestureCallbackResultSuccess; +} +%end + +%hook SBMainSwitcherViewController +- (void)viewDidAppear:(BOOL)arg1 { + statusBarVisibility = UIApplication.sharedApplication.statusBarHidden; + willShowMissionControl = NO; + + if ([[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC] && [[%c(RASettings) sharedInstance] missionControlEnabled]) { + if (!RAMissionControlManager.sharedInstance.isShowingMissionControl) { + [RAMissionControlManager.sharedInstance showMissionControl:YES]; + } else { + [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } + } else { + if ([RAMissionControlManager.sharedInstance isShowingMissionControl]) { + [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } + } + + %orig; + + [[%c(RADesktopManager) sharedInstance] performSelectorOnMainThread:@selector(hideDesktop) withObject:nil waitUntilDone:NO]; +} + +- (void)viewWillDisappear:(BOOL)arg1 { + if (!willShowMissionControl) { + [[%c(RADesktopManager) sharedInstance] reshowDesktop]; + //[[[%c(RADesktopManager) sharedInstance] currentDesktop] loadApps]; + } + %orig; +} + +%new - (void)RA_dismissSwitcherUnanimated { + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBWorkspaceApplicationTransitionContext *transitionContext = [[%c(SBWorkspaceApplicationTransitionContext) alloc] init]; + [transitionContext setAnimationDisabled:YES]; + + //set layout role to 'side' (deactivating) + SBWorkspaceDeactivatingEntity *deactivatingEntity = [%c(SBWorkspaceDeactivatingEntity) entity]; + [deactivatingEntity setLayoutRole:3]; + [transitionContext setEntity:deactivatingEntity forLayoutRole:3]; + + //set layout role for 'primary' (activating) + SBWorkspaceHomeScreenEntity *homescreenEntity = [[%c(SBWorkspaceHomeScreenEntity) alloc] init]; + [transitionContext setEntity:homescreenEntity forLayoutRole:2]; + + //create transititon request + SBMainWorkspaceTransitionRequest *transitionRequest = [[%c(SBMainWorkspaceTransitionRequest) alloc] initWithDisplay:[%c(FBDisplayManager) mainDisplay]]; + [transitionRequest setApplicationContext:transitionContext]; + + //create apptoapp transaction + SBAppToAppWorkspaceTransaction *transaction = [[%c(SBAppToAppWorkspaceTransaction) alloc] initWithTransitionRequest:transitionRequest]; + + //start closing + [transaction begin]; + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; +} + +//Because I cant think of a better solution +- (BOOL)toggleSwitcherNoninteractively { + if (![self isVisible]) { + return [self activateSwitcherNoninteractively]; + } else { + return [self dismissSwitcherNoninteractively]; + } +} + +- (BOOL)activateSwitcherNoninteractively { + if ([[%c(RASettings) sharedInstance] replaceAppSwitcherWithMC] && [[%c(RASettings) sharedInstance] missionControlEnabled]) { + if (!RAMissionControlManager.sharedInstance.isShowingMissionControl) { + [RAMissionControlManager.sharedInstance showMissionControl:YES]; + } else { + [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } + + return YES; + } else { + if ([RAMissionControlManager.sharedInstance isShowingMissionControl]) { + [RAMissionControlManager.sharedInstance hideMissionControl:YES]; + } + } + + return %orig; } %end diff --git a/MissionControl/Makefile b/MissionControl/Makefile index 897e584..a2769a3 100644 --- a/MissionControl/Makefile +++ b/MissionControl/Makefile @@ -1,8 +1,7 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../ -I../Theming/ -I../GestureSupport/ -I../WindowedMultitasking/ +CFLAGS = -I../ -I../Theming/ -I../GestureSupport/ -I../WindowedMultitasking/ -O2 CFLAGS += -fobjc-arc -LDFLAGS += -Wl,-segalign,4000 include $(THEOS)/makefiles/common.mk diff --git a/MissionControl/RAMissionControlManager.h b/MissionControl/RAMissionControlManager.h index 712333c..609a79f 100644 --- a/MissionControl/RAMissionControlManager.h +++ b/MissionControl/RAMissionControlManager.h @@ -5,15 +5,15 @@ @interface RAMissionControlManager : NSObject { RAMissionControlWindow *window; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; @property (nonatomic, readonly) BOOL isShowingMissionControl; @property (nonatomic) BOOL inhibitDismissalGesture; --(void) createWindow; --(void) showMissionControl:(BOOL)animated; --(void) hideMissionControl:(BOOL)animated; --(void) toggleMissionControl:(BOOL)animated; +- (void)createWindow; +- (void)showMissionControl:(BOOL)animated; +- (void)hideMissionControl:(BOOL)animated; +- (void)toggleMissionControl:(BOOL)animated; --(RAMissionControlWindow*) missionControlWindow; -@end \ No newline at end of file +- (RAMissionControlWindow*)missionControlWindow; +@end diff --git a/MissionControl/RAMissionControlManager.xm b/MissionControl/RAMissionControlManager.xm index bb2353c..c742c19 100644 --- a/MissionControl/RAMissionControlManager.xm +++ b/MissionControl/RAMissionControlManager.xm @@ -29,16 +29,12 @@ } @end -CGRect swappedForOrientation(CGRect in) -{ - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { +CGRect swappedForOrientation(CGRect in) { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { CGFloat x = in.origin.x; in.origin.x = in.origin.y; in.origin.y = x; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { CGFloat x = in.origin.x; in.origin.x = fabs(in.origin.y) + UIScreen.mainScreen.bounds.size.width; in.origin.y = x; @@ -47,16 +43,12 @@ CGRect swappedForOrientation(CGRect in) return in; } -CGRect swappedForOrientation2(CGRect in) -{ - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { +CGRect swappedForOrientation2(CGRect in) { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { CGFloat x = in.origin.x; in.origin.x = in.origin.y; in.origin.y = x; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { CGFloat x = in.origin.x; in.origin.x = -in.size.width; in.origin.y = x; @@ -66,55 +58,53 @@ CGRect swappedForOrientation2(CGRect in) } @implementation RAMissionControlManager -+(instancetype) sharedInstance -{ - SHARED_INSTANCE2(RAMissionControlManager, ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RAMissionControlManager, sharedInstance->originalAppView = nil; sharedInstance.inhibitDismissalGesture = NO; sharedInstance->hasMoved = NO; ); } --(void) showMissionControl:(BOOL)animated -{ - if (![NSThread isMainThread]) - { - dispatch_sync(dispatch_get_main_queue(), ^{ [self showMissionControl:animated]; }); +- (void)showMissionControl:(BOOL)animated { + if (![NSThread isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + [self showMissionControl:animated]; + }); return; } - + _isShowingMissionControl = YES; SBApplication *app = UIApplication.sharedApplication._accessibilityFrontMostApplication; - if (app) + if (app) { lastOpenedApp = app; + } [self createWindow]; - if (animated) - //window.alpha = 0; + if (animated) { window.frame = swappedForOrientation(CGRectMake(0, -window.frame.size.height, window.frame.size.width, window.frame.size.height)); - + } + //window.alpha = 0; + [window makeKeyAndVisible]; - if (lastOpenedApp && lastOpenedApp.isRunning) - { + if (lastOpenedApp && lastOpenedApp.isRunning) { originalAppView = [%c(RAHostManager) systemHostViewForApplication:lastOpenedApp].superview; originalAppFrame = originalAppView.frame; } - if (animated) - { + if (animated) { //[UIView animateWithDuration:0.5 animations:^{ window.alpha = 1; }]; - [UIView animateWithDuration:0.5 animations:^{ - window.frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height); + [UIView animateWithDuration:0.5 animations:^{ + window.frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height); - if (originalAppView) - originalAppView.frame = swappedForOrientation2(CGRectMake(originalAppFrame.origin.x, originalAppView.frame.size.height, originalAppFrame.size.width, originalAppFrame.size.height)); + if (originalAppView) { + originalAppView.frame = swappedForOrientation2(CGRectMake(originalAppFrame.origin.x, originalAppView.frame.size.height, originalAppFrame.size.width, originalAppFrame.size.height)); + } } completion:nil]; - } - else if (originalAppView) // dismiss even if not animating open - { + } else if (originalAppView) { // dismiss even if not animating open originalAppView.frame = swappedForOrientation2(CGRectMake(originalAppFrame.origin.x, originalAppView.frame.size.height, originalAppFrame.size.width, originalAppFrame.size.height)); } @@ -123,22 +113,24 @@ CGRect swappedForOrientation2(CGRect in) [[%c(RAGestureManager) sharedInstance] ignoreSwipesBeginningInRect:UIScreen.mainScreen.bounds forIdentifier:@"com.efrederickson.reachapp.windowedmultitasking.systemgesture"]; [[%c(RARunningAppsProvider) sharedInstance] addTarget:window]; [%c(RAOrientationLocker) lockOrientation]; - [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"RAMissionControlManager"]; + if (IS_IOS_OR_OLDER(iOS_10_0)) { //Not required on 10.x, not sure about other versions + [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"RAMissionControlManager"]; + } self.inhibitDismissalGesture = NO; [%c(RAControlCenterInhibitor) setInhibited:YES]; - if ([[%c(SBControlCenterController) sharedInstance] isVisible]) + if ([[%c(SBControlCenterController) sharedInstance] isVisible]) { [[%c(SBControlCenterController) sharedInstance] dismissAnimated:YES]; + } didStoreSnapshot = NO; } --(void) createWindow -{ - if (window) - { - if (originalAppView) +- (void)createWindow { + if (window) { + if (originalAppView) { originalAppView.frame = originalAppFrame; + } window.hidden = YES; window = nil; } @@ -148,8 +140,7 @@ CGRect swappedForOrientation2(CGRect in) [window _rotateWindowToOrientation:UIApplication.sharedApplication.statusBarOrientation updateStatusBar:YES duration:1 skipCallbacks:NO]; //_UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithStyle:1]; - _UIBackdropViewSettings *blurSettings = [_UIBackdropViewSettings settingsForStyle:THEMED(missionControlBlurStyle)]; - [blurSettings setBlurQuality:@"low"]; // speed++ hopefully + _UIBackdropViewSettings *blurSettings = [_UIBackdropViewSettings settingsForStyle:THEMED(missionControlBlurStyle) graphicsQuality:10]; // speed++ hopefully _UIBackdropView *blurView = [[%c(_UIBackdropView) alloc] initWithSettings:blurSettings]; blurView.frame = window.frame; [window addSubview:blurView]; @@ -162,35 +153,32 @@ CGRect swappedForOrientation2(CGRect in) [window addSubview:statusBar]; [statusBar setOrientation:UIApplication.sharedApplication.statusBarOrientation]; - // DESKTOPS + // DESKTOPS TODO: causes lag [self reloadDesktopSection]; - // APPS WITH PANES + // APPS WITH PANES TODO: also causes minor lag [self reloadWindowedAppsSection]; // APPS WITHOUT PANES [self reloadOtherAppsSection]; } --(void) reloadDesktopSection -{ +- (void)reloadDesktopSection { [window reloadDesktopSection]; } --(void) reloadWindowedAppsSection -{ +- (void)reloadWindowedAppsSection { [window reloadWindowedAppsSection:[[%c(RARunningAppsProvider) sharedInstance] runningApplications]]; } --(void) reloadOtherAppsSection -{ +- (void)reloadOtherAppsSection { [window reloadOtherAppsSection]; } --(void) hideMissionControl:(BOOL)animated -{ - if (!didStoreSnapshot) +- (void)hideMissionControl:(BOOL)animated { + if (!didStoreSnapshot) { [[%c(RASnapshotProvider) sharedInstance] storeSnapshotOfMissionControl:window]; + } [[%c(RARunningAppsProvider) sharedInstance] removeTarget:window]; void (^destructor)() = ^{ @@ -199,22 +187,26 @@ CGRect swappedForOrientation2(CGRect in) window = nil; // This goes here to prevent the wallpaper from appearing black when dismissing - [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"RAMissionControlManager"]; + //once again not needed on 10.x but not sure of older versions + if (IS_IOS_OR_OLDER(iOS_10_0)) { + [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"RAMissionControlManager"]; + } }; - if (animated) - { + if (animated) { [UIView animateWithDuration:0.5 animations:^{ - window.frame = swappedForOrientation(CGRectMake(0, -window.frame.size.height, window.frame.size.width, window.frame.size.height)); - - if (originalAppView) - originalAppView.frame = originalAppFrame; - } completion:^(BOOL _) { destructor(); }]; - } - else - { - if (originalAppView) + window.frame = swappedForOrientation(CGRectMake(0, -window.frame.size.height, window.frame.size.width, window.frame.size.height)); + + if (originalAppView) { + originalAppView.frame = originalAppFrame; + } + } completion:^(BOOL _) { + destructor(); + }]; + } else { + if (originalAppView) { originalAppView.frame = originalAppFrame; + } destructor(); } @@ -224,7 +216,7 @@ CGRect swappedForOrientation2(CGRect in) [[%c(RAGestureManager) sharedInstance] removeGestureWithIdentifier:@"com.efrederickson.reachapp.missioncontrol.dismissgesture"]; [[%c(RAGestureManager) sharedInstance] stopIgnoringSwipesForIdentifier:@"com.efrederickson.reachapp.windowedmultitasking.systemgesture"]; [%c(RAOrientationLocker) unlockOrientation]; - [%c(RAControlCenterInhibitor) setInhibited:NO]; + [%c(RAControlCenterInhibitor) setInhibited:NO]; //if (lastOpenedApp && lastOpenedApp.isRunning && UIApplication.sharedApplication._accessibilityFrontMostApplication != lastOpenedApp) //{ @@ -236,133 +228,118 @@ CGRect swappedForOrientation2(CGRect in) lastOpenedApp = nil; // Fix it opening the same app later if on the Homescreen } --(void) toggleMissionControl:(BOOL)animated -{ - if (_isShowingMissionControl) +- (void)toggleMissionControl:(BOOL)animated { + if (_isShowingMissionControl) { [self hideMissionControl:animated]; - else + } else { [self showMissionControl:animated]; + } } --(BOOL) RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity -{ - return self.isShowingMissionControl && self.inhibitDismissalGesture == NO; +- (BOOL)RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity { + return self.isShowingMissionControl && !self.inhibitDismissalGesture; } --(RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge -{ +- (RAGestureCallbackResult)RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { static CGPoint initialCenter; static CGRect initialAppFrame; - if (state == UIGestureRecognizerStateEnded) - { + if (state == UIGestureRecognizerStateEnded) { hasMoved = NO; [%c(RAControlCenterInhibitor) setInhibited:NO]; BOOL dismiss = NO; - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { dismiss = window.frame.origin.x + velocity.y > UIScreen.mainScreen.bounds.size.width / 2.0; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { dismiss = window.frame.origin.x + window.frame.size.width < UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 2.0; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) { dismiss = window.frame.origin.y + window.frame.size.height + velocity.y < UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 2; + } - if (dismiss) - { + if (dismiss) { // Close CGFloat distance = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - (window.frame.origin.y + window.frame.size.height); CGFloat duration = MIN(distance / velocity.y, 0.3); [UIView animateWithDuration:duration animations:^{ - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) { window.center = CGPointMake(window.center.x, -initialCenter.y); - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { + } + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { CGRect f = window.frame; f.origin.x = UIScreen.mainScreen.bounds.size.width; window.frame = f; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { CGRect f = window.frame; f.origin.x = -UIScreen.mainScreen.bounds.size.width; window.frame = f; } - if (originalAppView) + if (originalAppView) { originalAppView.frame = originalAppFrame; + } } completion:^(BOOL _) { [self hideMissionControl:NO]; }]; - } - else - { + } else { CGFloat distance = window.center.y + window.frame.origin.y /* origin.y is less than 0 so the + is actually a - operation */; CGFloat duration = MIN(distance / velocity.y, 0.3); [UIView animateWithDuration:duration animations:^{ window.center = initialCenter; - if (originalAppView) + if (originalAppView) { originalAppView.frame = swappedForOrientation2(CGRectMake(originalAppFrame.origin.x, originalAppView.frame.size.height, originalAppFrame.size.width, originalAppFrame.size.height)); + } }]; } - } - else if (state == UIGestureRecognizerStateBegan) - { + } else if (state == UIGestureRecognizerStateBegan) { //[[%c(RASnapshotProvider) sharedInstance] storeSnapshotOfMissionControl:window]; didStoreSnapshot = YES; hasMoved = YES; [%c(RAControlCenterInhibitor) setInhibited:YES]; initialCenter = window.center; - if (originalAppView) + if (originalAppView) { initialAppFrame = initialAppFrame; - } - else - { - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { + } + } else { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { CGRect f = window.frame; f.origin.x = UIScreen.mainScreen.bounds.size.width - location.y; window.frame = f; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { CGRect f = window.frame; f.origin.x = -UIScreen.mainScreen.bounds.size.width + location.y; window.frame = f; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortrait) { window.center = CGPointMake(window.center.x, location.y - initialCenter.y); + } - if (originalAppView) + if (originalAppView) { originalAppView.frame = swappedForOrientation2(CGRectMake(originalAppView.frame.origin.x, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - location.y), originalAppFrame.size.width, originalAppFrame.size.height)); + } } return RAGestureCallbackResultSuccess; } --(RAMissionControlWindow*) missionControlWindow { return window; } +- (RAMissionControlWindow*)missionControlWindow { + return window; +} --(void) setInhibitDismissalGesture:(BOOL)value -{ +- (void)setInhibitDismissalGesture:(BOOL)value { _inhibitDismissalGesture = value; - if (value && hasMoved) - { + if (value && hasMoved) { [self RAGestureCallback_handle:UIGestureRecognizerStateEnded withPoint:CGPointZero velocity:CGPointZero forEdge:UIRectEdgeBottom]; } } @end %hook SBLockStateAggregator --(void) _updateLockState -{ - %orig; - - if ([self hasAnyLockState]) - if (RAMissionControlManager.sharedInstance.isShowingMissionControl) - [RAMissionControlManager.sharedInstance hideMissionControl:NO]; +- (void)_updateLockState { + %orig; + + if ([self hasAnyLockState] && [RAMissionControlManager sharedInstance].isShowingMissionControl) { + [RAMissionControlManager.sharedInstance hideMissionControl:NO]; + } } -%end \ No newline at end of file +%end diff --git a/MissionControl/RAMissionControlPreviewView.h b/MissionControl/RAMissionControlPreviewView.h index 508fb9d..04f244b 100644 --- a/MissionControl/RAMissionControlPreviewView.h +++ b/MissionControl/RAMissionControlPreviewView.h @@ -1,12 +1,12 @@ #import "headers.h" @interface RAMissionControlPreviewView : UIImageView { - SBIcon *icon; + SBApplicationIcon *icon; SBIconView *iconView; } @property (nonatomic, retain) SBApplication *application; --(void) generatePreview; --(void) generatePreviewAsync; --(void) generateDesktopPreviewAsync:(id)desktop completion:(dispatch_block_t)completionBlock; -@end \ No newline at end of file +- (void)generatePreview; +- (void)generatePreviewAsync; +- (void)generateDesktopPreviewAsync:(id)desktop completion:(dispatch_block_t)completionBlock; +@end diff --git a/MissionControl/RAMissionControlPreviewView.xm b/MissionControl/RAMissionControlPreviewView.xm index f2880f9..1bc38a9 100644 --- a/MissionControl/RAMissionControlPreviewView.xm +++ b/MissionControl/RAMissionControlPreviewView.xm @@ -3,64 +3,72 @@ #import "RADesktopWindow.h" @implementation RAMissionControlPreviewView --(void) generatePreview -{ - [self performSelectorOnMainThread:@selector(setBackgroundColor:) withObject:[[UIColor blackColor] colorWithAlphaComponent:0.5] waitUntilDone:NO]; - //self.image = [[%c(RASnapshotProvider) sharedInstance] snapshotForIdentifier:self.application.bundleIdentifier]; - UIImage *img = [[%c(RASnapshotProvider) sharedInstance] snapshotForIdentifier:self.application.bundleIdentifier]; - [self performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:NO]; +- (void)generatePreview { + [self performSelectorOnMainThread:@selector(setBackgroundColor:) withObject:[[UIColor blackColor] colorWithAlphaComponent:0.5] waitUntilDone:NO]; + //self.image = [[%c(RASnapshotProvider) sharedInstance] snapshotForIdentifier:self.application.bundleIdentifier]; + UIImage *img = [[%c(RASnapshotProvider) sharedInstance] snapshotForIdentifier:self.application.bundleIdentifier]; + [self performSelectorOnMainThread:@selector(setImage:) withObject:img waitUntilDone:NO]; - //if (!icon) - // icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:self.application.bundleIdentifier]; - //if (icon && !iconView) - // iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + //if (!icon) + // icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:self.application.bundleIdentifier]; + //if (icon && !iconView) + // iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - NSOperationQueue* targetQueue = [NSOperationQueue mainQueue]; - [targetQueue addOperationWithBlock:^{ - if (!icon) - icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:self.application.bundleIdentifier]; - if (icon && !iconView) - iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - }]; - [targetQueue waitUntilAllOperationsAreFinished]; + NSOperationQueue* targetQueue = [NSOperationQueue mainQueue]; + [targetQueue addOperationWithBlock:^{ + if (!icon) { + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:self.application.bundleIdentifier]; + } else { + icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:self.application.bundleIdentifier]; + } + } + if (icon && !iconView) { + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + } else { + iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] _iconViewForIcon:icon]; + } + } + }]; + [targetQueue waitUntilAllOperationsAreFinished]; - iconView.layer.shadowRadius = THEMED(missionControlIconPreviewShadowRadius); // iconView.layer.cornerRadius; - iconView.layer.shadowOpacity = 0.8; - iconView.layer.shadowOffset = CGSizeMake(0, 0); - //iconView.layer.shouldRasterize = YES; - //iconView.layer.rasterizationScale = UIScreen.mainScreen.scale; - iconView.userInteractionEnabled = NO; - iconView.iconLabelAlpha = 0; - CGFloat scale = (iconView.frame.size.width - 3.0) / iconView.frame.size.width; - iconView.transform = CGAffineTransformMakeScale(scale, scale); + iconView.layer.shadowRadius = THEMED(missionControlIconPreviewShadowRadius); // iconView.layer.cornerRadius; + iconView.layer.shadowOpacity = 0.8; + iconView.layer.shadowOffset = CGSizeMake(0, 0); + //iconView.layer.shouldRasterize = YES; + //iconView.layer.rasterizationScale = UIScreen.mainScreen.scale; + iconView.userInteractionEnabled = NO; + iconView.iconLabelAlpha = 0; + CGFloat scale = (iconView.frame.size.width - 3.0) / iconView.frame.size.width; + iconView.transform = CGAffineTransformMakeScale(scale, scale); - [self performSelectorOnMainThread:@selector(addSubview:) withObject:iconView waitUntilDone:NO]; - [self performSelectorOnMainThread:@selector(updateIconViewFrame) withObject:nil waitUntilDone:NO]; + [self performSelectorOnMainThread:@selector(addSubview:) withObject:iconView waitUntilDone:NO]; + [self performSelectorOnMainThread:@selector(updateIconViewFrame) withObject:nil waitUntilDone:NO]; } --(void) generatePreviewAsync -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ - [self generatePreview]; - }); +- (void)generatePreviewAsync { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [self generatePreview]; + }); } --(void) generateDesktopPreviewAsync:(id)desktop_ completion:(dispatch_block_t)completionBlock -{ - RADesktopWindow *desktop = (RADesktopWindow*)desktop_; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ - UIImage *image = [[%c(RASnapshotProvider) sharedInstance] snapshotForDesktop:desktop]; - [self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; - if (completionBlock) - completionBlock(); - }); +- (void)generateDesktopPreviewAsync:(id)desktop_ completion:(dispatch_block_t)completionBlock { + RADesktopWindow *desktop = (RADesktopWindow*)desktop_; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + UIImage *image = [[%c(RASnapshotProvider) sharedInstance] snapshotForDesktop:desktop]; + [self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES]; + if (completionBlock) { + completionBlock(); + } + }); } --(void) updateIconViewFrame -{ - if (!iconView) - return; - [self bringSubviewToFront:iconView]; - iconView.frame = CGRectMake( (self.frame.size.width / 2) - (iconView.frame.size.width / 2), (self.frame.size.height / 2) - (iconView.frame.size.height / 2), iconView.frame.size.width, iconView.frame.size.height ); +- (void)updateIconViewFrame { + if (!iconView) { + return; + } + [self bringSubviewToFront:iconView]; + iconView.frame = CGRectMake( (self.frame.size.width / 2) - (iconView.frame.size.width / 2), (self.frame.size.height / 2) - (iconView.frame.size.height / 2), iconView.frame.size.width, iconView.frame.size.height ); } -@end \ No newline at end of file +@end diff --git a/MissionControl/RAMissionControlWindow.h b/MissionControl/RAMissionControlWindow.h index b6e7d54..4341ded 100644 --- a/MissionControl/RAMissionControlWindow.h +++ b/MissionControl/RAMissionControlWindow.h @@ -6,8 +6,8 @@ @interface RAMissionControlWindow : UIAutoRotatingWindow @property (nonatomic, weak) RAMissionControlManager *manager; --(void) reloadDesktopSection; --(void) reloadWindowedAppsSection; --(void) reloadWindowedAppsSection:(NSArray*)runningApplications; --(void) reloadOtherAppsSection; -@end \ No newline at end of file +- (void)reloadDesktopSection; +- (void)reloadWindowedAppsSection; +- (void)reloadWindowedAppsSection:(NSArray*)runningApplications; +- (void)reloadOtherAppsSection; +@end diff --git a/MissionControl/RAMissionControlWindow.xm b/MissionControl/RAMissionControlWindow.xm index 01dbb60..fb10f16 100644 --- a/MissionControl/RAMissionControlWindow.xm +++ b/MissionControl/RAMissionControlWindow.xm @@ -16,7 +16,7 @@ UIScrollView *desktopScrollView, *windowedAppScrollView, *otherRunningAppsScrollView; UILabel *desktopLabel, *windowedLabel, *otherLabel; UIButton *windowedKillAllButton, *otherKillAllButton; - + UIImageView *trashImageView; UIView *shadowView; UIImage *trashIcon; @@ -30,55 +30,42 @@ @end @implementation RAMissionControlWindow --(id) initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) - { +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { trashIcon = [%c(RAResourceImageProvider) imageForFilename:@"Trash.png"]; + self.windowLevel = 1000; } return self; } --(UIWindowLevel) windowLevel -{ - //return UIWindowLevelStatusBar + 1; - return 1000; -} - -- (BOOL)_shouldAutorotateToInterfaceOrientation:(int)arg1 checkForDismissal:(BOOL)arg2 isRotationDisabled:(BOOL*)arg3 -{ +- (BOOL)_shouldAutorotateToInterfaceOrientation:(int)arg1 checkForDismissal:(BOOL)arg2 isRotationDisabled:(BOOL*)arg3 { return YES; } --(void) reloadDesktopSection -{ - width = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 4.5714; - height = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 4.36; +- (void)reloadDesktopSection { + width = [UIScreen mainScreen].RA_interfaceOrientedBounds.size.width / 4.5714; + height = [UIScreen mainScreen].RA_interfaceOrientedBounds.size.height / 4.36; panePadding = width; int count = 1; - while (panePadding + width < UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width) - { + while (panePadding + width < [UIScreen mainScreen].RA_interfaceOrientedBounds.size.width) { count += 1; panePadding += width; } - panePadding = (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width - panePadding) / 5; + panePadding = ([UIScreen mainScreen].RA_interfaceOrientedBounds.size.width - panePadding) / 5; /*if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - width = (UIScreen.mainScreen.bounds.size.width / 3) * 0.9; - height = (UIScreen.mainScreen.bounds.size.height / 4) * 0.9; + width = ([UIScreen mainScreen].bounds.size.width / 3) * 0.9; + height = ([UIScreen mainScreen].bounds.size.height / 4) * 0.9; }*/ // DESKTOP CGFloat y = 20; - if (desktopScrollView) - { + if (desktopScrollView) { [desktopScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - } - else - { + } else { desktopLabel = [[UILabel alloc] initWithFrame:CGRectMake(panePadding, y, self.frame.size.width - 20, 25)]; - desktopLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14]; + desktopLabel.font = [UIFont fontWithName:(IS_IOS_OR_NEWER(iOS_9_0) ? @"SFUIText-Medium" : @"HelveticaNeue-Medium") size:14]; desktopLabel.textColor = UIColor.whiteColor; desktopLabel.text = LOCALIZE(@"DESKTOPS"); [self addSubview:desktopLabel]; @@ -94,25 +81,27 @@ CGFloat x = panePadding; int desktopIndex = 0; - for (RADesktopWindow *desktop in [[%c(RADesktopManager) sharedInstance] availableDesktops]) - { + for (RADesktopWindow *desktop in [[%c(RADesktopManager) sharedInstance] availableDesktops]) { RAMissionControlPreviewView *preview = [[RAMissionControlPreviewView alloc] initWithFrame:CGRectMake(x, (desktopScrollView.frame.size.height - height) / 2.0, width, height)]; x += panePadding + preview.frame.size.width; + preview.alpha = 0; - [desktopScrollView addSubview:preview]; + [UIView animateWithDuration:1 animations:^{ + preview.alpha = 1; + } completion:^(BOOL finished) { + [desktopScrollView addSubview:preview]; + }]; //preview.image = [[%c(RASnapshotProvider) sharedInstance] snapshotForDesktop:desktop]; + //fixed lag but need to fix wallpaper; [preview generateDesktopPreviewAsync:desktop completion:desktop == [[%c(RADesktopManager) sharedInstance] currentDesktop] ? ^{ [[%c(RADesktopManager) sharedInstance] performSelectorOnMainThread:@selector(hideDesktop) withObject:nil waitUntilDone:NO]; } : (dispatch_block_t)nil]; - if (desktop == [[%c(RADesktopManager) sharedInstance] currentDesktop] && [[%c(RASettings) sharedInstance] missionControlDesktopStyle] == 0) - { + if (desktop == [[%c(RADesktopManager) sharedInstance] currentDesktop] && [[%c(RASettings) sharedInstance] missionControlDesktopStyle] == 0) { preview.backgroundColor = [UIColor grayColor]; preview.clipsToBounds = YES; preview.layer.borderWidth = 2; preview.layer.cornerRadius = 10; preview.layer.borderColor = [UIColor whiteColor].CGColor; - } - else if (desktop != [[%c(RADesktopManager) sharedInstance] currentDesktop] && [[%c(RASettings) sharedInstance] missionControlDesktopStyle] == 1) - { + } else if (desktop != [[%c(RADesktopManager) sharedInstance] currentDesktop] && [[%c(RASettings) sharedInstance] missionControlDesktopStyle] == 1) { UIView *crapView = [[UIView alloc] initWithFrame:(CGRect){{ 0, 0 }, preview.frame.size }]; crapView.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.5]; [preview addSubview:crapView]; @@ -123,7 +112,7 @@ [preview addGestureRecognizer:g]; UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget: self action:@selector(handleDoubleDesktopTap:)]; - doubleTap.numberOfTapsRequired = 2; + doubleTap.numberOfTapsRequired = 2; [preview addGestureRecognizer:doubleTap]; [g requireGestureRecognizerToFail:doubleTap]; @@ -150,43 +139,45 @@ //[RADesktopManager.sharedInstance hideDesktop]; // ^^ see the generateDesktopPreviewAsync:completion: call about 40 lines up - //width = UIScreen.mainScreen.bounds.size.width / 4.5714; - //height = UIScreen.mainScreen.bounds.size.height / 4.36; + //width = [UIScreen mainScreen].bounds.size.width / 4.5714; + //height = [UIScreen mainScreen].bounds.size.height / 4.36; } --(void) reloadWindowedAppsSection -{ +- (void)reloadWindowedAppsSection { [self reloadWindowedAppsSection:runningApplications]; } --(void) reloadWindowedAppsSection:(NSArray*)runningApplicationsArg -{ +- (void)reloadWindowedAppsSection:(NSArray*)runningApplicationsArg { runningApplications = [runningApplicationsArg mutableCopy]; NSArray *switcherOrder = [[%c(RAAppSwitcherModelWrapper) appSwitcherAppIdentiferList] copy]; [runningApplications sortUsingComparator:^NSComparisonResult(SBApplication *obj1, SBApplication *obj2) { - return [@([switcherOrder indexOfObject:obj1.bundleIdentifier]) compare:@([switcherOrder indexOfObject:obj2.bundleIdentifier])]; + return [@([switcherOrder indexOfObject:obj1.bundleIdentifier]) compare:@([switcherOrder indexOfObject:obj2.bundleIdentifier])]; }]; - + appsWithoutWindows = [runningApplications mutableCopy]; - NSArray *visibleIcons = [[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers]; - for (SBApplication *app in runningApplications) - { - if ([visibleIcons containsObject:app.bundleIdentifier] == NO)// || [RAMissionControlManager.sharedInstance.inhibitedApplications containsObject:app.bundleIdentifier]) - [appsWithoutWindows removeObject:app]; + NSArray *visibleIcons = nil; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + visibleIcons = [[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers]; + } else { + visibleIcons = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] visibleIconIdentifiers]; + } + + for (SBApplication *app in runningApplications) { + if ([visibleIcons containsObject:app.bundleIdentifier]) { + continue; + }// || [RAMissionControlManager.sharedInstance.inhibitedApplications containsObject:app.bundleIdentifier]) + [appsWithoutWindows removeObject:app]; } CGFloat x = panePadding; CGFloat y = desktopScrollView.frame.origin.y + desktopScrollView.frame.size.height + 7; - if (windowedAppScrollView) - { + if (windowedAppScrollView) { [windowedAppScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - } - else - { + } else { windowedLabel = [[UILabel alloc] initWithFrame:CGRectMake(panePadding, y, self.frame.size.width - 20, 25)]; - windowedLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14]; + windowedLabel.font = [UIFont fontWithName:(IS_IOS_OR_NEWER(iOS_9_0) ? @"SFUIText-Medium" : @"HelveticaNeue-Medium") size:14]; windowedLabel.textColor = UIColor.whiteColor; windowedLabel.text = LOCALIZE(@"ON_THIS_DESKTOP"); [self addSubview:windowedLabel]; @@ -199,8 +190,7 @@ } BOOL empty = YES; - for (RAHostedAppView *app in [[%c(RADesktopManager) sharedInstance] currentDesktop].hostedWindows) - { + for (RAHostedAppView *app in [[%c(RADesktopManager) sharedInstance] currentDesktop].hostedWindows) { SBApplication *sbapp = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:app.bundleIdentifier]; [appsWithoutWindows removeObject:sbapp]; @@ -208,7 +198,11 @@ x += panePadding + preview.frame.size.width; preview.application = sbapp; - [windowedAppScrollView addSubview:preview]; + [UIView animateWithDuration:1 animations:^{ + preview.alpha = 1; + } completion:^(BOOL finished) { + [windowedAppScrollView addSubview:preview]; + }]; [preview generatePreviewAsync]; UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(topIconViewTap:)]; @@ -222,29 +216,24 @@ empty = NO; } - if (empty) - { + if (empty) { UILabel *emptyLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, (windowedAppScrollView.frame.size.height - 30) / 2, windowedAppScrollView.frame.size.width, 30)]; emptyLabel.textAlignment = NSTextAlignmentCenter; - emptyLabel.font = [UIFont fontWithName:@"Helvetica" size:25]; + emptyLabel.font = [UIFont systemFontOfSize:25]; emptyLabel.text = LOCALIZE(@"NO_APPS"); emptyLabel.textColor = [UIColor whiteColor]; emptyLabel.alpha = 0.7; [windowedAppScrollView addSubview:emptyLabel]; - if (windowedKillAllButton) - { + if (windowedKillAllButton) { [windowedKillAllButton removeFromSuperview]; windowedKillAllButton = nil; } - } - else - { - if (!windowedKillAllButton) - { + } else { + if (!windowedKillAllButton) { windowedKillAllButton = [UIButton buttonWithType:UIButtonTypeCustom]; [windowedKillAllButton setTitle:LOCALIZE(@"KILL_ALL") forState:UIControlStateNormal]; - windowedKillAllButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14]; + windowedKillAllButton.titleLabel.font = [UIFont fontWithName:(IS_IOS_OR_NEWER(iOS_9_0) ? @"SFUIText-Medium" : @"HelveticaNeue-Medium") size:14]; windowedKillAllButton.titleLabel.textColor = [UIColor whiteColor]; [windowedKillAllButton sizeToFit]; windowedKillAllButton.frame = CGRectMake(self.frame.size.width - panePadding - windowedKillAllButton.frame.size.width, y, windowedKillAllButton.frame.size.width, windowedKillAllButton.frame.size.height); @@ -255,19 +244,15 @@ windowedAppScrollView.contentSize = CGSizeMake(MAX(x, self.frame.size.width + (empty ? 0 : 1)), height * 1.15); // make slightly scrollable } --(void) reloadOtherAppsSection -{ +- (void)reloadOtherAppsSection { CGFloat x = panePadding; CGFloat y = windowedAppScrollView.frame.origin.y + windowedAppScrollView.frame.size.height + 7; - if (otherRunningAppsScrollView) - { + if (otherRunningAppsScrollView) { [otherRunningAppsScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - } - else - { + } else { otherLabel = [[UILabel alloc] initWithFrame:CGRectMake(panePadding, y, self.frame.size.width - 20, 25)]; - otherLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14]; + otherLabel.font = [UIFont fontWithName:(IS_IOS_OR_NEWER(iOS_9_0) ? @"SFUIText-Medium" : @"HelveticaNeue-Medium") size:14]; otherLabel.textColor = UIColor.whiteColor; otherLabel.text = LOCALIZE(@"RUNNING_ELSEWHERE"); [self addSubview:otherLabel]; @@ -280,15 +265,18 @@ } BOOL empty = YES; - for (SBApplication *app in appsWithoutWindows) - { + for (SBApplication *app in appsWithoutWindows) { empty = NO; RAMissionControlPreviewView *preview = [[RAMissionControlPreviewView alloc] initWithFrame:CGRectMake(x, (otherRunningAppsScrollView.frame.size.height - height) / 2, width, height)]; x += panePadding + preview.frame.size.width; preview.application = app; - [otherRunningAppsScrollView addSubview:preview]; + [UIView animateWithDuration:1 animations:^{ + preview.alpha = 1; + } completion:^(BOOL finished) { + [otherRunningAppsScrollView addSubview:preview]; + }]; [preview generatePreviewAsync]; UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(topIconViewTap:)]; @@ -301,29 +289,24 @@ preview.userInteractionEnabled = YES; } - if (empty) - { + if (empty) { UILabel *emptyLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, (windowedAppScrollView.frame.size.height - 30) / 2, windowedAppScrollView.frame.size.width, 30)]; emptyLabel.textAlignment = NSTextAlignmentCenter; - emptyLabel.font = [UIFont fontWithName:@"Helvetica" size:25]; + emptyLabel.font = [UIFont systemFontOfSize:25]; emptyLabel.text = LOCALIZE(@"NO_APPS"); emptyLabel.textColor = [UIColor whiteColor]; emptyLabel.alpha = 0.7; [otherRunningAppsScrollView addSubview:emptyLabel]; - if (otherKillAllButton) - { + if (otherKillAllButton) { [otherKillAllButton removeFromSuperview]; otherKillAllButton = nil; } - } - else - { - if (!otherKillAllButton) - { + } else { + if (!otherKillAllButton) { otherKillAllButton = [UIButton buttonWithType:UIButtonTypeCustom]; [otherKillAllButton setTitle:LOCALIZE(@"KILL_ALL") forState:UIControlStateNormal]; - otherKillAllButton.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14]; + otherKillAllButton.titleLabel.font = [UIFont fontWithName:(IS_IOS_OR_NEWER(iOS_9_0) ? @"SFUIText-Medium" : @"HelveticaNeue-Medium") size:14]; otherKillAllButton.titleLabel.textColor = [UIColor whiteColor]; [otherKillAllButton sizeToFit]; otherKillAllButton.frame = CGRectMake(self.frame.size.width - panePadding - otherKillAllButton.frame.size.width, y, otherKillAllButton.frame.size.width, otherKillAllButton.frame.size.height); @@ -335,8 +318,7 @@ otherRunningAppsScrollView.contentSize = CGSizeMake(MAX(x, self.frame.size.width + (empty ? 0 : 1)), height * 1.15); // make slightly scrollable } --(void) createNewDesktop:(UIButton*)view -{ +- (void)createNewDesktop:(UIButton*)view { [[%c(RADesktopManager) sharedInstance] addDesktop:NO]; [UIView animateWithDuration:0.4 animations:^{ @@ -346,64 +328,57 @@ }]; } --(void) removeCardForApplication:(SBApplication*)app -{ +- (void)removeCardForApplication:(SBApplication*)app { CGFloat originX = -1; UIView *targetView = nil; UIScrollView *parentView = [appsWithoutWindows containsObject:app] ? otherRunningAppsScrollView : windowedAppScrollView; NSArray *subviews = [parentView.subviews copy]; - for (UIView *view in subviews) - { - if ([view isKindOfClass:[RAMissionControlPreviewView class]]) - { + for (UIView *view in subviews) { + if ([view isKindOfClass:[RAMissionControlPreviewView class]]) { RAMissionControlPreviewView *real = (RAMissionControlPreviewView*)view; - if ([real.application.bundleIdentifier isEqualToString:app.bundleIdentifier]) - { + if ([real.application.bundleIdentifier isEqualToString:app.bundleIdentifier]) { originX = view.frame.origin.x; targetView = view; } } - if (originX == -1) + if (originX == -1) { continue; - else if (view.frame.origin.x == originX) - { + } else if (view.frame.origin.x == originX) { [UIView animateWithDuration:0.2 animations:^{ view.frame = CGRectOffset(view.frame, 0, view.frame.size.height + panePadding); } completion:^(BOOL _) { [view removeFromSuperview]; }]; - } - else if (view.frame.origin.x > originX) + } else if (view.frame.origin.x > originX) { [UIView animateWithDuration:0.4 animations:^{ view.frame = CGRectOffset(view.frame, -view.frame.size.width - panePadding, 0); }]; + } } - if (parentView.contentSize.width - 1 <= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width) + if (parentView.contentSize.width - 1 <= [UIScreen mainScreen].RA_interfaceOrientedBounds.size.width) { ; // don't make it too small to scroll - else if (targetView) + } else if (targetView) { parentView.contentSize = CGSizeMake(parentView.contentSize.width - targetView.frame.size.width - panePadding + 1, parentView.contentSize.height); + } } --(void) handleAppPreviewPan:(UILongPressGestureRecognizer*)gesture -{ +- (void)handleAppPreviewPan:(UILongPressGestureRecognizer*)gesture { static CGPoint initialCenter; static UIView *draggedView; static CGPoint lastPoint; CGPoint point = [gesture locationInView:self]; - if (gesture.state == UIGestureRecognizerStateBegan) - { - if (!trashImageView || trashImageView.superview == nil /* new window perhaps */) - { - trashImageView = [[UIImageView alloc] initWithFrame:CGRectMake((UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 2) - (75/2), UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height + 75, 75, 75)]; + if (gesture.state == UIGestureRecognizerStateBegan) { + if (!trashImageView || !trashImageView.superview /* new window perhaps */) { + trashImageView = [[UIImageView alloc] initWithFrame:CGRectMake(([UIScreen mainScreen].RA_interfaceOrientedBounds.size.width / 2) - (75/2), [UIScreen mainScreen].RA_interfaceOrientedBounds.size.height + 75, 75, 75)]; trashImageView.image = trashIcon; [self addSubview:trashImageView]; - shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width, 75)]; + shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, [UIScreen mainScreen].RA_interfaceOrientedBounds.size.height, [UIScreen mainScreen].RA_interfaceOrientedBounds.size.width, 75)]; shadowView.backgroundColor = [UIColor blackColor]; shadowView.layer.shadowColor = [UIColor blackColor].CGColor; shadowView.layer.shadowRadius = 75/2; @@ -415,15 +390,14 @@ [UIView animateWithDuration:0.4 animations:^{ shadowView.alpha = 1; trashImageView.alpha = 1; - trashImageView.frame = CGRectMake((UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 2) - (75/2), UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height - (75+45), 75, 75); + trashImageView.frame = CGRectMake(([UIScreen mainScreen].RA_interfaceOrientedBounds.size.width / 2) - (75/2), [UIScreen mainScreen].RA_interfaceOrientedBounds.size.height - (75+45), 75, 75); }]; - if (draggedView == nil) - { + if (!draggedView) { draggedView = [gesture.view snapshotViewAfterScreenUpdates:YES]; draggedView.frame = gesture.view.frame; draggedView.center = [gesture.view.superview convertPoint:gesture.view.center toView:self]; - + [self addSubview:draggedView]; gesture.view.alpha = 0.6; @@ -432,38 +406,33 @@ }]; } initialCenter = draggedView.center; - } - else if (gesture.state == UIGestureRecognizerStateChanged) - { + } else if (gesture.state == UIGestureRecognizerStateChanged) { //CGPoint newCenter = [gesture translationInView:draggedView]; //newCenter.x += initialCenter.x; //newCenter.y += initialCenter.y; //draggedView.center = newCenter; - CGPoint center = draggedView.center; - center.x += point.x - lastPoint.x; - center.y += point.y - lastPoint.y; - draggedView.center = center; - } - else - { + CGPoint center = draggedView.center; + center.x += point.x - lastPoint.x; + center.y += point.y - lastPoint.y; + draggedView.center = center; + } else { gesture.view.alpha = 1; //CGPoint center = [gesture translationInView:draggedView]; //center.x += initialCenter.x; //center.y += initialCenter.y; - CGPoint center = draggedView.center; - center.x += point.x - lastPoint.x; - center.y += point.y - lastPoint.y; + CGPoint center = draggedView.center; + center.x += point.x - lastPoint.x; + center.y += point.y - lastPoint.y; BOOL didKill = NO; - if (CGRectContainsPoint(trashImageView.frame, center) || CGRectContainsPoint(CGRectOffset(shadowView.frame, 0, -(75/2)), center)) - { + if (CGRectContainsPoint(trashImageView.frame, center) || CGRectContainsPoint(CGRectOffset(shadowView.frame, 0, -(75/2)), center)) { SBApplication *app = ((RAMissionControlPreviewView*)gesture.view).application; [[%c(RADesktopManager) sharedInstance] removeAppWithIdentifier:app.bundleIdentifier animated:NO]; [[%c(RAWindowStatePreservationSystemManager) sharedInstance] removeWindowInformationForIdentifier:app.bundleIdentifier]; - if ([[%c(RASettings) sharedInstance] missionControlKillApps]) + if ([[%c(RASettings) sharedInstance] missionControlKillApps]) { [%c(RAAppKiller) killAppWithSBApplication:app completion:^{ [runningApplications removeObject:app]; @@ -475,47 +444,43 @@ // [self removeCardForApplication:app]; //}); }]; + } didKill = YES; } [UIView animateWithDuration:0.4 animations:^{ shadowView.alpha = 0; trashImageView.alpha = 0; - trashImageView.frame = CGRectMake((UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 2) - (75/2), UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height + 75, 75, 75); - } completion:^(BOOL _) { - }]; + trashImageView.frame = CGRectMake(([UIScreen mainScreen].RA_interfaceOrientedBounds.size.width / 2) - (75/2), [UIScreen mainScreen].RA_interfaceOrientedBounds.size.height + 75, 75, 75); + } completion:nil]; - if (!didKill) - { - for (UIView *subview in desktopScrollView.subviews) - { - if ([subview isKindOfClass:[RAMissionControlPreviewView class]]) - { - if (CGRectContainsPoint((CGRect){ [desktopScrollView convertPoint:subview.frame.origin toView:self], subview.frame.size }, center) || (CGRectContainsPoint((CGRect){ [windowedAppScrollView convertPoint:subview.frame.origin toView:self], windowedAppScrollView.frame.size }, center) && gesture.view.superview != windowedAppScrollView)) - { - RADesktopWindow *desktop = [[%c(RADesktopManager) sharedInstance] desktopAtIndex:subview.tag]; - SBApplication *app = ((RAMissionControlPreviewView*)gesture.view).application; - - [[[%c(RADesktopManager) sharedInstance] currentDesktop] removeAppWithIdentifier:app.bundleIdentifier animated:NO]; - - [desktop createAppWindowForSBApplication:app animated:NO]; - - [[%c(RASnapshotProvider) sharedInstance] forceReloadSnapshotOfDesktop:[[%c(RADesktopManager) sharedInstance] currentDesktop]]; - [[%c(RASnapshotProvider) sharedInstance] forceReloadSnapshotOfDesktop:desktop]; - - [self reloadDesktopSection]; - [self reloadWindowedAppsSection]; - [self reloadOtherAppsSection]; - } + if (!didKill) { + for (UIView *subview in desktopScrollView.subviews) { + if (![subview isKindOfClass:[RAMissionControlPreviewView class]]) { + continue; + } + if (CGRectContainsPoint((CGRect){ [desktopScrollView convertPoint:subview.frame.origin toView:self], subview.frame.size }, center) || (CGRectContainsPoint((CGRect){ [windowedAppScrollView convertPoint:subview.frame.origin toView:self], windowedAppScrollView.frame.size }, center) && gesture.view.superview != windowedAppScrollView)) { + RADesktopWindow *desktop = [[%c(RADesktopManager) sharedInstance] desktopAtIndex:subview.tag]; + SBApplication *app = ((RAMissionControlPreviewView*)gesture.view).application; + + [[[%c(RADesktopManager) sharedInstance] currentDesktop] removeAppWithIdentifier:app.bundleIdentifier animated:NO]; + + [desktop createAppWindowForSBApplication:app animated:NO]; + + [[%c(RASnapshotProvider) sharedInstance] forceReloadSnapshotOfDesktop:[[%c(RADesktopManager) sharedInstance] currentDesktop]]; + [[%c(RASnapshotProvider) sharedInstance] forceReloadSnapshotOfDesktop:desktop]; + + [self reloadDesktopSection]; + [self reloadWindowedAppsSection]; + [self reloadOtherAppsSection]; } } } - [UIView animateWithDuration:0.4 animations:^{ - if (!didKill) - { + [UIView animateWithDuration:0.4 animations:^{ + if (!didKill) { draggedView.transform = CGAffineTransformIdentity; - draggedView.center = initialCenter; + draggedView.center = initialCenter; } } completion:^(BOOL _) { [draggedView removeFromSuperview]; @@ -525,22 +490,17 @@ lastPoint = point; } --(void) animateDesktopRemovalForDesktopAtIndexReloadingSectionAfter:(NSInteger)index -{ +- (void)animateDesktopRemovalForDesktopAtIndexReloadingSectionAfter:(NSInteger)index { CGFloat originX = -1; - for (UIView *v in desktopScrollView.subviews) - { - if (v.tag == index) - { + for (UIView *v in desktopScrollView.subviews) { + if (v.tag == index) { originX = v.frame.origin.x; [UIView animateWithDuration:0.2 animations:^{ v.frame = CGRectOffset(v.frame, 0, -panePadding); } completion:^(BOOL _) { [v removeFromSuperview]; }]; - } - else if (v.tag > index || (originX != -1 && originX < v.frame.origin.x)) - { + } else if (v.tag > index || (originX != -1 && originX < v.frame.origin.x)) { [UIView animateWithDuration:0.4 animations:^{ v.frame = CGRectOffset(v.frame, -v.frame.size.width - panePadding, 0); }]; @@ -551,51 +511,45 @@ }); } --(void) handleDesktopPan:(UIPanGestureRecognizer*)gesture -{ +- (void)handleDesktopPan:(UIPanGestureRecognizer*)gesture { static CGPoint initialCenter; - if (gesture.state == UIGestureRecognizerStateBegan) - { + if (gesture.state == UIGestureRecognizerStateBegan) { initialCenter = gesture.view.center; - } - else if (gesture.state == UIGestureRecognizerStateChanged) - { + } else if (gesture.state == UIGestureRecognizerStateChanged) { CGPoint newCenter = [gesture translationInView:gesture.view]; //newCenter.x += initialCenter.x; newCenter.x = initialCenter.x; - if (newCenter.y > 0 || gesture.view.tag == 0) + if (newCenter.y > 0 || gesture.view.tag == 0) { newCenter.y = initialCenter.y + (newCenter.y / 5); //initialCenter.y; - else + } else { newCenter.y += initialCenter.y; + } gesture.view.center = newCenter; - } - else - { - if (gesture.view.center.y - initialCenter.y < -80 && gesture.view.tag > 0) - { + } else { + if (gesture.view.center.y - initialCenter.y < -80 && gesture.view.tag > 0) { [[%c(RADesktopManager) sharedInstance] removeDesktopAtIndex:gesture.view.tag]; [UIView animateWithDuration:0.4 animations:^{ gesture.view.center = CGPointMake(gesture.view.center.x, -gesture.view.frame.size.height); } completion:^(BOOL _) { [self animateDesktopRemovalForDesktopAtIndexReloadingSectionAfter:gesture.view.tag]; }]; + } else { + [UIView animateWithDuration:0.4 animations:^{ + gesture.view.center = initialCenter; + }]; } - else - [UIView animateWithDuration:0.4 animations:^{ gesture.view.center = initialCenter; }]; } } --(void) activateDesktop:(UITapGestureRecognizer*)gesture -{ +- (void)activateDesktop:(UITapGestureRecognizer*)gesture { int desktop = gesture.view.tag; [[%c(RADesktopManager) sharedInstance] switchToDesktop:desktop]; [self.manager hideMissionControl:YES]; } --(void) handleSingleDesktopTap:(UITapGestureRecognizer*)gesture -{ +- (void)handleSingleDesktopTap:(UITapGestureRecognizer*)gesture { int desktop = gesture.view.tag; [[%c(RADesktopManager) sharedInstance] switchToDesktop:desktop actuallyShow:NO]; [self reloadDesktopSection]; @@ -603,13 +557,11 @@ [self reloadOtherAppsSection]; } --(void) handleDoubleDesktopTap:(UITapGestureRecognizer*)gesture -{ +- (void)handleDoubleDesktopTap:(UITapGestureRecognizer*)gesture { [self activateDesktop:gesture]; } --(void) topIconViewTap:(UITapGestureRecognizer*)gesture -{ +- (void)topIconViewTap:(UITapGestureRecognizer*)gesture { [self.manager hideMissionControl:YES]; __block __strong NSString *identifier = [[[gesture view] performSelector:@selector(application)] bundleIdentifier]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ @@ -618,68 +570,61 @@ }); } --(void) killAllWindowed -{ - for (UIView *view in windowedAppScrollView.subviews) - { - if ([view isKindOfClass:[RAMissionControlPreviewView class]]) - { - RAMissionControlPreviewView *realView = (RAMissionControlPreviewView*)view; - SBApplication *app = realView.application; - [%c(RAAppKiller) killAppWithSBApplication:app completion:^{ - [runningApplications removeObject:app]; - [self performSelectorOnMainThread:@selector(reloadWindowedAppsSection:) withObject:[[%c(RARunningAppsProvider) sharedInstance] runningApplications] waitUntilDone:YES]; - [self performSelectorOnMainThread:@selector(reloadOtherAppsSection) withObject:nil waitUntilDone:YES]; - }]; +- (void)killAllWindowed { + for (UIView *view in windowedAppScrollView.subviews) { + if (![view isKindOfClass:[RAMissionControlPreviewView class]]) { + continue; } + RAMissionControlPreviewView *realView = (RAMissionControlPreviewView*)view; + SBApplication *app = realView.application; + [%c(RAAppKiller) killAppWithSBApplication:app completion:^{ + [runningApplications removeObject:app]; + [self performSelectorOnMainThread:@selector(reloadWindowedAppsSection:) withObject:[[%c(RARunningAppsProvider) sharedInstance] runningApplications] waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(reloadOtherAppsSection) withObject:nil waitUntilDone:YES]; + }]; } } --(void) killAllOther -{ - for (UIView *view in otherRunningAppsScrollView.subviews) - { - if ([view isKindOfClass:[RAMissionControlPreviewView class]]) - { - RAMissionControlPreviewView *realView = (RAMissionControlPreviewView*)view; - SBApplication *app = realView.application; - [%c(RAAppKiller) killAppWithSBApplication:app completion:^{ - [self performSelectorOnMainThread:@selector(reloadWindowedAppsSection:) withObject:[[%c(RARunningAppsProvider) sharedInstance] runningApplications] waitUntilDone:YES]; - [self performSelectorOnMainThread:@selector(reloadOtherAppsSection) withObject:nil waitUntilDone:YES]; - }]; +- (void)killAllOther { + for (UIView *view in otherRunningAppsScrollView.subviews) { + if (![view isKindOfClass:[RAMissionControlPreviewView class]]) { + continue; } + RAMissionControlPreviewView *realView = (RAMissionControlPreviewView*)view; + SBApplication *app = realView.application; + [%c(RAAppKiller) killAppWithSBApplication:app completion:^{ + [self performSelectorOnMainThread:@selector(reloadWindowedAppsSection:) withObject:[[%c(RARunningAppsProvider) sharedInstance] runningApplications] waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(reloadOtherAppsSection) withObject:nil waitUntilDone:YES]; + }]; } } --(void) appDidStart:(SBApplication*)app -{ +- (void)appDidStart:(SBApplication*)app { [self reloadWindowedAppsSection:[[%c(RARunningAppsProvider) sharedInstance] runningApplications]]; [self reloadOtherAppsSection]; } --(void) appDidDie:(SBApplication*)app -{ +- (void)appDidDie:(SBApplication*)app { [self removeCardForApplication:app]; } --(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; - UIView *subview; - while ((subview = [objects nextObject])) - { - UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; - if (success) - return success; - } - return self; - //return [super hitTest:point withEvent:event]; +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; + UIView *subview; + while ((subview = [objects nextObject])) { + UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; + if (success) { + return success; + } + } + return self; + //return [super hitTest:point withEvent:event]; } -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - if (CGRectContainsPoint(self.frame, point)) +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + if (CGRectContainsPoint(self.frame, point)) { return YES; + } return [super pointInside:point withEvent:event]; } -@end \ No newline at end of file +@end diff --git a/Multiplexer.h b/Multiplexer.h index 77ec554..218cce6 100644 --- a/Multiplexer.h +++ b/Multiplexer.h @@ -1,20 +1,20 @@ @class SBApplication; @interface MultiplexerExtension : NSObject -@property (nonatomic, retain) NSString *name; -@property (nonatomic, retain) NSString *multiplexerVersion; +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *multiplexerVersion; @end @interface Multiplexer : NSObject { NSMutableArray *activeExtensions; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; --(NSString*) currentVersion; --(BOOL) isOnSupportedOS; +- (NSString*)currentVersion; +- (BOOL)isOnSupportedOS; --(void) registerExtension:(NSString*)name forMultiplexerVersion:(NSString*)version; +- (void)registerExtension:(NSString*)name forMultiplexerVersion:(NSString*)version; -+(id) createSBAppToAppWorkspaceTransactionForExitingApp:(SBApplication*)app; -+(BOOL) shouldShowControlCenterGrabberOnFirstSwipe; ++ (id)createSBAppToAppWorkspaceTransactionForExitingApp:(SBApplication*)app; ++ (BOOL)shouldShowControlCenterGrabberOnFirstSwipe; @end diff --git a/Multiplexer.xm b/Multiplexer.xm index 6e2dce5..ac49f72 100644 --- a/Multiplexer.xm +++ b/Multiplexer.xm @@ -2,28 +2,24 @@ #import "RACompatibilitySystem.h" #import "headers.h" -#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) -#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) -#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) - @implementation MultiplexerExtension @end @implementation Multiplexer -+(instancetype) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(Multiplexer, sharedInstance->activeExtensions = [NSMutableArray array]); } --(NSString*) currentVersion { return @"1.0"; } --(BOOL) isOnSupportedOS { return SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0") && SYSTEM_VERSION_LESS_THAN(@"9.0"); } +- (NSString*)currentVersion { + return @"1.0"; +} + +- (BOOL)isOnSupportedOS { + return IS_IOS_BETWEEN(iOS_8_0, iOS_10_2); +} --(void) registerExtension:(NSString*)name forMultiplexerVersion:(NSString*)version -{ - if ([self.currentVersion compare:version options:NSNumericSearch] == NSOrderedDescending) - { +- (void)registerExtension:(NSString*)name forMultiplexerVersion:(NSString*)version { + if ([self.currentVersion compare:version options:NSNumericSearch] == NSOrderedDescending) { [RACompatibilitySystem showWarning:[NSString stringWithFormat:@"Extension %@ was built for Multiplexer version %@, which is above the current version. Compliancy issues may occur.", name, version]]; } @@ -33,41 +29,36 @@ [activeExtensions addObject:ext]; } -+(id) createSBAppToAppWorkspaceTransactionForExitingApp:(SBApplication*)app -{ - if ([%c(SBAppToAppWorkspaceTransaction) respondsToSelector:@selector(initWithAlertManager:exitedApp:)]) - { ++ (SBAppToAppWorkspaceTransaction*)createSBAppToAppWorkspaceTransactionForExitingApp:(SBApplication*)app { + if ([%c(SBAppToAppWorkspaceTransaction) respondsToSelector:@selector(initWithAlertManager:exitedApp:)]) { return [[%c(SBAppToAppWorkspaceTransaction) alloc] initWithAlertManager:nil exitedApp:app]; + } else { + // ** below code from Mirmir (https://github.com/EthanArbuckle/Mirmir/blob/lamo_no_ms/Lamo/CDTLamo.mm#L114-L138) + SBWorkspaceApplicationTransitionContext *transitionContext = [[%c(SBWorkspaceApplicationTransitionContext) alloc] init]; + + //set layout role to 'side' (deactivating) + SBWorkspaceDeactivatingEntity *deactivatingEntity = [%c(SBWorkspaceDeactivatingEntity) entity]; + [deactivatingEntity setLayoutRole:3]; + [transitionContext setEntity:deactivatingEntity forLayoutRole:3]; + + //set layout role for 'primary' (activating) + SBWorkspaceHomeScreenEntity *homescreenEntity = [[%c(SBWorkspaceHomeScreenEntity) alloc] init]; + [transitionContext setEntity:homescreenEntity forLayoutRole:2]; + + [transitionContext setAnimationDisabled:YES]; + + //create transititon request + SBMainWorkspaceTransitionRequest *transitionRequest = [[%c(SBMainWorkspaceTransitionRequest) alloc] initWithDisplay:[%c(FBDisplayManager) mainDisplay]]; + [transitionRequest setApplicationContext:transitionContext]; + + return [[%c(SBAppToAppWorkspaceTransaction) alloc] initWithTransitionRequest:transitionRequest]; } - else - { - // ** below code from Mirmir (https://github.com/EthanArbuckle/Mirmir/blob/lamo_no_ms/Lamo/CDTLamo.mm#L114-L138) - SBWorkspaceApplicationTransitionContext *transitionContext = [[%c(SBWorkspaceApplicationTransitionContext) alloc] init]; - - //set layout role to 'side' (deactivating) - SBWorkspaceDeactivatingEntity *deactivatingEntity = [%c(SBWorkspaceDeactivatingEntity) entity]; - [deactivatingEntity setLayoutRole:3]; - [transitionContext setEntity:deactivatingEntity forLayoutRole:3]; - - //set layout role for 'primary' (activating) - SBWorkspaceHomeScreenEntity *homescreenEntity = [[%c(SBWorkspaceHomeScreenEntity) alloc] init]; - [transitionContext setEntity:homescreenEntity forLayoutRole:2]; - - [transitionContext setAnimationDisabled:YES]; - - //create transititon request - SBMainWorkspaceTransitionRequest *transitionRequest = [[%c(SBMainWorkspaceTransitionRequest) alloc] initWithDisplay:[[UIScreen mainScreen] valueForKey:@"_fbsDisplay"]]; - [transitionRequest setValue:transitionContext forKey:@"_applicationContext"]; - - return [[%c(SBAppToAppWorkspaceTransaction) alloc] initWithTransitionRequest:transitionRequest]; - // ** // - } } -+(BOOL) shouldShowControlCenterGrabberOnFirstSwipe -{ - if ([%c(SBUIController) respondsToSelector:@selector(shouldShowControlCenterTabControlOnFirstSwipe)]) ++ (BOOL)shouldShowControlCenterGrabberOnFirstSwipe { + if ([%c(SBUIController) respondsToSelector:@selector(shouldShowControlCenterTabControlOnFirstSwipe)]) { [[%c(SBUIController) sharedInstance] shouldShowControlCenterTabControlOnFirstSwipe]; + } return [[%c(SBControlCenterController) sharedInstance] _shouldShowGrabberOnFirstSwipe]; } -@end \ No newline at end of file +@end diff --git a/NotificationCenterApp/NCHook.xm b/NotificationCenterApp/NCHook.xm index 5c23d49..dd8e981 100644 --- a/NotificationCenterApp/NCHook.xm +++ b/NotificationCenterApp/NCHook.xm @@ -3,112 +3,149 @@ #import "RASettings.h" #import "headers.h" -@interface SBNotificationCenterViewController --(id)_newBulletinObserverViewControllerOfClass:(Class)aClass; +@interface SBNotificationCenterViewController () +- (id)_newBulletinObserverViewControllerOfClass:(Class)aClass; @end @interface SBNotificationCenterLayoutViewController @end @interface SBModeViewController --(void) _addBulletinObserverViewController:(id)arg1; +- (void)_addBulletinObserverViewController:(id)arg1; - (void)addViewController:(id)arg1; @end -NSString *getAppName() -{ +NSString *getAppName() { NSString *ident = [RASettings.sharedInstance NCApp] ?: @"com.apple.Preferences"; SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:ident]; return app ? app.displayName : nil; } RANCViewController *ncAppViewController; +BOOL shouldLoadView = NO; %group iOS8 %hook SBNotificationCenterViewController -- (void)viewWillAppear:(BOOL)animated -{ - %orig; +- (void)viewWillAppear:(BOOL)animated { + %orig; - BOOL hideBecauseLS = [[%c(SBLockScreenManager) sharedInstance] isUILocked] ? [RASettings.sharedInstance ncAppHideOnLS] : NO; + BOOL hideBecauseLS = [[%c(SBLockScreenManager) sharedInstance] isUILocked] ? [RASettings.sharedInstance ncAppHideOnLS] : NO; - if ([RASettings.sharedInstance NCAppEnabled] && !hideBecauseLS) - { + if ([RASettings.sharedInstance NCAppEnabled] && !hideBecauseLS) { SBModeViewController* modeVC = MSHookIvar(self, "_modeController"); - if (ncAppViewController == nil) + if (!ncAppViewController) { ncAppViewController = [self _newBulletinObserverViewControllerOfClass:[RANCViewController class]]; + } [modeVC _addBulletinObserverViewController:ncAppViewController]; } } -+ (NSString *)_localizableTitleForBulletinViewControllerOfClass:(__unsafe_unretained Class)aClass -{ - if (aClass == [RANCViewController class]) - { ++ (NSString *)_localizableTitleForBulletinViewControllerOfClass:(__unsafe_unretained Class)aClass { + if (aClass == [RANCViewController class]) { BOOL useGenericLabel = THEMED(quickAccessUseGenericTabLabel) || [RASettings.sharedInstance quickAccessUseGenericTabLabel]; - if (useGenericLabel) + if (useGenericLabel) { return LOCALIZE(@"APP"); + } return ncAppViewController.hostedApp.displayName ?: getAppName() ?: LOCALIZE(@"APP"); - } - else + } else { return %orig; + } } %end %end %group iOS9 %hook SBNotificationCenterLayoutViewController -- (void)_loadContentViewControllers -{ - %orig; +- (void)viewWillAppear:(BOOL)animated { + %orig; - BOOL hideBecauseLS = [[%c(SBLockScreenManager) sharedInstance] isUILocked] ? [RASettings.sharedInstance ncAppHideOnLS] : NO; + BOOL hideBecauseLS = [[%c(SBLockScreenManager) sharedInstance] isUILocked] ? [RASettings.sharedInstance ncAppHideOnLS] : NO; - if ([RASettings.sharedInstance NCAppEnabled] && !hideBecauseLS) - { + if ([RASettings.sharedInstance NCAppEnabled] && !hideBecauseLS) { SBModeViewController* modeVC = MSHookIvar(self, "_modeViewController"); - if (ncAppViewController == nil) + if (!ncAppViewController) { ncAppViewController = [[RANCViewController alloc] init]; + } [modeVC _addBulletinObserverViewController:ncAppViewController]; } } %end // This is more of a hack than anything else. Note that `_localizableTitleForColumnViewController` on iOS 9 does not seem to work (I may be doing something else wrong) -// if more than one custom nc tab is added, this will not work correctly. +// if more than one custom nc tab is added, this will not work correctly. %hook SBModeViewController -- (void)_layoutHeaderViewIfNecessary -{ +- (void)_layoutHeaderViewIfNecessary { %orig; NSString *text = @""; BOOL useGenericLabel = THEMED(quickAccessUseGenericTabLabel) || [RASettings.sharedInstance quickAccessUseGenericTabLabel]; - if (useGenericLabel) + if (useGenericLabel) { text = LOCALIZE(@"APP"); - else + } else { text = ncAppViewController.hostedApp.displayName ?: getAppName() ?: LOCALIZE(@"APP"); + } - for (UIView *view in MSHookIvar(self, "_headerView").subviews) - { - if ([view isKindOfClass:[UISegmentedControl class]]) - { + for (UIView *view in MSHookIvar(self, "_headerView").subviews) { + if ([view isKindOfClass:[UISegmentedControl class]]) { UISegmentedControl *segment = (UISegmentedControl*)view; - if (segment.numberOfSegments > 2) + if (segment.numberOfSegments > 2) { [segment setTitle:text forSegmentAtIndex:2]; + } } } } %end %end -%ctor -{ - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) - { - %init(iOS9); +%group iOS10 +%hook SBPagedScrollView +static BOOL hasEnteredPages = NO; + +- (void)layoutSubviews { + %orig; + + if (!hasEnteredPages && [RASettings.sharedInstance NCAppEnabled] && [self.superview isKindOfClass:[%c(SBSearchEtceteraLayoutView) class]] && [[%c(SBNotificationCenterController) sharedInstance] isVisible]) { + if (!ncAppViewController) { + ncAppViewController = [[RANCViewController alloc] init]; + } + + NSMutableArray *newArray = [[self pageViews] mutableCopy]; + [newArray addObject:ncAppViewController.view]; + [self setPageViews:newArray]; + hasEnteredPages = YES; } - else - { +} +%end + +%hook SBNotificationCenterViewController +- (void)viewWillAppear:(BOOL)arg1 { + %orig; + + shouldLoadView = YES; + [ncAppViewController viewDidAppear:arg1]; +} + +- (void)viewDidDisappear:(BOOL)arg1 { + %orig; + + shouldLoadView = NO; + [ncAppViewController viewDidDisappear:arg1]; +} + +- (UIPageControl*)pageControl { + UIPageControl *original = %orig; + original.numberOfPages = 3; + return original; +} +%end +%end + +%ctor { + if (IS_IOS_OR_NEWER(iOS_10_0)) { + %init(iOS10); + } else if (IS_IOS_BETWEEN(iOS_9_0, iOS_9_3)) { + %init(iOS9); + } else { %init(iOS8); } -} \ No newline at end of file +} diff --git a/NotificationCenterApp/RANCViewController.h b/NotificationCenterApp/RANCViewController.h index 4845fdc..d88f4ea 100644 --- a/NotificationCenterApp/RANCViewController.h +++ b/NotificationCenterApp/RANCViewController.h @@ -6,8 +6,8 @@ @end @interface RANCViewController : SBNCColumnViewController -+(instancetype) sharedViewController; ++ (instancetype)sharedViewController; --(RAHostedAppView*) hostedApp; --(void) forceReloadAppLikelyBecauseTheSettingChanged; -@end \ No newline at end of file +- (RAHostedAppView*)hostedApp; +- (void)forceReloadAppLikelyBecauseTheSettingChanged; +@end diff --git a/NotificationCenterApp/RANCViewController.xm b/NotificationCenterApp/RANCViewController.xm index 98f435e..81ce35a 100644 --- a/NotificationCenterApp/RANCViewController.xm +++ b/NotificationCenterApp/RANCViewController.xm @@ -12,34 +12,33 @@ @end extern RANCViewController *ncAppViewController; +extern BOOL shouldLoadView; @implementation RANCViewController -+(instancetype) sharedViewController -{ ++ (instancetype)sharedViewController { return ncAppViewController; } --(void) forceReloadAppLikelyBecauseTheSettingChanged -{ +- (void)forceReloadAppLikelyBecauseTheSettingChanged { [appView unloadApp]; [appView removeFromSuperview]; appView = nil; } -int patchOrientation(int in) -{ - if (in == 3) +int patchOrientation(int in) { + if (in == 3) { return 1; + } return in; } -int rotationDegsForOrientation(int o) -{ - if (o == UIInterfaceOrientationLandscapeRight) +int rotationDegsForOrientation(int o) { + if (o == UIInterfaceOrientationLandscapeRight) { return 270; - else if (o == UIInterfaceOrientationLandscapeLeft) + } else if (o == UIInterfaceOrientationLandscapeLeft) { return 90; + } return 0; } @@ -48,34 +47,32 @@ int rotationDegsForOrientation(int o) //-(void)hostWillDismiss; //-(void)hostDidDismiss; -- (void)insertAppropriateViewWithContent -{ +- (void)insertAppropriateViewWithContent { [self viewDidAppear:YES]; } -- (void)insertTableView -{ +- (void)insertTableView { } -- (void)viewWillLayoutSubviews -{ +- (void)viewWillLayoutSubviews { [self viewDidAppear:YES]; } --(void) viewDidAppear:(BOOL)animated -{ +- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - if ([[%c(SBLockScreenManager) sharedInstance] isUILocked]) - { - if (isLockedLabel == nil) - { + if (IS_IOS_OR_NEWER(iOS_10_0) && !shouldLoadView) { + return; + } + + if ([[%c(SBLockScreenManager) sharedInstance] isUILocked]) { + if (!isLockedLabel) { isLockedLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 400)]; isLockedLabel.numberOfLines = 2; isLockedLabel.textAlignment = NSTextAlignmentCenter; isLockedLabel.textColor = [UIColor whiteColor]; - isLockedLabel.font = [UIFont systemFontOfSize:UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 36 : 30]; + isLockedLabel.font = [UIFont systemFontOfSize:IS_IPAD ? 36 : 30]; [self.view addSubview:isLockedLabel]; } @@ -83,15 +80,12 @@ int rotationDegsForOrientation(int o) isLockedLabel.text = LOCALIZE(@"UNLOCK_FOR_NCAPP"); return; - } - else if (isLockedLabel) - { + } else if (isLockedLabel) { [isLockedLabel removeFromSuperview]; isLockedLabel = nil; } - if (!appView) - { + if (!appView) { NSString *ident = [RASettings.sharedInstance NCApp]; appView = [[RAHostedAppView alloc] initWithBundleIdentifier:ident]; appView.frame = UIScreen.mainScreen.bounds; @@ -103,15 +97,12 @@ int rotationDegsForOrientation(int o) [appView loadApp]; appView.hideStatusBar = YES; - if (NO)// (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) - { + if (NO) {// (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) appView.autosizesApp = YES; appView.allowHidingStatusBar = YES; appView.transform = CGAffineTransformIdentity; appView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); - } - else - { + } else { appView.autosizesApp = NO; appView.allowHidingStatusBar = YES; @@ -122,7 +113,7 @@ int rotationDegsForOrientation(int o) appView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(rotationDegsForOrientation(UIApplication.sharedApplication.statusBarOrientation))); // Explicitly, SpringBoard's status bar since the NC is shown in SpringBoard CGFloat scale = self.view.frame.size.height / UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height; appView.transform = CGAffineTransformScale(appView.transform, scale, scale); - + // Align vertically CGRect f = appView.frame; f.origin.y = 0; @@ -131,55 +122,52 @@ int rotationDegsForOrientation(int o) } //[appView rotateToOrientation:UIApplication.sharedApplication.statusBarOrientation]; - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) // Must manually place view controller :( - { + + if (IS_IOS_BETWEEN(iOS_9_0, iOS_9_3)) { // Must manually place view controller :( CGRect frame = self.view.frame; frame.origin.x = UIScreen.mainScreen.bounds.size.width * 2.0; self.view.frame = frame; } } -- (void)hostDidDismiss -{ - if (appView.isCurrentlyHosting) - { +- (void)hostDidDismiss { + if (appView.isCurrentlyHosting) { appView.hideStatusBar = NO; - [appView unloadApp]; + [appView unloadApp]; } } --(void) viewDidDisappear:(BOOL)animated -{ +- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; appView.hideStatusBar = NO; - if (appView.isCurrentlyHosting) - { - [appView unloadApp]; + if (appView.isCurrentlyHosting) { + [appView unloadApp]; } } --(RAHostedAppView*) hostedApp { return appView; } +- (RAHostedAppView*)hostedApp { + return appView; +} -- (void)forwardInvocation:(NSInvocation *)anInvocation -{ +- (void)forwardInvocation:(NSInvocation *)anInvocation { // Override - NSLog(@"[ReachApp] RANCViewController: ignoring invocation: %@", anInvocation); + LogDebug(@"[ReachApp] RANCViewController: ignoring invocation: %@", anInvocation); } -- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector -{ +- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *signature = [super methodSignatureForSelector:aSelector]; - if (signature == nil && class_respondsToSelector(%c(SBBulletinObserverViewController), aSelector)) + if (!signature && class_respondsToSelector(%c(SBBulletinObserverViewController), aSelector)) { signature = [%c(SBBulletinObserverViewController) instanceMethodSignatureForSelector:aSelector]; + } return signature; } -- (BOOL)isKindOfClass:(Class)aClass -{ - if (aClass == %c(SBBulletinObserverViewController) || aClass == %c(SBNCColumnViewController)) +- (BOOL)isKindOfClass:(Class)aClass { + if (aClass == %c(SBBulletinObserverViewController) || aClass == %c(SBNCColumnViewController)) { return YES; - else + } else { return [super isKindOfClass:aClass]; + } } @end diff --git a/RAAppKiller.h b/RAAppKiller.h index 5f90de7..4229da1 100644 --- a/RAAppKiller.h +++ b/RAAppKiller.h @@ -2,9 +2,8 @@ #import "RARunningAppsProvider.h" @interface RAAppKiller : NSObject -+(void) killAppWithIdentifier:(NSString*)identifier; -+(void) killAppWithIdentifier:(NSString*)identifier completion:(void(^)())handler; -+(void) killAppWithSBApplication:(SBApplication*)app; -+(void) killAppWithSBApplication:(SBApplication*)app completion:(void(^)())handler; ++ (void)killAppWithIdentifier:(NSString*)identifier; ++ (void)killAppWithIdentifier:(NSString*)identifier completion:(void(^)())handler; ++ (void)killAppWithSBApplication:(SBApplication*)app; ++ (void)killAppWithSBApplication:(SBApplication*)app completion:(void(^)())handler; @end - diff --git a/RAAppKiller.xm b/RAAppKiller.xm index 10ec13c..6b48f43 100644 --- a/RAAppKiller.xm +++ b/RAAppKiller.xm @@ -9,35 +9,29 @@ extern "C" void BKSTerminateApplicationForReasonAndReportWithDescription(NSStrin @end @implementation RAAppKiller : NSObject -+(instancetype) sharedInstance -{ - SHARED_INSTANCE2(RAAppKiller, ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RAAppKiller, [sharedInstance initialize]; ); } -+(void) killAppWithIdentifier:(NSString*)identifier -{ ++ (void)killAppWithIdentifier:(NSString*)identifier { return [RAAppKiller killAppWithIdentifier:identifier completion:nil]; } -+(void) killAppWithIdentifier:(NSString*)identifier completion:(void(^)())handler -{ ++ (void)killAppWithIdentifier:(NSString*)identifier completion:(void(^)())handler { return [RAAppKiller killAppWithSBApplication:[[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier] completion:handler]; } -+(void) killAppWithSBApplication:(SBApplication*)app -{ ++ (void)killAppWithSBApplication:(SBApplication*)app { return [RAAppKiller killAppWithSBApplication:app completion:nil]; } -+(void) killAppWithSBApplication:(SBApplication*)app completion:(void(^)())handler -{ ++ (void)killAppWithSBApplication:(SBApplication*)app completion:(void(^)())handler { return [RAAppKiller checkAppDead:app withTries:0 andCompletion:handler]; } -+(void) checkAppDead:(SBApplication*)app withTries:(int)tries andCompletion:(void(^)())handler -{ ++ (void)checkAppDead:(SBApplication*)app withTries:(int)tries andCompletion:(void(^)())handler { /* BOOL isDeadOrMaxed = (app.pid == 0 || app.isRunning == NO) && tries < 5; if (isDeadOrMaxed) @@ -47,13 +41,13 @@ extern "C" void BKSTerminateApplicationForReasonAndReportWithDescription(NSStrin handler(); } } - else + else { if (tries == 0) { // Try nicely FBApplicationProcess *process = [[%c(FBProcessManager) sharedInstance] createApplicationProcessForBundleID:app.bundleIdentifier]; - [process killForReason:1 andReport:NO withDescription:@"PSY SLAYED" completion:nil]; + [process killForReason:1 andReport:NO withDescription:@"PSY SLAYED" completion:nil]; } /*else if (tries == 1) { @@ -78,16 +72,13 @@ extern "C" void BKSTerminateApplicationForReasonAndReportWithDescription(NSStrin BKSTerminateApplicationForReasonAndReportWithDescription(app.bundleIdentifier, 5, 1, @"Multiplexer requested this process to be slayed."); } --(void) initialize -{ +- (void)initialize { completionDictionary = [NSMutableDictionary dictionary]; [RARunningAppsProvider.sharedInstance addTarget:self]; } --(void) appDidDie:(__unsafe_unretained SBApplication*)app -{ - if (completionDictionary && [completionDictionary objectForKey:app.bundleIdentifier] != nil) - { +- (void)appDidDie:(__unsafe_unretained SBApplication*)app { + if (completionDictionary && [completionDictionary objectForKey:app.bundleIdentifier]) { dispatch_block_t block = completionDictionary[app.bundleIdentifier]; block(); [completionDictionary removeObjectForKey:app.bundleIdentifier]; diff --git a/RAAppSelectorView.h b/RAAppSelectorView.h index 824cfff..0826c21 100644 --- a/RAAppSelectorView.h +++ b/RAAppSelectorView.h @@ -3,11 +3,11 @@ @class RAAppSelectorView; @protocol RAAppSelectorViewDelegate --(void) appSelector:(RAAppSelectorView*)view appWasSelected:(NSString*)bundleIdentifier; +- (void)appSelector:(RAAppSelectorView*)view appWasSelected:(NSString*)bundleIdentifier; @end @interface RAAppSelectorView : UIScrollView @property (nonatomic, weak) NSObject *target; --(void) relayoutApps; -@end \ No newline at end of file +- (void)relayoutApps; +@end diff --git a/RAAppSelectorView.xm b/RAAppSelectorView.xm index 8155789..e844e79 100644 --- a/RAAppSelectorView.xm +++ b/RAAppSelectorView.xm @@ -1,79 +1,86 @@ #import "RAAppSelectorView.h" @implementation RAAppSelectorView --(id) initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) - { - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7]; +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7]; + self.scrollEnabled = YES; } return self; } --(void) relayoutApps -{ +- (void)relayoutApps { [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; - static CGSize fullSize = [%c(SBIconView) defaultIconSize]; - fullSize.height = fullSize.width; - CGFloat padding = 20; + static CGSize fullSize = [%c(SBIconView) defaultIconSize]; + fullSize.height = fullSize.width; + CGFloat padding = 20; - NSInteger numIconsPerLine = 0; - CGFloat tmpWidth = 10; - while (tmpWidth + fullSize.width <= self.frame.size.width) - { - numIconsPerLine++; - tmpWidth += fullSize.width + 20; - } - padding = (self.frame.size.width - (numIconsPerLine * fullSize.width)) / (numIconsPerLine + 1); + NSInteger numIconsPerLine = 0; + CGFloat tmpWidth = 10; + while (tmpWidth + fullSize.width <= self.frame.size.width) { + numIconsPerLine++; + tmpWidth += fullSize.width + 20; + } + padding = (self.frame.size.width - (numIconsPerLine * fullSize.width)) / (numIconsPerLine + 1); CGSize contentSize = CGSizeMake(padding, 10); int horizontal = 0; static NSMutableArray *allApps = nil; - if (!allApps) - { - allApps = [[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] mutableCopy]; - [allApps sortUsingComparator: ^(NSString* a, NSString* b) { - NSString *a_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:a].displayName; - NSString *b_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:b].displayName; - return [a_ caseInsensitiveCompare:b_]; + if (!allApps) { + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + allApps = [[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] mutableCopy]; + } else { + allApps = [[[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] visibleIconIdentifiers] mutableCopy]; + } + [allApps sortUsingComparator: ^(NSString* a, NSString* b) { + NSString *a_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:a].displayName; + NSString *b_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:b].displayName; + return [a_ caseInsensitiveCompare:b_]; }]; //[allApps removeObject:currentBundleIdentifier]; } - for (NSString *str in allApps) - { + + for (NSString *str in allApps) { SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:str]; - SBIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; - SBIconView *iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - if (!iconView || [icon isKindOfClass:[%c(SBApplicationIcon) class]] == NO) - continue; - - iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); - contentSize.width += iconView.frame.size.width + padding; + SBApplicationIcon *icon = nil; + SBIconView *iconView = nil; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + } else { + icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] _iconViewForIcon:icon]; + } + if (!iconView || ![icon isKindOfClass:[%c(SBApplicationIcon) class]]) { + continue; + } - horizontal++; - if (horizontal >= numIconsPerLine) - { - horizontal = 0; - contentSize.width = padding; - contentSize.height += iconView.frame.size.height + 10; - } + iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); + contentSize.width += iconView.frame.size.width + padding; - iconView.restorationIdentifier = app.bundleIdentifier; - UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; - [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; - [self addSubview:iconView]; + horizontal++; + if (horizontal >= numIconsPerLine) { + horizontal = 0; + contentSize.width = padding; + contentSize.height += iconView.frame.size.height + 10; + } + + iconView.restorationIdentifier = app.bundleIdentifier; + UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; + [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; + [self addSubview:iconView]; } contentSize.width = self.frame.size.width; contentSize.height += fullSize.height * 1.5; - [self setContentSize:contentSize]; + self.contentSize = contentSize; } --(void) appViewItemTap:(UITapGestureRecognizer*)recognizer -{ - if (self.target) - if ([self.target respondsToSelector:@selector(appSelector:appWasSelected:)]) - [self.target appSelector:self appWasSelected:recognizer.view.restorationIdentifier]; +- (void)appViewItemTap:(UITapGestureRecognizer*)recognizer { + if (self.target && [self.target respondsToSelector:@selector(appSelector:appWasSelected:)]) { + [self.target appSelector:self appWasSelected:recognizer.view.restorationIdentifier]; + } } -@end \ No newline at end of file +@end diff --git a/RAAppSliderProvider.h b/RAAppSliderProvider.h index 325a8d2..3a5c545 100644 --- a/RAAppSliderProvider.h +++ b/RAAppSliderProvider.h @@ -6,13 +6,13 @@ @property (nonatomic, retain) NSArray *availableIdentifiers; @property (nonatomic) NSInteger currentIndex; --(BOOL) canGoLeft; --(BOOL) canGoRight; +- (BOOL)canGoLeft; +- (BOOL)canGoRight; --(RAHostedAppView*) viewToTheLeft; --(RAHostedAppView*) viewToTheRight; --(RAHostedAppView*) viewAtCurrentIndex; +- (RAHostedAppView*)viewToTheLeft; +- (RAHostedAppView*)viewToTheRight; +- (RAHostedAppView*)viewAtCurrentIndex; --(void) goToTheLeft; --(void) goToTheRight; +- (void)goToTheLeft; +- (void)goToTheRight; @end diff --git a/RAAppSliderProvider.mm b/RAAppSliderProvider.mm index efd9dfc..b3555a6 100644 --- a/RAAppSliderProvider.mm +++ b/RAAppSliderProvider.mm @@ -9,33 +9,32 @@ @interface RAAppSliderProvider () { @implementation RAAppSliderProvider @synthesize currentIndex, availableIdentifiers; --(id) init -{ - if (self = [super init]) - { +- (instancetype)init { + self = [super init]; + if (self) { cachedViews = [NSMutableDictionary dictionary]; } return self; } --(BOOL) canGoLeft -{ +- (BOOL)canGoLeft { return currentIndex - 1 >= 0 && availableIdentifiers.count > 0; } --(BOOL) canGoRight -{ +- (BOOL)canGoRight { return availableIdentifiers.count > currentIndex + 1; } --(RAHostedAppView*) viewToTheLeft -{ - if (self.canGoLeft) - { +- (RAHostedAppView*)viewToTheLeft { + if (self.canGoLeft) { NSString *ident = [availableIdentifiers objectAtIndex:currentIndex - 1]; - - if (!ident) return nil; - if ([cachedViews objectForKey:ident]) return cachedViews[ident]; + + if (!ident) { + return nil; + } + if ([cachedViews objectForKey:ident]) { + return cachedViews[ident]; + } RAHostedAppView *view = [[RAHostedAppView alloc] initWithBundleIdentifier:ident]; [view preloadApp]; @@ -45,14 +44,16 @@ -(RAHostedAppView*) viewToTheLeft return nil; } --(RAHostedAppView*) viewToTheRight -{ - if (self.canGoRight) - { +- (RAHostedAppView*)viewToTheRight { + if (self.canGoRight) { NSString *ident = [availableIdentifiers objectAtIndex:currentIndex + 1]; - - if (!ident) return nil; - if ([cachedViews objectForKey:ident]) return cachedViews[ident]; + + if (!ident) { + return nil; + } + if ([cachedViews objectForKey:ident]) { + return cachedViews[ident]; + } RAHostedAppView *view = [[RAHostedAppView alloc] initWithBundleIdentifier:ident]; [view preloadApp]; @@ -62,12 +63,15 @@ -(RAHostedAppView*) viewToTheRight return nil; } --(RAHostedAppView*) viewAtCurrentIndex -{ +- (RAHostedAppView*)viewAtCurrentIndex { NSString *ident = [availableIdentifiers objectAtIndex:currentIndex]; - - if (!ident) return nil; - if ([cachedViews objectForKey:ident]) return cachedViews[ident]; + + if (!ident) { + return nil; + } + if ([cachedViews objectForKey:ident]) { + return cachedViews[ident]; + } RAHostedAppView *view = [[RAHostedAppView alloc] initWithBundleIdentifier:ident]; [view preloadApp]; @@ -75,15 +79,17 @@ -(RAHostedAppView*) viewAtCurrentIndex return view; } --(void) goToTheLeft -{ - if (self.canGoLeft) - currentIndex--; +- (void)goToTheLeft { + if (!self.canGoLeft) { + return; + } + currentIndex--; } --(void) goToTheRight -{ - if (self.canGoRight) - currentIndex++; +- (void)goToTheRight { + if (!self.canGoRight) { + return; + } + currentIndex++; } @end diff --git a/RAAppSliderProviderView.h b/RAAppSliderProviderView.h index 58206ac..ff68569 100644 --- a/RAAppSliderProviderView.h +++ b/RAAppSliderProviderView.h @@ -10,13 +10,13 @@ @property (nonatomic, retain) RAAppSliderProvider *swipeProvider; @property (nonatomic) BOOL isSwipeable; --(CGRect) clientFrame; --(NSString*) currentBundleIdentifier; +- (CGRect)clientFrame; +- (NSString*)currentBundleIdentifier; --(void) goToTheLeft; --(void) goToTheRight; +- (void)goToTheLeft; +- (void)goToTheRight; --(void) load; --(void) unload; --(void) updateCurrentView; -@end \ No newline at end of file +- (void)load; +- (void)unload; +- (void)updateCurrentView; +@end diff --git a/RAAppSliderProviderView.mm b/RAAppSliderProviderView.mm index d5d6155..c793d91 100644 --- a/RAAppSliderProviderView.mm +++ b/RAAppSliderProviderView.mm @@ -7,99 +7,89 @@ @implementation RAAppSliderProviderView @synthesize swipeProvider; --(void) goToTheLeft -{ +- (void)goToTheLeft { [swipeProvider goToTheLeft]; [self updateCurrentView]; } --(void) goToTheRight -{ +- (void)goToTheRight { [swipeProvider goToTheRight]; [self updateCurrentView]; } --(void) load -{ +- (void)load { [currentView loadApp]; } --(void) unload -{ - if (!currentView || !currentView.bundleIdentifier) +- (void)unload { + if (!currentView || !currentView.bundleIdentifier) { return; + } [RAGestureManager.sharedInstance removeGestureWithIdentifier:currentView.bundleIdentifier]; [currentView unloadApp]; } --(void) updateCurrentView -{ +- (void)updateCurrentView { [self unload]; - if (currentView) + if (currentView) { [currentView removeFromSuperview]; + } currentView = [swipeProvider viewAtCurrentIndex]; - if (self.isSwipeable && self.swipeProvider) - { - self.backgroundColor = [UIColor clearColor]; // redColor]; - self.userInteractionEnabled = YES; + if (self.isSwipeable && self.swipeProvider) { + self.backgroundColor = [UIColor clearColor]; // redColor]; + self.userInteractionEnabled = YES; [RAGestureManager.sharedInstance addGestureRecognizerWithTarget:self forEdge:UIRectEdgeLeft | UIRectEdgeRight identifier:currentView.bundleIdentifier priority:RAGesturePriorityHigh]; //[RAGestureManager.sharedInstance addGestureRecognizerWithTarget:self forEdge:UIRectEdgeRight identifier:currentView.bundleIdentifier priority:RAGesturePriorityHigh]; - currentView.frame = CGRectMake(0, 0, self.frame.size.width - 0, self.frame.size.height); - } - else - currentView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); - [self addSubview:currentView]; - [self load]; + currentView.frame = CGRectMake(0, 0, self.frame.size.width - 0, self.frame.size.height); + } else { + currentView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); + } + [self addSubview:currentView]; + [self load]; } --(CGRect) clientFrame -{ - if (!currentView) return CGRectZero; +- (CGRect)clientFrame { + if (!currentView) { + return CGRectZero; + } CGRect frame = currentView.frame; frame.size.height = self.frame.size.height; return frame; } --(NSString*) currentBundleIdentifier -{ +- (NSString*)currentBundleIdentifier { return currentView ? currentView.bundleIdentifier : nil; } --(BOOL) RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity -{ +- (BOOL)RAGestureCallback_canHandle:(CGPoint)point velocity:(CGPoint)velocity { return point.y <= [self convertPoint:self.frame.origin toView:nil].y + self.frame.size.height; } --(RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge -{ +- (RAGestureCallbackResult)RAGestureCallback_handle:(UIGestureRecognizerState)state withPoint:(CGPoint)location velocity:(CGPoint)velocity forEdge:(UIRectEdge)edge { static BOOL didHandle = NO; - if (state == UIGestureRecognizerStateEnded) - { + if (state == UIGestureRecognizerStateEnded) { didHandle = NO; return RAGestureCallbackResultSuccessAndStop; } - if (didHandle) return RAGestureCallbackResultSuccessAndStop; + if (didHandle) { + return RAGestureCallbackResultSuccessAndStop; + } - if (edge == UIRectEdgeLeft) - { + if (edge == UIRectEdgeLeft) { didHandle = YES; - if (self.swipeProvider.canGoLeft) - { + if (self.swipeProvider.canGoLeft) { [self unload]; [self goToTheLeft]; } return RAGestureCallbackResultSuccessAndStop; - } - else if (edge == UIRectEdgeRight) - { + } else if (edge == UIRectEdgeRight) { didHandle = YES; - if (self.swipeProvider.canGoRight) - { + if (self.swipeProvider.canGoRight) { [self unload]; [self goToTheRight]; } @@ -107,4 +97,4 @@ -(RAGestureCallbackResult) RAGestureCallback_handle:(UIGestureRecognizerState)st } return RAGestureCallbackResultFailure; } -@end \ No newline at end of file +@end diff --git a/RAAppSwitcherModelWrapper.h b/RAAppSwitcherModelWrapper.h index 1db8095..699e014 100644 --- a/RAAppSwitcherModelWrapper.h +++ b/RAAppSwitcherModelWrapper.h @@ -1,9 +1,9 @@ #import "headers.h" @interface RAAppSwitcherModelWrapper : NSObject -+(void) addToFront:(SBApplication*)app; -+(void) addIdentifierToFront:(NSString*)ident; -+(NSArray*) appSwitcherAppIdentiferList; ++ (void)addToFront:(SBApplication*)app; ++ (void)addIdentifierToFront:(NSString*)ident; ++ (NSArray*)appSwitcherAppIdentiferList; -+(void) removeItemWithIdentifier:(NSString*)ident; -@end \ No newline at end of file ++ (void)removeItemWithIdentifier:(NSString*)ident; +@end diff --git a/RAAppSwitcherModelWrapper.xm b/RAAppSwitcherModelWrapper.xm index 7b31d4f..625c4fc 100644 --- a/RAAppSwitcherModelWrapper.xm +++ b/RAAppSwitcherModelWrapper.xm @@ -1,54 +1,47 @@ #import "RAAppSwitcherModelWrapper.h" @implementation RAAppSwitcherModelWrapper -+(void) addToFront:(SBApplication*)app -{ ++ (void)addToFront:(SBApplication*)app { SBAppSwitcherModel *model = [%c(SBAppSwitcherModel) sharedInstance]; - if ([model respondsToSelector:@selector(addToFront:)]) // iOS 7 + 8 - { + if ([model respondsToSelector:@selector(addToFront:)]) { // iOS 7 + 8 SBDisplayLayout *layout = [%c(SBDisplayLayout) fullScreenDisplayLayoutForApplication:app]; [model addToFront:layout]; - } - else // iOS 9 - { + } else { // iOS 9 SBDisplayItem *layout = [%c(SBDisplayItem) displayItemWithType:@"App" displayIdentifier:app.bundleIdentifier]; [model addToFront:layout role:2]; } - } -+(void) addIdentifierToFront:(NSString*)ident -{ ++ (void)addIdentifierToFront:(NSString*)ident { [RAAppSwitcherModelWrapper addToFront:[[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:ident]]; } -+(NSArray*) appSwitcherAppIdentiferList -{ ++ (NSArray*)appSwitcherAppIdentiferList { SBAppSwitcherModel *model = [%c(SBAppSwitcherModel) sharedInstance]; - if ([model respondsToSelector:@selector(snapshotOfFlattenedArrayOfAppIdentifiersWhichIsOnlyTemporary)]) + if ([model respondsToSelector:@selector(snapshotOfFlattenedArrayOfAppIdentifiersWhichIsOnlyTemporary)]) { return [model snapshotOfFlattenedArrayOfAppIdentifiersWhichIsOnlyTemporary]; + } - // iOS 9 most likely. + // iOS 9 most likely. NSMutableArray *ret = [NSMutableArray array]; id list = [model mainSwitcherDisplayItems]; // NSArray - for (SBDisplayItem *item in list) - { + for (SBDisplayItem *item in list) { [ret addObject:item.displayIdentifier]; } return ret; } -+(void) removeItemWithIdentifier:(NSString*)ident -{ - SBDisplayItem *item = [%c(SBDisplayItem) displayItemWithType:@"App" displayIdentifier:ident]; - id appSwitcherModel = [%c(SBAppSwitcherModel) sharedInstance]; - if ([appSwitcherModel respondsToSelector:@selector(removeDisplayItem:)]) - [[%c(SBAppSwitcherModel) sharedInstance] removeDisplayItem:item]; - else - [[%c(SBAppSwitcherModel) sharedInstance] remove:item]; ++ (void)removeItemWithIdentifier:(NSString*)ident { + SBDisplayItem *item = [%c(SBDisplayItem) displayItemWithType:@"App" displayIdentifier:ident]; + id appSwitcherModel = [%c(SBAppSwitcherModel) sharedInstance]; + if ([appSwitcherModel respondsToSelector:@selector(removeDisplayItem:)]) { + [[%c(SBAppSwitcherModel) sharedInstance] removeDisplayItem:item]; + } else { + [[%c(SBAppSwitcherModel) sharedInstance] remove:item]; + } } @end diff --git a/RACompatibilitySystem.h b/RACompatibilitySystem.h index fd27153..064bb51 100644 --- a/RACompatibilitySystem.h +++ b/RACompatibilitySystem.h @@ -1,8 +1,5 @@ -@interface RACompatibilitySystem : NSObject { - -} +@interface RACompatibilitySystem : NSObject //+(instancetype) sharedInstance; - -+(void) showWarning:(NSString*)info; -+(void) showError:(NSString*)info; -@end \ No newline at end of file ++ (void)showWarning:(NSString*)info; ++ (void)showError:(NSString*)info; +@end diff --git a/RACompatibilitySystem.mm b/RACompatibilitySystem.mm index 1479b0e..9295827 100644 --- a/RACompatibilitySystem.mm +++ b/RACompatibilitySystem.mm @@ -3,34 +3,34 @@ #include #import #import "headers.h" +#import "UIAlertController+Window.h" @implementation RACompatibilitySystem -+(NSString*) aggregateSystemInfo -{ ++ (NSString*)aggregateSystemInfo { NSMutableString *ret = [[NSMutableString alloc] init]; - struct utsname systemInfo; - uname(&systemInfo); - NSString *sysInfo = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; - - [ret appendString:[NSString stringWithFormat:@"%@, %@ %@\n", sysInfo, UIDevice.currentDevice.systemName, UIDevice.currentDevice.systemVersion]]; + struct utsname systemInfo; + uname(&systemInfo); + NSString *sysInfo = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; - return ret; + [ret appendString:[NSString stringWithFormat:@"%@, %@ %@\n", sysInfo, UIDevice.currentDevice.systemName, UIDevice.currentDevice.systemVersion]]; + + return ret; } -+(void) showWarning:(NSString*)info -{ ++ (void)showWarning:(NSString*)info { NSString *message = [NSString stringWithFormat:@"System info: %@\n\nWARNING: POTENTIAL INCOMPATIBILITY DETECTED\n%@", [self aggregateSystemInfo], info]; - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Multiplexer Compatibility" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Multiplexer Compatibility" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [alert show]; } -+(void) showError:(NSString*)info -{ ++ (void)showError:(NSString*)info { NSString *message = [NSString stringWithFormat:@"System info: %@\n\n***ERROR***: POTENTIAL INCOMPATIBILITY DETECTED\n%@", [self aggregateSystemInfo], info]; - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Multiplexer Compatibility" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Multiplexer Compatibility" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [alert show]; } -@end \ No newline at end of file +@end diff --git a/RAControlCenterInhibitor.h b/RAControlCenterInhibitor.h index 4aa3755..11a090e 100644 --- a/RAControlCenterInhibitor.h +++ b/RAControlCenterInhibitor.h @@ -1,4 +1,4 @@ @interface RAControlCenterInhibitor : NSObject -+(void) setInhibited:(BOOL)value; -+(BOOL) isInhibited; -@end \ No newline at end of file ++ (void)setInhibited:(BOOL)value; ++ (BOOL)isInhibited; +@end diff --git a/RAControlCenterInhibitor.xm b/RAControlCenterInhibitor.xm index ab16c45..a1254b5 100644 --- a/RAControlCenterInhibitor.xm +++ b/RAControlCenterInhibitor.xm @@ -4,27 +4,36 @@ BOOL overrideCC = NO; @implementation RAControlCenterInhibitor : NSObject -+(void) setInhibited:(BOOL)value -{ ++ (void)setInhibited:(BOOL)value { overrideCC = value; } -+(BOOL) isInhibited -{ ++ (BOOL)isInhibited { return overrideCC; } @end %hook SBUIController -- (void)_showControlCenterGestureBeganWithLocation:(CGPoint)arg1 -{ - if (!overrideCC) - %orig; +- (void)_showControlCenterGestureBeganWithLocation:(CGPoint)arg1 { + if (!overrideCC) { + return; + } + %orig; } -- (void)handleShowControlCenterSystemGesture:(__unsafe_unretained id)arg1 -{ - if (!overrideCC) - %orig; +- (void)handleShowControlCenterSystemGesture:(__unsafe_unretained id)arg1 { + if (!overrideCC) { + return; + } + %orig; +} +%end + +%hook SBControlCenterController +- (void)presentAnimated:(BOOL)arg1 completion:(id)arg2 { + if (!overrideCC) { + return; + } + %orig; } %end diff --git a/RAFakePhoneMode.h b/RAFakePhoneMode.h index bee002b..5a9b9a2 100644 --- a/RAFakePhoneMode.h +++ b/RAFakePhoneMode.h @@ -1,10 +1,10 @@ #import "headers.h" @interface RAFakePhoneMode : NSObject -+(CGSize) fakedSize; -+(BOOL) shouldFakeForThisProcess; -+(void) updateAppSizing; ++ (CGSize)fakedSize; ++ (BOOL)shouldFakeForThisProcess; ++ (void)updateAppSizing; -+(BOOL) shouldFakeForAppWithIdentifier:(NSString*)identifier; -+(CGSize) fakeSizeForAppWithIdentifier:(NSString*)identifier; -@end \ No newline at end of file ++ (BOOL)shouldFakeForAppWithIdentifier:(NSString*)identifier; ++ (CGSize)fakeSizeForAppWithIdentifier:(NSString*)identifier; +@end diff --git a/RAFakePhoneMode.xm b/RAFakePhoneMode.xm index b20a6ca..e4633f3 100644 --- a/RAFakePhoneMode.xm +++ b/RAFakePhoneMode.xm @@ -8,72 +8,62 @@ I split them apart when i was trying to find some issue with app resizing/touche */ #define RA_4S_SIZE CGSizeMake(320, 480) -#define RA_5S_SIZE CGSizeMake(320, 512) +#define RA_5S_SIZE CGSizeMake(320, 568) #define RA_6P_SIZE CGSizeMake(414, 736) CGSize forcePhoneModeSize = RA_6P_SIZE; @implementation RAFakePhoneMode -+(void) load -{ - // Prevent iPhone issue - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // somehow, this is needed to make sure that both force resizing and Fake Phone Mode work. Without the dispatch_after, even if fake phone mode is disabled, - // force resizing seems to render touches incorrectly ¯\_(ツ)_/¯ - IF_NOT_SPRINGBOARD - { - if ([RAFakePhoneMode shouldFakeForThisProcess]) - { - dlopen("/Library/MobileSubstrate/DynamicLibraries/ReachAppFakePhoneMode.dylib", RTLD_NOW); - } - } - }); ++ (void)load { + // Prevent iPhone issue + if (!IS_IPAD) { + return; + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ // somehow, this is needed to make sure that both force resizing and Fake Phone Mode work. Without the dispatch_after, even if fake phone mode is disabled, + // force resizing seems to render touches incorrectly ¯\_(ツ)_/¯ + IF_NOT_SPRINGBOARD { + if ([RAFakePhoneMode shouldFakeForThisProcess]) { + dlopen("/Library/MobileSubstrate/DynamicLibraries/ReachAppFakePhoneMode.dylib", RTLD_NOW); + } } + }); } -+(CGSize) fakedSize -{ - if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) - return CGSizeMake(forcePhoneModeSize.height, forcePhoneModeSize.width); - return forcePhoneModeSize; ++ (CGSize)fakedSize { + if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) { + return CGSizeMake(forcePhoneModeSize.height, forcePhoneModeSize.width); + } + return forcePhoneModeSize; } -+(CGSize) fakeSizeForAppWithIdentifier:(NSString*)identifier -{ - return forcePhoneModeSize; ++ (CGSize)fakeSizeForAppWithIdentifier:(NSString*)identifier { + return forcePhoneModeSize; } -+(void) updateAppSizing -{ - CGRect f = UIWindow.keyWindow.frame; - f.origin = CGPointZero; - UIWindow.keyWindow.frame = f; ++ (void)updateAppSizing { + CGRect f = UIWindow.keyWindow.frame; + f.origin = CGPointZero; + UIWindow.keyWindow.frame = f; } -+(BOOL) shouldFakeForAppWithIdentifier:(NSString*)identifier -{ - IF_SPRINGBOARD { - return [RAMessagingServer.sharedInstance getDataForIdentifier:identifier].forcePhoneMode; - } - NSLog(@"[ReachApp] WARNING: +[RAFakePhoneMode shouldFakeForAppWithIdentifier:] called from outside SpringBoard!"); - return NO; ++ (BOOL)shouldFakeForAppWithIdentifier:(NSString*)identifier { + IF_SPRINGBOARD { + return [RAMessagingServer.sharedInstance getDataForIdentifier:identifier].forcePhoneMode; + } + LogWarn(@"[ReachApp] WARNING: +[RAFakePhoneMode shouldFakeForAppWithIdentifier:] called from outside SpringBoard!"); + return NO; } -+(BOOL) shouldFakeForThisProcess -{ - static char fakeFlag = 0; - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^{ - if (!RAMessagingClient.sharedInstance.hasRecievedData) - { - [RAMessagingClient.sharedInstance requestUpdateFromServer]; - } - - fakeFlag = RAMessagingClient.sharedInstance.currentData.forcePhoneMode; - }); - - return fakeFlag; ++ (BOOL)shouldFakeForThisProcess { + static char fakeFlag = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (!RAMessagingClient.sharedInstance.hasRecievedData) { + [RAMessagingClient.sharedInstance requestUpdateFromServer]; + } + fakeFlag = RAMessagingClient.sharedInstance.currentData.forcePhoneMode; + }); + return fakeFlag; } @end diff --git a/RAHostManager.h b/RAHostManager.h index ae34e28..df94627 100644 --- a/RAHostManager.h +++ b/RAHostManager.h @@ -1,7 +1,7 @@ #import "headers.h" @interface RAHostManager : NSObject -+(UIView*) systemHostViewForApplication:(SBApplication*)app; -+(UIView*) enabledHostViewForApplication:(SBApplication*)app; -+(NSObject*) hostManagerForApp:(SBApplication*)app; -@end \ No newline at end of file ++ (UIView*)systemHostViewForApplication:(SBApplication*)app; ++ (UIView*)enabledHostViewForApplication:(SBApplication*)app; ++ (NSObject*)hostManagerForApp:(SBApplication*)app; +@end diff --git a/RAHostManager.xm b/RAHostManager.xm index a6fc12e..74b2882 100644 --- a/RAHostManager.xm +++ b/RAHostManager.xm @@ -2,56 +2,58 @@ #import "RACompatibilitySystem.h" @implementation RAHostManager -+(UIView*) systemHostViewForApplication:(SBApplication*)app -{ - if (!app) ++ (UIView*)systemHostViewForApplication:(SBApplication*)app { + if (!app) { return nil; - if ([app respondsToSelector:@selector(mainScene)]) // iOS 8 + } + if ([app respondsToSelector:@selector(mainScene)]) { // iOS 8 return MSHookIvar(app.mainScene.contextHostManager, "_hostView"); - else if ([app respondsToSelector:@selector(mainScreenContextHostManager)]) + } else if ([app respondsToSelector:@selector(mainScreenContextHostManager)]) { return MSHookIvar([app mainScreenContextHostManager], "_hostView"); - + } [RACompatibilitySystem showWarning:@"Unable to find valid method for accessing system context host views"]; return nil; } -+(UIView*) enabledHostViewForApplication:(SBApplication*)app -{ - if (!app) ++ (UIView*)enabledHostViewForApplication:(SBApplication*)app { + if (!app) { return nil; + } - if ([app respondsToSelector:@selector(mainScene)]) - { - FBScene *scene = [app mainScene]; - FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; + if ([app respondsToSelector:@selector(mainScene)]) { + [[UIApplication sharedApplication] launchApplicationWithIdentifier:app.bundleIdentifier suspended:YES]; - FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; - if (!settings) - return nil; + FBScene *scene = [app mainScene]; + FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; - SET_BACKGROUNDED(settings, NO); - [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; + FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; + if (!settings) { + return nil; + } - [contextHostManager enableHostingForRequester:@"reachapp" orderFront:YES]; - return [contextHostManager hostViewForRequester:@"reachapp" enableAndOrderFront:YES]; + SET_BACKGROUNDED(settings, NO); + [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; + + [contextHostManager enableHostingForRequester:@"reachapp" orderFront:YES]; + UIView *hostView = [contextHostManager hostViewForRequester:@"reachapp" enableAndOrderFront:YES]; + return hostView; } [RACompatibilitySystem showWarning:@"Unable to find valid method for accessing context host views"]; return nil; } -+(NSObject*) hostManagerForApp:(SBApplication*)app -{ - if (!app) ++ (NSObject*)hostManagerForApp:(SBApplication*)app { + if (!app) { return nil; - - if ([app respondsToSelector:@selector(mainScene)]) - { - FBScene *scene = [app mainScene]; - return (NSObject*)[scene contextHostManager]; + } + + if ([app respondsToSelector:@selector(mainScene)]) { + FBScene *scene = [app mainScene]; + return (NSObject*)[scene contextHostManager]; } [RACompatibilitySystem showWarning:@"Unable to find valid method for accessing context host view managers"]; return nil; } -@end \ No newline at end of file +@end diff --git a/RAHostedAppView.h b/RAHostedAppView.h index a42179e..e78cea9 100644 --- a/RAHostedAppView.h +++ b/RAHostedAppView.h @@ -8,14 +8,14 @@ FBWindowContextHostWrapperView *view; } -+(void) iPad_iOS83_fixHosting; ++ (void)iPad_iOS83_fixHosting; --(id) initWithBundleIdentifier:(NSString*)bundleIdentifier; +- (instancetype)initWithBundleIdentifier:(NSString*)bundleIdentifier; @property (nonatomic) BOOL showSplashscreenInsteadOfSpinner; @property (nonatomic) BOOL renderWallpaper; -@property (nonatomic, retain) NSString *bundleIdentifier; +@property (nonatomic, copy) NSString *bundleIdentifier; @property (nonatomic) BOOL autosizesApp; @property (nonatomic) BOOL allowHidingStatusBar; @@ -25,15 +25,15 @@ @property (nonatomic) BOOL isCurrentlyHosting; --(SBApplication*) app; --(NSString*) displayName; +- (SBApplication*)app; +- (NSString*)displayName; @property (nonatomic, readonly) UIInterfaceOrientation orientation; --(void) rotateToOrientation:(UIInterfaceOrientation)o; +- (void)rotateToOrientation:(UIInterfaceOrientation)o; --(void) preloadApp; --(void) loadApp; --(void) unloadApp; --(void) unloadApp:(BOOL)forceImmediate; +- (void)preloadApp; +- (void)loadApp; +- (void)unloadApp; +- (void)unloadApp:(BOOL)forceImmediate; -@end \ No newline at end of file +@end diff --git a/RAHostedAppView.xm b/RAHostedAppView.xm index 6fb3f79..1aaffed 100644 --- a/RAHostedAppView.xm +++ b/RAHostedAppView.xm @@ -4,7 +4,7 @@ #import "RAMessagingServer.h" #import "RASnapshotProvider.h" #import "RASpringBoardKeyboardActivation.h" -#import "Asphaleia2.h" +#import "Asphaleia.h" #import "dispatch_after_cancel.h" NSMutableDictionary *appsBeingHosted = [NSMutableDictionary dictionary]; @@ -30,428 +30,396 @@ NSMutableDictionary *appsBeingHosted = [NSMutableDictionary dictionary]; @end @implementation RAHostedAppView --(id) initWithBundleIdentifier:(NSString*)bundleIdentifier -{ - if (self = [super init]) - { - self.bundleIdentifier = bundleIdentifier; - self.autosizesApp = NO; - self.allowHidingStatusBar = YES; - self.showSplashscreenInsteadOfSpinner = NO; - startTries = 0; - disablePreload = NO; - self.renderWallpaper = NO; - self.backgroundColor = [UIColor clearColor]; - } - return self; +- (instancetype)initWithBundleIdentifier:(NSString*)bundleIdentifier { + self = [super init]; + if (self) { + self.bundleIdentifier = bundleIdentifier; + self.autosizesApp = NO; + self.allowHidingStatusBar = YES; + self.showSplashscreenInsteadOfSpinner = NO; + startTries = 0; + disablePreload = NO; + self.renderWallpaper = NO; + self.backgroundColor = [UIColor clearColor]; + } + return self; } --(void) _preloadOrAttemptToUpdateReachabilityCounterpart -{ - if (app) - { - if ([app mainScene]) - { - isPreloading = NO; - if (((SBReachabilityManager*)[%c(SBReachabilityManager) sharedInstance]).reachabilityModeActive && [GET_SBWORKSPACE respondsToSelector:@selector(RA_updateViewSizes)]) - [GET_SBWORKSPACE performSelector:@selector(RA_updateViewSizes) withObject:nil afterDelay:0.5]; // App is launched using ReachApp - animations commence. We have to wait for those animations to finish or this won't work. - } - else if (![app mainScene]) - { - if (disablePreload) - disablePreload = NO; - else - [self preloadApp]; - } +- (void)_preloadOrAttemptToUpdateReachabilityCounterpart { + if (!app) { + return; + } + + if ([app mainScene]) { + isPreloading = NO; + if (((SBReachabilityManager*)[%c(SBReachabilityManager) sharedInstance]).reachabilityModeActive && [GET_SBWORKSPACE respondsToSelector:@selector(RA_updateViewSizes)]) { + [GET_SBWORKSPACE performSelector:@selector(RA_updateViewSizes) withObject:nil afterDelay:0.5]; // App is launched using ReachApp - animations commence. We have to wait for those animations to finish or this won't work. } + } else if (![app mainScene]) { + if (disablePreload) { + disablePreload = NO; + } else { + [self preloadApp]; + } + } } --(void) setBundleIdentifier:(NSString*)value -{ - _orientation = UIInterfaceOrientationPortrait; - _bundleIdentifier = value; - app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:value]; +- (void)setBundleIdentifier:(NSString*)value { + _orientation = UIInterfaceOrientationPortrait; + _bundleIdentifier = value; + app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:value]; } --(void) setShouldUseExternalKeyboard:(BOOL)value -{ - _shouldUseExternalKeyboard = value; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:value forApp:self.bundleIdentifier completion:nil]; +- (void)setShouldUseExternalKeyboard:(BOOL)value { + _shouldUseExternalKeyboard = value; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:value forApp:self.bundleIdentifier completion:nil]; } --(void) preloadApp -{ - startTries++; - if (startTries > 5) - { - isPreloading = NO; - NSLog(@"[ReachApp] maxed out preload attempts for app %@", app.bundleIdentifier); - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"MULTIPLEXER") message:[NSString stringWithFormat:@"Unable to start app %@", app.displayName] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - return; - } - - if (app == nil) - return; - - if (_isCurrentlyHosting) - return; - - isPreloading = YES; - FBScene *scene = [app mainScene]; - if (![app pid] || scene == nil) - { - [UIApplication.sharedApplication launchApplicationWithIdentifier:self.bundleIdentifier suspended:YES]; - [[%c(FBProcessManager) sharedInstance] createApplicationProcessForBundleID:self.bundleIdentifier]; // ummm...? - } - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [self _preloadOrAttemptToUpdateReachabilityCounterpart]; }); - // this ^ runs either way. when _preloadOrAttemptToUpdateReachabilityCounterpart runs, if the app is "loaded" it will not call preloadApp again, otherwise - // it will call it again. +- (void)preloadApp { + startTries++; + if (startTries > 5) { + isPreloading = NO; + LogDebug(@"[ReachApp] maxed out preload attempts for app %@", app.bundleIdentifier); + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Zypen" + message:[NSString stringWithFormat:@"Unable to start app %@", app.displayName] + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) {}]; + [alert addAction:defaultAction]; + [self.inputViewController presentViewController:alert animated:YES completion:nil]; + return; + } + + if (!app || _isCurrentlyHosting) { + return; + } + + isPreloading = YES; + FBScene *scene = [app mainScene]; + if (![app pid] || !scene) { + [UIApplication.sharedApplication launchApplicationWithIdentifier:self.bundleIdentifier suspended:YES]; + [[%c(FBProcessManager) sharedInstance] createApplicationProcessForBundleID:self.bundleIdentifier]; // ummm...? + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [self _preloadOrAttemptToUpdateReachabilityCounterpart]; }); + // this ^ runs either way. when _preloadOrAttemptToUpdateReachabilityCounterpart runs, if the app is "loaded" it will not call preloadApp again, otherwise + // it will call it again. } --(void) _actualLoadApp -{ - if (isPreloading) - { - [self performSelector:@selector(_actualLoadApp) withObject:nil afterDelay:0.3]; - return; - } +- (void)_actualLoadApp { + if (isPreloading) { + [self performSelector:@selector(_actualLoadApp) withObject:nil afterDelay:0.3]; + return; + } + + if (_isCurrentlyHosting) { + return; + } - if (_isCurrentlyHosting) - return; - _isCurrentlyHosting = YES; + _isCurrentlyHosting = YES; - appsBeingHosted[app.bundleIdentifier] = [appsBeingHosted objectForKey:app.bundleIdentifier] ? @([appsBeingHosted[app.bundleIdentifier] intValue] + 1) : @1; - view = (FBWindowContextHostWrapperView*)[RAHostManager enabledHostViewForApplication:app]; - contextHostManager = (FBWindowContextHostManager*)[RAHostManager hostManagerForApp:app]; - view.backgroundColorWhileNotHosting = [UIColor clearColor]; - view.backgroundColorWhileHosting = [UIColor clearColor]; + appsBeingHosted[app.bundleIdentifier] = [appsBeingHosted objectForKey:app.bundleIdentifier] ? @([appsBeingHosted[app.bundleIdentifier] intValue] + 1) : @1; + view = (FBWindowContextHostWrapperView*)[RAHostManager enabledHostViewForApplication:app]; + contextHostManager = (FBWindowContextHostManager*)[RAHostManager hostManagerForApp:app]; + view.backgroundColorWhileNotHosting = [UIColor clearColor]; + view.backgroundColorWhileHosting = [UIColor clearColor]; - view.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); - //view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + view.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); + //view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self addSubview:view]; + [self addSubview:view]; - [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:app.bundleIdentifier completion:nil]; - //if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - [RAHostedAppView iPad_iOS83_fixHosting]; + [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:app.bundleIdentifier completion:nil]; + if (IS_IPAD) { + [RAHostedAppView iPad_iOS83_fixHosting]; + } - [RARunningAppsProvider.sharedInstance addTarget:self]; + [RARunningAppsProvider.sharedInstance addTarget:self]; - loadedTimer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(verifyHostingAndRehostIfNecessary) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:loadedTimer forMode:NSRunLoopCommonModes]; + loadedTimer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(verifyHostingAndRehostIfNecessary) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:loadedTimer forMode:NSRunLoopCommonModes]; } --(void) loadApp -{ - startTries = 0; - disablePreload = NO; - [self preloadApp]; - if (!app) - return; - - if (_isCurrentlyHosting) - return; - - if ([UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:app]) - { - isForemostAppLabel = [[UILabel alloc] initWithFrame:self.bounds]; - isForemostAppLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; - isForemostAppLabel.textColor = [UIColor whiteColor]; - isForemostAppLabel.textAlignment = NSTextAlignmentCenter; - isForemostAppLabel.font = [UIFont systemFontOfSize:36]; - isForemostAppLabel.numberOfLines = 0; - isForemostAppLabel.lineBreakMode = NSLineBreakByWordWrapping; - isForemostAppLabel.text = [NSString stringWithFormat:LOCALIZE(@"ACTIVE_APP_WARNING"),self.app.displayName]; - [self addSubview:isForemostAppLabel]; - return; - } +- (void)loadApp { + startTries = 0; + disablePreload = NO; + [self preloadApp]; + if (!app || _isCurrentlyHosting) { + return; + } + + if ([UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:app]) { + isForemostAppLabel = [[UILabel alloc] initWithFrame:self.bounds]; + isForemostAppLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; + isForemostAppLabel.textColor = [UIColor whiteColor]; + isForemostAppLabel.textAlignment = NSTextAlignmentCenter; + isForemostAppLabel.font = [UIFont systemFontOfSize:36]; + isForemostAppLabel.numberOfLines = 0; + isForemostAppLabel.lineBreakMode = NSLineBreakByWordWrapping; + isForemostAppLabel.text = [NSString stringWithFormat:LOCALIZE(@"ACTIVE_APP_WARNING"),self.app.displayName]; + [self addSubview:isForemostAppLabel]; + return; + } + + IF_BIOLOCKDOWN { + id failedBlock = ^{ + [self removeLoadingIndicator]; + if (!authenticationDidFailLabel) { + authenticationDidFailLabel = [[UILabel alloc] initWithFrame:self.bounds]; + authenticationDidFailLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; + authenticationDidFailLabel.textColor = [UIColor whiteColor]; + authenticationDidFailLabel.textAlignment = NSTextAlignmentCenter; + authenticationDidFailLabel.font = [UIFont systemFontOfSize:36]; + authenticationDidFailLabel.numberOfLines = 0; + authenticationDidFailLabel.lineBreakMode = NSLineBreakByWordWrapping; + authenticationDidFailLabel.text = [NSString stringWithFormat:LOCALIZE(@"BIOLOCKDOWN_AUTH_FAILED"),self.app.displayName]; + [self addSubview:authenticationDidFailLabel]; + + authenticationFailedRetryTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadApp)]; + [self addGestureRecognizer:authenticationFailedRetryTapGesture]; + self.userInteractionEnabled = YES; + } + }; - IF_BIOLOCKDOWN { - id failedBlock = ^{ - [self removeLoadingIndicator]; - if (!authenticationDidFailLabel) - { - authenticationDidFailLabel = [[UILabel alloc] initWithFrame:self.bounds]; - authenticationDidFailLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; - authenticationDidFailLabel.textColor = [UIColor whiteColor]; - authenticationDidFailLabel.textAlignment = NSTextAlignmentCenter; - authenticationDidFailLabel.font = [UIFont systemFontOfSize:36]; - authenticationDidFailLabel.numberOfLines = 0; - authenticationDidFailLabel.lineBreakMode = NSLineBreakByWordWrapping; - authenticationDidFailLabel.text = [NSString stringWithFormat:LOCALIZE(@"BIOLOCKDOWN_AUTH_FAILED"),self.app.displayName]; - [self addSubview:authenticationDidFailLabel]; - - authenticationFailedRetryTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadApp)]; - [self addGestureRecognizer:authenticationFailedRetryTapGesture]; - self.userInteractionEnabled = YES; - } - }; - - BIOLOCKDOWN_AUTHENTICATE_APP(app.bundleIdentifier, ^{ - [self _actualLoadApp]; - }, failedBlock /* stupid commas */); - } - else - { - IF_ASPHALEIA2 { - void (^failedBlock)() = ^{ - [self removeLoadingIndicator]; - if (!authenticationDidFailLabel) - { - authenticationDidFailLabel = [[UILabel alloc] initWithFrame:self.bounds]; - authenticationDidFailLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; - authenticationDidFailLabel.textColor = [UIColor whiteColor]; - authenticationDidFailLabel.textAlignment = NSTextAlignmentCenter; - authenticationDidFailLabel.font = [UIFont systemFontOfSize:36]; - authenticationDidFailLabel.numberOfLines = 0; - authenticationDidFailLabel.lineBreakMode = NSLineBreakByWordWrapping; - authenticationDidFailLabel.text = [NSString stringWithFormat:LOCALIZE(@"ASPHALEIA2_AUTH_FAILED"),self.app.displayName]; - [self addSubview:authenticationDidFailLabel]; - - authenticationFailedRetryTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadApp)]; - [self addGestureRecognizer:authenticationFailedRetryTapGesture]; - self.userInteractionEnabled = YES; - } - }; - - ASPHALEIA2_AUTHENTICATE_APP(app.bundleIdentifier, ^{ - [self _actualLoadApp]; - }, failedBlock); - } - else - [self _actualLoadApp]; - } + BIOLOCKDOWN_AUTHENTICATE_APP(app.bundleIdentifier, ^{ + [self _actualLoadApp]; + }, failedBlock /* stupid commas */); + } else IF_ASPHALEIA { + void (^failedBlock)() = ^{ + [self removeLoadingIndicator]; + if (!authenticationDidFailLabel) { + authenticationDidFailLabel = [[UILabel alloc] initWithFrame:self.bounds]; + authenticationDidFailLabel.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; + authenticationDidFailLabel.textColor = [UIColor whiteColor]; + authenticationDidFailLabel.textAlignment = NSTextAlignmentCenter; + authenticationDidFailLabel.font = [UIFont systemFontOfSize:36]; + authenticationDidFailLabel.numberOfLines = 0; + authenticationDidFailLabel.lineBreakMode = NSLineBreakByWordWrapping; + authenticationDidFailLabel.text = [NSString stringWithFormat:LOCALIZE(@"ASPHALEIA_AUTH_FAILED"),self.app.displayName]; + [self addSubview:authenticationDidFailLabel]; + + authenticationFailedRetryTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadApp)]; + [self addGestureRecognizer:authenticationFailedRetryTapGesture]; + self.userInteractionEnabled = YES; + } + }; - if (self.showSplashscreenInsteadOfSpinner) - { - if (splashScreenImageView) - { - [splashScreenImageView removeFromSuperview]; - splashScreenImageView = nil; - } - UIImage *img = [RASnapshotProvider.sharedInstance snapshotForIdentifier:self.bundleIdentifier]; - splashScreenImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; - splashScreenImageView.image = img; - [self insertSubview:splashScreenImageView atIndex:0]; + ASPHALEIA_AUTHENTICATE_APP(app.bundleIdentifier, ^{ + [self _actualLoadApp]; + }, failedBlock); + } else { + [self _actualLoadApp]; + } + + if (self.showSplashscreenInsteadOfSpinner) { + if (splashScreenImageView) { + [splashScreenImageView removeFromSuperview]; + splashScreenImageView = nil; } - else - { - if (!activityView) - { - activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; - [self addSubview:activityView]; - } - - CGFloat size = 50; - activityView.frame = CGRectMake((self.bounds.size.width - size) / 2, (self.bounds.size.height - size) / 2, size, size); - - [activityView startAnimating]; + UIImage *img = [RASnapshotProvider.sharedInstance snapshotForIdentifier:self.bundleIdentifier]; + splashScreenImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; + splashScreenImageView.image = img; + [self insertSubview:splashScreenImageView atIndex:0]; + } else { + if (!activityView) { + activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + [self addSubview:activityView]; } + + CGFloat size = 50; + activityView.frame = CGRectMake((self.bounds.size.width - size) / 2, (self.bounds.size.height - size) / 2, size, size); + + [activityView startAnimating]; + } } --(void) verifyHostingAndRehostIfNecessary -{ - if (!isPreloading && _isCurrentlyHosting && (app.isRunning == NO || view.contextHosted == NO)) // && (app.pid == 0 || view == nil || view.manager == nil)) // || view._isReallyHosting == NO)) - { - //[activityView startAnimating]; - [self unloadApp]; - [self loadApp]; - } - else - { - [self removeLoadingIndicator]; - [loadedTimer invalidate]; - loadedTimer = nil; - } +- (void)verifyHostingAndRehostIfNecessary { + if (!isPreloading && _isCurrentlyHosting && (!app.isRunning || !view.contextHosted)) { // && (app.pid == 0 || view == nil || view.manager == nil)) // || view._isReallyHosting == NO)) + //[activityView startAnimating]; + [self unloadApp]; + [self loadApp]; + } else { + [self removeLoadingIndicator]; + [loadedTimer invalidate]; + loadedTimer = nil; + } } --(void) appDidDie:(SBApplication*)app_ -{ - if (app_ == self.app) - { - [self verifyHostingAndRehostIfNecessary]; - } +- (void)appDidDie:(SBApplication*)app_ { + if (app_ != self.app) { + return; + } + [self verifyHostingAndRehostIfNecessary]; } --(void) removeLoadingIndicator -{ - if (self.showSplashscreenInsteadOfSpinner) - { - [splashScreenImageView removeFromSuperview]; - splashScreenImageView = nil; - } - else if (activityView) - [activityView stopAnimating]; +- (void)removeLoadingIndicator { + if (self.showSplashscreenInsteadOfSpinner) { + [splashScreenImageView removeFromSuperview]; + splashScreenImageView = nil; + } else if (activityView) { + [activityView stopAnimating]; + } } --(void) drawRect:(CGRect)rect -{ - if (_renderWallpaper) - [[RASnapshotProvider.sharedInstance wallpaperImage] drawInRect:rect]; +- (void)drawRect:(CGRect)rect { + if (!_renderWallpaper) { + return; + } + [[RASnapshotProvider.sharedInstance wallpaperImage] drawInRect:rect]; } --(void) setFrame:(CGRect)frame -{ - [super setFrame:frame]; - [view setFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + [view setFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; - if (self.autosizesApp) - { - RAMessageAppData data = [RAMessagingServer.sharedInstance getDataForIdentifier:self.bundleIdentifier]; - data.canHideStatusBarIfWanted = self.allowHidingStatusBar; - [RAMessagingServer.sharedInstance setData:data forIdentifier:self.bundleIdentifier]; - [RAMessagingServer.sharedInstance resizeApp:self.bundleIdentifier toSize:CGSizeMake(frame.size.width, frame.size.height) completion:nil]; + if (self.autosizesApp) { + RAMessageAppData data = [RAMessagingServer.sharedInstance getDataForIdentifier:self.bundleIdentifier]; + data.canHideStatusBarIfWanted = self.allowHidingStatusBar; + [RAMessagingServer.sharedInstance setData:data forIdentifier:self.bundleIdentifier]; + [RAMessagingServer.sharedInstance resizeApp:self.bundleIdentifier toSize:CGSizeMake(frame.size.width, frame.size.height) completion:nil]; - } - else if (self.bundleIdentifier) - { - [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:nil]; - } + } else if (self.bundleIdentifier) { + [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:nil]; + } } --(void) setHideStatusBar:(BOOL)value -{ - _hideStatusBar = value; +- (void)setHideStatusBar:(BOOL)value { + _hideStatusBar = value; - if (!self.bundleIdentifier) - return; + if (!self.bundleIdentifier) { + return; + } - if (value) - [RAMessagingServer.sharedInstance forceStatusBarVisibility:!value forApp:self.bundleIdentifier completion:nil]; - else - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:nil]; + if (value) { + [RAMessagingServer.sharedInstance forceStatusBarVisibility:!value forApp:self.bundleIdentifier completion:nil]; + } else { + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:nil]; + } } --(void) unloadApp -{ - [self unloadApp:NO]; +- (void)unloadApp { + [self unloadApp:NO]; } --(void) unloadApp:(BOOL)forceImmediate -{ - //if (activityView) - // [activityView stopAnimating]; - [self removeLoadingIndicator]; - [loadedTimer invalidate]; - loadedTimer = nil; +- (void)unloadApp:(BOOL)forceImmediate { + //if (activityView) + // [activityView stopAnimating]; + [self removeLoadingIndicator]; + [loadedTimer invalidate]; + loadedTimer = nil; - [RARunningAppsProvider.sharedInstance removeTarget:self]; + [RARunningAppsProvider.sharedInstance removeTarget:self]; - disablePreload = YES; + disablePreload = YES; - if (_isCurrentlyHosting == NO) - return; - - _isCurrentlyHosting = NO; + if (!_isCurrentlyHosting) { + return; + } - FBScene *scene = [app mainScene]; + _isCurrentlyHosting = NO; - if (authenticationDidFailLabel) - { - [authenticationDidFailLabel removeFromSuperview]; - authenticationDidFailLabel = nil; + FBScene *scene = [app mainScene]; - [self removeGestureRecognizer:authenticationFailedRetryTapGesture]; - self.userInteractionEnabled = NO; - } + if (authenticationDidFailLabel) { + [authenticationDidFailLabel removeFromSuperview]; + authenticationDidFailLabel = nil; - if (isForemostAppLabel) - { - [isForemostAppLabel removeFromSuperview]; - isForemostAppLabel = nil; - } + [self removeGestureRecognizer:authenticationFailedRetryTapGesture]; + self.userInteractionEnabled = NO; + } - if ([RASpringBoardKeyboardActivation.sharedInstance.currentIdentifier isEqual:self.bundleIdentifier]) - [RASpringBoardKeyboardActivation.sharedInstance hideKeyboard]; + if (isForemostAppLabel) { + [isForemostAppLabel removeFromSuperview]; + isForemostAppLabel = nil; + } - if (contextHostManager) - { - [contextHostManager disableHostingForRequester:@"reachapp"]; - contextHostManager = nil; - } - - //if ([UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:app]) - // return; + if ([RASpringBoardKeyboardActivation.sharedInstance.currentIdentifier isEqual:self.bundleIdentifier]) { + [RASpringBoardKeyboardActivation.sharedInstance hideKeyboard]; + } - __weak RAHostedAppView *weakSelf = self; - __block BOOL didRun = NO; - RAMessageCompletionCallback block = ^(BOOL success) { - if (didRun || (weakSelf && [UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:weakSelf.app])) - return; - if (!scene) - return; + if (contextHostManager) { + [contextHostManager disableHostingForRequester:@"reachapp"]; + contextHostManager = nil; + } - appsBeingHosted[app.bundleIdentifier] = [appsBeingHosted objectForKey:app.bundleIdentifier] ? @([appsBeingHosted[app.bundleIdentifier] intValue] - 1) : @0; + //if ([UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:app]) + // return; - if ([appsBeingHosted[app.bundleIdentifier] intValue] > 0) - return; + __weak RAHostedAppView *weakSelf = self; + __block BOOL didRun = NO; + RAMessageCompletionCallback block = ^(BOOL success) { + if (didRun || (weakSelf && [UIApplication.sharedApplication._accessibilityFrontMostApplication isEqual:weakSelf.app])) { + return; + } + if (!scene) { + return; + } - FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; - SET_BACKGROUNDED(settings, YES); - [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; - //FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; - didRun = YES; - }; + appsBeingHosted[app.bundleIdentifier] = [appsBeingHosted objectForKey:app.bundleIdentifier] ? @([appsBeingHosted[app.bundleIdentifier] intValue] - 1) : @0; - [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:app.bundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance unRotateApp:self.bundleIdentifier completion:nil]; - if (forceImmediate) - { - [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:nil]; - block(YES); - } - else - { - // >Somewhere in the messaging server, the block is being removed from the waitingCompletions dictionary without being called. - // >This is a large issue (probably to do with asynchronous code) TODO: FIXME - // lol im retarded, it's the default empty callback the messaging server made - //[RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:block]; - //[RAMessagingServer.sharedInstance unRotateApp:self.bundleIdentifier completion:block]; - - [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:block]; + if ([appsBeingHosted[app.bundleIdentifier] intValue] > 0) { + return; } + + FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; + SET_BACKGROUNDED(settings, YES); + [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; + //FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; + didRun = YES; + }; + + [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:app.bundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance unRotateApp:self.bundleIdentifier completion:nil]; + if (forceImmediate) { + [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:nil]; + block(YES); + } else { + // >Somewhere in the messaging server, the block is being removed from the waitingCompletions dictionary without being called. + // >This is a large issue (probably to do with asynchronous code) TODO: FIXME + // lol im retarded, it's the default empty callback the messaging server made + //[RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:self.bundleIdentifier completion:block]; + //[RAMessagingServer.sharedInstance unRotateApp:self.bundleIdentifier completion:block]; + + [RAMessagingServer.sharedInstance endResizingApp:self.bundleIdentifier completion:block]; + } } --(void) rotateToOrientation:(UIInterfaceOrientation)o -{ - _orientation = o; +- (void)rotateToOrientation:(UIInterfaceOrientation)o { + _orientation = o; - [RAMessagingServer.sharedInstance rotateApp:self.bundleIdentifier toOrientation:o completion:nil]; + [RAMessagingServer.sharedInstance rotateApp:self.bundleIdentifier toOrientation:o completion:nil]; } -+(void) iPad_iOS83_fixHosting -{ - for (NSString *bundleIdentifier in appsBeingHosted.allKeys) - { - NSNumber *num = appsBeingHosted[bundleIdentifier]; - if (num.intValue > 0) - { - SBApplication *app_ = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:bundleIdentifier]; - FBWindowContextHostManager *manager = (FBWindowContextHostManager*)[RAHostManager hostManagerForApp:app_]; - if (manager) - { - NSLog(@"[ReachApp] rehosting for iPad: %@", bundleIdentifier); - [manager enableHostingForRequester:@"reachapp" priority:1]; - } - } ++ (void)iPad_iOS83_fixHosting { + for (NSString *bundleIdentifier in appsBeingHosted.allKeys) { + NSNumber *num = appsBeingHosted[bundleIdentifier]; + if (num.intValue > 0) { + SBApplication *app_ = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:bundleIdentifier]; + FBWindowContextHostManager *manager = (FBWindowContextHostManager*)[RAHostManager hostManagerForApp:app_]; + if (manager) { + LogDebug(@"[ReachApp] rehosting for iPad: %@", bundleIdentifier); + [manager enableHostingForRequester:@"reachapp" priority:1]; + } } - + } } // This allows for any subviews (with gestures) (e.g. the SwipeOver bar with a negative y origin) to recieve touch events. -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - BOOL isContained = NO; - for (UIView *subview in self.subviews) - { - if (CGRectContainsPoint(subview.frame, point)) // [self convertPoint:point toView:view])) - isContained = YES; +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + BOOL isContained = NO; + for (UIView *subview in self.subviews) { + if (CGRectContainsPoint(subview.frame, point)) { // [self convertPoint:point toView:view])) + isContained = YES; } - return isContained; + } + return isContained; } --(SBApplication*) app { return app; } --(NSString*) displayName { return app.displayName; } +- (SBApplication*)app { + return app; +} + +- (NSString*)displayName { + return app.displayName; +} @end diff --git a/RAHostedWidgetView.xm b/RAHostedWidgetView.xm index 387ee27..308e3e6 100644 --- a/RAHostedWidgetView.xm +++ b/RAHostedWidgetView.xm @@ -8,32 +8,33 @@ @end @implementation RAHostedWidgetView --(SBApplication*) app { return nil; } --(NSString*) displayName { return [self loadWidget].displayName; } +- (SBApplication*)app { + return nil; +} + +- (NSString*)displayName { + return [self loadWidget].displayName; +} //-(void) rotateToOrientation:(UIInterfaceOrientation)o; --(RAWidgetBase*) loadWidget -{ +- (RAWidgetBase*)loadWidget { widget = [RAWidgetHostManager.sharedInstance widgetForIdentifier:self.bundleIdentifier]; return widget; } --(void) preloadApp -{ +- (void)preloadApp { [self loadWidget]; } --(void) loadApp -{ +- (void)loadApp { widget.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); [self addSubview:widget]; [widget didAppear]; } --(void) unloadApp -{ +- (void)unloadApp { [widget didDisappear]; [widget removeFromSuperview]; } -@end \ No newline at end of file +@end diff --git a/RAInsetLabel.mm b/RAInsetLabel.mm index a3a6886..58ed09f 100644 --- a/RAInsetLabel.mm +++ b/RAInsetLabel.mm @@ -1,8 +1,7 @@ #import "RAInsetLabel.h" @implementation RAInsetLabel -- (void)drawTextInRect:(CGRect)rect -{ - [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.textInset)]; +- (void)drawTextInRect:(CGRect)rect { + [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.textInset)]; } -@end \ No newline at end of file +@end diff --git a/RALocalizer.h b/RALocalizer.h index 989bbd8..2248678 100644 --- a/RALocalizer.h +++ b/RALocalizer.h @@ -1,7 +1,6 @@ @interface RALocalizer : NSObject { NSDictionary *translation; } -+(id) sharedInstance; - --(NSString*) localizedStringForKey:(NSString*)key; -@end \ No newline at end of file ++ (instancetype)sharedInstance; +- (NSString*)localizedStringForKey:(NSString*)key; +@end diff --git a/RALocalizer.mm b/RALocalizer.mm index 4ea386f..3446cc3 100644 --- a/RALocalizer.mm +++ b/RALocalizer.mm @@ -2,38 +2,37 @@ #import "headers.h" @implementation RALocalizer -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(RALocalizer, [sharedInstance loadTranslation]); } --(BOOL) attemptLoadForLanguageCode:(NSString*)code -{ +- (BOOL)attemptLoadForLanguageCode:(NSString*)code { NSString *expandedPath = [NSString stringWithFormat:@"%@/Localizations/%@.strings",RA_BASE_PATH,code]; NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:expandedPath]; - if (plist) - { + if (plist) { translation = plist; return YES; } return NO; } --(void) loadTranslation -{ +- (void)loadTranslation { NSArray *langs = [NSLocale preferredLanguages]; - for (NSString *lang in langs) - { - if ([self attemptLoadForLanguageCode:lang]) + for (NSString *lang in langs) { + NSDictionary *components = [NSLocale componentsFromLocaleIdentifier:lang]; + NSString *languageDesignator = components[NSLocaleLanguageCode]; + + if ([self attemptLoadForLanguageCode:languageDesignator]) { break; + } } - if (!translation) + if (!translation) { [self attemptLoadForLanguageCode:@"en"]; + } } --(NSString*) localizedStringForKey:(NSString*)key -{ - return [translation objectForKey:key] ? translation[key] : key; +- (NSString*)localizedStringForKey:(NSString*)key { + return ![translation objectForKey:key] ? key : translation[key]; } -@end \ No newline at end of file +@end diff --git a/RAOrientationLocker.h b/RAOrientationLocker.h index dd6d5d5..9478357 100644 --- a/RAOrientationLocker.h +++ b/RAOrientationLocker.h @@ -1,6 +1,6 @@ #import "headers.h" @interface RAOrientationLocker : NSObject -+(void) lockOrientation; -+(void) unlockOrientation; -@end \ No newline at end of file ++ (void)lockOrientation; ++ (void)unlockOrientation; +@end diff --git a/RAOrientationLocker.xm b/RAOrientationLocker.xm index cfa7dd0..71228c5 100644 --- a/RAOrientationLocker.xm +++ b/RAOrientationLocker.xm @@ -1,19 +1,19 @@ #import "RAOrientationLocker.h" @implementation RAOrientationLocker -+(void) lockOrientation -{ - if ([%c(SBUIController) instancesRespondToSelector:@selector(_lockOrientationForSwitcher)]) ++ (void)lockOrientation { + if ([%c(SBUIController) instancesRespondToSelector:@selector(_lockOrientationForSwitcher)]) { [[%c(SBUIController) sharedInstance] _lockOrientationForSwitcher]; // iOS 8 - else // iOS 9 + } else { // iOS 9 [[%c(SBMainSwitcherGestureCoordinator) sharedInstance] _lockOrientation]; + } } -+(void) unlockOrientation -{ - if ([%c(SBUIController) instancesRespondToSelector:@selector(releaseSwitcherOrientationLock)]) ++ (void)unlockOrientation { + if ([%c(SBUIController) instancesRespondToSelector:@selector(releaseSwitcherOrientationLock)]) { [[%c(SBUIController) sharedInstance] releaseSwitcherOrientationLock]; // iOS 8 - else // iOS 9 + } else { // iOS 9 [[%c(SBMainSwitcherGestureCoordinator) sharedInstance] _releaseOrientationLock]; + } } -@end \ No newline at end of file +@end diff --git a/RAResourceImageProvider.h b/RAResourceImageProvider.h index edf4b5a..585fc2c 100644 --- a/RAResourceImageProvider.h +++ b/RAResourceImageProvider.h @@ -1,7 +1,8 @@ #import "headers.h" @interface RAResourceImageProvider : NSObject -+(UIImage*) imageForFilename:(NSString*)filename; -+(UIImage*) imageForFilename:(NSString*)filename size:(CGSize)size tintedTo:(UIColor*)tint; -+(UIImage*) imageForFilename:(NSString*)filename constrainedToSize:(CGSize)size; -@end \ No newline at end of file ++ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; ++ (UIImage*)imageForFilename:(NSString*)filename; ++ (UIImage*)imageForFilename:(NSString*)filename size:(CGSize)size tintedTo:(UIColor*)tint; ++ (UIImage*)imageForFilename:(NSString*)filename constrainedToSize:(CGSize)size; +@end diff --git a/RAResourceImageProvider.mm b/RAResourceImageProvider.mm index 1867f48..db9d082 100644 --- a/RAResourceImageProvider.mm +++ b/RAResourceImageProvider.mm @@ -5,86 +5,75 @@ NSCache *_rsImgCache = [NSCache new]; @implementation RAResourceImageProvider -+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize -{ - // from: https://stackoverflow.com/questions/2658738/the-simplest-way-to-resize-an-uiimage - // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution). - // Pass 1.0 to force exact pixel size. - UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); - [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return newImage; ++ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize { + // from: https://stackoverflow.com/questions/2658738/the-simplest-way-to-resize-an-uiimage + // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution). + // Pass 1.0 to force exact pixel size. + UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); + [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return newImage; } -+(id) loadAndCacheImageWithStrippedPath:(NSString*)stripped -{ - NSString *pdfPath = [NSString stringWithFormat:@"%@/Resources/%@.pdf",resourcePath,stripped]; - NSString *pngPath = [NSString stringWithFormat:@"%@/Resources/%@.png",resourcePath,stripped]; - - if ([NSFileManager.defaultManager fileExistsAtPath:pdfPath]) - { - RAPDFImage *pdf = [RAPDFImage imageWithContentsOfFile:pdfPath]; - - if (pdf) - [_rsImgCache setObject:pdf forKey:stripped]; - - return pdf; - } - else if ([NSFileManager.defaultManager fileExistsAtPath:pngPath]) - { - UIImage *img = [UIImage imageWithContentsOfFile:pngPath]; - if (img) - [_rsImgCache setObject:img forKey:stripped]; - - return img; - } - - return nil; ++ (id)loadAndCacheImageWithStrippedPath:(NSString*)stripped { + NSString *pdfPath = [NSString stringWithFormat:@"%@/Resources/%@.pdf",resourcePath,stripped]; + NSString *pngPath = [NSString stringWithFormat:@"%@/Resources/%@.png",resourcePath,stripped]; + + if ([NSFileManager.defaultManager fileExistsAtPath:pdfPath]) { + RAPDFImage *pdf = [RAPDFImage imageWithContentsOfFile:pdfPath]; + + if (pdf) { + [_rsImgCache setObject:pdf forKey:stripped]; + } + return pdf; + } else if ([NSFileManager.defaultManager fileExistsAtPath:pngPath]) { + UIImage *img = [UIImage imageWithContentsOfFile:pngPath]; + if (img) { + [_rsImgCache setObject:img forKey:stripped]; + } + return img; + } + + return nil; } -+(id) getOrCacheImageWithFilename:(NSString*)strippedPath -{ - return [_rsImgCache objectForKey:strippedPath] ?: [self loadAndCacheImageWithStrippedPath:strippedPath]; ++ (id)getOrCacheImageWithFilename:(NSString*)strippedPath { + return [_rsImgCache objectForKey:strippedPath] ?: [self loadAndCacheImageWithStrippedPath:strippedPath]; } -+(UIImage*) convertToUIImageIfNeeded:(id)arg sizeIfNeeded:(CGSize)size forceSizing:(BOOL)force -{ - if ([arg isKindOfClass:UIImage.class]) - { - if (force) - return [self imageWithImage:arg scaledToSize:size]; - else - return (UIImage*)arg; - } - - if ([arg isKindOfClass:[RAPDFImage class]]) - { - UIImage *image = [arg imageWithOptions:[RAPDFImageOptions optionsWithSize:size]]; - return image; - } - - return nil; ++ (UIImage*)convertToUIImageIfNeeded:(id)arg sizeIfNeeded:(CGSize)size forceSizing:(BOOL)force { + if ([arg isKindOfClass:UIImage.class]) { + if (force) { + return [self imageWithImage:arg scaledToSize:size]; + } else { + return (UIImage*)arg; + } + } + + if ([arg isKindOfClass:[RAPDFImage class]]) { + UIImage *image = [arg imageWithOptions:[RAPDFImageOptions optionsWithSize:size]]; + return image; + } + + return nil; } -+(UIImage*) imageForFilename:(NSString*)filename -{ - NSString *strippedPath = [[filename lastPathComponent] stringByDeletingPathExtension]; - id img = [self getOrCacheImageWithFilename:strippedPath]; ++ (UIImage*)imageForFilename:(NSString*)filename { + NSString *strippedPath = [[filename lastPathComponent] stringByDeletingPathExtension]; + id img = [self getOrCacheImageWithFilename:strippedPath]; - return [self convertToUIImageIfNeeded:img sizeIfNeeded:CGSizeMake(200, 200) forceSizing:NO]; + return [self convertToUIImageIfNeeded:img sizeIfNeeded:CGSizeMake(200, 200) forceSizing:NO]; } -+(UIImage*) imageForFilename:(NSString*)filename size:(CGSize)size tintedTo:(UIColor*)tint -{ - return [[self imageForFilename:filename constrainedToSize:size] _flatImageWithColor:tint]; ++ (UIImage*)imageForFilename:(NSString*)filename size:(CGSize)size tintedTo:(UIColor*)tint { + return [[self imageForFilename:filename constrainedToSize:size] _flatImageWithColor:tint]; } -+(UIImage*) imageForFilename:(NSString*)filename constrainedToSize:(CGSize)size -{ - NSString *strippedPath = [[filename lastPathComponent] stringByDeletingPathExtension]; - id img = [self getOrCacheImageWithFilename:strippedPath]; ++ (UIImage*)imageForFilename:(NSString*)filename constrainedToSize:(CGSize)size { + NSString *strippedPath = [[filename lastPathComponent] stringByDeletingPathExtension]; + id img = [self getOrCacheImageWithFilename:strippedPath]; - return [self convertToUIImageIfNeeded:img sizeIfNeeded:size forceSizing:YES]; + return [self convertToUIImageIfNeeded:img sizeIfNeeded:size forceSizing:YES]; } -@end \ No newline at end of file +@end diff --git a/RARunningAppsProvider.h b/RARunningAppsProvider.h index 99d52e6..f668603 100644 --- a/RARunningAppsProvider.h +++ b/RARunningAppsProvider.h @@ -1,23 +1,24 @@ #import "headers.h" +#import @protocol RARunningAppsProviderDelegate @optional --(void) appDidStart:(__unsafe_unretained SBApplication*)app; --(void) appDidDie:(__unsafe_unretained SBApplication*)app; +- (void)appDidStart:(__unsafe_unretained SBApplication*)app; +- (void)appDidDie:(__unsafe_unretained SBApplication*)app; @end @interface RARunningAppsProvider : NSObject { NSMutableArray *apps; NSMutableArray *targets; - NSLock *lock; + pthread_mutex_t mutex; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; --(void) addRunningApp:(__unsafe_unretained SBApplication*)app; --(void) removeRunningApp:(__unsafe_unretained SBApplication*)app; +- (void)addRunningApp:(__unsafe_unretained SBApplication*)app; +- (void)removeRunningApp:(__unsafe_unretained SBApplication*)app; --(void) addTarget:(__weak NSObject*)target; --(void) removeTarget:(__weak NSObject*)target; +- (void)addTarget:(__weak NSObject*)target; +- (void)removeTarget:(__weak NSObject*)target; --(NSArray*) runningApplications; -@end \ No newline at end of file +- (NSArray*)runningApplications; +@end diff --git a/RARunningAppsProvider.xm b/RARunningAppsProvider.xm index 362a53d..6eefc5a 100644 --- a/RARunningAppsProvider.xm +++ b/RARunningAppsProvider.xm @@ -1,75 +1,91 @@ #import "RARunningAppsProvider.h" @implementation RARunningAppsProvider -+(instancetype) sharedInstance -{ - SHARED_INSTANCE2(RARunningAppsProvider, - sharedInstance->apps = [NSMutableArray array]; ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RARunningAppsProvider, + sharedInstance->apps = [NSMutableArray array]; sharedInstance->targets = [NSMutableArray array]; - sharedInstance->lock = [[NSLock alloc] init]; ); } --(void) addRunningApp:(__unsafe_unretained SBApplication*)app -{ - [lock lock]; +- (instancetype)init { + self = [super init]; + if (self) { + pthread_mutex_init(&mutex, NULL); + } + return self; +} + +- (void)addRunningApp:(__unsafe_unretained SBApplication*)app { + pthread_mutex_lock(&mutex); [apps addObject:app]; - for (NSObject* target in targets) - if ([target respondsToSelector:@selector(appDidStart:)]) - dispatch_async(dispatch_get_main_queue(), ^{ + for (NSObject* target in targets) { + if ([target respondsToSelector:@selector(appDidStart:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ [target appDidStart:app]; }); + } + } - [lock unlock]; + pthread_mutex_unlock(&mutex); } --(void) removeRunningApp:(__unsafe_unretained SBApplication*)app -{ - [lock lock]; +- (void)removeRunningApp:(__unsafe_unretained SBApplication*)app { + pthread_mutex_lock(&mutex); [apps removeObject:app]; - for (NSObject* target in targets) - if ([target respondsToSelector:@selector(appDidDie:)]) - dispatch_async(dispatch_get_main_queue(), ^{ + for (NSObject* target in targets) { + if ([target respondsToSelector:@selector(appDidDie:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ [target appDidDie:app]; }); + } + } - [lock unlock]; + pthread_mutex_unlock(&mutex); } --(void) addTarget:(__weak NSObject*)target -{ - [lock lock]; +- (void)addTarget:(__weak NSObject*)target { + pthread_mutex_lock(&mutex); - if ([targets containsObject:target] == NO) + if (![targets containsObject:target]) { [targets addObject:target]; + } - [lock unlock]; + pthread_mutex_unlock(&mutex); } --(void) removeTarget:(__weak NSObject*)target -{ - [lock lock]; +- (void)removeTarget:(__weak NSObject*)target { + pthread_mutex_lock(&mutex); [targets removeObject:target]; - [lock unlock]; + pthread_mutex_unlock(&mutex); +} + +- (void)dealloc { + pthread_mutex_destroy(&mutex); } --(NSArray*) runningApplications { return apps; } --(NSMutableArray*) mutableRunningApplications { return apps; } +- (NSArray*)runningApplications { + return apps; +} + +- (NSMutableArray*)mutableRunningApplications { + return apps; +} @end %hook SBApplication -- (void)updateProcessState:(unsafe_id)arg1 -{ +- (void)updateProcessState:(unsafe_id)arg1 { %orig; - if (self.isRunning && [RARunningAppsProvider.sharedInstance.mutableRunningApplications containsObject:self] == NO) + if (self.isRunning && ![RARunningAppsProvider.sharedInstance.mutableRunningApplications containsObject:self]) { [RARunningAppsProvider.sharedInstance addRunningApp:self]; - else if (!self.isRunning && [RARunningAppsProvider.sharedInstance.mutableRunningApplications containsObject:self]) + } else if (!self.isRunning && [RARunningAppsProvider.sharedInstance.mutableRunningApplications containsObject:self]) { [RARunningAppsProvider.sharedInstance removeRunningApp:self]; + } } -%end \ No newline at end of file +%end diff --git a/RASBWorkspaceFetcher.h b/RASBWorkspaceFetcher.h index 12a55db..01b3f3f 100644 --- a/RASBWorkspaceFetcher.h +++ b/RASBWorkspaceFetcher.h @@ -1,6 +1,6 @@ @class SBWorkspace; @interface RASBWorkspaceFetcher : NSObject -+(Class) SBWorkspaceClass; -+(SBWorkspace*) getCurrentSBWorkspaceImplementationInstanceForThisOS; -@end \ No newline at end of file ++ (Class)SBWorkspaceClass; ++ (SBWorkspace*)getCurrentSBWorkspaceImplementationInstanceForThisOS; +@end diff --git a/RASBWorkspaceFetcher.xm b/RASBWorkspaceFetcher.xm index 25f66fc..5806503 100644 --- a/RASBWorkspaceFetcher.xm +++ b/RASBWorkspaceFetcher.xm @@ -5,29 +5,27 @@ // REASON: HEADERS.H IMPORTS THIS FILE @interface __SBWorkspace__class_impl_dummy : NSObject -+(id) sharedInstance; ++ (id)sharedInstance; @end Class SBWorkspace_class_implementation_class = nil; @implementation RASBWorkspaceFetcher -+(Class) SBWorkspaceClass -{ ++ (Class)SBWorkspaceClass { return SBWorkspace_class_implementation_class; } -+(SBWorkspace*) getCurrentSBWorkspaceImplementationInstanceForThisOS -{ - if ([SBWorkspace_class_implementation_class respondsToSelector:@selector(sharedInstance)]) ++ (SBWorkspace*)getCurrentSBWorkspaceImplementationInstanceForThisOS { + if ([SBWorkspace_class_implementation_class respondsToSelector:@selector(sharedInstance)]) { return [SBWorkspace_class_implementation_class sharedInstance]; - NSLog(@"[ReachApp] \"SBWorkspace\" class '%s' does not have '+sharedInstance' method", class_getName(SBWorkspace_class_implementation_class)); + } + HBLogError(@"[ReachApp] \"SBWorkspace\" class '%s' does not have '+sharedInstance' method", class_getName(SBWorkspace_class_implementation_class)); return nil; } @end -%ctor -{ +%ctor { // SBMainWorkspace: iOS 9 // SBWorkspace: iOS 8 - SBWorkspace_class_implementation_class = objc_getClass("SBMainWorkspace") ?: objc_getClass("SBWorkspace"); -} \ No newline at end of file + SBWorkspace_class_implementation_class = %c(SBMainWorkspace) ?: %c(SBWorkspace); +} diff --git a/RASettings.h b/RASettings.h index 5e77277..10b71d2 100644 --- a/RASettings.h +++ b/RASettings.h @@ -1,6 +1,6 @@ #import -enum RAGrabArea { +typedef NS_ENUM(NSInteger, RAGrabArea) { RAGrabAreaBottomLeftThird = 1, RAGrabAreaBottomMiddleThird = 2, RAGrabAreaBottomRightThird = 3, @@ -14,79 +14,79 @@ enum RAGrabArea { @interface RASettings : NSObject { NSDictionary *_settings; } -+(instancetype)sharedInstance; - -+(BOOL) isParagonInstalled; -+(BOOL) isActivatorInstalled; -+(BOOL) isLibStatusBarInstalled; - --(void) reloadSettings; --(void) resetSettings; - --(BOOL) enabled; - --(BOOL) reachabilityEnabled; --(BOOL) disableAutoDismiss; --(BOOL) enableRotation; --(BOOL) showNCInstead; --(BOOL) homeButtonClosesReachability; --(BOOL) showBottomGrabber; --(BOOL) showWidgetSelector; --(BOOL) scalingRotationMode; --(BOOL) autoSizeWidgetSelector; --(BOOL) showAllAppsInWidgetSelector; --(BOOL) showRecentAppsInWidgetSelector; --(BOOL) pagingEnabled; --(NSMutableArray*) favoriteApps; --(BOOL) unifyStatusBar; --(BOOL) flipTopAndBottom; --(BOOL) showFavorites; - --(BOOL) NCAppEnabled; --(NSString*) NCApp; --(BOOL) ncAppHideOnLS; - --(BOOL) alwaysEnableGestures; --(BOOL) snapWindows; --(BOOL) snapRotation; --(BOOL) launchIntoWindows; --(BOOL) windowedMultitaskingCompleteAnimations; --(BOOL) openLinksInWindows; --(BOOL) showSnapHelper; - --(NSInteger) globalBackgroundMode; --(BOOL) shouldShowStatusBarIcons; --(BOOL) shouldShowStatusBarNativeIcons; --(BOOL) backgrounderEnabled; --(BOOL) shouldShowIconIndicatorsGlobally; --(BOOL) showNativeStateIconIndicators; --(NSDictionary*) rawCompiledBackgrounderSettingsForIdentifier:(NSString*)identifier; - --(BOOL) missionControlEnabled; --(BOOL) replaceAppSwitcherWithMC; --(BOOL) missionControlKillApps; --(NSInteger) missionControlDesktopStyle; --(BOOL) missionControlPagingEnabled; - --(BOOL) isFirstRun; --(void) setFirstRun:(BOOL)value; - --(BOOL) swipeOverEnabled; --(BOOL) alwaysShowSOGrabber; - --(BOOL) exitAppAfterUsingActivatorAction; - --(BOOL) quickAccessUseGenericTabLabel; ++ (instancetype)sharedInstance; + ++ (BOOL)isParagonInstalled; ++ (BOOL)isActivatorInstalled; ++ (BOOL)isLibStatusBarInstalled; + +- (void)reloadSettings; +- (void)resetSettings; + +- (BOOL)enabled; + +- (BOOL)reachabilityEnabled; +- (BOOL)disableAutoDismiss; +- (BOOL)enableRotation; +- (BOOL)showNCInstead; +- (BOOL)homeButtonClosesReachability; +- (BOOL)showBottomGrabber; +- (BOOL)showWidgetSelector; +- (BOOL)scalingRotationMode; +- (BOOL)autoSizeWidgetSelector; +- (BOOL)showAllAppsInWidgetSelector; +- (BOOL)showRecentAppsInWidgetSelector; +- (BOOL)pagingEnabled; +- (NSMutableArray*)favoriteApps; +- (BOOL)unifyStatusBar; +- (BOOL)flipTopAndBottom; +- (BOOL)showFavorites; + +- (BOOL)NCAppEnabled; +- (NSString*)NCApp; +- (BOOL)ncAppHideOnLS; + +- (BOOL)alwaysEnableGestures; +- (BOOL)snapWindows; +- (BOOL)snapRotation; +- (BOOL)launchIntoWindows; +- (BOOL)windowedMultitaskingCompleteAnimations; +- (BOOL)openLinksInWindows; +- (BOOL)showSnapHelper; + +- (NSInteger)globalBackgroundMode; +- (BOOL)shouldShowStatusBarIcons; +- (BOOL)shouldShowStatusBarNativeIcons; +- (BOOL)backgrounderEnabled; +- (BOOL)shouldShowIconIndicatorsGlobally; +- (BOOL)showNativeStateIconIndicators; +- (NSDictionary*)rawCompiledBackgrounderSettingsForIdentifier:(NSString*)identifier; + +- (BOOL)missionControlEnabled; +- (BOOL)replaceAppSwitcherWithMC; +- (BOOL)missionControlKillApps; +- (NSInteger)missionControlDesktopStyle; +- (BOOL)missionControlPagingEnabled; + +- (BOOL)isFirstRun; +- (void)setFirstRun:(BOOL)value; + +- (BOOL)swipeOverEnabled; +- (BOOL)alwaysShowSOGrabber; + +- (BOOL)exitAppAfterUsingActivatorAction; + +- (BOOL)quickAccessUseGenericTabLabel; #if DEBUG --(BOOL) debug_showIPCMessages; +- (BOOL)debug_showIPCMessages; #endif --(BOOL) windowedMultitaskingEnabled; --(NSInteger) windowRotationLockMode; --(RAGrabArea) windowedMultitaskingGrabArea; --(RAGrabArea) swipeOverGrabArea; --(BOOL) onlyShowWindowBarIconsOnOverlay; +- (BOOL)windowedMultitaskingEnabled; +- (NSInteger)windowRotationLockMode; +- (RAGrabArea)windowedMultitaskingGrabArea; +- (RAGrabArea)swipeOverGrabArea; +- (BOOL)onlyShowWindowBarIconsOnOverlay; --(NSString*) currentThemeIdentifier; -@end \ No newline at end of file +- (NSString*)currentThemeIdentifier; +@end diff --git a/RASettings.mm b/RASettings.mm index 2019066..86403ed 100644 --- a/RASettings.mm +++ b/RASettings.mm @@ -4,74 +4,65 @@ #import "RAThemeManager.h" #import "RANCViewController.h" -#define BOOL(key, default) ([_settings objectForKey:key] != nil ? [_settings[key] boolValue] : default) +#define BOOL(key, default) ([_settings objectForKey:key] ? [_settings[key] boolValue] : default) NSCache *backgrounderSettingsCache = [NSCache new]; @implementation RASettings -+(BOOL) isParagonInstalled -{ ++ (BOOL)isParagonInstalled { static BOOL installed = NO; - static dispatch_once_t onceToken = 0; + static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ installed = [NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/ParagonPlus.dylib"]; }); return installed; } -+(BOOL) isActivatorInstalled -{ ++ (BOOL)isActivatorInstalled { static BOOL installed = NO; - static dispatch_once_t onceToken = 0; + static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/libactivator.dylib"]) - { + if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/libactivator.dylib"]) { installed = YES; - dlopen("/Library/MobileSubstrate/DynamicLibraries/libactivator.dylib", RTLD_LAZY); + dlopen("/Library/MobileSubstrate/DynamicLibraries/libactivator.dylib", RTLD_LAZY); } }); return installed; } -+(BOOL) isLibStatusBarInstalled -{ ++ (BOOL)isLibStatusBarInstalled { static BOOL installed = NO; - static dispatch_once_t onceToken = 0; + static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/libstatusbar.dylib"]) - { + if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/libstatusbar.dylib"]) { installed = YES; - dlopen("/Library/MobileSubstrate/DynamicLibraries/libstatusbar.dylib", RTLD_LAZY); + dlopen("/Library/MobileSubstrate/DynamicLibraries/libstatusbar.dylib", RTLD_LAZY); } }); return installed; } -+(instancetype) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE(RASettings); } --(id) init -{ - if (self = [super init]) - { +- (instancetype)init { + self = [super init]; + if (self) { [self reloadSettings]; } return self; } --(void) reloadSettings -{ +- (void)reloadSettings { @autoreleasepool { //NSLog(@"[ReachApp] reloading settings"); // Prepare specialized setting change cases NSString *previousNCAppSetting = self.NCApp; // Reload Settings - if (_settings) - { + if (_settings) { //CFRelease((__bridge CFDictionaryRef)_settings); _settings = nil; } @@ -81,49 +72,44 @@ -(void) reloadSettings BOOL failed = NO; - if (keyList) - { + if (keyList) { //_settings = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); _settings = (NSDictionary*)CFBridgingRelease(CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); CFRelease(keyList); - if (!_settings) - { + if (!_settings) { //NSLog(@"[ReachApp] failure loading from CFPreferences"); failed = YES; } - } - else - { + } else { //NSLog(@"[ReachApp] failure loading keyList"); failed = YES; } CFRelease(appID); - if (failed) - { + if (failed) { _settings = [NSDictionary dictionaryWithContentsOfFile:@"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist"]; //NSLog(@"[ReachApp] settings sandbox load: %@", _settings == nil ? @"failed" : @"succeed"); } - if (_settings == nil) - { - NSLog(@"[ReachApp] could not load settings from CFPreferences or NSDictionary"); + if (!_settings) { + LogError(@"[ReachApp] could not load settings from CFPreferences or NSDictionary"); } - if ([previousNCAppSetting isEqual:self.NCApp] == NO) + if (![previousNCAppSetting isEqual:self.NCApp]) { [[objc_getClass("RANCViewController") sharedViewController] forceReloadAppLikelyBecauseTheSettingChanged]; // using objc_getClass allows RASettings to be used in reachappsettings and other places + } - if ([self shouldShowStatusBarIcons] == NO && [objc_getClass("SBApplication") respondsToSelector:@selector(RA_clearAllStatusBarIcons)]) + if (![self shouldShowStatusBarIcons] && [objc_getClass("SBApplication") respondsToSelector:@selector(RA_clearAllStatusBarIcons)]) { [objc_getClass("SBApplication") performSelector:@selector(RA_clearAllStatusBarIcons)]; + } [RAThemeManager.sharedInstance invalidateCurrentThemeAndReload:[self currentThemeIdentifier]]; [backgrounderSettingsCache removeAllObjects]; } } --(void) resetSettings -{ +- (void)resetSettings { IF_NOT_SPRINGBOARD { @throw [NSException exceptionWithName:@"NotSpringBoardException" reason:@"Cannot reset settings outside of SpringBoard" userInfo:nil]; } @@ -131,187 +117,166 @@ -(void) resetSettings CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (keyList) - { + if (keyList) { CFPreferencesSetMultiple(NULL, keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRelease(keyList); - } - else - { - NSLog(@"[ReachApp] unable to get keyList to reset settings"); + } else { + LogError(@"[ReachApp] unable to get keyList to reset settings"); } CFPreferencesAppSynchronize(appID); CFRelease(appID); - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.respring"), nil, nil, YES); + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.respring"), nil, nil, YES); } --(BOOL) enabled -{ +- (BOOL)enabled { return BOOL(@"enabled", YES); } #if DEBUG --(BOOL) debug_showIPCMessages { return BOOL(@"debug_showIPCMessages", YES); } +- (BOOL)debug_showIPCMessages { + return BOOL(@"debug_showIPCMessages", YES); +} #endif --(BOOL) reachabilityEnabled { return [self enabled] && BOOL(@"reachabilityEnabled", YES); } +- (BOOL)reachabilityEnabled { + return [self enabled] && BOOL(@"reachabilityEnabled", YES); +} --(BOOL) disableAutoDismiss -{ +- (BOOL)disableAutoDismiss { return BOOL(@"disableAutoDismiss", YES); } --(BOOL) enableRotation -{ +- (BOOL)enableRotation { return BOOL(@"enableRotation", YES); } --(BOOL) showNCInstead -{ +- (BOOL)showNCInstead { return BOOL(@"showNCInstead", NO); } --(BOOL) homeButtonClosesReachability -{ +- (BOOL)homeButtonClosesReachability { return BOOL(@"homeButtonClosesReachability", YES); } --(BOOL) showBottomGrabber -{ +- (BOOL)showBottomGrabber { return BOOL(@"showBottomGrabber", NO); } --(BOOL) showWidgetSelector -{ +- (BOOL)showWidgetSelector { return BOOL(@"showAppSelector", YES); } --(BOOL) scalingRotationMode -{ +- (BOOL)scalingRotationMode { return BOOL(@"rotationMode", NO); } --(BOOL) autoSizeWidgetSelector -{ +- (BOOL)autoSizeWidgetSelector { return BOOL(@"autoSizeAppChooser", YES); } --(BOOL) showAllAppsInWidgetSelector -{ +- (BOOL)showAllAppsInWidgetSelector { return BOOL(@"showAllAppsInAppChooser", YES); } --(BOOL) showRecentAppsInWidgetSelector -{ +- (BOOL)showRecentAppsInWidgetSelector { return BOOL(@"showRecents", YES); } --(BOOL) pagingEnabled -{ +- (BOOL)pagingEnabled { return BOOL(@"pagingEnabled", YES); } --(BOOL) NCAppEnabled -{ +- (BOOL)NCAppEnabled { return [self enabled] && BOOL(@"ncAppEnabled", YES); } --(BOOL) shouldShowStatusBarNativeIcons { return BOOL(@"shouldShowStatusBarNativeIcons", NO); } +- (BOOL)shouldShowStatusBarNativeIcons { + return BOOL(@"shouldShowStatusBarNativeIcons", NO); +} --(NSMutableArray*) favoriteApps -{ +- (NSMutableArray*)favoriteApps { NSMutableArray *favorites = [[NSMutableArray alloc] init]; - for (NSString *key in _settings.allKeys) - { - if ([key hasPrefix:@"Favorites-"]) - { + for (NSString *key in _settings.allKeys) { + if ([key hasPrefix:@"Favorites-"]) { NSString *ident = [key substringFromIndex:10]; - if ([_settings[key] boolValue]) + if ([_settings[key] boolValue]) { [favorites addObject:ident]; + } } } return favorites; } --(BOOL) unifyStatusBar -{ +- (BOOL)unifyStatusBar { return BOOL(@"unifyStatusBar", YES); } --(BOOL) flipTopAndBottom -{ +- (BOOL)flipTopAndBottom { return BOOL(@"flipTopAndBottom", NO); } --(NSString*) NCApp -{ - return [_settings objectForKey:@"NCApp"] == nil ? @"com.apple.Preferences" : _settings[@"NCApp"]; +- (NSString*)NCApp { + return ![_settings objectForKey:@"NCApp"] ? @"com.apple.Preferences" : _settings[@"NCApp"]; } --(BOOL) alwaysEnableGestures -{ +- (BOOL)alwaysEnableGestures { return BOOL(@"alwaysEnableGestures", YES); } --(BOOL) snapWindows -{ +- (BOOL)snapWindows { return BOOL(@"snapWindows", YES); } --(BOOL) launchIntoWindows -{ +- (BOOL)launchIntoWindows { return BOOL(@"launchIntoWindows", NO); } --(BOOL) openLinksInWindows { return BOOL(@"openLinksInWindows", NO); } +- (BOOL)openLinksInWindows { + return BOOL(@"openLinksInWindows", NO); +} --(BOOL) backgrounderEnabled -{ +- (BOOL)backgrounderEnabled { return [self enabled] && BOOL(@"backgrounderEnabled", YES); } --(BOOL) shouldShowIconIndicatorsGlobally -{ +- (BOOL)shouldShowIconIndicatorsGlobally { return BOOL(@"showIconIndicators", YES); } --(BOOL) showNativeStateIconIndicators -{ +- (BOOL)showNativeStateIconIndicators { return BOOL(@"showNativeStateIconIndicators", NO); } --(BOOL) missionControlEnabled -{ +- (BOOL)missionControlEnabled { return [self enabled] && BOOL(@"missionControlEnabled", YES); } --(BOOL) replaceAppSwitcherWithMC -{ +- (BOOL)replaceAppSwitcherWithMC { return BOOL(@"replaceAppSwitcherWithMC", NO); } --(BOOL) missionControlKillApps { return BOOL(@"mcKillApps", YES); } +- (BOOL)missionControlKillApps { + return BOOL(@"mcKillApps", YES); +} --(BOOL) snapRotation -{ +- (BOOL)snapRotation { return BOOL(@"snapRotation", YES); } --(NSInteger) globalBackgroundMode -{ - return [_settings objectForKey:@"globalBackgroundMode"] == nil ? RABackgroundModeNative : [_settings[@"globalBackgroundMode"] intValue]; +- (NSInteger)globalBackgroundMode { + return ![_settings objectForKey:@"globalBackgroundMode"] ? RABackgroundModeNative : [_settings[@"globalBackgroundMode"] intValue]; } --(NSInteger) windowRotationLockMode -{ - return [_settings objectForKey:@"windowRotationLockMode"] == nil ? 0 : [_settings[@"windowRotationLockMode"] intValue]; +- (NSInteger)windowRotationLockMode { + return ![_settings objectForKey:@"windowRotationLockMode"] ? 0 : [_settings[@"windowRotationLockMode"] intValue]; } --(BOOL) shouldShowStatusBarIcons { return BOOL(@"shouldShowStatusBarIcons", YES); } +- (BOOL)shouldShowStatusBarIcons { + return BOOL(@"shouldShowStatusBarIcons", YES); +} --(NSDictionary*) _createAndCacheBackgrounderSettingsForIdentifier:(NSString*)identifier -{ +- (NSDictionary*)_createAndCacheBackgrounderSettingsForIdentifier:(NSString*)identifier { NSMutableDictionary *ret = [NSMutableDictionary dictionary]; ret[@"enabled"] = _settings[[NSString stringWithFormat:@"backgrounder-%@-enabled",identifier]] ?: @NO; @@ -325,62 +290,94 @@ -(NSDictionary*) _createAndCacheBackgrounderSettingsForIdentifier:(NSString*)ide ret[@"showStatusBarIcon"] = _settings[[NSString stringWithFormat:@"backgrounder-%@-showStatusBarIcon",identifier]] ?: @YES; ret[@"backgroundModes"] = [NSMutableDictionary dictionary]; - ret[@"backgroundModes"][kBGModeUnboundedTaskCompletion] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeUnboundedTaskCompletion]] ?: @NO; - ret[@"backgroundModes"][kBGModeContinuous] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeContinuous]] ?: @NO; - ret[@"backgroundModes"][kBGModeFetch] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeFetch]] ?: @NO; - ret[@"backgroundModes"][kBGModeRemoteNotification] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeRemoteNotification]] ?: @NO; - ret[@"backgroundModes"][kBGModeExternalAccessory] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeExternalAccessory]] ?: @NO; - ret[@"backgroundModes"][kBGModeVoIP] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeVoIP]] ?: @NO; - ret[@"backgroundModes"][kBGModeLocation] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeLocation]] ?: @NO; - ret[@"backgroundModes"][kBGModeAudio] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeAudio]] ?: @NO; - ret[@"backgroundModes"][kBGModeBluetoothCentral] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeBluetoothCentral]] ?: @NO; - ret[@"backgroundModes"][kBGModeBluetoothPeripheral] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBGModeBluetoothPeripheral]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeUnboundedTaskCompletion] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeUnboundedTaskCompletion]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeContinuous] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeContinuous]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeFetch] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeFetch]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeRemoteNotification] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeRemoteNotification]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeExternalAccessory] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeExternalAccessory]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeVoIP] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeVoIP]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeLocation] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeLocation]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeAudio] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeAudio]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeBluetoothCentral] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeBluetoothCentral]] ?: @NO; + ret[@"backgroundModes"][kBKSBackgroundModeBluetoothPeripheral] = _settings[[NSString stringWithFormat:@"backgrounder-%@-backgroundmodes-%@",identifier,kBKSBackgroundModeBluetoothPeripheral]] ?: @NO; [backgrounderSettingsCache setObject:ret forKey:identifier]; return ret; } --(NSDictionary*) rawCompiledBackgrounderSettingsForIdentifier:(NSString*)identifier -{ +- (NSDictionary*)rawCompiledBackgrounderSettingsForIdentifier:(NSString*)identifier { return [backgrounderSettingsCache objectForKey:identifier] ?: [self _createAndCacheBackgrounderSettingsForIdentifier:identifier]; } --(BOOL) isFirstRun -{ - NSLog(@"[ReachApp] %d", BOOL(@"isFirstRun", YES)); - return BOOL(@"isFirstRun", YES); +- (BOOL)isFirstRun { + LogDebug(@"[ReachApp] %d", BOOL(@"isFirstRun", YES)); + return BOOL(@"isFirstRun", YES); } --(void) setFirstRun:(BOOL)value -{ +- (void)setFirstRun:(BOOL)value { CFPreferencesSetAppValue(CFSTR("isFirstRun"), value ? kCFBooleanTrue : kCFBooleanFalse, CFSTR("com.efrederickson.reachapp.settings")); CFPreferencesAppSynchronize(CFSTR("com.efrederickson.reachapp.settings")); [self reloadSettings]; } --(BOOL) alwaysShowSOGrabber { return BOOL(@"alwaysShowSOGrabber", NO); } +- (BOOL)alwaysShowSOGrabber { + return BOOL(@"alwaysShowSOGrabber", NO); +} + +- (BOOL)swipeOverEnabled { + return [self enabled] && BOOL(@"swipeOverEnabled", YES); +} + +- (BOOL)windowedMultitaskingEnabled { + return [self enabled] && BOOL(@"windowedMultitaskingEnabled", YES); +} + +- (BOOL)exitAppAfterUsingActivatorAction { + return BOOL(@"exitAppAfterUsingActivatorAction", YES); +} --(BOOL) swipeOverEnabled { return [self enabled] && BOOL(@"swipeOverEnabled", YES); } --(BOOL) windowedMultitaskingEnabled { return [self enabled] && BOOL(@"windowedMultitaskingEnabled", YES); } --(BOOL) exitAppAfterUsingActivatorAction { return BOOL(@"exitAppAfterUsingActivatorAction", YES); } --(BOOL) windowedMultitaskingCompleteAnimations { return BOOL(@"windowedMultitaskingCompleteAnimations", NO); } --(NSString*) currentThemeIdentifier { return _settings[@"currentThemeIdentifier"] ?: @"com.eljahandandrew.multiplexer.themes.default"; } --(NSInteger) missionControlDesktopStyle { return [_settings[@"missionControlDesktopStyle"] ?: @1 intValue]; } --(BOOL) missionControlPagingEnabled { return BOOL(@"missionControlPagingEnabled", NO); } --(BOOL) showFavorites { return BOOL(@"showFavorites", YES); } --(BOOL) onlyShowWindowBarIconsOnOverlay { return BOOL(@"onlyShowWindowBarIconsOnOverlay", NO); } --(BOOL) quickAccessUseGenericTabLabel { return BOOL(@"quickAccessUseGenericTabLabel", NO); } --(BOOL) ncAppHideOnLS { return BOOL(@"ncAppHideOnLS", NO); } --(BOOL) showSnapHelper { return BOOL(@"showSnapHelper", NO); } +- (BOOL)windowedMultitaskingCompleteAnimations { + return BOOL(@"windowedMultitaskingCompleteAnimations", NO); +} + +- (NSString*)currentThemeIdentifier { + return _settings[@"currentThemeIdentifier"] ?: @"com.eljahandandrew.multiplexer.themes.default"; +} + +- (NSInteger)missionControlDesktopStyle { + return [_settings[@"missionControlDesktopStyle"] ?: @1 intValue]; +} + +- (BOOL)missionControlPagingEnabled { + return BOOL(@"missionControlPagingEnabled", NO); +} + +- (BOOL)showFavorites { + return BOOL(@"showFavorites", YES); +} + +- (BOOL)onlyShowWindowBarIconsOnOverlay { + return BOOL(@"onlyShowWindowBarIconsOnOverlay", NO); +} + +- (BOOL)quickAccessUseGenericTabLabel { + return BOOL(@"quickAccessUseGenericTabLabel", NO); +} + +- (BOOL)ncAppHideOnLS { + return BOOL(@"ncAppHideOnLS", NO); +} + +- (BOOL)showSnapHelper { + return BOOL(@"showSnapHelper", NO); +} --(RAGrabArea) windowedMultitaskingGrabArea -{ - return [_settings objectForKey:@"windowedMultitaskingGrabArea"] == nil ? RAGrabAreaBottomLeftThird : (RAGrabArea)[_settings[@"windowedMultitaskingGrabArea"] intValue]; +- (RAGrabArea)windowedMultitaskingGrabArea { + return ![_settings objectForKey:@"windowedMultitaskingGrabArea"] ? RAGrabAreaBottomLeftThird : (RAGrabArea)[_settings[@"windowedMultitaskingGrabArea"] intValue]; } --(RAGrabArea) swipeOverGrabArea -{ - return [_settings objectForKey:@"swipeOverGrabArea"] == nil ? RAGrabAreaSideAnywhere : (RAGrabArea)[_settings[@"swipeOverGrabArea"] intValue]; +- (RAGrabArea)swipeOverGrabArea { + return ![_settings objectForKey:@"swipeOverGrabArea"] ? RAGrabAreaSideAnywhere : (RAGrabArea)[_settings[@"swipeOverGrabArea"] intValue]; } -@end \ No newline at end of file +@end diff --git a/RASnapshotProvider.h b/RASnapshotProvider.h index a54aaa6..86a901a 100644 --- a/RASnapshotProvider.h +++ b/RASnapshotProvider.h @@ -3,18 +3,18 @@ @interface RASnapshotProvider : NSObject { NSCache *imageCache; } -+(id) sharedInstance; ++ (instancetype)sharedInstance; --(UIImage*) snapshotForDesktop:(RADesktopWindow*)desktop; --(void) forceReloadSnapshotOfDesktop:(RADesktopWindow*)desktop; +- (UIImage*)snapshotForDesktop:(RADesktopWindow*)desktop; +- (void)forceReloadSnapshotOfDesktop:(RADesktopWindow*)desktop; --(UIImage*) storedSnapshotOfMissionControl; --(void) storeSnapshotOfMissionControl:(UIWindow*)window; +- (UIImage*)storedSnapshotOfMissionControl; +- (void)storeSnapshotOfMissionControl:(UIWindow*)window; --(UIImage*) snapshotForIdentifier:(NSString*)identifier; --(void) forceReloadOfSnapshotForIdentifier:(NSString*)identifier; +- (UIImage*)snapshotForIdentifier:(NSString*)identifier; +- (void)forceReloadOfSnapshotForIdentifier:(NSString*)identifier; --(UIImage*) wallpaperImage; +- (UIImage*)wallpaperImage; --(void) forceReloadEverything; -@end \ No newline at end of file +- (void)forceReloadEverything; +@end diff --git a/RASnapshotProvider.xm b/RASnapshotProvider.xm index 5c59fdc..f93ee3a 100644 --- a/RASnapshotProvider.xm +++ b/RASnapshotProvider.xm @@ -1,15 +1,14 @@ #import "headers.h" #import "RASnapshotProvider.h" #import "RAWindowBar.h" +#import "RAResourceImageProvider.h" @implementation RASnapshotProvider -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(RASnapshotProvider, sharedInstance->imageCache = [NSCache new]); } --(UIImage*) snapshotForIdentifier:(NSString*)identifier orientation:(UIInterfaceOrientation)orientation -{ +- (UIImage*)snapshotForIdentifier:(NSString*)identifier orientation:(UIInterfaceOrientation)orientation { /*if (![NSThread isMainThread]) { __block id result = nil; @@ -20,69 +19,67 @@ [targetQueue waitUntilAllOperationsAreFinished]; return result; }*/ - @autoreleasepool { + if ([imageCache objectForKey:identifier]) { + return [imageCache objectForKey:identifier]; + } - if ([imageCache objectForKey:identifier] != nil) return [imageCache objectForKey:identifier]; - UIImage *image = nil; SBDisplayItem *item = [%c(SBDisplayItem) displayItemWithType:@"App" displayIdentifier:identifier]; __block SBAppSwitcherSnapshotView *view = nil; ON_MAIN_THREAD(^{ - if ([%c(SBUIController) respondsToSelector:@selector(switcherController)]) - { + if ([%c(SBUIController) respondsToSelector:@selector(switcherController)]) { view = [[[%c(SBUIController) sharedInstance] switcherController] performSelector:@selector(_snapshotViewForDisplayItem:) withObject:item]; [view setOrientation:orientation orientationBehavior:0]; - } - else - { - //SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; - //view = [[%c(SBAppSwitcherSnapshotView) alloc] initWithDisplayItem:item application:app orientation:orientation preferringDownscaledSnapshot:NO async:NO withQueue:nil]; + } else { + SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; + view = [[%c(SBAppSwitcherSnapshotView) alloc] initWithDisplayItem:item application:app orientation:orientation preferringDownscaledSnapshot:NO async:NO withQueue:nil]; } }); - - if (view) - { - [view performSelectorOnMainThread:@selector(_loadSnapshotSync) withObject:nil waitUntilDone:YES]; - image = MSHookIvar(view, "_snapshotImageView").image; + + if (view) { + if ([view respondsToSelector:@selector(_loadSnapshotSync)]) { + [view performSelectorOnMainThread:@selector(_loadSnapshotSync) withObject:nil waitUntilDone:YES]; + image = MSHookIvar(view, "_snapshotImageView").image; + } else { + _SBAppSwitcherSnapshotContext *snapshotContext = MSHookIvar<_SBAppSwitcherSnapshotContext*>(view, "_snapshotContext"); + SBSwitcherSnapshotImageView *snapshotImageView = snapshotContext.snapshotImageView; + image = snapshotImageView.image; + } } - if (!image) - { + if (!image) { SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:identifier]; - if (app && app.mainSceneID) - { - @try - { + if (app && app.mainSceneID) { + @try { CGRect frame = CGRectMake(0, 0, 0, 0); UIView *view = [%c(SBUIController) _zoomViewWithSplashboardLaunchImageForApplication:app sceneID:app.mainSceneID screen:UIScreen.mainScreen interfaceOrientation:0 includeStatusBar:YES snapshotFrame:&frame]; - if (view) - { - UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, [UIScreen mainScreen].scale); - CGContextRef c = UIGraphicsGetCurrentContext(); - //CGContextSetAllowsAntialiasing(c, YES); - [view.layer performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; + if (view) { + UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 0); + + ON_MAIN_THREAD(^{ + [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES]; + }); + image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - view.layer.contents = nil; } } - @catch (NSException *ex) - { - NSLog(@"[ReachApp] error generating snapshot: %@", ex); + @catch (NSException *ex) { + LogError(@"[ReachApp] error generating snapshot: %@", ex); } } - if (!image) // we can only hope it does not reach this point of desperation + if (!image) { // we can only hope it does not reach this point of desperation image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/Default.png", app.path]]; + } } - if (image) - { + if (image) { [imageCache setObject:image forKey:identifier]; } @@ -90,73 +87,61 @@ } } --(UIImage*) snapshotForIdentifier:(NSString*)identifier -{ +- (UIImage*)snapshotForIdentifier:(NSString*)identifier { return [self snapshotForIdentifier:identifier orientation:UIApplication.sharedApplication.statusBarOrientation]; } --(void) forceReloadOfSnapshotForIdentifier:(NSString*)identifier -{ +- (void)forceReloadOfSnapshotForIdentifier:(NSString*)identifier { [imageCache removeObjectForKey:identifier]; } --(UIImage*) storedSnapshotOfMissionControl -{ +- (UIImage*)storedSnapshotOfMissionControl { return [imageCache objectForKey:@"missioncontrol"]; } --(void) storeSnapshotOfMissionControl:(UIWindow*)window -{ - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].RA_interfaceOrientedBounds.size, YES, [UIScreen mainScreen].scale); - //CGContextRef c = UIGraphicsGetCurrentContext(); - //CGContextSetAllowsAntialiasing(c, YES); - //[window.layer performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; - - ON_MAIN_THREAD(^{ - [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES]; - }); +- (void)storeSnapshotOfMissionControl:(UIWindow*)window { + UIGraphicsBeginImageContextWithOptions(window.bounds.size, YES, 0); - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - window.layer.contents = nil; + [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES]; - if (image) - [imageCache setObject:image forKey:@"missioncontrol"]; - }); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + if (image) { + [imageCache setObject:image forKey:@"missioncontrol"]; + } } --(NSString*) createKeyForDesktop:(RADesktopWindow*)desktop -{ +- (NSString*)createKeyForDesktop:(RADesktopWindow*)desktop { return [NSString stringWithFormat:@"desktop-%lu", (unsigned long)desktop.hash]; } --(UIImage*) snapshotForDesktop:(RADesktopWindow*)desktop -{ +- (UIImage*)snapshotForDesktop:(RADesktopWindow*)desktop { NSString *key = [self createKeyForDesktop:desktop]; - if ([imageCache objectForKey:key] != nil) return [imageCache objectForKey:key]; + if ([imageCache objectForKey:key]) { + return [imageCache objectForKey:key]; + } UIImage *img = [self renderPreviewForDesktop:desktop]; - if (img) + if (img) { [imageCache setObject:img forKey:key]; + } return img; } --(void) forceReloadSnapshotOfDesktop:(RADesktopWindow*)desktop -{ +- (void)forceReloadSnapshotOfDesktop:(RADesktopWindow*)desktop { [imageCache removeObjectForKey:[self createKeyForDesktop:desktop]]; } -- (UIImage*)rotateImageToMatchOrientation:(UIImage*)oldImage -{ +- (UIImage*)rotateImageToMatchOrientation:(UIImage*)oldImage { CGFloat degrees = 0; - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight) { degrees = 270; - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { degrees = 90; - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { degrees = 180; + } // https://stackoverflow.com/questions/20764623/rotate-newly-created-ios-image-90-degrees-prior-to-saving-as-png @@ -193,90 +178,84 @@ return newImage; } --(UIImage*) renderPreviewForDesktop:(RADesktopWindow*)desktop -{ +- (UIImage*)renderPreviewForDesktop:(RADesktopWindow*)desktop { @autoreleasepool { - UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen.bounds.size, YES, UIScreen.mainScreen.scale); - CGContextRef c = UIGraphicsGetCurrentContext(); + UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); - [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; + [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; ON_MAIN_THREAD(^{ - [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; + [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; //}); - [MSHookIvar([%c(SBWallpaperController) sharedInstance], "_wallpaperWindow").layer performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; // Wallpaper + UIImage *image = [self wallpaperImage:NO]; + CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height); + //since drawInRect doesnt work + CGContextTranslateCTM(context, 0, image.size.height); + CGContextScaleCTM(context, 1.0, -1.0); + + CGContextDrawImage(context, imageRect, image.CGImage); // Wallpaper + + CGContextScaleCTM(context, 1.0, -1.0); + CGContextTranslateCTM(context, 0, -imageRect.size.height); //[[[[%c(SBUIController) sharedInstance] window] layer] performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; // Icons //ON_MAIN_THREAD(^{ //[MSHookIvar([%c(SBWallpaperController) sharedInstance], "_wallpaperWindow") drawViewHierarchyInRect:UIScreen.mainScreen.bounds afterScreenUpdates:YES]; - - [[[%c(SBUIController) sharedInstance] window] drawViewHierarchyInRect:UIScreen.mainScreen.bounds afterScreenUpdates:YES]; - - [desktop drawViewHierarchyInRect:UIScreen.mainScreen.bounds afterScreenUpdates:YES]; + if (IS_IOS_OR_NEWER(iOS_9_0)) { //not sure why broken + UIView *view = [[%c(SBIconController) sharedInstance] view]; + [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; + } else { + [[[%c(SBUIController) sharedInstance] window] drawViewHierarchyInRect:[UIScreen mainScreen].bounds afterScreenUpdates:NO]; + } + + [desktop drawViewHierarchyInRect:desktop.bounds afterScreenUpdates:NO]; }); //[desktop.layer performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; // Desktop windows - - for (UIView *view in desktop.subviews) // Application views - { - if ([view isKindOfClass:[RAWindowBar class]]) - { - RAHostedAppView *hostedView = [((RAWindowBar*)view) attachedView]; - - UIImage *image = [self snapshotForIdentifier:hostedView.bundleIdentifier orientation:hostedView.orientation]; - CIImage *coreImage = image.CIImage; - if (!coreImage) - coreImage = [CIImage imageWithCGImage:image.CGImage]; - - //coreImage = [coreImage imageByApplyingTransform:view.transform]; - CGFloat rotation = atan2(hostedView.transform.b, hostedView.transform.a); - - CGAffineTransform transform = CGAffineTransformMakeRotation(rotation); - coreImage = [coreImage imageByApplyingTransform:transform]; - image = [UIImage imageWithCIImage:coreImage]; - [image drawInRect:view.frame]; // by using frame, we take care of scale. + + for (UIView *view in desktop.subviews) { // Application views + if (![view isKindOfClass:[RAWindowBar class]]) { + continue; + } + RAHostedAppView *hostedView = [((RAWindowBar*)view) attachedView]; + + UIImage *image = [self snapshotForIdentifier:hostedView.bundleIdentifier orientation:hostedView.orientation]; + CIImage *coreImage = image.CIImage; + if (!coreImage) { + coreImage = [CIImage imageWithCGImage:image.CGImage]; } + //coreImage = [coreImage imageByApplyingTransform:view.transform]; + CGFloat rotation = atan2(hostedView.transform.b, hostedView.transform.a); + + CGAffineTransform transform = CGAffineTransformMakeRotation(rotation); + coreImage = [coreImage imageByApplyingTransform:transform]; + image = [UIImage imageWithCIImage:coreImage]; + [image drawInRect:view.frame]; // by using frame, we take care of scale. } //if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) // CGContextRotateCTM(c, DEGREES_TO_RADIANS(90)); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); image = [self rotateImageToMatchOrientation:image]; - MSHookIvar([%c(SBWallpaperController) sharedInstance], "_wallpaperWindow").layer.contents = nil; - [[[%c(SBUIController) sharedInstance] window] layer].contents = nil; - desktop.layer.contents = nil; [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; return image; } } --(UIImage*) wallpaperImage -{ +- (UIImage*)wallpaperImage { return [self wallpaperImage:YES]; } --(UIImage*) wallpaperImage:(BOOL)blurred -{ +- (UIImage*)wallpaperImage:(BOOL)blurred { NSString *key = blurred ? @"wallpaperImageBlurred" : @"wallpaperImage"; - if ([imageCache objectForKey:key]) + if ([imageCache objectForKey:key]) { return [imageCache objectForKey:key]; + } + //its really that easy elijah (ok maybe i need to resize the image); + UIImage *oldImage = [[%c(SBWallpaperController) sharedInstance] sharedWallpaperView].displayedImage; + UIImage *image = [RAResourceImageProvider imageWithImage:oldImage scaledToSize:[UIScreen mainScreen].bounds.size]; - UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen.bounds.size, YES, UIScreen.mainScreen.scale); - CGContextRef c = UIGraphicsGetCurrentContext(); - - [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"RAWallpaperSnapshot"]; - - [MSHookIvar([%c(SBWallpaperController) sharedInstance], "_wallpaperWindow").layer performSelectorOnMainThread:@selector(renderInContext:) withObject:(__bridge id)c waitUntilDone:YES]; // Wallpaper - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - MSHookIvar([%c(SBWallpaperController) sharedInstance], "_wallpaperWindow").layer.contents = nil; - [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"RAWallpaperSnapshot"]; - - //UIImageView *imgView = [[UIImageView alloc] initWithImage:image];//Frame:(CGRect){CGPointZero,image.size}]; - //imgView.image = image; - - if (blurred) - { + if (blurred) { CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"]; [gaussianBlurFilter setDefaults]; CIImage *inputImage = [CIImage imageWithCGImage:[image CGImage]]; @@ -296,8 +275,7 @@ return image; } --(void) forceReloadEverything -{ +- (void)forceReloadEverything { [imageCache removeAllObjects]; } -@end \ No newline at end of file +@end diff --git a/README.md b/README.md index fd4fe15..94deb16 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ http://moreinfo.thebigboss.org/moreinfo/depiction.php?file=multiplexerDp - iOS 9-like "slide over" (Swipe Over) - Mission Control with multiple desktops (Mission Control) - Windowed multitasking (Empoleon) -- An app in a Notication Center tab (Quick Access) +- An app in a Notification Center tab (Quick Access) - Backgrounding features (Aura) ### Wiki @@ -18,22 +18,22 @@ See /wiki for some code tutorials. - Empoleon: working - fs daemon: working - SwipeOver: fixed -- Reachability: fixed +- Reachability: working - GestureSupport: fixed -- Backgrounding: fixed +- Backgrounding: working - KeyboardSupport: hackily fixed but it works now -- MissionControl: initialization broken, otherwise fixed +- MissionControl: fixed - NCApp: fixed -- assertiond hooks: unknown +- assertiond hooks: working - backboardd hooks: unknown -- fake phone mode: unknown +- fake phone mode: fixed see the update_status file for more info on the iOS 9 changes. ### API -There is a full public API (as opposed to the private/interval api and headers) that allows anyone to create addons, widgets, and tweaks (Tweakception!) for Multiplexer. +There is a full public API (as opposed to the private/interval api and headers) that allows anyone to create addons, widgets, and tweaks (Tweakception!) for Multiplexer. The public api can be found in public_api. This api is less likely to change or be removed as opposed to the other headers and stuff. For the end user's ease of use, please register your extensions with -[Multiplexer registerExtension:forMultiplexerVersion:]. I hope to also move the core functions into extensions, provide api requirements, etc at some point. Currently it is only compatible with iOS 8, however some measures have been taken to ease the process of making it compatible with other iOS editions (whether future or past). -There are some "options" or features that are in here but are disabled or otherwise removed because either they don't work or there's no point having them. +There are some "options" or features that are in here but are disabled or otherwise removed because either they don't work or there's no point having them. diff --git a/ReachAppIntegrator.h b/ReachAppIntegrator.h index 5dcb85a..95aa471 100644 --- a/ReachAppIntegrator.h +++ b/ReachAppIntegrator.h @@ -3,7 +3,8 @@ #import #define CHECK_FOR_REACHAPP \ -if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/ReachApp.dylib"]) \ - dlopen("/Library/MobileSubstrate/DynamicLibraries/ReachApp.dylib", RTLD_NOW | RTLD_GLOBAL); +if ([NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/ReachApp.dylib"]) { \ + dlopen("/Library/MobileSubstrate/DynamicLibraries/ReachApp.dylib", RTLD_NOW | RTLD_GLOBAL); \ +} -#define IF_REACHAPP if (objc_getClass("RAWidget") != nil) \ No newline at end of file +#define IF_REACHAPP if (objc_getClass("RAWidget") != nil) diff --git a/Reachability/RAReachabilityManager.h b/Reachability/RAReachabilityManager.h index 73e2940..82dbafb 100644 --- a/Reachability/RAReachabilityManager.h +++ b/Reachability/RAReachabilityManager.h @@ -3,11 +3,11 @@ @class RAAppSliderProviderView; @interface RAReachabilityManager : NSObject -+(id) sharedInstance; ++ (instancetype)sharedInstance; --(void) launchTopAppWithIdentifier:(NSString*)identifier; --(void) launchWidget:(RAWidget*)widget; --(void) showAppWithSliderProvider:(__weak RAAppSliderProviderView*)view; +- (void)launchTopAppWithIdentifier:(NSString*)identifier; +- (void)launchWidget:(RAWidget*)widget; +- (void)showAppWithSliderProvider:(__weak RAAppSliderProviderView*)view; --(void) showWidgetSelector; -@end \ No newline at end of file +- (void)showWidgetSelector; +@end diff --git a/Reachability/RAReachabilityManager.mm b/Reachability/RAReachabilityManager.mm index 0b06ef4..6cefcb4 100644 --- a/Reachability/RAReachabilityManager.mm +++ b/Reachability/RAReachabilityManager.mm @@ -5,34 +5,29 @@ #import "RAMessagingServer.h" @implementation RAReachabilityManager -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE(RAReachabilityManager); } --(void) launchTopAppWithIdentifier:(NSString*)identifier -{ +- (void)launchTopAppWithIdentifier:(NSString*)identifier { //[[objc_getClass("SBWorkspace") sharedInstance] RA_closeCurrentView]; [GET_SBWORKSPACE RA_launchTopAppWithIdentifier:identifier]; } --(void) launchWidget:(RAWidget*)widget -{ +- (void)launchWidget:(RAWidget*)widget { //[[objc_getClass("SBWorkspace") sharedInstance] RA_closeCurrentView]; [GET_SBWORKSPACE RA_setView:[widget view] preferredHeight:[widget preferredHeight]]; } --(void) showWidgetSelector -{ +- (void)showWidgetSelector { //[[objc_getClass("SBWorkspace") sharedInstance] RA_closeCurrentView]; [GET_SBWORKSPACE RA_showWidgetSelector]; } --(void) showAppWithSliderProvider:(__weak RAAppSliderProviderView*)view -{ +- (void)showAppWithSliderProvider:(__weak RAAppSliderProviderView*)view { //[[objc_getClass("SBWorkspace") sharedInstance] RA_closeCurrentView]; [view updateCurrentView]; [view load]; [GET_SBWORKSPACE RA_setView:view preferredHeight:view.frame.size.height]; } -@end \ No newline at end of file +@end diff --git a/Reachability/Reachability.xm b/Reachability/Reachability.xm index 4e67858..70729b2 100644 --- a/Reachability/Reachability.xm +++ b/Reachability/Reachability.xm @@ -11,17 +11,17 @@ #import "RAWidgetSectionManager.h" #import "RASettings.h" #import "RAAppSliderProviderView.h" +#import "RABackgrounder.h" #import "RADesktopManager.h" #import "RADesktopWindow.h" #import "RAMessagingServer.h" #import "RAAppSwitcherModelWrapper.h" - -#define SPRINGBOARD ([NSBundle.mainBundle.bundleIdentifier isEqual:@"com.apple.springboard"]) +#import "RAKeyboardStateListener.h" /*FBWindowContextHostWrapperView*/ UIView *view = nil; NSString *lastBundleIdentifier = @""; NSString *currentBundleIdentifier = @""; -UIViewController *ncViewController = nil; +SBNotificationCenterViewController *ncViewController = nil; UIView *draggerView = nil; BOOL overrideOrientation = NO; @@ -30,8 +30,8 @@ CGPoint firstLocation = CGPointZero; CGFloat grabberCenter_X = 0; BOOL showingNC = NO; BOOL overrideDisableForStatusBar = NO; -CGRect pre_topAppFrame = CGRectZero; -CGAffineTransform pre_topAppTransform = CGAffineTransformIdentity; +//CGRect pre_topAppFrame = CGRectZero; +//CGAffineTransform pre_topAppTransform = CGAffineTransformIdentity; UIView *bottomDraggerView = nil; CGFloat old_grabberCenterY = -1; @@ -40,814 +40,778 @@ BOOL wasEnabled = NO; %group hooks %hook SBReachabilityManager -+(BOOL)reachabilitySupported -{ - return YES; ++ (BOOL)reachabilitySupported { + return YES; } -- (void)_handleReachabilityActivated -{ - overrideOrientation = YES; - %orig; - overrideOrientation = NO; +- (void)_handleReachabilityActivated { + overrideOrientation = YES; + %orig; + overrideOrientation = NO; } -- (void)enableExpirationTimerForEndedInteraction -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return; - %orig; +- (void)enableExpirationTimerForEndedInteraction { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return; + } + %orig; } -- (void)_handleSignificantTimeChanged -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return; - %orig; +- (void)_handleSignificantTimeChanged { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return; + } + %orig; } -- (void)_keepAliveTimerFired:(unsafe_id)arg1 -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return; - %orig; +- (void)_keepAliveTimerFired:(unsafe_id)arg1 { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return; + } + %orig; } -- (void)_setKeepAliveTimerForDuration:(double)arg1 -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return; - %orig; +- (void)_setKeepAliveTimerForDuration:(double)arg1 { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return; + } + %orig; } -- (void)deactivateReachabilityModeForObserver:(unsafe_id)arg1 -{ - if (overrideDisableForStatusBar) - return; - %orig; - - if (wasEnabled) - { - wasEnabled = NO; - // Notify both top and bottom apps Reachability is closing - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [(RAAppSliderProviderView*)view unload]; - [view removeFromSuperview]; - view = nil; - } - if (lastBundleIdentifier && lastBundleIdentifier.length > 0) - { - [RAMessagingServer.sharedInstance endResizingApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:lastBundleIdentifier completion:nil]; - } - if (currentBundleIdentifier) - [RAMessagingServer.sharedInstance endResizingApp:currentBundleIdentifier completion:nil]; - [GET_SBWORKSPACE RA_closeCurrentView]; - } - +- (void)deactivateReachabilityModeForObserver:(unsafe_id)arg1 { + //Disable for keyboard here + if (overrideDisableForStatusBar || [RAKeyboardStateListener sharedInstance].visible) { + return; + } + %orig; + + if (wasEnabled) { + wasEnabled = NO; + // Notify both top and bottom apps Reachability is closing + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [(RAAppSliderProviderView*)view unload]; + [view removeFromSuperview]; + view = nil; + } + if (lastBundleIdentifier && lastBundleIdentifier.length > 0) { + [RAMessagingServer.sharedInstance endResizingApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:lastBundleIdentifier completion:nil]; + } + if (currentBundleIdentifier) { + [RAMessagingServer.sharedInstance endResizingApp:currentBundleIdentifier completion:nil]; + } + [GET_SBWORKSPACE RA_closeCurrentView]; + } } -- (void)_handleReachabilityDeactivated -{ - if (overrideDisableForStatusBar) - return; - - %orig; +- (void)_handleReachabilityDeactivated { + if (overrideDisableForStatusBar) { + return; + } + %orig; } -- (void)_updateReachabilityModeActive:(_Bool)arg1 withRequestingObserver:(unsafe_id)arg2 -{ - if (overrideDisableForStatusBar) - return; - %orig; +- (void)_updateReachabilityModeActive:(_Bool)arg1 withRequestingObserver:(unsafe_id)arg2 { + if (overrideDisableForStatusBar) { + return; + } + %orig; } %end %hook SBReachabilitySettings --(CGFloat) reachabilityDefaultKeepAlive -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return 9999999999; - return %orig; +- (CGFloat)reachabilityDefaultKeepAlive { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return 9999999999; + } + return %orig; } --(CGFloat) reachabilityInteractiveKeepAlive -{ - if ([RASettings.sharedInstance disableAutoDismiss]) - return 9999999999; - return %orig; +- (CGFloat)reachabilityInteractiveKeepAlive { + if ([RASettings.sharedInstance disableAutoDismiss]) { + return 9999999999; + } + return %orig; } %end id SBWorkspace$sharedInstance; %hook SB_WORKSPACE_CLASS -%new +(id) sharedInstance -{ - return SBWorkspace$sharedInstance; +%new + (instancetype)sharedInstance { + return SBWorkspace$sharedInstance; } --(id) init -{ - SBWorkspace$sharedInstance = %orig; - return SBWorkspace$sharedInstance; +- (id)init { + SBWorkspace$sharedInstance = %orig; + return SBWorkspace$sharedInstance; } -%new -(BOOL) isUsingReachApp -{ - return (view || showingNC); +%new - (BOOL)isUsingReachApp { + return (view || showingNC); } -- (void)_exitReachabilityModeWithCompletion:(unsafe_id)arg1 -{ - if (overrideDisableForStatusBar) - return; - - %orig; +- (void)_exitReachabilityModeWithCompletion:(unsafe_id)arg1 { + if (overrideDisableForStatusBar) { + return; + } + %orig; } -- (void)handleReachabilityModeDeactivated -{ - if (overrideDisableForStatusBar) - return; - - %orig; +- (void)handleReachabilityModeDeactivated { + if (overrideDisableForStatusBar) { + return; + } + %orig; } -%new -(void) RA_closeCurrentView -{ - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [(RAAppSliderProviderView*)view unload]; - [view removeFromSuperview]; - view = nil; - } +%new - (void)RA_closeCurrentView { + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [(RAAppSliderProviderView*)view unload]; + [view removeFromSuperview]; + view = nil; + } + + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:currentBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:currentBundleIdentifier completion:nil]; + + if ([RASettings.sharedInstance showNCInstead]) { + showingNC = NO; + UIWindow *window = MSHookIvar(self, "_reachabilityEffectWindow"); + [window _setRotatableViewOrientation:UIInterfaceOrientationPortrait updateStatusBar:YES duration:0.0 force:YES]; + window.rootViewController = nil; + SBNotificationCenterViewController *viewController = [[%c(SBNotificationCenterController) performSelector:@selector(sharedInstance)] performSelector:@selector(viewController)]; + if ([viewController respondsToSelector:@selector(hostWillDismiss)]) { + [viewController performSelector:@selector(hostWillDismiss)]; + [viewController performSelector:@selector(hostDidDismiss)]; + } else { + [viewController performSelector:@selector(_loadContainerView)]; + } + //[viewController.view removeFromSuperview]; + } else { + SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:currentBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:currentBundleIdentifier completion:nil]; - - if ([RASettings.sharedInstance showNCInstead]) - { - showingNC = NO; - UIWindow *window = MSHookIvar(self, "_reachabilityEffectWindow"); - [window _setRotatableViewOrientation:UIInterfaceOrientationPortrait updateStatusBar:YES duration:0.0 force:YES]; - window.rootViewController = nil; - UIViewController *viewController = [[%c(SBNotificationCenterController) performSelector:@selector(sharedInstance)] performSelector:@selector(viewController)]; - [viewController performSelector:@selector(hostWillDismiss)]; - [viewController performSelector:@selector(hostDidDismiss)]; - //[viewController.view removeFromSuperview]; + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + [((RAAppSliderProviderView*)view) unload]; } - else - { - SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - [((RAAppSliderProviderView*)view) unload]; - } - - // Give them a little time to receive the notifications... - if (view) - { - if ([view superview] != nil) - [view removeFromSuperview]; - } - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - if (lastBundleIdentifier && lastBundleIdentifier.length > 0) - { - if (app && [app pid] && [app mainScene]) - { - FBScene *scene = [app mainScene]; - FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; - SET_BACKGROUNDED(settings, YES); - [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; - MSHookIvar([app mainScene].contextHostManager, "_hostView").frame = pre_topAppFrame; - MSHookIvar([app mainScene].contextHostManager, "_hostView").transform = pre_topAppTransform; - - SBApplication *currentApp = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:currentBundleIdentifier]; - if ([currentApp mainScene]) - { - MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").frame = pre_topAppFrame; - MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").transform = pre_topAppTransform; - } - - FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; - [contextHostManager disableHostingForRequester:@"reachapp"]; - } - } - view = nil; - lastBundleIdentifier = nil; - }); + // Give them a little time to receive the notifications... + if (view && [view superview]) { + [view removeFromSuperview]; } -} + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + if (lastBundleIdentifier && lastBundleIdentifier.length > 0) { + if (app && [app pid] && [app mainScene]) { + FBScene *scene = [app mainScene]; + FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; + SET_BACKGROUNDED(settings, YES); + [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; + //MSHookIvar([app mainScene].contextHostManager, "_hostView").frame = pre_topAppFrame; + //MSHookIvar([app mainScene].contextHostManager, "_hostView").transform = pre_topAppTransform; -- (void)_disableReachabilityImmediately:(_Bool)arg1 -{ - if (overrideDisableForStatusBar) - return; - - %orig; + SBApplication *currentApp = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:currentBundleIdentifier]; + if ([currentApp mainScene]) { + //MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").frame = pre_topAppFrame; + //MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").transform = pre_topAppTransform; + } - if (![RASettings.sharedInstance reachabilityEnabled] && wasEnabled == NO) - { - return; - } - - if (arg1 && wasEnabled) - { - wasEnabled = NO; - - // Notify both top and bottom apps Reachability is closing - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [(RAAppSliderProviderView*)view unload]; - [view removeFromSuperview]; - view = nil; + FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; + [contextHostManager disableHostingForRequester:@"reachapp"]; } - if (lastBundleIdentifier && lastBundleIdentifier.length > 0) - { - [RAMessagingServer.sharedInstance endResizingApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:lastBundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:lastBundleIdentifier completion:nil]; - } - if (currentBundleIdentifier) - [RAMessagingServer.sharedInstance endResizingApp:currentBundleIdentifier completion:nil]; - - [self RA_closeCurrentView]; - if (draggerView) - draggerView = nil; - } + } + view = nil; + lastBundleIdentifier = nil; + }); + } } -- (void) handleReachabilityModeActivated -{ - %orig; - if (![RASettings.sharedInstance reachabilityEnabled]) - return; - wasEnabled = YES; - - CGFloat knobWidth = 60; - CGFloat knobHeight = 25; - draggerView = [[UIView alloc] initWithFrame:CGRectMake( - (UIScreen.mainScreen.bounds.size.width / 2) - (knobWidth / 2), - [UIScreen mainScreen].bounds.size.height * .3, - knobWidth, knobHeight)]; - draggerView.alpha = 0.3; - draggerView.layer.cornerRadius = 10; - grabberCenter_X = draggerView.center.x; +- (void)_disableReachabilityImmediately:(_Bool)arg1 { + //Disable for keyboard here + if (overrideDisableForStatusBar || [RAKeyboardStateListener sharedInstance].visible) { + return; + } - UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); - if ([RASettings.sharedInstance showNCInstead]) - { - showingNC = YES; + %orig; - if (ncViewController == nil) - ncViewController = [[%c(SBNotificationCenterViewController) alloc] init]; - ncViewController.view.frame = (CGRect) { { 0, 0 }, w.frame.size }; - w.rootViewController = ncViewController; - [w addSubview:ncViewController.view]; + if (![RASettings.sharedInstance reachabilityEnabled] && !wasEnabled) { + return; + } - //[[%c(SBNotificationCenterController) performSelector:@selector(sharedInstance)] performSelector:@selector(_setupForViewPresentation)]; - [ncViewController performSelector:@selector(hostWillPresent)]; - [ncViewController performSelector:@selector(hostDidPresent)]; + if (arg1 && wasEnabled) { + wasEnabled = NO; - if ([RASettings.sharedInstance enableRotation]) - { - [w _setRotatableViewOrientation:[UIApplication sharedApplication].statusBarOrientation updateStatusBar:YES duration:0.0 force:YES]; - } + // Notify both top and bottom apps Reachability is closing + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [(RAAppSliderProviderView*)view unload]; + [view removeFromSuperview]; + view = nil; } - else - { - currentBundleIdentifier = [[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier; - if (!currentBundleIdentifier) - return; - - if ([RASettings.sharedInstance showWidgetSelector]) - { - [self RA_showWidgetSelector]; - } - else - { - SBApplication *app = nil; - FBScene *scene = nil; - NSMutableArray *bundleIdentifiers = [[RAAppSwitcherModelWrapper appSwitcherAppIdentiferList] mutableCopy]; - while (scene == nil && bundleIdentifiers.count > 0) - { - lastBundleIdentifier = bundleIdentifiers[0]; - - if ([lastBundleIdentifier isEqual:currentBundleIdentifier]) - { - [bundleIdentifiers removeObjectAtIndex:0]; - continue; - } - - app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; - scene = [app mainScene]; - if (!scene) - if (bundleIdentifiers.count > 0) - [bundleIdentifiers removeObjectAtIndex:0]; - } - if (lastBundleIdentifier == nil || lastBundleIdentifier.length == 0) - return; - - [self RA_launchTopAppWithIdentifier:lastBundleIdentifier]; - } + if (lastBundleIdentifier && lastBundleIdentifier.length > 0) { + [RAMessagingServer.sharedInstance endResizingApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:lastBundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setHosted:NO forIdentifier:lastBundleIdentifier completion:nil]; } - - draggerView.backgroundColor = UIColor.lightGrayColor; - UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - if (grabberCenter_Y == -1) - grabberCenter_Y = w.frame.size.height - (knobHeight / 2); - if (grabberCenter_Y < 0) - grabberCenter_Y = UIScreen.mainScreen.bounds.size.height * 0.3; - draggerView.center = CGPointMake(grabberCenter_X, grabberCenter_Y); - recognizer.delegate = (id)self; - [draggerView addGestureRecognizer:recognizer]; - - UILongPressGestureRecognizer *recognizer2 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(RA_handleLongPress:)]; - recognizer2.delegate = (id)self; - [draggerView addGestureRecognizer:recognizer2]; - - UITapGestureRecognizer *recognizer3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(RA_detachAppAndClose:)]; - recognizer3.numberOfTapsRequired = 2; - recognizer3.delegate = (id)self; - [draggerView addGestureRecognizer:recognizer3]; - - [w addSubview:draggerView]; - - if ([RASettings.sharedInstance showBottomGrabber]) - { - bottomDraggerView = [[UIView alloc] initWithFrame:CGRectMake( - (UIScreen.mainScreen.bounds.size.width / 2) - (knobWidth / 2), - -(knobHeight / 2), - knobWidth, knobHeight)]; - bottomDraggerView.alpha = 0.3; - bottomDraggerView.layer.cornerRadius = 10; - bottomDraggerView.backgroundColor = UIColor.lightGrayColor; - [bottomDraggerView addGestureRecognizer:recognizer]; - [MSHookIvar(self,"_reachabilityWindow") addSubview:bottomDraggerView]; + if (currentBundleIdentifier) { + [RAMessagingServer.sharedInstance endResizingApp:currentBundleIdentifier completion:nil]; } - // Update sizes of reachability (and their contained apps) and the location of the dragger view - [self updateViewSizes:draggerView.center animate:NO]; -} - -%new -(void)RA_showWidgetSelector -{ - if (view) - [self RA_closeCurrentView]; - - UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); - //CGSize iconSize = [%c(SBIconView) defaultIconImageSize]; - static CGSize fullSize = [%c(SBIconView) defaultIconSize]; - fullSize.height = fullSize.width; // otherwise it often looks like {60,74} - CGFloat padding = 20; - - NSInteger numIconsPerLine = 0; - CGFloat tmpWidth = 10; - while (tmpWidth + fullSize.width <= w.frame.size.width) - { - numIconsPerLine++; - tmpWidth += fullSize.width + 20; + [self RA_closeCurrentView]; + if (draggerView) { + draggerView = nil; } - padding = (w.frame.size.width - (numIconsPerLine * fullSize.width)) / numIconsPerLine; - - UIView *widgetSelectorView = [[RAWidgetSectionManager sharedInstance] createViewForEnabledSectionsWithBaseFrame:w.frame preferredIconSize:fullSize iconsThatFitPerLine:numIconsPerLine spacing:padding]; - widgetSelectorView.frame = (CGRect){ { 0, 0 }, widgetSelectorView.frame.size }; - //widgetSelectorView.frame = w.frame; - - if (draggerView) - [w insertSubview:widgetSelectorView belowSubview:draggerView]; - else - [w addSubview:widgetSelectorView]; - view = widgetSelectorView; - - if ([RASettings.sharedInstance autoSizeWidgetSelector]) - { - CGFloat moddedHeight = widgetSelectorView.frame.size.height; - if (old_grabberCenterY == -1) - old_grabberCenterY = UIScreen.mainScreen.bounds.size.height * 0.3; - old_grabberCenterY = grabberCenter_Y; - grabberCenter_Y = moddedHeight; - } - CGPoint newCenter = CGPointMake(draggerView.center.x, grabberCenter_Y); - draggerView.center = newCenter; - draggerView.hidden = YES; - [self updateViewSizes:newCenter animate:YES]; + } } -CGFloat startingY = -1; -%new -(void)handlePan:(UIPanGestureRecognizer*)sender -{ - UIView *view = draggerView; //sender.view; - - if (sender.state == UIGestureRecognizerStateBegan) - { - startingY = grabberCenter_Y; - grabberCenter_X = view.center.x; - firstLocation = view.center; - grabberCenter_Y = [sender locationInView:view.superview].y; - draggerView.alpha = 0.8; - bottomDraggerView.alpha = 0; - } - else if (sender.state == UIGestureRecognizerStateChanged) - { - CGPoint translation = [sender translationInView:view]; - - if (firstLocation.y + translation.y < 50) - { - view.center = CGPointMake(grabberCenter_X, 50); - grabberCenter_Y = 50; - } - else if (firstLocation.y + translation.y > UIScreen.mainScreen.bounds.size.height - 30) - { - view.center = CGPointMake(grabberCenter_X, UIScreen.mainScreen.bounds.size.height - 30); - grabberCenter_Y = UIScreen.mainScreen.bounds.size.height - 30; - } - else - { - view.center = CGPointMake(grabberCenter_X, firstLocation.y + translation.y); - grabberCenter_Y = [sender locationInView:view.superview].y; +- (void)handleReachabilityModeActivated { + %orig; + if (![RASettings.sharedInstance reachabilityEnabled]) { + return; + } + wasEnabled = YES; + + CGFloat knobWidth = 60; + CGFloat knobHeight = 25; + draggerView = [[UIView alloc] initWithFrame:CGRectMake( + (UIScreen.mainScreen.bounds.size.width / 2) - (knobWidth / 2), + [UIScreen mainScreen].bounds.size.height * .3, + knobWidth, knobHeight)]; + draggerView.alpha = 0.3; + draggerView.layer.cornerRadius = 10; + grabberCenter_X = draggerView.center.x; + + UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); + if ([RASettings.sharedInstance showNCInstead]) { + showingNC = YES; + + if (!ncViewController) { + ncViewController = [[%c(SBNotificationCenterViewController) alloc] init]; + } + ncViewController.view.frame = (CGRect) { { 0, 0 }, w.frame.size }; + w.rootViewController = ncViewController; + [w addSubview:ncViewController.view]; + + //[[%c(SBNotificationCenterController) performSelector:@selector(sharedInstance)] performSelector:@selector(_setupForViewPresentation)]; + if ([ncViewController respondsToSelector:@selector(hostWillPresent)]) { + [ncViewController performSelector:@selector(hostWillPresent)]; + [ncViewController performSelector:@selector(hostDidPresent)]; + } else { + [ncViewController _loadContainerView]; + } + + if ([RASettings.sharedInstance enableRotation]) { + [w _setRotatableViewOrientation:[UIApplication sharedApplication].statusBarOrientation updateStatusBar:YES duration:0.0 force:YES]; + } + } else { + currentBundleIdentifier = [[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier; + if (!currentBundleIdentifier) { + return; + } + + if ([RASettings.sharedInstance showWidgetSelector]) { + [self RA_showWidgetSelector]; + } else { + SBApplication *app = nil; + FBScene *scene = nil; + NSMutableArray *bundleIdentifiers = [[RAAppSwitcherModelWrapper appSwitcherAppIdentiferList] mutableCopy]; + while (!scene && bundleIdentifiers.count > 0) { + lastBundleIdentifier = bundleIdentifiers[0]; + + if ([lastBundleIdentifier isEqual:currentBundleIdentifier]) { + [bundleIdentifiers removeObjectAtIndex:0]; + continue; } - [self updateViewSizes:view.center animate:YES]; - } - else if (sender.state == UIGestureRecognizerStateEnded) - { - draggerView.alpha = 0.3; - bottomDraggerView.alpha = 0.3; - if (startingY != -1 && fabs(grabberCenter_Y - startingY) < 3) - [self RA_handleLongPress:nil]; - startingY = -1; - [self updateViewSizes:view.center animate:YES]; - } + app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; + scene = [app mainScene]; + if (!scene && bundleIdentifiers.count > 0) { + [bundleIdentifiers removeObjectAtIndex:0]; + } + } + if (!lastBundleIdentifier || lastBundleIdentifier.length == 0) { + return; + } + + [self RA_launchTopAppWithIdentifier:lastBundleIdentifier]; + } + } + + draggerView.backgroundColor = UIColor.lightGrayColor; + UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; + if (grabberCenter_Y == -1) { + grabberCenter_Y = w.frame.size.height - (knobHeight / 2); + } + if (grabberCenter_Y < 0) { + grabberCenter_Y = UIScreen.mainScreen.bounds.size.height * 0.3; + } + draggerView.center = CGPointMake(grabberCenter_X, grabberCenter_Y); + recognizer.delegate = (id)self; + [draggerView addGestureRecognizer:recognizer]; + + UILongPressGestureRecognizer *recognizer2 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(RA_handleLongPress:)]; + recognizer2.delegate = (id)self; + [draggerView addGestureRecognizer:recognizer2]; + + UITapGestureRecognizer *recognizer3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(RA_detachAppAndClose:)]; + recognizer3.numberOfTapsRequired = 2; + recognizer3.delegate = (id)self; + [draggerView addGestureRecognizer:recognizer3]; + + [w addSubview:draggerView]; + + if ([RASettings.sharedInstance showBottomGrabber]) { + bottomDraggerView = [[UIView alloc] initWithFrame:CGRectMake( + (UIScreen.mainScreen.bounds.size.width / 2) - (knobWidth / 2), + -(knobHeight / 2), + knobWidth, knobHeight)]; + bottomDraggerView.alpha = 0.3; + bottomDraggerView.layer.cornerRadius = 10; + bottomDraggerView.backgroundColor = UIColor.lightGrayColor; + [bottomDraggerView addGestureRecognizer:recognizer]; + [MSHookIvar(self,"_reachabilityWindow") addSubview:bottomDraggerView]; + } + + // Update sizes of reachability (and their contained apps) and the location of the dragger view + [self updateViewSizes:draggerView.center animate:NO]; } -%new -(void) RA_handleLongPress:(UILongPressGestureRecognizer*)gesture -{ - [self RA_showWidgetSelector]; +%new - (void)RA_showWidgetSelector { + if (view) { + [self RA_closeCurrentView]; + } + + UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); + //CGSize iconSize = [%c(SBIconView) defaultIconImageSize]; + static CGSize fullSize = [%c(SBIconView) defaultIconSize]; + fullSize.height = fullSize.width; // otherwise it often looks like {60,74} + CGFloat padding = 20; + + NSInteger numIconsPerLine = 0; + CGFloat tmpWidth = 10; + while (tmpWidth + fullSize.width <= w.frame.size.width) { + numIconsPerLine++; + tmpWidth += fullSize.width + 20; + } + padding = (w.frame.size.width - (numIconsPerLine * fullSize.width)) / numIconsPerLine; + + UIView *widgetSelectorView = [[RAWidgetSectionManager sharedInstance] createViewForEnabledSectionsWithBaseFrame:w.frame preferredIconSize:fullSize iconsThatFitPerLine:numIconsPerLine spacing:padding]; + widgetSelectorView.frame = (CGRect){ { 0, 0 }, widgetSelectorView.frame.size }; + //widgetSelectorView.frame = w.frame; + + if (draggerView) { + [w insertSubview:widgetSelectorView belowSubview:draggerView]; + } else { + [w addSubview:widgetSelectorView]; + } + view = widgetSelectorView; + + if ([RASettings.sharedInstance autoSizeWidgetSelector]) { + CGFloat moddedHeight = widgetSelectorView.frame.size.height; + if (old_grabberCenterY == -1) { + old_grabberCenterY = UIScreen.mainScreen.bounds.size.height * 0.3; + } + old_grabberCenterY = grabberCenter_Y; + grabberCenter_Y = moddedHeight; + } + CGPoint newCenter = CGPointMake(draggerView.center.x, grabberCenter_Y); + draggerView.center = newCenter; + draggerView.hidden = YES; + [self updateViewSizes:newCenter animate:YES]; } -%new -(void) RA_detachAppAndClose:(UITapGestureRecognizer*)gesture -{ - NSString *ident = lastBundleIdentifier; - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - RAAppSliderProviderView *temp = (RAAppSliderProviderView*)view; - ident = temp.currentBundleIdentifier; - [temp unload]; +CGFloat startingY = -1; +%new - (void)handlePan:(UIPanGestureRecognizer*)sender { + UIView *view = draggerView; //sender.view; + + if (sender.state == UIGestureRecognizerStateBegan) { + startingY = grabberCenter_Y; + grabberCenter_X = view.center.x; + firstLocation = view.center; + grabberCenter_Y = [sender locationInView:view.superview].y; + draggerView.alpha = 0.8; + bottomDraggerView.alpha = 0; + } else if (sender.state == UIGestureRecognizerStateChanged) { + CGPoint translation = [sender translationInView:view]; + + if (firstLocation.y + translation.y < 50) { + view.center = CGPointMake(grabberCenter_X, 50); + grabberCenter_Y = 50; + } else if (firstLocation.y + translation.y > UIScreen.mainScreen.bounds.size.height - 30) { + view.center = CGPointMake(grabberCenter_X, UIScreen.mainScreen.bounds.size.height - 30); + grabberCenter_Y = UIScreen.mainScreen.bounds.size.height - 30; + } else { + view.center = CGPointMake(grabberCenter_X, firstLocation.y + translation.y); + grabberCenter_Y = [sender locationInView:view.superview].y; + } + + [self updateViewSizes:view.center animate:YES]; + } else if (sender.state == UIGestureRecognizerStateEnded) { + draggerView.alpha = 0.3; + bottomDraggerView.alpha = 0.3; + if (startingY != -1 && fabs(grabberCenter_Y - startingY) < 3) { + [self RA_handleLongPress:nil]; } + startingY = -1; + [self updateViewSizes:view.center animate:YES]; + } +} - if (!ident || ident.length == 0) - return; +%new - (void)RA_handleLongPress:(UILongPressGestureRecognizer*)gesture { + [self RA_showWidgetSelector]; +} - [self handleReachabilityModeDeactivated]; +%new - (void)RA_detachAppAndClose:(UITapGestureRecognizer*)gesture { + NSString *ident = lastBundleIdentifier; + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + RAAppSliderProviderView *temp = (RAAppSliderProviderView*)view; + ident = temp.currentBundleIdentifier; + [temp unload]; + } + + if (!ident || ident.length == 0) { + return; + } + + [self handleReachabilityModeDeactivated]; + SBApplication *app = [[%c(SBApplicationController) sharedInstance] RA_applicationWithBundleIdentifier:ident]; + RAIconIndicatorViewInfo indicatorInfo = [[%c(RABackgrounder) sharedInstance] allAggregatedIndicatorInfoForIdentifier:ident]; + + // Close app + [[%c(RABackgrounder) sharedInstance] temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:app andCloseForegroundApp:NO]; + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBDeactivationSettings *deactiveSets = [[%c(SBDeactivationSettings) alloc] init]; + [deactiveSets setFlag:YES forDeactivationSetting:20]; + [deactiveSets setFlag:NO forDeactivationSetting:2]; + [app _setDeactivationSettings:deactiveSets]; + + // Open in window [RADesktopManager.sharedInstance.currentDesktop createAppWindowWithIdentifier:ident animated:YES]; -} + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; -%new - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ - if ([view isKindOfClass:[UIScrollView class]]) - return NO; - return YES; + // Pop forced foreground backgrounding + [[%c(RABackgrounder) sharedInstance] queueRemoveTemporaryOverrideForIdentifier:ident]; + [[%c(RABackgrounder) sharedInstance] removeTemporaryOverrideForIdentifier:ident]; + [[%c(RABackgrounder) sharedInstance] updateIconIndicatorForIdentifier:ident withInfo:indicatorInfo]; } -%new -(void) RA_updateViewSizes -{ - [self updateViewSizes:draggerView.center animate:YES]; +%new - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + if ([view isKindOfClass:[UIScrollView class]]) { + return NO; + } + return YES; } -%new -(void) updateViewSizes:(CGPoint) center animate:(BOOL)animate -{ - // Resizing - UIWindow *topWindow = MSHookIvar(self, "_reachabilityEffectWindow"); - UIWindow *bottomWindow = MSHookIvar(self, "_reachabilityWindow"); - - CGRect topFrame = CGRectMake(topWindow.frame.origin.x, topWindow.frame.origin.y, topWindow.frame.size.width, center.y); - CGRect bottomFrame = CGRectMake(bottomWindow.frame.origin.x, center.y, bottomWindow.frame.size.width, UIScreen.mainScreen._referenceBounds.size.height - center.y); - - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { - topFrame = CGRectMake(topWindow.frame.origin.x, 0, topWindow.frame.size.width, center.y); - bottomFrame = CGRectMake(bottomWindow.frame.origin.x, center.y, bottomWindow.frame.size.width, UIScreen.mainScreen._referenceBounds.size.height - center.y); - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) - { - - } - - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - RAAppSliderProviderView *sliderView = (RAAppSliderProviderView*)view; - sliderView.frame = topFrame; - } - - /*if ([RASettings.sharedInstance flipTopAndBottom]) - { - CGRect tmp = topFrame; - topFrame = bottomFrame; - bottomFrame = tmp; - }*/ - - if (animate) - { - [UIView animateWithDuration:0.3 animations:^{ - bottomWindow.frame = bottomFrame; - topWindow.frame = topFrame; - if (view && [view isKindOfClass:[UIScrollView class]]) - view.frame = topFrame; - }]; - } - else - { - bottomWindow.frame = bottomFrame; - topWindow.frame = topFrame; - if (view && [view isKindOfClass:[UIScrollView class]]) - view.frame = topFrame; - } - - if ([RASettings.sharedInstance showNCInstead]) - { - if (ncViewController) - ncViewController.view.frame = (CGRect) { { 0, 0 }, topFrame.size }; - } - else if (lastBundleIdentifier != nil || [view isKindOfClass:[RAAppSliderProviderView class]]) - { - // Notify clients - - CGFloat width = - 1, height = -1; - - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - RAAppSliderProviderView *sliderView = (RAAppSliderProviderView*)view; - //width = sliderView.clientFrame.size.width; - //height = sliderView.clientFrame.size.height; - - - if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - width = center.y; - height = topWindow.frame.size.width; - } - else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { - //width = topWindow.frame.size.height; - width = bottomWindow.frame.origin.y; - height = topWindow.frame.size.width; - } - else - { - width = sliderView.clientFrame.size.width; - height = sliderView.clientFrame.size.height; - } - } - else - { - if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - width = center.y; - height = topWindow.frame.size.width; - } - else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { - width = bottomWindow.frame.origin.y; - height = topWindow.frame.size.width; - } - else - { - width = topWindow.frame.size.width; - height = topWindow.frame.size.height; - } - } - - NSString *targetIdentifier = lastBundleIdentifier; - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - targetIdentifier = [((RAAppSliderProviderView*)view) currentBundleIdentifier]; - - if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - [RAMessagingServer.sharedInstance moveApp:targetIdentifier toOrigin:CGPointMake(bottomWindow.frame.size.height, 0) completion:nil]; - - [RAMessagingServer.sharedInstance resizeApp:targetIdentifier toSize:CGSizeMake(width, height) completion:nil]; - } - - if ([view isKindOfClass:[%c(FBWindowContextHostWrapperView) class]] == NO && [view isKindOfClass:[RAAppSliderProviderView class]] == NO) - return; // only resize when the app is being shown. That way it's more like native Reachability - - [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:currentBundleIdentifier completion:nil]; - - [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; - - CGFloat width = -1, height = -1; - - if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - width = bottomWindow.frame.size.height; - height = bottomWindow.frame.size.width; - } - else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) - { - //width = center.y; - width = bottomWindow.frame.size.height; - height = bottomWindow.frame.size.width; - - [RAMessagingServer.sharedInstance moveApp:currentBundleIdentifier toOrigin:CGPointMake(bottomWindow.frame.origin.y, 0) completion:nil]; - } - else - { - width = bottomWindow.frame.size.width; - height = bottomWindow.frame.size.height; - } - [RAMessagingServer.sharedInstance resizeApp:currentBundleIdentifier toSize:CGSizeMake(width, height) completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:currentBundleIdentifier completion:nil]; +%new - (void)RA_updateViewSizes { + [self updateViewSizes:draggerView.center animate:YES]; +} - if ([RASettings.sharedInstance unifyStatusBar]) - [RAMessagingServer.sharedInstance forceStatusBarVisibility:NO forApp:currentBundleIdentifier completion:nil]; +%new - (void)updateViewSizes:(CGPoint)center animate:(BOOL)animate { + // Resizing + UIWindow *topWindow = MSHookIvar(self, "_reachabilityEffectWindow"); + UIWindow *bottomWindow = MSHookIvar(self, "_reachabilityWindow"); + + CGRect topFrame = CGRectMake(topWindow.frame.origin.x, topWindow.frame.origin.y, topWindow.frame.size.width, center.y); + CGRect bottomFrame = CGRectMake(bottomWindow.frame.origin.x, center.y, bottomWindow.frame.size.width, UIScreen.mainScreen._referenceBounds.size.height - center.y); + + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { + topFrame = CGRectMake(topWindow.frame.origin.x, 0, topWindow.frame.size.width, center.y); + bottomFrame = CGRectMake(bottomWindow.frame.origin.x, center.y, bottomWindow.frame.size.width, UIScreen.mainScreen._referenceBounds.size.height - center.y); + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) { + + } + + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + RAAppSliderProviderView *sliderView = (RAAppSliderProviderView*)view; + sliderView.frame = topFrame; + } + + /*if ([RASettings.sharedInstance flipTopAndBottom]) + { + CGRect tmp = topFrame; + topFrame = bottomFrame; + bottomFrame = tmp; + }*/ + + if (animate) { + [UIView animateWithDuration:0.3 animations:^{ + bottomWindow.frame = bottomFrame; + topWindow.frame = topFrame; + if (view && [view isKindOfClass:[UIScrollView class]]) { + view.frame = topFrame; + } + }]; + } else { + bottomWindow.frame = bottomFrame; + topWindow.frame = topFrame; + if (view && [view isKindOfClass:[UIScrollView class]]) { + view.frame = topFrame; + } + } + + if ([RASettings.sharedInstance showNCInstead] && ncViewController) { + ncViewController.view.frame = (CGRect) { { 0, 0 }, topFrame.size }; + } else if (lastBundleIdentifier || [view isKindOfClass:[RAAppSliderProviderView class]]) { + // Notify clients + + CGFloat width = - 1, height = -1; + + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + RAAppSliderProviderView *sliderView = (RAAppSliderProviderView*)view; + //width = sliderView.clientFrame.size.width; + //height = sliderView.clientFrame.size.height; + + + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + width = center.y; + height = topWindow.frame.size.width; + } else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { + //width = topWindow.frame.size.height; + width = bottomWindow.frame.origin.y; + height = topWindow.frame.size.width; + } else { + width = sliderView.clientFrame.size.width; + height = sliderView.clientFrame.size.height; + } + } else { + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + width = center.y; + height = topWindow.frame.size.width; + } else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { + width = bottomWindow.frame.origin.y; + height = topWindow.frame.size.width; + } else { + width = topWindow.frame.size.width; + height = topWindow.frame.size.height; + } + } + + NSString *targetIdentifier = lastBundleIdentifier; + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + targetIdentifier = [((RAAppSliderProviderView*)view) currentBundleIdentifier]; + } + + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { + [RAMessagingServer.sharedInstance moveApp:targetIdentifier toOrigin:CGPointMake(bottomWindow.frame.size.height, 0) completion:nil]; + } + + [RAMessagingServer.sharedInstance resizeApp:targetIdentifier toSize:CGSizeMake(width, height) completion:nil]; + } + + if (![view isKindOfClass:[%c(FBWindowContextHostWrapperView) class]] && ![view isKindOfClass:[RAAppSliderProviderView class]] && IS_IOS_OR_OLDER(iOS_8_4)) { + return; // only resize when the app is being shown. That way it's more like native Reachability + } + + if (![view isKindOfClass:[%c(FBSceneHostWrapperView) class]] && ![view isKindOfClass:[RAAppSliderProviderView class]] && IS_IOS_OR_NEWER(iOS_9_0)) { + return; // iOS 9 + } + + [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:currentBundleIdentifier completion:nil]; + + [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; + + CGFloat width = -1, height = -1; + + if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) { + width = bottomWindow.frame.size.height; + height = bottomWindow.frame.size.width; + } else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) { + //width = center.y; + width = bottomWindow.frame.size.height; + height = bottomWindow.frame.size.width; + + [RAMessagingServer.sharedInstance moveApp:currentBundleIdentifier toOrigin:CGPointMake(bottomWindow.frame.origin.y, 0) completion:nil]; + } else { + width = bottomWindow.frame.size.width; + height = bottomWindow.frame.size.height; + } + [RAMessagingServer.sharedInstance resizeApp:currentBundleIdentifier toSize:CGSizeMake(width, height) completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:currentBundleIdentifier completion:nil]; + + if ([RASettings.sharedInstance unifyStatusBar]) { + [RAMessagingServer.sharedInstance forceStatusBarVisibility:NO forApp:currentBundleIdentifier completion:nil]; + } } -%new -(void) RA_launchTopAppWithIdentifier:(NSString*) bundleIdentifier -{ - UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); - SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; - FBScene *scene = [app mainScene]; - if (app == nil) - return; +%new - (void)RA_launchTopAppWithIdentifier:(NSString*)bundleIdentifier { + UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); + SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:lastBundleIdentifier]; + FBScene *scene = [app mainScene]; + if (!app) { + return; + } - [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:app.bundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:app.bundleIdentifier completion:nil]; - [RAMessagingServer.sharedInstance rotateApp:app.bundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; - [RAMessagingServer.sharedInstance forceStatusBarVisibility:YES forApp:app.bundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setHosted:YES forIdentifier:app.bundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:app.bundleIdentifier completion:nil]; + [RAMessagingServer.sharedInstance rotateApp:app.bundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; + [RAMessagingServer.sharedInstance forceStatusBarVisibility:YES forApp:app.bundleIdentifier completion:nil]; - if (![app pid] || [app mainScene] == nil) - { - overrideDisableForStatusBar = YES; - [UIApplication.sharedApplication launchApplicationWithIdentifier:bundleIdentifier suspended:YES]; - [[%c(FBProcessManager) sharedInstance] createApplicationProcessForBundleID:bundleIdentifier]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - [self RA_launchTopAppWithIdentifier:bundleIdentifier]; - [self updateViewSizes:draggerView.center animate:YES]; - }); - return; - } + if (![app pid] || ![app mainScene]) { + overrideDisableForStatusBar = YES; + [UIApplication.sharedApplication launchApplicationWithIdentifier:bundleIdentifier suspended:YES]; + [[%c(FBProcessManager) sharedInstance] createApplicationProcessForBundleID:bundleIdentifier]; - [RAAppSwitcherModelWrapper addIdentifierToFront:bundleIdentifier]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self RA_launchTopAppWithIdentifier:bundleIdentifier]; + [self updateViewSizes:draggerView.center animate:YES]; + }); + return; + } - FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; + [RAAppSwitcherModelWrapper addIdentifierToFront:bundleIdentifier]; - FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; - SET_BACKGROUNDED(settings, NO); - [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; + FBWindowContextHostManager *contextHostManager = [scene contextHostManager]; - [contextHostManager enableHostingForRequester:@"reachapp" orderFront:YES]; - view = [contextHostManager hostViewForRequester:@"reachapp" enableAndOrderFront:YES]; + FBSMutableSceneSettings *settings = [[scene mutableSettings] mutableCopy]; + SET_BACKGROUNDED(settings, NO); + [scene _applyMutableSettings:settings withTransitionContext:nil completion:nil]; - if (draggerView && draggerView.superview == w) - [w insertSubview:view belowSubview:draggerView]; - else - [w addSubview:view]; + [UIApplication.sharedApplication launchApplicationWithIdentifier:bundleIdentifier suspended:YES]; - //if ([RASettings.sharedInstance enableRotation] && ![RASettings.sharedInstance scalingRotationMode]) - { - [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; - } - /*else if ([RASettings.sharedInstance scalingRotationMode] && [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) - { - overrideDisableForStatusBar = YES; - - // Force portrait - [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:UIInterfaceOrientationPortrait completion:nil]; - [RAMessagingServer.sharedInstance rotateApp:currentBundleIdentifier toOrientation:UIInterfaceOrientationPortrait completion:nil]; - - // Scale app - CGFloat scale = view.frame.size.width / UIScreen.mainScreen.bounds.size.height; - pre_topAppTransform = MSHookIvar([app mainScene].contextHostManager, "_hostView").transform; - MSHookIvar([app mainScene].contextHostManager, "_hostView").transform = CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeRotation(M_PI_2)); - pre_topAppFrame = MSHookIvar([app mainScene].contextHostManager, "_hostView").frame; - MSHookIvar([app mainScene].contextHostManager, "_hostView").frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height); - UIWindow *window = MSHookIvar(self,"_reachabilityEffectWindow"); - window.frame = (CGRect) { window.frame.origin, { window.frame.size.width, view.frame.size.width } }; - - window = MSHookIvar(self,"_reachabilityWindow"); - window.frame = (CGRect) { { window.frame.origin.x, view.frame.size.width }, { window.frame.size.width, view.frame.size.width } }; - - SBApplication *currentApp = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:currentBundleIdentifier]; - if ([currentApp mainScene]) // just checking... - { - MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").transform = CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeRotation(M_PI_2)); - MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height); - } + [contextHostManager enableHostingForRequester:@"reachapp" orderFront:YES]; + view = [contextHostManager hostViewForRequester:@"reachapp" enableAndOrderFront:YES]; - // Gotta for the animations to finish... ;_; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - overrideDisableForStatusBar = NO; - }); - }*/ - draggerView.hidden = NO; - overrideDisableForStatusBar = NO; -} + view.accessibilityHint = bundleIdentifier; -%new -(void) RA_setView:(UIView*)view_ preferredHeight:(CGFloat)pHeight -{ - view_.hidden = NO; - UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); - if (view) - { - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; - [(RAAppSliderProviderView*)view unload]; - } - [view removeFromSuperview]; - view = nil; - } - view = view_; + if (draggerView && draggerView.superview == w) { + [w insertSubview:view belowSubview:draggerView]; + } else { [w addSubview:view]; - if (draggerView && draggerView.superview) - [draggerView.superview bringSubviewToFront:draggerView]; - - CGPoint center = (CGPoint){ draggerView.center.x, pHeight <= 0 ? draggerView.center.y : pHeight }; - [self updateViewSizes:center animate:YES]; - draggerView.hidden = NO; - draggerView.center = center; + } - if ([view isKindOfClass:[RAAppSliderProviderView class]]) - { - NSString *targetIdentifier = ((RAAppSliderProviderView*)view).currentBundleIdentifier; - [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:targetIdentifier completion:nil]; - [RAMessagingServer.sharedInstance rotateApp:targetIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; - [RAMessagingServer.sharedInstance forceStatusBarVisibility:YES forApp:targetIdentifier completion:nil]; - } + //if ([RASettings.sharedInstance enableRotation] && ![RASettings.sharedInstance scalingRotationMode]) + { + [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; + } + /*else if ([RASettings.sharedInstance scalingRotationMode] && [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) + { + overrideDisableForStatusBar = YES; + + // Force portrait + [RAMessagingServer.sharedInstance rotateApp:lastBundleIdentifier toOrientation:UIInterfaceOrientationPortrait completion:nil]; + [RAMessagingServer.sharedInstance rotateApp:currentBundleIdentifier toOrientation:UIInterfaceOrientationPortrait completion:nil]; + + // Scale app + CGFloat scale = view.frame.size.width / UIScreen.mainScreen.bounds.size.height; + pre_topAppTransform = MSHookIvar([app mainScene].contextHostManager, "_hostView").transform; + MSHookIvar([app mainScene].contextHostManager, "_hostView").transform = CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeRotation(M_PI_2)); + pre_topAppFrame = MSHookIvar([app mainScene].contextHostManager, "_hostView").frame; + MSHookIvar([app mainScene].contextHostManager, "_hostView").frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height); + UIWindow *window = MSHookIvar(self,"_reachabilityEffectWindow"); + window.frame = (CGRect) { window.frame.origin, { window.frame.size.width, view.frame.size.width } }; + + window = MSHookIvar(self,"_reachabilityWindow"); + window.frame = (CGRect) { { window.frame.origin.x, view.frame.size.width }, { window.frame.size.width, view.frame.size.width } }; + + SBApplication *currentApp = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:currentBundleIdentifier]; + if ([currentApp mainScene]) // just checking... + { + MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").transform = CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeRotation(M_PI_2)); + MSHookIvar([currentApp mainScene].contextHostManager, "_hostView").frame = CGRectMake(0, 0, window.frame.size.width, window.frame.size.height); + } + + // Gotta for the animations to finish... ;_; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + overrideDisableForStatusBar = NO; + }); + }*/ + draggerView.hidden = NO; + overrideDisableForStatusBar = NO; } -%new -(void) RA_animateWidgetSelectorOut:(id)completion -{ - [UIView animateWithDuration:0.3 - animations:^{ - view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.01, 0.01); - view.alpha = 0; - } - completion:completion]; +%new - (void)RA_setView:(UIView*)view_ preferredHeight:(CGFloat)pHeight { + view_.hidden = NO; + UIWindow *w = MSHookIvar(self, "_reachabilityEffectWindow"); + if (view) { + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + [RAMessagingServer.sharedInstance endResizingApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:NO forApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [RAMessagingServer.sharedInstance unforceStatusBarVisibilityForApp:[((RAAppSliderProviderView*)view) currentBundleIdentifier] completion:nil]; + [(RAAppSliderProviderView*)view unload]; + } + [view removeFromSuperview]; + view = nil; + } + view = view_; + [w addSubview:view]; + if (draggerView && draggerView.superview) { + [draggerView.superview bringSubviewToFront:draggerView]; + } + + CGPoint center = (CGPoint){ draggerView.center.x, pHeight <= 0 ? draggerView.center.y : pHeight }; + [self updateViewSizes:center animate:YES]; + draggerView.hidden = NO; + draggerView.center = center; + + if ([view isKindOfClass:[RAAppSliderProviderView class]]) { + NSString *targetIdentifier = ((RAAppSliderProviderView*)view).currentBundleIdentifier; + [RAMessagingServer.sharedInstance setShouldUseExternalKeyboard:YES forApp:targetIdentifier completion:nil]; + [RAMessagingServer.sharedInstance rotateApp:targetIdentifier toOrientation:[UIApplication sharedApplication].statusBarOrientation completion:nil]; + [RAMessagingServer.sharedInstance forceStatusBarVisibility:YES forApp:targetIdentifier completion:nil]; + } } -%new -(void) appViewItemTap:(UITapGestureRecognizer*)sender -{ - int pid = [sender.view tag]; - SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithPid:pid]; - if (!app) - app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:sender.view.restorationIdentifier]; +%new - (void)RA_animateWidgetSelectorOut:(id)completion { + [UIView animateWithDuration:0.3 + animations:^{ + view.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.01, 0.01); + view.alpha = 0; + } + completion:completion]; +} - if (app) - { - // before we re-assign view... - [self RA_animateWidgetSelectorOut:^(BOOL a){ - [view removeFromSuperview]; - view = nil; - - lastBundleIdentifier = app.bundleIdentifier; - [self RA_launchTopAppWithIdentifier:app.bundleIdentifier]; - - if ([RASettings.sharedInstance autoSizeWidgetSelector]) - { - if (old_grabberCenterY == -1) - old_grabberCenterY = UIScreen.mainScreen.bounds.size.height * 0.3; - grabberCenter_Y = old_grabberCenterY; - draggerView.center = CGPointMake(grabberCenter_X, grabberCenter_Y); - } - [self updateViewSizes:draggerView.center animate:YES]; - }]; - } +%new - (void)appViewItemTap:(UITapGestureRecognizer*)sender { + int pid = [sender.view tag]; + SBApplication *app = [[%c(SBApplicationController) sharedInstance] applicationWithPid:pid]; + if (!app) { + app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:sender.view.restorationIdentifier]; + } + + if (app) { + // before we re-assign view... + [self RA_animateWidgetSelectorOut:^(BOOL a){ + [view removeFromSuperview]; + view = nil; + + lastBundleIdentifier = app.bundleIdentifier; + [self RA_launchTopAppWithIdentifier:app.bundleIdentifier]; + + if ([RASettings.sharedInstance autoSizeWidgetSelector]) { + if (old_grabberCenterY == -1) { + old_grabberCenterY = UIScreen.mainScreen.bounds.size.height * 0.3; + } + grabberCenter_Y = old_grabberCenterY; + draggerView.center = CGPointMake(grabberCenter_X, grabberCenter_Y); + } + [self updateViewSizes:draggerView.center animate:YES]; + }]; + } } %end %hook SpringBoard -- (UIInterfaceOrientation)activeInterfaceOrientation -{ - return overrideOrientation ? UIInterfaceOrientationPortrait : %orig; +- (UIInterfaceOrientation)activeInterfaceOrientation { + return overrideOrientation ? UIInterfaceOrientationPortrait : %orig; } %end %end -%ctor -{ - if (SPRINGBOARD) - { - Class c = objc_getClass("SBMainWorkspace") ?: objc_getClass("SBWorkspace"); - %init(hooks, SB_WORKSPACE_CLASS=c); - } -} \ No newline at end of file +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + Class c = %c(SBMainWorkspace) ?: %c(SBWorkspace); + %init(hooks, SB_WORKSPACE_CLASS=c); +} diff --git a/Reachability/UIKit.xm b/Reachability/UIKit.xm index bfe4ce1..dab3950 100644 --- a/Reachability/UIKit.xm +++ b/Reachability/UIKit.xm @@ -4,20 +4,17 @@ BOOL allowClosingReachabilityNatively = NO; %hook UIApplication -- (void)_deactivateReachability -{ - if (allowClosingReachabilityNatively == NO) - { - NSLog(@"[ReachApp] attempting to close reachability but not allowed to."); - return; - } - - if ([RAMessagingClient.sharedInstance isBeingHosted]) - { - NSLog(@"[ReachApp] stopping reachability from closing because hosted"); - return; - } - %orig; +- (void)_deactivateReachability { + if (!allowClosingReachabilityNatively) { + LogDebug(@"[ReachApp] attempting to close reachability but not allowed to."); + return; + } + + if ([RAMessagingClient.sharedInstance isBeingHosted]) { + LogDebug(@"[ReachApp] stopping reachability from closing because hosted"); + return; + } + %orig; } %end @@ -71,7 +68,7 @@ BOOL allowClosingReachabilityNatively = NO; } %end -%hook UIInputWindowController +%hook UIInputWindowController - (void)moveFromPlacement:(unsafe_id)arg1 toPlacement:(unsafe_id)arg2 starting:(unsafe_id)arg3 completion:(unsafe_id)arg4 { overrideViewControllerDismissal = YES; @@ -79,4 +76,4 @@ BOOL allowClosingReachabilityNatively = NO; overrideViewControllerDismissal = NO; } %end -*/ \ No newline at end of file +*/ diff --git a/SKBounceAnimation.h b/SKBounceAnimation.h index c8d030c..e8a9b65 100644 --- a/SKBounceAnimation.h +++ b/SKBounceAnimation.h @@ -25,7 +25,7 @@ extern SKBounceAnimationStiffness SKBounceAnimationStiffnessHeavy; @property (nonatomic, assign) BOOL shake; //if shaking, set fromValue to the furthest value, and toValue to the current value @property (nonatomic, assign) SKBounceAnimationStiffness stiffness; -+ (SKBounceAnimation*) animationWithKeyPath:(NSString*)keyPath; ++ (SKBounceAnimation*)animationWithKeyPath:(NSString*)keyPath; -@end \ No newline at end of file +@end diff --git a/SpringBoard.xm b/SpringBoard.xm index 7ac95a4..4f9b4ff 100644 --- a/SpringBoard.xm +++ b/SpringBoard.xm @@ -15,34 +15,50 @@ #import "RAMissionControlManager.h" #import "RADesktopManager.h" #import "RADesktopWindow.h" -#import "Asphaleia2.h" +#import "Asphaleia.h" #import "RASnapshotProvider.h" extern BOOL overrideDisableForStatusBar; %hook SBUIController -- (_Bool)clickedMenuButton -{ - if ([[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver]) - { +- (_Bool)clickedMenuButton { + if ([[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver]) { [[%c(RASwipeOverManager) sharedInstance] stopUsingSwipeOver]; return YES; } - if ([RASettings.sharedInstance homeButtonClosesReachability] && [GET_SBWORKSPACE isUsingReachApp] && ((SBReachabilityManager*)[%c(SBReachabilityManager) sharedInstance]).reachabilityModeActive) - { - overrideDisableForStatusBar = NO; - [[%c(SBReachabilityManager) sharedInstance] _handleReachabilityDeactivated]; - return YES; - } + if ([RASettings.sharedInstance homeButtonClosesReachability] && [GET_SBWORKSPACE isUsingReachApp] && ((SBReachabilityManager*)[%c(SBReachabilityManager) sharedInstance]).reachabilityModeActive) { + overrideDisableForStatusBar = NO; + [[%c(SBReachabilityManager) sharedInstance] _handleReachabilityDeactivated]; + return YES; + } - if ([[%c(RAMissionControlManager) sharedInstance] isShowingMissionControl]) - { - [[%c(RAMissionControlManager) sharedInstance] hideMissionControl:YES]; - return YES; - } + if ([[%c(RAMissionControlManager) sharedInstance] isShowingMissionControl]) { + [[%c(RAMissionControlManager) sharedInstance] hideMissionControl:YES]; + return YES; + } - return %orig; + return %orig; +} + +- (BOOL)handleHomeButtonSinglePressUp { + if ([[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver]) { + [[%c(RASwipeOverManager) sharedInstance] stopUsingSwipeOver]; + return YES; + } + + if ([RASettings.sharedInstance homeButtonClosesReachability] && [GET_SBWORKSPACE isUsingReachApp] && ((SBReachabilityManager*)[%c(SBReachabilityManager) sharedInstance]).reachabilityModeActive) { + overrideDisableForStatusBar = NO; + [[%c(SBReachabilityManager) sharedInstance] _handleReachabilityDeactivated]; + return YES; + } + + if ([[%c(RAMissionControlManager) sharedInstance] isShowingMissionControl]) { + [[%c(RAMissionControlManager) sharedInstance] hideMissionControl:YES]; + return YES; + } + + return %orig; } /*- (_Bool)handleMenuDoubleTap @@ -61,142 +77,138 @@ extern BOOL overrideDisableForStatusBar; }*/ // This should help fix the problems where closing an app with Tage or the iPad Gesture would cause the app to suspend(?) and lock up the device. -- (void)_suspendGestureBegan -{ - %orig; - [UIApplication.sharedApplication._accessibilityFrontMostApplication clearDeactivationSettings]; +- (void)_suspendGestureBegan { + %orig; + [UIApplication.sharedApplication._accessibilityFrontMostApplication clearDeactivationSettings]; } %end %hook SpringBoard --(void) _performDeferredLaunchWork -{ - %orig; - [RADesktopManager sharedInstance]; // load desktop (and previous windows!) +- (void)_performDeferredLaunchWork { + %orig; + [RADesktopManager sharedInstance]; // load desktop (and previous windows!) - // No applications show in the mission control until they have been launched by the user. - // This prevents always-running apps like Mail or Pebble from perpetually showing in Mission Control. - //[[%c(RAMissionControlManager) sharedInstance] setInhibitedApplications:[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers]]; + // No applications show in the mission control until they have been launched by the user. + // This prevents always-running apps like Mail or Pebble from perpetually showing in Mission Control. + //[[%c(RAMissionControlManager) sharedInstance] setInhibitedApplications:[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers]]; } %end %hook SBApplicationController -%new -(SBApplication*) RA_applicationWithBundleIdentifier:(__unsafe_unretained NSString*)bundleIdentifier -{ - if ([self respondsToSelector:@selector(applicationWithBundleIdentifier:)]) - return [self applicationWithBundleIdentifier:bundleIdentifier]; - else if ([self respondsToSelector:@selector(applicationWithDisplayIdentifier:)]) - return [self applicationWithDisplayIdentifier:bundleIdentifier]; +%new - (SBApplication*)RA_applicationWithBundleIdentifier:(__unsafe_unretained NSString*)bundleIdentifier { + if ([self respondsToSelector:@selector(applicationWithBundleIdentifier:)]) { + return [self applicationWithBundleIdentifier:bundleIdentifier]; + } else if ([self respondsToSelector:@selector(applicationWithDisplayIdentifier:)]) { + return [self applicationWithDisplayIdentifier:bundleIdentifier]; + } - [RACompatibilitySystem showWarning:@"Unable to find valid -[SBApplicationController applicationWithBundleIdentifier:] replacement"]; - return nil; + [RACompatibilitySystem showWarning:@"Unable to find valid -[SBApplicationController applicationWithBundleIdentifier:] replacement"]; + return nil; } %end %hook SBToAppsWorkspaceTransaction -- (void)_willBegin -{ - @autoreleasepool { - NSArray *apps = nil; - if ([self respondsToSelector:@selector(toApplications)]) - apps = [self toApplications]; - else - apps = [MSHookIvar(self, "_toApplications") copy]; - for (SBApplication *app in apps) - { - dispatch_async(dispatch_get_main_queue(), ^{ - [RADesktopManager.sharedInstance removeAppWithIdentifier:app.bundleIdentifier animated:NO forceImmediateUnload:YES]; - }); - } - } - %orig; +- (void)_willBegin { + @autoreleasepool { + NSArray *apps = nil; + if ([self respondsToSelector:@selector(toApplications)]) { + apps = [self toApplications]; + } else { + apps = [MSHookIvar(self, "_toApplications") copy]; + } + for (SBApplication *app in apps) { + dispatch_async(dispatch_get_main_queue(), ^{ + [RADesktopManager.sharedInstance removeAppWithIdentifier:app.bundleIdentifier animated:NO forceImmediateUnload:YES]; + }); + } + } + %orig; } -// On iOS 8.3 and above, on the iPad, if a FBWindowContextWhatever creates a hosting context / enabled hosting, all the other hosted windows stop. -// This fixes that. --(void)_didComplete -{ - %orig; +// On iOS 8.3 and above, on the iPad, if a FBWindowContextWhatever creates a hosting context / enabled hosting, all the other hosted windows stop. +// This fixes that. +- (void)_didComplete { + %orig; - //if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - // can't hurt to check all devices - especially if it changes/has changed to include phones. - // however this was presumably done in preparation for the iOS 9 multitasking - [RAHostedAppView iPad_iOS83_fixHosting]; + // can't hurt to check all devices - especially if it changes/has changed to include phones. + // however this was presumably done in preparation for the iOS 9 multitasking + if (IS_IPAD) { + [RAHostedAppView iPad_iOS83_fixHosting]; + } } %end /* %hook SBRootFolderView -- (_Bool)_hasMinusPages +- (_Bool)_hasMinusPages { - return RADesktopManager.sharedInstance.currentDesktop.hostedWindows.count > 0 ? YES : %orig; + return RADesktopManager.sharedInstance.currentDesktop.hostedWindows.count > 0 ? YES : %orig; } -- (unsigned long long)_minusPageCount +- (unsigned long long)_minusPageCount { - return RADesktopManager.sharedInstance.currentDesktop.hostedWindows.count > 0 ? 1 : %orig; + return RADesktopManager.sharedInstance.currentDesktop.hostedWindows.count > 0 ? 1 : %orig; } %end */ %hook SpringBoard --(void)noteInterfaceOrientationChanged:(int)arg1 duration:(float)arg2 -{ - %orig; - [RASnapshotProvider.sharedInstance forceReloadEverything]; +- (void)noteInterfaceOrientationChanged:(int)arg1 duration:(float)arg2 { + %orig; + [RASnapshotProvider.sharedInstance forceReloadEverything]; } %end %hook SBApplication -- (void)didActivateWithTransactionID:(unsigned long long)arg1 -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [RASnapshotProvider.sharedInstance forceReloadOfSnapshotForIdentifier:self.bundleIdentifier]; - }); - - %orig; +- (void)didActivateWithTransactionID:(unsigned long long)arg1 { + dispatch_async(dispatch_get_main_queue(), ^{ + [RASnapshotProvider.sharedInstance forceReloadOfSnapshotForIdentifier:self.bundleIdentifier]; + }); + + %orig; } %end %hook SBLockScreenManager -- (void)_postLockCompletedNotification:(_Bool)arg1 -{ - %orig; - - if (arg1) - { - if ([[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver]) - [[%c(RASwipeOverManager) sharedInstance] stopUsingSwipeOver]; - } +- (void)_postLockCompletedNotification:(_Bool)arg1 { + %orig; + + if (arg1) { + if ([[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver]) { + [[%c(RASwipeOverManager) sharedInstance] stopUsingSwipeOver]; + } + } } %end %hook UIScreen -%new -(CGRect) RA_interfaceOrientedBounds -{ - if ([self respondsToSelector:@selector(_interfaceOrientedBounds)]) - return [self _interfaceOrientedBounds]; - return [self bounds]; +%new - (CGRect)RA_interfaceOrientedBounds { + if ([self respondsToSelector:@selector(_interfaceOrientedBounds)]) { + return [self _interfaceOrientedBounds]; + } + return [self bounds]; } %end -void respring_notification(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) -{ - [[UIApplication sharedApplication] _relaunchSpringBoardNow]; +void respring_notification(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + if (IS_IOS_OR_NEWER(iOS_9_3)) { + SBSRelaunchAction *restartAction = [%c(SBSRelaunchAction) actionWithReason:@"RestartRenderServer" options:SBSRelaunchOptionsFadeToBlack targetURL:nil]; + [[%c(FBSSystemService) sharedService] sendActions:[NSSet setWithObject:restartAction] withResult:nil]; + } else { + [[UIApplication sharedApplication] _relaunchSpringBoardNow]; + } } -void reset_settings_notification(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) -{ - [RASettings.sharedInstance resetSettings]; +void reset_settings_notification(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + [RASettings.sharedInstance resetSettings]; } -%ctor -{ - if (IS_SPRINGBOARD) - { - %init; - LOAD_ASPHALEIA; +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + %init; + LOAD_ASPHALEIA; - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, respring_notification, CFSTR("com.efrederickson.reachapp.respring"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, reset_settings_notification, CFSTR("com.efrederickson.reachapp.resetSettings"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - } + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &respring_notification, CFSTR("com.efrederickson.reachapp.respring"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &reset_settings_notification, CFSTR("com.efrederickson.reachapp.resetSettings"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); } diff --git a/SwipeOver/Makefile b/SwipeOver/Makefile index 4ca58cf..814ab49 100644 --- a/SwipeOver/Makefile +++ b/SwipeOver/Makefile @@ -1,8 +1,7 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../ -I../Theming/ -I../GestureSupport/ -I../WindowedMultitasking/ -I../Messaging/ -I../KeyboardSupport -I../MissionControl +CFLAGS = -I../ -I../Theming/ -I../GestureSupport/ -I../WindowedMultitasking/ -I../Messaging/ -I../KeyboardSupport -I../MissionControl -O2 CFLAGS += -fobjc-arc -LDFLAGS += -Wl,-segalign,4000 include $(THEOS)/makefiles/common.mk TWEAK_NAME = ReachAppSwipeOver diff --git a/SwipeOver/RASwipeOverManager.h b/SwipeOver/RASwipeOverManager.h index eb5a95a..5fae0af 100644 --- a/SwipeOver/RASwipeOverManager.h +++ b/SwipeOver/RASwipeOverManager.h @@ -4,22 +4,22 @@ NSString *currentAppIdentifier; BOOL isUsingSwipeOver; } -+(id) sharedInstance; ++ (instancetype)sharedInstance; --(void) startUsingSwipeOver; --(void) stopUsingSwipeOver; --(BOOL) isUsingSwipeOver; +- (void)startUsingSwipeOver; +- (void)stopUsingSwipeOver; +- (BOOL)isUsingSwipeOver; --(void) createEdgeView; +- (void)createEdgeView; --(void) showApp:(NSString*)identifier; // if identifier is nil it will use the app switcher data --(void) closeCurrentView; // App or selector --(void) showAppSelector; // No widget chooser, not enough horizontal space. TODO: make it work anyway +- (void)showApp:(NSString*)identifier; // if identifier is nil it will use the app switcher data +- (void)closeCurrentView; // App or selector +- (void)showAppSelector; // No widget chooser, not enough horizontal space. TODO: make it work anyway --(BOOL) isEdgeViewShowing; --(void) convertSwipeOverViewToSideBySide; +- (BOOL)isEdgeViewShowing; +- (void)convertSwipeOverViewToSideBySide; --(void) sizeViewForTranslation:(CGPoint)translation state:(UIGestureRecognizerState)state; +- (void)sizeViewForTranslation:(CGPoint)translation state:(UIGestureRecognizerState)state; @end #define RASWIPEOVER_VIEW_TAG 996 diff --git a/SwipeOver/RASwipeOverManager.xm b/SwipeOver/RASwipeOverManager.xm index 4fecffd..2255378 100644 --- a/SwipeOver/RASwipeOverManager.xm +++ b/SwipeOver/RASwipeOverManager.xm @@ -9,6 +9,7 @@ #import "RAAppSelectorView.h" #import "RAAppSwitcherModelWrapper.h" #import "RAOrientationLocker.h" +#import "UIAlertController+Window.h" extern int rotationDegsForOrientation(int o); @@ -25,17 +26,23 @@ extern int rotationDegsForOrientation(int o); @end @implementation RASwipeOverManager -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE(RASwipeOverManager); } --(BOOL) isUsingSwipeOver { return isUsingSwipeOver; } --(void) showAppSelector { [overlayWindow showAppSelector]; } --(BOOL) isEdgeViewShowing { return overlayWindow.frame.origin.x < SCREEN_WIDTH; } +- (BOOL)isUsingSwipeOver { + return isUsingSwipeOver; +} + +- (void)showAppSelector { + [overlayWindow showAppSelector]; +} --(void) startUsingSwipeOver -{ +- (BOOL)isEdgeViewShowing { + return overlayWindow.frame.origin.x < SCREEN_WIDTH; +} + +- (void)startUsingSwipeOver { start = 0; isUsingSwipeOver = YES; currentAppIdentifier = [[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier; @@ -45,13 +52,11 @@ extern int rotationDegsForOrientation(int o); [%c(RAOrientationLocker) lockOrientation]; } --(void) stopUsingSwipeOver -{ +- (void)stopUsingSwipeOver { [overlayWindow removeOverlayFromUnderlyingAppImmediately]; - if (currentAppIdentifier) - { + if (currentAppIdentifier) { [[%c(RAMessagingServer) sharedInstance] endResizingApp:currentAppIdentifier completion:nil]; - [[%c(RAMessagingServer) sharedInstance] setShouldUseExternalKeyboard:YES forApp:currentAppIdentifier completion:nil]; + [[%c(RAMessagingServer) sharedInstance] setShouldUseExternalKeyboard:YES forApp:currentAppIdentifier completion:nil]; } [%c(RAOrientationLocker) unlockOrientation]; @@ -60,22 +65,21 @@ extern int rotationDegsForOrientation(int o); currentAppIdentifier = nil; CGRect newFrame = overlayWindow.frame; - switch ([UIApplication.sharedApplication statusBarOrientation]) - { - case UIInterfaceOrientationPortrait: - newFrame = (CGRect) { { newFrame.origin.x + newFrame.size.height, newFrame.origin.y }, newFrame.size }; - case UIInterfaceOrientationPortraitUpsideDown: - newFrame = (CGRect) { { newFrame.origin.x - newFrame.size.height, newFrame.origin.y }, newFrame.size }; - case UIInterfaceOrientationLandscapeLeft: - newFrame = (CGRect) { { newFrame.origin.x, newFrame.origin.y - newFrame.size.height }, newFrame.size }; - case UIInterfaceOrientationLandscapeRight: - newFrame = (CGRect) { { newFrame.origin.x, newFrame.origin.y + newFrame.size.height }, newFrame.size }; + switch ([UIApplication.sharedApplication statusBarOrientation]) { + case UIInterfaceOrientationPortrait: + newFrame = (CGRect) { { newFrame.origin.x + newFrame.size.height, newFrame.origin.y }, newFrame.size }; + case UIInterfaceOrientationPortraitUpsideDown: + newFrame = (CGRect) { { newFrame.origin.x - newFrame.size.height, newFrame.origin.y }, newFrame.size }; + case UIInterfaceOrientationLandscapeLeft: + newFrame = (CGRect) { { newFrame.origin.x, newFrame.origin.y - newFrame.size.height }, newFrame.size }; + case UIInterfaceOrientationLandscapeRight: + newFrame = (CGRect) { { newFrame.origin.x, newFrame.origin.y + newFrame.size.height }, newFrame.size }; } [UIView animateWithDuration:0.3 animations:^{ - if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) + if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) { [((RAHostedAppView*)overlayWindow.currentView) viewWithTag:9903553].alpha = 0; - + } overlayWindow.frame = newFrame; } completion:^(BOOL _) { [self closeCurrentView]; @@ -85,82 +89,79 @@ extern int rotationDegsForOrientation(int o); }]; } --(void) createEdgeView -{ - overlayWindow = [[RASwipeOverOverlay alloc] initWithFrame:UIScreen.mainScreen.RA_interfaceOrientedBounds]; - if (SYSTEM_VERSION_LESS_THAN(@"9.0")) - [overlayWindow _rotateWindowToOrientation:UIApplication.sharedApplication.statusBarOrientation updateStatusBar:YES duration:0.001 skipCallbacks:NO]; +- (void)createEdgeView { + overlayWindow = [[RASwipeOverOverlay alloc] initWithFrame:[UIScreen mainScreen].RA_interfaceOrientedBounds]; + if (IS_IOS_OR_OLDER(iOS_8_4)) { + [overlayWindow _rotateWindowToOrientation:[UIApplication sharedApplication].statusBarOrientation updateStatusBar:YES duration:0.001 skipCallbacks:NO]; + } [overlayWindow showEnoughToDarkenUnderlyingApp]; [overlayWindow makeKeyAndVisible]; - [overlayWindow updateForOrientation:UIApplication.sharedApplication.statusBarOrientation]; - + [overlayWindow updateForOrientation:[UIApplication sharedApplication].statusBarOrientation]; + [self showApp:nil]; } --(void) showApp:(NSString*)identifier -{ +- (void)showApp:(NSString*)identifier { [self closeCurrentView]; SBApplication *app = nil; - FBScene *scene = nil; - - if (identifier) - app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:identifier]; - else - { - NSMutableArray *bundleIdentifiers = [[%c(RAAppSwitcherModelWrapper) appSwitcherAppIdentiferList] mutableCopy]; - while (scene == nil && bundleIdentifiers.count > 0) - { - identifier = bundleIdentifiers[0]; - - if ([identifier isEqual:currentAppIdentifier]) - { - [bundleIdentifiers removeObjectAtIndex:0]; - continue; - } - - app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:identifier]; - break; + FBScene *scene = nil; + + if (identifier) { + app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:identifier]; + } else { + NSMutableArray *bundleIdentifiers = [[%c(RAAppSwitcherModelWrapper) appSwitcherAppIdentiferList] mutableCopy]; + while (!scene && bundleIdentifiers.count > 0) { + identifier = bundleIdentifiers[0]; + + if ([identifier isEqual:currentAppIdentifier]) { + [bundleIdentifiers removeObjectAtIndex:0]; + continue; } - } - if (app) - { - SBDisplayLayout *layout = [%c(SBDisplayLayout) fullScreenDisplayLayoutForApplication:app]; - if (layout) - [[%c(SBAppSwitcherModel) sharedInstance] addToFront:layout]; - } + app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:identifier]; + break; + } + } - if (identifier == nil || identifier.length == 0) - return; + if (app) { + SBDisplayLayout *layout = [%c(SBDisplayLayout) fullScreenDisplayLayoutForApplication:app]; + if (layout) { + [[%c(SBAppSwitcherModel) sharedInstance] addToFront:layout]; + } + } - RAHostedAppView *view = [[%c(RAHostedAppView) alloc] initWithBundleIdentifier:identifier]; - view.autosizesApp = NO; - if (overlayWindow.isHidingUnderlyingApp == NO) + if (!identifier || identifier.length == 0) { + return; + } + + RAHostedAppView *view = [[%c(RAHostedAppView) alloc] initWithBundleIdentifier:identifier]; + view.autosizesApp = NO; + if (!overlayWindow.isHidingUnderlyingApp) { view.autosizesApp = YES; - view.shouldUseExternalKeyboard = YES; - view.allowHidingStatusBar = NO; - view.frame = UIScreen.mainScreen._referenceBounds; - view.showSplashscreenInsteadOfSpinner = YES; + } + view.shouldUseExternalKeyboard = YES; + view.allowHidingStatusBar = NO; + view.frame = UIScreen.mainScreen._referenceBounds; + view.showSplashscreenInsteadOfSpinner = YES; view.renderWallpaper = YES; - [view rotateToOrientation:UIInterfaceOrientationPortrait]; - [view loadApp]; - - UIImageView *detachView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -20, view.frame.size.width, 20)]; - detachView.image = [[%c(RAResourceImageProvider) imageForFilename:@"SwipeOverDetachImage" constrainedToSize:CGSizeMake(97, 28)] _flatImageWithColor:THEMED(swipeOverDetachImageColor)]; - detachView.contentMode = UIViewContentModeScaleAspectFit; - UITapGestureRecognizer *detachGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(detachViewAndCloseSwipeOver)]; - [detachView addGestureRecognizer:detachGesture]; - detachView.backgroundColor = THEMED(swipeOverDetachBarColor); - detachView.userInteractionEnabled = YES; - detachGesture.delegate = overlayWindow; - detachView.tag = 9903553; - [view addSubview:detachView]; - - if (overlayWindow.isHidingUnderlyingApp == NO) // side-by-side - view.frame = CGRectMake(10, 0, view.frame.size.width, view.frame.size.height); - else // overlay - { + [view rotateToOrientation:UIInterfaceOrientationPortrait]; + [view loadApp]; + + UIImageView *detachView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -20, view.frame.size.width, 20)]; + detachView.image = [[%c(RAResourceImageProvider) imageForFilename:@"SwipeOverDetachImage" constrainedToSize:CGSizeMake(97, 28)] _flatImageWithColor:THEMED(swipeOverDetachImageColor)]; + detachView.contentMode = UIViewContentModeScaleAspectFit; + UITapGestureRecognizer *detachGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(detachViewAndCloseSwipeOver)]; + [detachView addGestureRecognizer:detachGesture]; + detachView.backgroundColor = THEMED(swipeOverDetachBarColor); + detachView.userInteractionEnabled = YES; + detachGesture.delegate = overlayWindow; + detachView.tag = 9903553; + [view addSubview:detachView]; + + if (!overlayWindow.isHidingUnderlyingApp) { // side-by-side + view.frame = CGRectMake(10, 0, view.frame.size.width, view.frame.size.height); + } else { // overlay view.frame = CGRectMake(SCREEN_WIDTH - 50, 0, view.frame.size.width, view.frame.size.height); CGFloat scale = 0.1; // MIN(MAX(scale, 0.1), 0.98); @@ -168,41 +169,38 @@ extern int rotationDegsForOrientation(int o); view.center = (CGPoint) { SCREEN_WIDTH - (view.frame.size.width / 2), view.center.y }; } - view.tag = RASWIPEOVER_VIEW_TAG; - [overlayWindow addSubview:view]; + view.tag = RASWIPEOVER_VIEW_TAG; + [overlayWindow addSubview:view]; [self updateClientSizes:YES]; } --(void) closeCurrentView -{ - if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) - { +- (void)closeCurrentView { + if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) { ((RAHostedAppView*)overlayWindow.currentView).shouldUseExternalKeyboard = NO; [((RAHostedAppView*)overlayWindow.currentView) unloadApp]; } [[overlayWindow currentView] removeFromSuperview]; } --(void) convertSwipeOverViewToSideBySide -{ - if (currentAppIdentifier == nil || [[%c(SBReachabilityManager) sharedInstance] reachabilityModeActive]) - { +- (void)convertSwipeOverViewToSideBySide { + if (!currentAppIdentifier || [[%c(SBReachabilityManager) sharedInstance] reachabilityModeActive]) { [self stopUsingSwipeOver]; return; } - if (UIApplication.sharedApplication.statusBarOrientation != UIInterfaceOrientationPortrait) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"MULTIPLEXER") message:@"Sorry, SwipeOver's side-by-side mode is not currently compatible with landscape." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + if (UIApplication.sharedApplication.statusBarOrientation != UIInterfaceOrientationPortrait) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"MULTIPLEXER") message:@"Sorry, SwipeOver's side-by-side mode is not currently compatible with landscape." preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [alert show]; return; } [[%c(RAMessagingServer) sharedInstance] setShouldUseExternalKeyboard:YES forApp:currentAppIdentifier completion:nil]; - if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) + if ([[overlayWindow currentView] isKindOfClass:[%c(RAHostedAppView) class]]) { ((RAHostedAppView*)[overlayWindow currentView]).autosizesApp = YES; + } [overlayWindow currentView].transform = CGAffineTransformIdentity; [overlayWindow removeOverlayFromUnderlyingApp]; [overlayWindow currentView].frame = (CGRect) { { 10, 0 }, [overlayWindow currentView].frame.size }; @@ -211,8 +209,7 @@ extern int rotationDegsForOrientation(int o); [self updateClientSizes:YES]; } --(void) detachViewAndCloseSwipeOver -{ +- (void)detachViewAndCloseSwipeOver { SBApplication *app = ((RAHostedAppView*)overlayWindow.currentView).app; [self stopUsingSwipeOver]; @@ -220,59 +217,51 @@ extern int rotationDegsForOrientation(int o); [desktop createAppWindowForSBApplication:app animated:YES]; } --(void) updateClientSizes:(BOOL)reloadAppSelectorSizeNow -{ - if (currentAppIdentifier && overlayWindow.isHidingUnderlyingApp == NO) - { +- (void)updateClientSizes:(BOOL)reloadAppSelectorSizeNow { + if (currentAppIdentifier && !overlayWindow.isHidingUnderlyingApp) { CGFloat underWidth = [overlayWindow isHidingUnderlyingApp] ? -1 : overlayWindow.frame.origin.x; [[%c(RAMessagingServer) sharedInstance] resizeApp:currentAppIdentifier toSize:CGSizeMake(underWidth, -1) completion:nil]; } - - if (overlayWindow.isShowingAppSelector && reloadAppSelectorSizeNow) + + if (overlayWindow.isShowingAppSelector && reloadAppSelectorSizeNow) { [self showAppSelector]; - else if (overlayWindow.isHidingUnderlyingApp == NO) // Update swiped-over app in side-by-side mode. RAHostedAppView takes care of the app sizing if we resize the RAHostedAppView. - { + } else if (!overlayWindow.isHidingUnderlyingApp) { // Update swiped-over app in side-by-side mode. RAHostedAppView takes care of the app sizing if we resize the RAHostedAppView. overlayWindow.currentView.frame = CGRectMake(10, 0, SCREEN_WIDTH - overlayWindow.frame.origin.x - 10, overlayWindow.currentView.frame.size.height); } } --(void) sizeViewForTranslation:(CGPoint)translation state:(UIGestureRecognizerState)state -{ +- (void)sizeViewForTranslation:(CGPoint)translation state:(UIGestureRecognizerState)state { static CGFloat lastX = -1; static CGFloat overlayOriginX = -1; UIView *targetView = [overlayWindow isHidingUnderlyingApp] ? [overlayWindow viewWithTag:RASWIPEOVER_VIEW_TAG] : overlayWindow; - if (start == 0) + if (start == 0) { start = targetView.center.x; - - if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled || state == UIGestureRecognizerStateFailed) - { + } + + if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled || state == UIGestureRecognizerStateFailed) { lastX = -1; start = 0; overlayOriginX = -1; CGFloat scale = (SCREEN_WIDTH - targetView.frame.origin.x) / [overlayWindow currentView].bounds.size.width; - if (scale <= 0.12 && (!CGPointEqualToPoint(translation, CGPointZero))) - { - [self stopUsingSwipeOver]; + if (scale <= 0.12 && (!CGPointEqualToPoint(translation, CGPointZero))) { + [self stopUsingSwipeOver]; return; } - } - else - { + } else { //if (start + translation.x + (targetView.frame.size.width / 2) < UIScreen.mainScreen.bounds.size.width && [overlayWindow isHidingUnderlyingApp]) // return; //if (start + translation.x + targetView.frame.size.width - (targetView.frame.size.width / 2) < 0 && [overlayWindow isHidingUnderlyingApp] == NO) // return; - if (overlayWindow.isHidingUnderlyingApp) - { - if ([[overlayWindow currentView] isKindOfClass:[%c(RAAppSelectorView) class]] == NO) - { - if (lastX == -1) + if (overlayWindow.isHidingUnderlyingApp) { + if (![[overlayWindow currentView] isKindOfClass:[%c(RAAppSelectorView) class]]) { + if (lastX == -1) { lastX = translation.x; + } CGFloat newScale = (lastX - translation.x) / SCREEN_WIDTH; - lastX = translation.x; + lastX = translation.x; newScale = newScale + sqrt(targetView.transform.a * targetView.transform.a + targetView.transform.c * targetView.transform.c); CGFloat scale = MIN(MAX(newScale, 0.1), UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation) ? (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / targetView.bounds.size.height) - 0.02 : 0.98); @@ -291,11 +280,10 @@ extern int rotationDegsForOrientation(int o); //targetView.transform = CGAffineTransformMakeScale(scale, scale); //targetView.center = (CGPoint) { SCREEN_WIDTH - (targetView.frame.size.width / 2), targetView.center.y }; } - } - else - { - if (overlayOriginX == -1) + } else { + if (overlayOriginX == -1) { overlayOriginX = overlayWindow.frame.origin.x; + } overlayWindow.frame = CGRectMake(overlayOriginX + translation.x, overlayWindow.frame.origin.y, SCREEN_WIDTH - (overlayOriginX + translation.x), overlayWindow.frame.size.height); //targetView.frame = CGRectMake(SCREEN_WIDTH - (start + translation.x), 0, SCREEN_WIDTH - (SCREEN_WIDTH - start + translation.x), targetView.frame.size.height); targetView.center = (CGPoint) { start + translation.x, targetView.center.y }; @@ -303,4 +291,4 @@ extern int rotationDegsForOrientation(int o); } [self updateClientSizes:state == UIGestureRecognizerStateEnded]; } -@end \ No newline at end of file +@end diff --git a/SwipeOver/RASwipeOverOverlay.h b/SwipeOver/RASwipeOverOverlay.h index 82fc7d3..a264462 100644 --- a/SwipeOver/RASwipeOverOverlay.h +++ b/SwipeOver/RASwipeOverOverlay.h @@ -1,20 +1,20 @@ #import "headers.h" #import "RAAppSelectorView.h" -@interface RASwipeOverOverlay : UIAutoRotatingWindow { +@interface RASwipeOverOverlay : UIAutoRotatingWindow { BOOL isHidingUnderlyingApp; - UIView *darkenerView; + UIVisualEffectView *darkenerView; } @property (nonatomic, retain) UIView *grabberView; --(BOOL) isHidingUnderlyingApp; --(void) showEnoughToDarkenUnderlyingApp; --(void) removeOverlayFromUnderlyingApp; --(void) removeOverlayFromUnderlyingAppImmediately; +- (BOOL)isHidingUnderlyingApp; +- (void)showEnoughToDarkenUnderlyingApp; +- (void)removeOverlayFromUnderlyingApp; +- (void)removeOverlayFromUnderlyingAppImmediately; --(BOOL) isShowingAppSelector; --(void) showAppSelector; +- (BOOL)isShowingAppSelector; +- (void)showAppSelector; --(UIView*) currentView; -@end \ No newline at end of file +- (UIView*)currentView; +@end diff --git a/SwipeOver/RASwipeOverOverlay.xm b/SwipeOver/RASwipeOverOverlay.xm index 3a061a0..b6cfb81 100644 --- a/SwipeOver/RASwipeOverOverlay.xm +++ b/SwipeOver/RASwipeOverOverlay.xm @@ -4,10 +4,8 @@ @implementation RASwipeOverOverlay @synthesize grabberView; --(id) initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) - { +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { //self.backgroundColor = [UIColor blueColor]; //self.alpha = 0.4; self.windowLevel = UIWindowLevelStatusBar + 1; @@ -21,39 +19,39 @@ [self addGestureRecognizer:g2]; CGFloat knobWidth = 10; - CGFloat knobHeight = 30; - grabberView = [[UIView alloc] initWithFrame:CGRectMake(2, (self.frame.size.height / 2) - (knobHeight / 2), knobWidth - 4, knobHeight)]; - grabberView.alpha = 0.5; - grabberView.layer.cornerRadius = knobWidth / 2; - grabberView.backgroundColor = [UIColor whiteColor]; - [self addSubview:grabberView]; + CGFloat knobHeight = 30; + grabberView = [[UIView alloc] initWithFrame:CGRectMake(2, (self.frame.size.height / 2) - (knobHeight / 2), knobWidth - 4, knobHeight)]; + grabberView.alpha = 0.5; + grabberView.layer.cornerRadius = knobWidth / 2; + grabberView.backgroundColor = [UIColor whiteColor]; + [self addSubview:grabberView]; } return self; } --(BOOL) isHidingUnderlyingApp { return isHidingUnderlyingApp; } +- (BOOL)isHidingUnderlyingApp { + return isHidingUnderlyingApp; +} --(void) showEnoughToDarkenUnderlyingApp -{ - if (isHidingUnderlyingApp) +- (void)showEnoughToDarkenUnderlyingApp { + if (isHidingUnderlyingApp) { return; + } isHidingUnderlyingApp = YES; - // TODO: use UIBlurEffect? - darkenerView = [[UIView alloc] initWithFrame:self.frame]; - darkenerView.backgroundColor = [UIColor blackColor]; - darkenerView.alpha = 0.35; - darkenerView.userInteractionEnabled = YES; + UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + darkenerView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + darkenerView.frame = self.frame; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(darkenerViewTap:)]; [darkenerView addGestureRecognizer:tap]; [self addSubview:darkenerView]; grabberView.hidden = YES; } --(void) removeOverlayFromUnderlyingApp -{ - if (!isHidingUnderlyingApp) +- (void)removeOverlayFromUnderlyingApp { + if (!isHidingUnderlyingApp) { return; + } isHidingUnderlyingApp = NO; [UIView animateWithDuration:0.3 animations:^{ @@ -65,72 +63,65 @@ }]; } --(void) removeOverlayFromUnderlyingAppImmediately -{ - if (!isHidingUnderlyingApp) +- (void)removeOverlayFromUnderlyingAppImmediately { + if (!isHidingUnderlyingApp) { return; + } isHidingUnderlyingApp = NO; [darkenerView removeFromSuperview]; darkenerView = nil; } --(void) showAppSelector -{ +- (void)showAppSelector { [self longPress:nil]; } --(UIView*) currentView -{ +- (UIView*)currentView { return [self viewWithTag:RASWIPEOVER_VIEW_TAG]; } --(BOOL) isShowingAppSelector -{ +- (BOOL)isShowingAppSelector { return [[self currentView] isKindOfClass:[%c(RAAppSelectorView) class]]; } --(void) darkenerViewTap:(UITapGestureRecognizer*)gesture -{ +- (void)darkenerViewTap:(UITapGestureRecognizer*)gesture { [RASwipeOverManager.sharedInstance convertSwipeOverViewToSideBySide]; } --(void) handlePan:(UIPanGestureRecognizer*)gesture -{ +- (void)handlePan:(UIPanGestureRecognizer*)gesture { CGPoint newPoint = [gesture translationInView:gesture.view]; - [RASwipeOverManager.sharedInstance sizeViewForTranslation:newPoint state:gesture.state]; + [RASwipeOverManager.sharedInstance sizeViewForTranslation:newPoint state:gesture.state]; } --(void) longPress:(UILongPressGestureRecognizer*)gesture -{ +- (void)longPress:(UILongPressGestureRecognizer*)gesture { [RASwipeOverManager.sharedInstance closeCurrentView]; - if ([[self currentView] isKindOfClass:[%c(RAAppSelectorView) class]]) - { - [(RAAppSelectorView*)[self currentView] relayoutApps]; - [self currentView].frame = CGRectMake(isHidingUnderlyingApp ? 0 : 10, 0, self.frame.size.width - (isHidingUnderlyingApp ? 0 : 10), self.frame.size.height); - return; - } - RAAppSelectorView *appSelector = [[%c(RAAppSelectorView) alloc] initWithFrame:CGRectMake(isHidingUnderlyingApp ? 0 : 10, 0, self.frame.size.width - (isHidingUnderlyingApp ? 0 : 10), self.frame.size.height)]; + if ([[self currentView] isKindOfClass:[%c(RAAppSelectorView) class]]) { + [(RAAppSelectorView*)[self currentView] relayoutApps]; + [self currentView].frame = CGRectMake(isHidingUnderlyingApp ? 0 : 10, 0, self.frame.size.width - (isHidingUnderlyingApp ? 0 : 10), self.frame.size.height); + return; + } + RAAppSelectorView *appSelector = [[%c(RAAppSelectorView) alloc] initWithFrame:CGRectMake(isHidingUnderlyingApp ? 0 : 10, 0, self.frame.size.width - (isHidingUnderlyingApp ? 0 : 10), self.frame.size.height)]; appSelector.tag = RASWIPEOVER_VIEW_TAG; appSelector.target = self; [appSelector relayoutApps]; [self addSubview:appSelector]; } --(void) appSelector:(RAAppSelectorView*)view appWasSelected:(NSString*)bundleIdentifier -{ +- (void)appSelector:(RAAppSelectorView*)view appWasSelected:(NSString*)bundleIdentifier { grabberView.alpha = 1; [[self currentView] removeFromSuperview]; [RASwipeOverManager.sharedInstance showApp:bundleIdentifier]; } -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { UIView *v = [self viewWithTag:RASWIPEOVER_VIEW_TAG]; - if ([v isKindOfClass:[%c(RAAppSelectorView) class]]) + if ([v isKindOfClass:[%c(RAAppSelectorView) class]]) { return NO; - if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) + } + if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { return NO; + } return YES; } -@end \ No newline at end of file +@end diff --git a/SwipeOver/SwipeOverGesture.xm b/SwipeOver/SwipeOverGesture.xm index 6ced5fb..4f9ec5f 100644 --- a/SwipeOver/SwipeOverGesture.xm +++ b/SwipeOver/SwipeOverGesture.xm @@ -16,189 +16,182 @@ NSDate *lastTouch; CGPoint startingPoint; BOOL firstSwipe = NO; -CGRect adjustFrameForRotation() -{ - CGFloat portraitWidth = 30; - CGFloat portraitHeight = 50; - - CGFloat width = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width; - CGFloat height = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height; - - switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) - { - case UIInterfaceOrientationPortrait: - NSLog(@"[ReachApp] portrait"); - return (CGRect){ { width - portraitWidth + 5, (height - portraitHeight) / 2 }, { portraitWidth, portraitHeight } }; - case UIInterfaceOrientationPortraitUpsideDown: - NSLog(@"[ReachApp] portrait upside down"); - return (CGRect){ { 0, 0}, { 50, 50 } }; - case UIInterfaceOrientationLandscapeLeft: - NSLog(@"[ReachApp] landscape left"); - return (CGRect){ { ((width - portraitWidth) / 2), -(portraitWidth / 2) }, { portraitWidth, portraitHeight } }; - case UIInterfaceOrientationLandscapeRight: - NSLog(@"[ReachApp] landscape right"); - return (CGRect){ { (height - portraitHeight) / 2, width - portraitWidth - 5 }, { portraitWidth, portraitHeight } }; +CGRect adjustFrameForRotation() { + CGFloat portraitWidth = 30; + CGFloat portraitHeight = 50; + + CGFloat width = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width; + CGFloat height = UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height; + + switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) { + case UIInterfaceOrientationPortrait: { + LogDebug(@"[ReachApp] portrait"); + return (CGRect){ { width - portraitWidth + 5, (height - portraitHeight) / 2 }, { portraitWidth, portraitHeight } }; + } + case UIInterfaceOrientationPortraitUpsideDown: { + LogDebug(@"[ReachApp] portrait upside down"); + return (CGRect){ { 0, 0}, { 50, 50 } }; } - return CGRectZero; + case UIInterfaceOrientationLandscapeLeft: { + LogDebug(@"[ReachApp] landscape left"); + return (CGRect){ { ((width - portraitWidth) / 2), -(portraitWidth / 2) }, { portraitWidth, portraitHeight } }; + } + case UIInterfaceOrientationLandscapeRight: { + LogDebug(@"[ReachApp] landscape right"); + return (CGRect){ { (height - portraitHeight) / 2, width - portraitWidth - 5 }, { portraitWidth, portraitHeight } }; + } + } + return CGRectZero; } -CGPoint adjustCenterForOffscreenSlide(CGPoint center) -{ - CGFloat portraitWidth = 30; - //CGFloat portraitHeight = 50; - - switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) - { - case UIInterfaceOrientationPortrait: - return (CGPoint) { center.x + portraitWidth, center.y }; - case UIInterfaceOrientationPortraitUpsideDown: - return (CGPoint) { center.x - portraitWidth, center.y }; - case UIInterfaceOrientationLandscapeLeft: - return (CGPoint) { center.x, center.y - portraitWidth }; - case UIInterfaceOrientationLandscapeRight: - return (CGPoint) { center.x, center.y + portraitWidth }; - } - return CGPointZero; +CGPoint adjustCenterForOffscreenSlide(CGPoint center) { + CGFloat portraitWidth = 30; + //CGFloat portraitHeight = 50; + + switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) { + case UIInterfaceOrientationPortrait: + return (CGPoint) { center.x + portraitWidth, center.y }; + case UIInterfaceOrientationPortraitUpsideDown: + return (CGPoint) { center.x - portraitWidth, center.y }; + case UIInterfaceOrientationLandscapeLeft: + return (CGPoint) { center.x, center.y - portraitWidth }; + case UIInterfaceOrientationLandscapeRight: + return (CGPoint) { center.x, center.y + portraitWidth }; + } + return CGPointZero; } -CGAffineTransform adjustTransformRotation() -{ - switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) - { - case UIInterfaceOrientationPortrait: - return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0)); - case UIInterfaceOrientationPortraitUpsideDown: - return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180)); - case UIInterfaceOrientationLandscapeLeft: - return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90)); - case UIInterfaceOrientationLandscapeRight: - return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90)); - } - return CGAffineTransformIdentity; +CGAffineTransform adjustTransformRotation() { + switch ([[UIApplication.sharedApplication _accessibilityFrontMostApplication] statusBarOrientation]) { + case UIInterfaceOrientationPortrait: + return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0)); + case UIInterfaceOrientationPortraitUpsideDown: + return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180)); + case UIInterfaceOrientationLandscapeLeft: + return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90)); + case UIInterfaceOrientationLandscapeRight: + return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90)); + } + return CGAffineTransformIdentity; } -BOOL swipeOverLocationIsInValidArea(CGFloat y) -{ - if (y == 0) return YES; // more than likely, UIGestureRecognizerStateEnded - - switch ([[%c(RASettings) sharedInstance] swipeOverGrabArea]) - { - case RAGrabAreaSideAnywhere: - return YES; - case RAGrabAreaSideTopThird: - return y <= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0; - case RAGrabAreaSideMiddleThird: - return y >= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0 && y <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0) * 2; - case RAGrabAreaSideBottomThird: - return y >= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0) * 2; - default: - return NO; - } +BOOL swipeOverLocationIsInValidArea(CGFloat y) { + if (y == 0) { + return YES; // more than likely, UIGestureRecognizerStateEnded + } + + switch ([[%c(RASettings) sharedInstance] swipeOverGrabArea]) { + case RAGrabAreaSideAnywhere: + return YES; + case RAGrabAreaSideTopThird: + return y <= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0; + case RAGrabAreaSideMiddleThird: + return y >= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0 && y <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0) * 2; + case RAGrabAreaSideBottomThird: + return y >= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 3.0) * 2; + default: + return NO; + } } -%ctor -{ - [[%c(RAGestureManager) sharedInstance] addGestureRecognizer:^RAGestureCallbackResult(UIGestureRecognizerState state, CGPoint location, CGPoint velocity) { - lastTouch = [NSDate date]; - - if ([%c(Multiplexer) shouldShowControlCenterGrabberOnFirstSwipe] || [[%c(RASettings) sharedInstance] alwaysShowSOGrabber]) - { - if (isShowingGrabber == NO && isPastGrabber == NO) - { - firstSwipe = YES; - isShowingGrabber = YES; - - grabberView = [[UIView alloc] init]; - - _UIBackdropView *bgView = [[%c(_UIBackdropView) alloc] initWithStyle:1]; - bgView.frame = CGRectMake(0, 0, grabberView.frame.size.width, grabberView.frame.size.height); - [grabberView addSubview:bgView]; - - //grabberView.backgroundColor = UIColor.redColor; - grabberView.frame = adjustFrameForRotation(); - - UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, grabberView.frame.size.width - 20, grabberView.frame.size.height - 20)]; - imgView.image = [%c(RAResourceImageProvider) imageForFilename:@"Grabber" constrainedToSize:CGSizeMake(grabberView.frame.size.width - 20, grabberView.frame.size.height - 20)]; - [grabberView addSubview:imgView]; - grabberView.layer.cornerRadius = 5; - grabberView.clipsToBounds = YES; - - grabberView.transform = adjustTransformRotation(); - //[UIWindow.keyWindow addSubview:grabberView]; // The desktop view most likely - [[[%c(RAHostManager) systemHostViewForApplication:UIApplication.sharedApplication._accessibilityFrontMostApplication] superview] addSubview:grabberView]; - - static void (^dismisser)() = ^{ // top kek, needs "static" so it's not a local, self-retaining block - if ([[NSDate date] timeIntervalSinceDate:lastTouch] > 2) - { - [UIView animateWithDuration:0.2 animations:^{ - //grabberView.frame = CGRectOffset(grabberView.frame, 40, 0); - grabberView.center = adjustCenterForOffscreenSlide(grabberView.center); - } completion:^(BOOL _) { - [grabberView removeFromSuperview]; - grabberView = nil; - isShowingGrabber = NO; - isPastGrabber = NO; - }]; - } - else if (grabberView) // left there - { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - dismisser(); - }); - } - }; - dismisser(); - - return RAGestureCallbackResultSuccess; - } - else if (CGRectContainsPoint(grabberView.frame, location) || (isShowingGrabber && !firstSwipe && [[%c(RASettings) sharedInstance] swipeOverGrabArea] != RAGrabAreaSideAnywhere && [[%c(RASettings) sharedInstance] swipeOverGrabArea] != RAGrabAreaSideMiddleThird)) - { - [grabberView removeFromSuperview]; - grabberView = nil; - isShowingGrabber = NO; - isPastGrabber = YES; - } - else if (isPastGrabber == NO) - { - if (state == UIGestureRecognizerStateEnded) - firstSwipe = NO; - startingPoint = CGPointZero; - isPastGrabber = NO; - return RAGestureCallbackResultSuccess; - } - } +%ctor { + [[%c(RAGestureManager) sharedInstance] addGestureRecognizer:^RAGestureCallbackResult(UIGestureRecognizerState state, CGPoint location, CGPoint velocity) { + lastTouch = [NSDate date]; + + if ([%c(Multiplexer) shouldShowControlCenterGrabberOnFirstSwipe] || [[%c(RASettings) sharedInstance] alwaysShowSOGrabber]) { + if (!isShowingGrabber && !isPastGrabber) { + firstSwipe = YES; + isShowingGrabber = YES; + + grabberView = [[UIView alloc] init]; + + _UIBackdropView *bgView = [[%c(_UIBackdropView) alloc] initWithStyle:1]; + bgView.frame = CGRectMake(0, 0, grabberView.frame.size.width, grabberView.frame.size.height); + [grabberView addSubview:bgView]; + + //grabberView.backgroundColor = UIColor.redColor; + grabberView.frame = adjustFrameForRotation(); + + UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, grabberView.frame.size.width - 20, grabberView.frame.size.height - 20)]; + imgView.image = [%c(RAResourceImageProvider) imageForFilename:@"Grabber" constrainedToSize:CGSizeMake(grabberView.frame.size.width - 20, grabberView.frame.size.height - 20)]; + [grabberView addSubview:imgView]; + grabberView.layer.cornerRadius = 5; + grabberView.clipsToBounds = YES; + + grabberView.transform = adjustTransformRotation(); + //[UIWindow.keyWindow addSubview:grabberView]; // The desktop view most likely + [[[%c(RAHostManager) systemHostViewForApplication:UIApplication.sharedApplication._accessibilityFrontMostApplication] superview] addSubview:grabberView]; + + static void (^dismisser)() = ^{ // top kek, needs "static" so it's not a local, self-retaining block + if ([[NSDate date] timeIntervalSinceDate:lastTouch] > 2) { + [UIView animateWithDuration:0.2 animations:^{ + //grabberView.frame = CGRectOffset(grabberView.frame, 40, 0); + grabberView.center = adjustCenterForOffscreenSlide(grabberView.center); + } completion:^(BOOL _) { + [grabberView removeFromSuperview]; + grabberView = nil; + isShowingGrabber = NO; + isPastGrabber = NO; + }]; + } else if (grabberView) { // left there + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + dismisser(); + }); + } + }; + dismisser(); - CGPoint translation; - switch (state) { - case UIGestureRecognizerStateBegan: - startingPoint = location; - break; - case UIGestureRecognizerStateChanged: - translation = CGPointMake(location.x - startingPoint.x, location.y - startingPoint.y); - break; - case UIGestureRecognizerStateEnded: - startingPoint = CGPointZero; - isPastGrabber = NO; - break; + return RAGestureCallbackResultSuccess; + } else if (CGRectContainsPoint(grabberView.frame, location) || (isShowingGrabber && !firstSwipe && [[%c(RASettings) sharedInstance] swipeOverGrabArea] != RAGrabAreaSideAnywhere && [[%c(RASettings) sharedInstance] swipeOverGrabArea] != RAGrabAreaSideMiddleThird)) { + [grabberView removeFromSuperview]; + grabberView = nil; + isShowingGrabber = NO; + isPastGrabber = YES; + } else if (!isPastGrabber) { + if (state == UIGestureRecognizerStateEnded) { + firstSwipe = NO; } + startingPoint = CGPointZero; + isPastGrabber = NO; + return RAGestureCallbackResultSuccess; + } + } - if (![RASwipeOverManager.sharedInstance isUsingSwipeOver]) - [RASwipeOverManager.sharedInstance startUsingSwipeOver]; - - //if (state == UIGestureRecognizerStateChanged) - [RASwipeOverManager.sharedInstance sizeViewForTranslation:translation state:state]; + CGPoint translation; + switch (state) { + case UIGestureRecognizerStateBegan: { + startingPoint = location; + break; + } + case UIGestureRecognizerStateChanged: { + translation = CGPointMake(location.x - startingPoint.x, location.y - startingPoint.y); + break; + } + case UIGestureRecognizerStateEnded: { + startingPoint = CGPointZero; + isPastGrabber = NO; + break; + } + } - return RAGestureCallbackResultSuccess; - } withCondition:^BOOL(CGPoint location, CGPoint velocity) { - if ([[%c(RAKeyboardStateListener) sharedInstance] visible] && ![RASwipeOverManager.sharedInstance isUsingSwipeOver]) - { - CGRect realKBFrame = CGRectMake(0, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height, [[%c(RAKeyboardStateListener) sharedInstance] size].width, [[%c(RAKeyboardStateListener) sharedInstance] size].height); - realKBFrame = CGRectOffset(realKBFrame, 0, -realKBFrame.size.height); - - if (CGRectContainsPoint(realKBFrame, location) || realKBFrame.size.height > 50) - return NO; - } - - return [[%c(RASettings) sharedInstance] swipeOverEnabled] && ![[%c(SBLockScreenManager) sharedInstance] isUILocked] && ![[%c(SBUIController) sharedInstance] isAppSwitcherShowing] && ![[%c(SBNotificationCenterController) sharedInstance] isVisible] && ![[%c(RAMissionControlManager) sharedInstance] isShowingMissionControl] && (swipeOverLocationIsInValidArea(location.y) || isShowingGrabber); - } forEdge:UIRectEdgeRight identifier:@"com.efrederickson.reachapp.swipeover.systemgesture" priority:RAGesturePriorityDefault]; -} \ No newline at end of file + if (![RASwipeOverManager.sharedInstance isUsingSwipeOver]) { + [RASwipeOverManager.sharedInstance startUsingSwipeOver]; + } + + //if (state == UIGestureRecognizerStateChanged) + [RASwipeOverManager.sharedInstance sizeViewForTranslation:translation state:state]; + + return RAGestureCallbackResultSuccess; + } withCondition:^BOOL(CGPoint location, CGPoint velocity) { + if ([[%c(RAKeyboardStateListener) sharedInstance] visible] && ![RASwipeOverManager.sharedInstance isUsingSwipeOver]) { + CGRect realKBFrame = CGRectMake(0, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height, [[%c(RAKeyboardStateListener) sharedInstance] size].width, [[%c(RAKeyboardStateListener) sharedInstance] size].height); + realKBFrame = CGRectOffset(realKBFrame, 0, -realKBFrame.size.height); + + if (CGRectContainsPoint(realKBFrame, location) || realKBFrame.size.height > 50) { + return NO; + } + } + + return [[%c(RASettings) sharedInstance] swipeOverEnabled] && ![[%c(SBLockScreenManager) sharedInstance] isUILocked] && ![[%c(SBUIController) sharedInstance] isAppSwitcherShowing] && ![[%c(SBNotificationCenterController) sharedInstance] isVisible] && ![[%c(RAMissionControlManager) sharedInstance] isShowingMissionControl] && (swipeOverLocationIsInValidArea(location.y) || isShowingGrabber); + } forEdge:UIRectEdgeRight identifier:@"com.efrederickson.reachapp.swipeover.systemgesture" priority:RAGesturePriorityDefault]; +} diff --git a/Theming/RATheme.h b/Theming/RATheme.h index 0259708..4cdd506 100644 --- a/Theming/RATheme.h +++ b/Theming/RATheme.h @@ -2,8 +2,8 @@ @interface RATheme : NSObject -@property (nonatomic, retain) NSString *themeIdentifier; -@property (nonatomic, retain) NSString *themeName; +@property (nonatomic, copy) NSString *themeIdentifier; +@property (nonatomic, copy) NSString *themeName; // Backgrounder @property (nonatomic, retain) UIColor *backgroundingIndicatorBackgroundColor; @@ -56,4 +56,4 @@ @property (nonatomic, retain) UIColor *swipeOverDetachBarColor; @property (nonatomic, retain) UIColor *swipeOverDetachImageColor; -@end \ No newline at end of file +@end diff --git a/Theming/RAThemeLoader.h b/Theming/RAThemeLoader.h index 59090ac..6a45f9f 100644 --- a/Theming/RAThemeLoader.h +++ b/Theming/RAThemeLoader.h @@ -1,7 +1,7 @@ #import "RATheme.h" @interface RAThemeLoader : NSObject -+(RATheme*)loadFromFile:(NSString*)baseName; ++ (RATheme*)loadFromFile:(NSString*)baseName; -+(RATheme*) themeFromDictionary:(NSDictionary*)dict; -@end \ No newline at end of file ++ (RATheme*)themeFromDictionary:(NSDictionary*)dict; +@end diff --git a/Theming/RAThemeLoader.mm b/Theming/RAThemeLoader.mm index cb405d3..58a6c25 100644 --- a/Theming/RAThemeLoader.mm +++ b/Theming/RAThemeLoader.mm @@ -6,16 +6,14 @@ //#define COLOR(name) [UIColor RA_colorWithHexString:dict[name]] @implementation RAThemeLoader -+(RATheme*)loadFromFile:(NSString*)baseName -{ ++ (RATheme*)loadFromFile:(NSString*)baseName { NSString *fullPath = [NSString stringWithFormat:@"%@/Themes/%@.plist",RA_BASE_PATH,[[baseName lastPathComponent] stringByDeletingPathExtension]]; NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:fullPath]; return [RAThemeLoader themeFromDictionary:dict]; } -+(RATheme*) themeFromDictionary:(NSDictionary*)dict -{ ++ (RATheme*)themeFromDictionary:(NSDictionary*)dict { RATheme *ret = [[RATheme alloc] init]; ret.themeIdentifier = dict[@"identifier"]; @@ -64,52 +62,55 @@ +(RATheme*) themeFromDictionary:(NSDictionary*)dict ret.swipeOverDetachBarColor = COLOR(@"swipeOverDetachBarColor"); ret.swipeOverDetachImageColor = COLOR(@"swipeOverDetachImageColor") ?: [UIColor RA_colorWithHexString:@"737273"]; - ret.quickAccessUseGenericTabLabel = [dict objectForKey:@"quickAccessUseGenericTabLabel"] == nil ? NO : [dict[@"quickAccessUseGenericTabLabel"] boolValue]; + ret.quickAccessUseGenericTabLabel = ![dict objectForKey:@"quickAccessUseGenericTabLabel"] ? NO : [dict[@"quickAccessUseGenericTabLabel"] boolValue]; return ret; } -+(NSTextAlignment) getTextAlignment:(NSObject*)value -{ - if ([value isKindOfClass:[NSString class]]) - { - if ([value isEqual:@"NSTextAlignmentLeft"] || [value isEqual:@"0"] || [value isEqual:@"Left"]) ++ (NSTextAlignment)getTextAlignment:(NSObject*)value { + if ([value isKindOfClass:[NSString class]]) { + if ([value isEqual:@"NSTextAlignmentLeft"] || [value isEqual:@"0"] || [value isEqual:@"Left"]) { return NSTextAlignmentLeft; - if ([value isEqual:@"NSTextAlignmentCenter"] || [value isEqual:@"1"] || [value isEqual:@"Center"]) + } + if ([value isEqual:@"NSTextAlignmentCenter"] || [value isEqual:@"1"] || [value isEqual:@"Center"]) { return NSTextAlignmentCenter; - if ([value isEqual:@"NSTextAlignmentRight"] || [value isEqual:@"2"] || [value isEqual:@"Right"]) + } + if ([value isEqual:@"NSTextAlignmentRight"] || [value isEqual:@"2"] || [value isEqual:@"Right"]) { return NSTextAlignmentRight; - if ([value isEqual:@"NSTextAlignmentJustified"] || [value isEqual:@"3"] || [value isEqual:@"Justified"]) + } + if ([value isEqual:@"NSTextAlignmentJustified"] || [value isEqual:@"3"] || [value isEqual:@"Justified"]) { return NSTextAlignmentJustified; - if ([value isEqual:@"NSTextAlignmentNatural"] || [value isEqual:@"4"] || [value isEqual:@"Natural"]) + } + if ([value isEqual:@"NSTextAlignmentNatural"] || [value isEqual:@"4"] || [value isEqual:@"Natural"]) { return NSTextAlignmentNatural; - } - else if ([value isKindOfClass:[NSNumber class]]) - { + } + } else if ([value isKindOfClass:[NSNumber class]]) { int actualValue = [((NSNumber*)value) intValue]; - if (actualValue == 0) + if (actualValue == 0) { return NSTextAlignmentLeft; - else if (actualValue == 1) + } else if (actualValue == 1) { return NSTextAlignmentCenter; - else if (actualValue == 2) + } else if (actualValue == 2) { return NSTextAlignmentRight; - else if (actualValue == 3) + } else if (actualValue == 3) { return NSTextAlignmentJustified; - else if (actualValue == 4) + } else if (actualValue == 4) { return NSTextAlignmentNatural; + } } return NSTextAlignmentCenter; } -+(UIColor*) tryGetColorFromThemeImageName:(NSString*)name -{ ++ (UIColor*)tryGetColorFromThemeImageName:(NSString*)name { NSString *expandedPath = [NSString stringWithFormat:@"%@/ThemingImages/%@.png",RA_BASE_PATH,[[name lastPathComponent] stringByDeletingPathExtension]]; BOOL exists = [NSFileManager.defaultManager fileExistsAtPath:expandedPath]; - if (!exists) + if (!exists) { return nil; + } UIImage *image = [UIImage imageWithContentsOfFile:expandedPath]; - if (image) + if (image) { return [UIColor colorWithPatternImage:image]; + } return nil; } -@end \ No newline at end of file +@end diff --git a/Theming/RAThemeManager.h b/Theming/RAThemeManager.h index 63abe5b..4c7f8ff 100644 --- a/Theming/RAThemeManager.h +++ b/Theming/RAThemeManager.h @@ -5,10 +5,10 @@ RATheme *currentTheme; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; --(RATheme*) currentTheme; --(NSArray*) allThemes; +- (RATheme*)currentTheme; +- (NSArray*)allThemes; --(void) invalidateCurrentThemeAndReload:(NSString*)currentIdentifier; -@end \ No newline at end of file +- (void)invalidateCurrentThemeAndReload:(NSString*)currentIdentifier; +@end diff --git a/Theming/RAThemeManager.mm b/Theming/RAThemeManager.mm index 3f69220..105e295 100644 --- a/Theming/RAThemeManager.mm +++ b/Theming/RAThemeManager.mm @@ -4,18 +4,21 @@ #import "headers.h" @implementation RAThemeManager -+(instancetype) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(RAThemeManager, [sharedInstance invalidateCurrentThemeAndReload:nil]); // will be reloaded by RASettings } --(RATheme*) currentTheme { return currentTheme; } --(NSArray*) allThemes { return allThemes.allValues; } +- (RATheme*)currentTheme { + return currentTheme; +} + +- (NSArray*)allThemes { + return allThemes.allValues; +} --(void) invalidateCurrentThemeAndReload:(NSString*)currentIdentifier -{ +- (void)invalidateCurrentThemeAndReload:(NSString*)currentIdentifier { #if DEBUG - NSLog(@"[ReachApp] loading themes..."); + LogDebug(@"[ReachApp] loading themes..."); NSDate *startTime = [NSDate date]; #endif @@ -26,33 +29,31 @@ -(void) invalidateCurrentThemeAndReload:(NSString*)currentIdentifier NSString *folderName = [NSString stringWithFormat:@"%@/Themes/", RA_BASE_PATH]; NSArray *themeFileNames = [NSFileManager.defaultManager subpathsAtPath:folderName]; - for (NSString *themeName in themeFileNames) - { - if ([themeName hasSuffix:@"plist"] == NO) + for (NSString *themeName in themeFileNames) { + if (![themeName hasSuffix:@"plist"]) { continue; + } RATheme *theme = [RAThemeLoader loadFromFile:themeName]; - if (theme && theme.themeIdentifier) - { - //NSLog(@"[ReachApp] adding %@", theme.themeIdentifier); + if (theme && theme.themeIdentifier) { + //LogDebug(@"[ReachApp] adding %@", theme.themeIdentifier); allThemes[theme.themeIdentifier] = theme; - if ([theme.themeIdentifier isEqual:currentIdentifier]) + if ([theme.themeIdentifier isEqual:currentIdentifier]) { currentTheme = theme; + } } } - if (!currentTheme) - { + if (!currentTheme) { currentTheme = [allThemes objectForKey:@"com.eljahandandrew.multiplexer.themes.default"]; - if (!currentTheme && allThemes.allKeys.count > 0) - { + if (!currentTheme && allThemes.allKeys.count > 0) { currentTheme = allThemes[allThemes.allKeys[0]]; } } #if DEBUG NSDate *endTime = [NSDate date]; - NSLog(@"[ReachApp] loaded %ld themes in %f seconds.", (long)allThemes.count, [endTime timeIntervalSinceDate:startTime]); + LogDebug(@"[ReachApp] loaded %ld themes in %f seconds.", (long)allThemes.count, [endTime timeIntervalSinceDate:startTime]); #endif } -@end \ No newline at end of file +@end diff --git a/TutorialApp/multiplexertutorial/Tweak.xm b/TutorialApp/multiplexertutorial/Tweak.xm index 41d6677..1415752 100644 --- a/TutorialApp/multiplexertutorial/Tweak.xm +++ b/TutorialApp/multiplexertutorial/Tweak.xm @@ -15,8 +15,8 @@ void open_settings(CFNotificationCenterRef a, void *b, CFStringRef c, const void %ctor { - if ([NSBundle.mainBundle.bundleIdentifier isEqual:@"com.apple.springboard"]) - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, open_settings, CFSTR("com.elijahandandrew.multiplexer.tutorial.open_settings"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); - else - %init; -} \ No newline at end of file + if (IN_SPRINGBOARD) + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, open_settings, CFSTR("com.elijahandandrew.multiplexer.tutorial.open_settings"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + else + %init; +} diff --git a/Tweak.xm b/Tweak.xm index cc91ecb..a909a3b 100644 --- a/Tweak.xm +++ b/Tweak.xm @@ -3,7 +3,7 @@ #include /* -This project thanks: +This project thanks: ForceReach: https://github.com/PoomSmart/ForceReach/ Reference: https://github.com/fewjative/Reference MessageBox: https://github.com/b3ll/MessageBox @@ -14,30 +14,29 @@ Various concepts / help / ideas: Ethan Arbuckle (@its_not_herpes) Many concepts and ideas have been used from them. Unlike shinvou's claims, however, there was no copyright violation. Nor did I use any of his code. Or Auxo 3's for that matter. See here for context: https://www.reddit.com/r/jailbreak/comments/3esp30/question_how_come_we_all_desperately_waited_for/cti3eck -Any code based off of or using parts of the above projects is documented. +Any code based off of or using parts of the above projects is documented. */ // IS_SPRINGBOARD macro optimized from always comparing NSBundle - because it won't change in-process BOOL $__IS_SPRINGBOARD = NO; -%ctor -{ - $__IS_SPRINGBOARD = [NSBundle.mainBundle.bundleIdentifier isEqual:@"com.apple.springboard"]; +%ctor { + $__IS_SPRINGBOARD = [[NSBundle mainBundle].bundleIdentifier isEqual:@"com.apple.springboard"]; } -void SET_BACKGROUNDED(id settings, BOOL value) -{ +void SET_BACKGROUNDED(id settings, BOOL value) { #if __has_feature(objc_arc) // stupid ARC... - ptrdiff_t bgOffset = ivar_getOffset(class_getInstanceVariable([settings class], "_backgrounded")); - char *bgPtr = ((char *)(__bridge void *)settings) + bgOffset; - memcpy(bgPtr, &value, sizeof(value)); + ptrdiff_t bgOffset = ivar_getOffset(class_getInstanceVariable([settings class], "_backgrounded")); + char *bgPtr = ((char *)(__bridge void *)settings) + bgOffset; + memcpy(bgPtr, &value, sizeof(value)); #else // ARC is off, easy way - if (value) + if (value) { object_setInstanceVariable(settings, "_backgrounded", (void*)YES); // strangely it doesn't like using the val, i have to do this. - else + } else { object_setInstanceVariable(settings, "_backgrounded", (void*)NO); + } #endif } diff --git a/UIAlertController+Window.h b/UIAlertController+Window.h new file mode 100644 index 0000000..748c4f5 --- /dev/null +++ b/UIAlertController+Window.h @@ -0,0 +1,16 @@ +// +// UIAlertController+Window.h +// FFM +// +// Created by Eric Larson on 6/17/15. +// Copyright (c) 2015 ForeFlight, LLC. All rights reserved. +// + +#import + +@interface UIAlertController (Window) + +- (void)show; +- (void)show:(BOOL)animated; + +@end diff --git a/UIAlertController+Window.m b/UIAlertController+Window.m new file mode 100644 index 0000000..3a48c9c --- /dev/null +++ b/UIAlertController+Window.m @@ -0,0 +1,54 @@ +// +// UIAlertController+Window.m +// FFM +// +// Created by Eric Larson on 6/17/15. +// Copyright (c) 2015 ForeFlight, LLC. All rights reserved. +// + +#import "UIAlertController+Window.h" +#import + +@interface UIAlertController (Private) + +@property (nonatomic, strong) UIWindow *alertWindow; + +@end + +@implementation UIAlertController (Private) + +@dynamic alertWindow; + +- (void)setAlertWindow:(UIWindow *)alertWindow { + objc_setAssociatedObject(self, @selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIWindow *)alertWindow { + return objc_getAssociatedObject(self, @selector(alertWindow)); +} + +@end + +@implementation UIAlertController (Window) + +- (void)show { + [self show:YES]; +} + +- (void)show:(BOOL)animated { + self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.alertWindow.rootViewController = [[UIViewController alloc] init]; + self.alertWindow.windowLevel = UIWindowLevelAlert + 1; + [self.alertWindow makeKeyAndVisible]; + [self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + + // precaution to insure window gets destroyed + self.alertWindow.hidden = YES; + self.alertWindow = nil; +} + +@end diff --git a/UIColor+HexString.h b/UIColor+HexString.h index 20e266f..1999511 100644 --- a/UIColor+HexString.h +++ b/UIColor+HexString.h @@ -9,6 +9,6 @@ @interface UIColor (HexString) -+ (UIColor *) RA_colorWithHexString:(NSString*)hexString; ++ (UIColor *)RA_colorWithHexString:(NSString*)hexString; @end diff --git a/UIColor+HexString.m b/UIColor+HexString.m index 399fb0a..8eb5cf8 100644 --- a/UIColor+HexString.m +++ b/UIColor+HexString.m @@ -10,48 +10,53 @@ @implementation UIColor (HexString) -+ (CGFloat) RA_colorComponentFrom: (NSString *) string start: (NSUInteger) start length: (NSUInteger) length { - NSString *substring = [string substringWithRange: NSMakeRange(start, length)]; - NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring]; ++ (CGFloat)RA_colorComponentFrom:(NSString *)string start:(NSUInteger)start length:(NSUInteger)length { + NSString *substring = [string substringWithRange:NSMakeRange(start, length)]; + NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat:@"%@%@", substring, substring]; unsigned hexComponent; [[NSScanner scannerWithString:fullHex] scanHexInt:&hexComponent]; return hexComponent / 255.0; } -+ (UIColor *) RA_colorWithHexString: (NSString *) hexString { - if (hexString.length == 0) - return nil; - NSString *colorString = [[hexString stringByReplacingOccurrencesOfString: @"#" withString: @""] uppercaseString]; ++ (UIColor *)RA_colorWithHexString: (NSString *) hexString { + if (hexString.length == 0) { + return nil; + } + NSString *colorString = [[hexString stringByReplacingOccurrencesOfString:@"#" withString:@""] uppercaseString]; CGFloat alpha, red, blue, green; switch ([colorString length]) { - case 3: // #RGB - alpha = 1.0f; - red = [self RA_colorComponentFrom: colorString start: 0 length: 1]; - green = [self RA_colorComponentFrom: colorString start: 1 length: 1]; - blue = [self RA_colorComponentFrom: colorString start: 2 length: 1]; - break; - case 4: // #ARGB - alpha = [self RA_colorComponentFrom: colorString start: 0 length: 1]; - red = [self RA_colorComponentFrom: colorString start: 1 length: 1]; - green = [self RA_colorComponentFrom: colorString start: 2 length: 1]; - blue = [self RA_colorComponentFrom: colorString start: 3 length: 1]; - break; - case 6: // #RRGGBB - alpha = 1.0f; - red = [self RA_colorComponentFrom: colorString start: 0 length: 2]; - green = [self RA_colorComponentFrom: colorString start: 2 length: 2]; - blue = [self RA_colorComponentFrom: colorString start: 4 length: 2]; - break; - case 8: // #AARRGGBB - alpha = [self RA_colorComponentFrom: colorString start: 0 length: 2]; - red = [self RA_colorComponentFrom: colorString start: 2 length: 2]; - green = [self RA_colorComponentFrom: colorString start: 4 length: 2]; - blue = [self RA_colorComponentFrom: colorString start: 6 length: 2]; - break; - default: - return nil; + case 3: { // #RGB + alpha = 1.0f; + red = [self RA_colorComponentFrom:colorString start:0 length:1]; + green = [self RA_colorComponentFrom:colorString start:1 length:1]; + blue = [self RA_colorComponentFrom:colorString start:2 length:1]; + break; + } + case 4: { // #ARGB + alpha = [self RA_colorComponentFrom:colorString start:0 length:1]; + red = [self RA_colorComponentFrom:colorString start:1 length:1]; + green = [self RA_colorComponentFrom:colorString start:2 length:1]; + blue = [self RA_colorComponentFrom:colorString start:3 length:1]; + break; + } + case 6: { // #RRGGBB + alpha = 1.0f; + red = [self RA_colorComponentFrom: colorString start: 0 length: 2]; + green = [self RA_colorComponentFrom: colorString start: 2 length: 2]; + blue = [self RA_colorComponentFrom: colorString start: 4 length: 2]; + break; + } + case 8: { // #AARRGGBB + alpha = [self RA_colorComponentFrom: colorString start: 0 length: 2]; + red = [self RA_colorComponentFrom: colorString start: 2 length: 2]; + green = [self RA_colorComponentFrom: colorString start: 4 length: 2]; + blue = [self RA_colorComponentFrom: colorString start: 6 length: 2]; + break; + } + default: + return nil; } - return [UIColor colorWithRed: red green: green blue: blue alpha: alpha]; + return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; } @end diff --git a/UIKit.xm b/UIKit.xm index 65c9203..3a367c1 100644 --- a/UIKit.xm +++ b/UIKit.xm @@ -16,68 +16,67 @@ NSMutableDictionary *oldFrames = [NSMutableDictionary new]; static Class $memorized$UITextEffectsWindow$class; %hook UIWindow --(void) setFrame:(CGRect)frame -{ - if ([self.class isEqual:$memorized$UITextEffectsWindow$class] == NO && [RAMessagingClient.sharedInstance shouldResize]) - { - if ([oldFrames objectForKey:@(self.hash)] == nil) - [oldFrames setObject:[NSValue valueWithCGRect:frame] forKey:@(self.hash)]; - - frame.origin.x = RAMessagingClient.sharedInstance.currentData.wantedClientOriginX == -1 ? 0 : RAMessagingClient.sharedInstance.currentData.wantedClientOriginX; - frame.origin.y = RAMessagingClient.sharedInstance.currentData.wantedClientOriginY == -1 ? 0 : RAMessagingClient.sharedInstance.currentData.wantedClientOriginY; - CGFloat overrideWidth = [RAMessagingClient.sharedInstance resizeSize].width; - CGFloat overrideHeight = [RAMessagingClient.sharedInstance resizeSize].height; - if (overrideWidth != -1 && overrideWidth != 0) - frame.size.width = overrideWidth; - if (overrideHeight != -1 && overrideHeight != 0) - frame.size.height = overrideHeight; - - if (self.subviews.count > 0) - { - ((UIView*)self.subviews[0]).frame = frame; - } +- (void)setFrame:(CGRect)frame { + if (![self.class isEqual:$memorized$UITextEffectsWindow$class] && [RAMessagingClient.sharedInstance shouldResize]) { + if (![oldFrames objectForKey:@(self.hash)]) { + [oldFrames setObject:[NSValue valueWithCGRect:frame] forKey:@(self.hash)]; + } + + frame.origin.x = RAMessagingClient.sharedInstance.currentData.wantedClientOriginX == -1 ? 0 : RAMessagingClient.sharedInstance.currentData.wantedClientOriginX; + frame.origin.y = RAMessagingClient.sharedInstance.currentData.wantedClientOriginY == -1 ? 0 : RAMessagingClient.sharedInstance.currentData.wantedClientOriginY; + CGFloat overrideWidth = [RAMessagingClient.sharedInstance resizeSize].width; + CGFloat overrideHeight = [RAMessagingClient.sharedInstance resizeSize].height; + if (overrideWidth != -1 && overrideWidth != 0) { + frame.size.width = overrideWidth; + } + if (overrideHeight != -1 && overrideHeight != 0) { + frame.size.height = overrideHeight; + } + + if (self.subviews.count > 0) { + ((UIView*)self.subviews[0]).frame = frame; } + } - %orig(frame); + %orig(frame); } -- (void)_rotateWindowToOrientation:(UIInterfaceOrientation)arg1 updateStatusBar:(BOOL)arg2 duration:(double)arg3 skipCallbacks:(BOOL)arg4 -{ - if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) - return; - %orig; +- (void)_rotateWindowToOrientation:(UIInterfaceOrientation)arg1 updateStatusBar:(BOOL)arg2 duration:(double)arg3 skipCallbacks:(BOOL)arg4 { + if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) { + return; + } + %orig; } -- (BOOL)_shouldAutorotateToInterfaceOrientation:(int)arg1 checkForDismissal:(BOOL)arg2 isRotationDisabled:(BOOL*)arg3 -{ - if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) - return NO; - return %orig; +- (BOOL)_shouldAutorotateToInterfaceOrientation:(int)arg1 checkForDismissal:(BOOL)arg2 isRotationDisabled:(BOOL*)arg3 { + if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) { + return NO; + } + return %orig; } -- (void)_setWindowInterfaceOrientation:(int)arg1 -{ - if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) - return; - %orig([RAMessagingClient.sharedInstance shouldForceOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:[RAMessagingClient.sharedInstance forcedOrientation]] ? [RAMessagingClient.sharedInstance forcedOrientation] : arg1); +- (void)_setWindowInterfaceOrientation:(int)arg1 { + if ([RAMessagingClient.sharedInstance shouldForceOrientation] && arg1 != [RAMessagingClient.sharedInstance forcedOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:arg1]) { + return; + } + %orig([RAMessagingClient.sharedInstance shouldForceOrientation] && [UIApplication.sharedApplication _isSupportedOrientation:[RAMessagingClient.sharedInstance forcedOrientation]] ? [RAMessagingClient.sharedInstance forcedOrientation] : arg1); } -- (void)_sendTouchesForEvent:(unsafe_id)arg1 -{ - %orig; +- (void)_sendTouchesForEvent:(unsafe_id)arg1 { + %orig; - dispatch_async(dispatch_get_main_queue(), ^{ - [RAMessagingClient.sharedInstance notifySpringBoardOfFrontAppChangeToSelf]; - }); + dispatch_async(dispatch_get_main_queue(), ^{ + [RAMessagingClient.sharedInstance notifySpringBoardOfFrontAppChangeToSelf]; + }); } %end %hook UIApplication --(void) applicationDidResume -{ - %orig; - [RAMessagingClient.sharedInstance requestUpdateFromServer]; - //[RAFakePhoneMode updateAppSizing]; +%property (nonatomic, assign) BOOL RA_networkActivity; +- (void)applicationDidResume { + %orig; + [RAMessagingClient.sharedInstance requestUpdateFromServer]; + //[RAFakePhoneMode updateAppSizing]; } /* +(void) _startWindowServerIfNecessary @@ -87,22 +86,18 @@ static Class $memorized$UITextEffectsWindow$class; [RAFakePhoneMode updateAppSizing]; } */ --(void) _setStatusBarHidden:(BOOL)arg1 animationParameters:(unsafe_id)arg2 changeApplicationFlag:(BOOL)arg3 -{ - //if ([RASettings.sharedInstance unifyStatusBar]) - if ([RAMessagingClient.sharedInstance shouldHideStatusBar]) - { - arg1 = YES; - arg3 = YES; - } - else if ([RAMessagingClient.sharedInstance shouldShowStatusBar]) - { - arg1 = NO; - arg3 = YES; - } - //arg1 = ((forcingRotation&&NO) || overrideDisplay) ? (isTopApp ? NO : YES) : arg1; - - %orig(arg1, arg2, arg3); +- (void)_setStatusBarHidden:(BOOL)arg1 animationParameters:(unsafe_id)arg2 changeApplicationFlag:(BOOL)arg3 { + //if ([RASettings.sharedInstance unifyStatusBar]) + if ([RAMessagingClient.sharedInstance shouldHideStatusBar]) { + arg1 = YES; + arg3 = YES; + } else if ([RAMessagingClient.sharedInstance shouldShowStatusBar]) { + arg1 = NO; + arg3 = YES; + } + //arg1 = ((forcingRotation&&NO) || overrideDisplay) ? (isTopApp ? NO : YES) : arg1; + + %orig(arg1, arg2, arg3); } /* @@ -114,150 +109,126 @@ static Class $memorized$UITextEffectsWindow$class; } */ -%new -(void) RA_forceRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation isReverting:(BOOL)reverting -{ - if (!reverting) - { - if (setPreviousOrientation == NO) - { - setPreviousOrientation = YES; - prevousOrientation = UIApplication.sharedApplication.statusBarOrientation; - if (wasStatusBarHidden == -1) - wasStatusBarHidden = UIApplication.sharedApplication.statusBarHidden; - } +%new - (void)RA_forceRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation isReverting:(BOOL)reverting { + if (!reverting) { + if (!setPreviousOrientation) { + setPreviousOrientation = YES; + prevousOrientation = UIApplication.sharedApplication.statusBarOrientation; + if (wasStatusBarHidden == -1) { + wasStatusBarHidden = UIApplication.sharedApplication.statusBarHidden; + } } - else if (setPreviousOrientation) - { - orientation = prevousOrientation; + } else if (setPreviousOrientation) { + orientation = prevousOrientation; - setPreviousOrientation = NO; - } + setPreviousOrientation = NO; + } - if (![UIApplication.sharedApplication _isSupportedOrientation:orientation]) - { - return; - } + if (![UIApplication.sharedApplication _isSupportedOrientation:orientation]) { + return; + } - for (UIWindow *window in [[UIApplication sharedApplication] windows]) - { - [window _setRotatableViewOrientation:orientation updateStatusBar:YES duration:0.25 force:YES]; - } + for (UIWindow *window in [[UIApplication sharedApplication] windows]) { + [window _setRotatableViewOrientation:orientation updateStatusBar:YES duration:0.25 force:YES]; + } } -%new -(void) RA_forceStatusBarVisibility:(BOOL)visible orRevert:(BOOL)revert -{ - if (revert) - { - if (wasStatusBarHidden != -1) - { - [UIApplication.sharedApplication _setStatusBarHidden:wasStatusBarHidden animationParameters:nil changeApplicationFlag:YES]; - } +%new - (void)RA_forceStatusBarVisibility:(BOOL)visible orRevert:(BOOL)revert { + if (revert) { + if (wasStatusBarHidden != -1) { + [UIApplication.sharedApplication _setStatusBarHidden:wasStatusBarHidden animationParameters:nil changeApplicationFlag:YES]; } - else - { - if (wasStatusBarHidden == -1) - wasStatusBarHidden = UIApplication.sharedApplication.statusBarHidden; - [UIApplication.sharedApplication _setStatusBarHidden:visible animationParameters:nil changeApplicationFlag:YES]; + } else { + if (wasStatusBarHidden == -1) { + wasStatusBarHidden = UIApplication.sharedApplication.statusBarHidden; } + [UIApplication.sharedApplication _setStatusBarHidden:visible animationParameters:nil changeApplicationFlag:YES]; + } } -%new -(void) RA_updateWindowsForSizeChange:(CGSize)size isReverting:(BOOL)revert -{ - if (revert) - { - for (UIWindow *window in [[UIApplication sharedApplication] windows]) - { - CGRect frame = window.frame; - if ([oldFrames objectForKey:@(window.hash)] != nil) - { - frame = [[oldFrames objectForKey:@(window.hash)] CGRectValue]; - [oldFrames removeObjectForKey:@(window.hash)]; - } - - [UIView animateWithDuration:0.4 animations:^{ - [window setFrame:frame]; - }]; - } - - if ([oldFrames objectForKey:@"statusBar"] != nil) - UIApplication.sharedApplication.statusBar.frame = [oldFrames[@"statusBar"] CGRectValue]; - - return; +%new - (void)RA_updateWindowsForSizeChange:(CGSize)size isReverting:(BOOL)revert { + if (revert) { + for (UIWindow *window in [[UIApplication sharedApplication] windows]) { + CGRect frame = window.frame; + if ([oldFrames objectForKey:@(window.hash)]) { + frame = [[oldFrames objectForKey:@(window.hash)] CGRectValue]; + [oldFrames removeObjectForKey:@(window.hash)]; + } + + [UIView animateWithDuration:0.4 animations:^{ + [window setFrame:frame]; + }]; } - if (size.width != -1) - { - if ([oldFrames objectForKey:@"statusBar"] == nil) - [oldFrames setObject:[NSValue valueWithCGRect:UIApplication.sharedApplication.statusBar.frame] forKey:@"statusBar"]; - UIApplication.sharedApplication.statusBar.frame = CGRectMake(0, 0, size.width, UIApplication.sharedApplication.statusBar.frame.size.height); + if ([oldFrames objectForKey:@"statusBar"]) { + UIApplication.sharedApplication.statusBar.frame = [oldFrames[@"statusBar"] CGRectValue]; } + return; + } - for (UIWindow *window in [[UIApplication sharedApplication] windows]) { - if ([oldFrames objectForKey:@(window.hash)] == nil) - [oldFrames setObject:[NSValue valueWithCGRect:window.frame] forKey:@(window.hash)]; + if (size.width != -1) { + if (![oldFrames objectForKey:@"statusBar"]) { + [oldFrames setObject:[NSValue valueWithCGRect:UIApplication.sharedApplication.statusBar.frame] forKey:@"statusBar"]; + } + UIApplication.sharedApplication.statusBar.frame = CGRectMake(0, 0, size.width, UIApplication.sharedApplication.statusBar.frame.size.height); + } - [UIView animateWithDuration:0.3 animations:^{ - [window setFrame:window.frame]; // updates with client message app data in the setFrame: hook - }]; + for (UIWindow *window in [[UIApplication sharedApplication] windows]) { + if (![oldFrames objectForKey:@(window.hash)]) { + [oldFrames setObject:[NSValue valueWithCGRect:window.frame] forKey:@(window.hash)]; } + + [UIView animateWithDuration:0.3 animations:^{ + [window setFrame:window.frame]; // updates with client message app data in the setFrame: hook + }]; + } } --(BOOL) isNetworkActivityIndicatorVisible -{ - if ([RAMessagingClient.sharedInstance isBeingHosted]) - return [objc_getAssociatedObject(self, @selector(RA_networkActivity)) boolValue]; - else - return %orig; +- (BOOL)isNetworkActivityIndicatorVisible { + if ([RAMessagingClient.sharedInstance isBeingHosted]) { + return self.RA_networkActivity; + } else { + return %orig; + } } --(void) setNetworkActivityIndicatorVisible:(BOOL)arg1 -{ - %orig(arg1); - if ([RAMessagingClient.sharedInstance isBeingHosted]) - { - objc_setAssociatedObject(self, @selector(RA_networkActivity), @(arg1), OBJC_ASSOCIATION_RETAIN_NONATOMIC); - - StatusBarData *data = [UIStatusBarServer getStatusBarData]; - data->itemIsEnabled[24] = arg1; // 24 = activity indicator - [UIApplication.sharedApplication.statusBar forceUpdateToData:data animated:YES]; - } +- (void)setNetworkActivityIndicatorVisible:(BOOL)arg1 { + %orig(arg1); + if ([RAMessagingClient.sharedInstance isBeingHosted]) { + self.RA_networkActivity = arg1; + StatusBarData *data = [UIStatusBarServer getStatusBarData]; + data->itemIsEnabled[26] = arg1; // 26 = activity indicator TODO: check if ios 8 + [UIApplication.sharedApplication.statusBar forceUpdateToData:data animated:YES]; + } } --(BOOL) openURL:(__unsafe_unretained NSURL*)url -{ - if ([RAMessagingClient.sharedInstance isBeingHosted])// || [RASettings.sharedInstance openLinksInWindows]) - { - return [RAMessagingClient.sharedInstance notifyServerToOpenURL:url openInWindow:[RASettings.sharedInstance openLinksInWindows]]; - } - return %orig; +- (BOOL)openURL:(__unsafe_unretained NSURL*)url { + if ([RAMessagingClient.sharedInstance isBeingHosted]) { // || [RASettings.sharedInstance openLinksInWindows]) + return [RAMessagingClient.sharedInstance notifyServerToOpenURL:url openInWindow:[RASettings.sharedInstance openLinksInWindows]]; + } + return %orig; } %end %hook UIStatusBar --(void) statusBarServer:(unsafe_id)arg1 didReceiveStatusBarData:(StatusBarData*)arg2 withActions:(int)arg3 -{ - if ([RAMessagingClient.sharedInstance isBeingHosted]) - arg2->itemIsEnabled[24] = [UIApplication.sharedApplication isNetworkActivityIndicatorVisible]; - %orig; +- (void)statusBarServer:(unsafe_id)arg1 didReceiveStatusBarData:(StatusBarData*)arg2 withActions:(int)arg3 { + if ([RAMessagingClient.sharedInstance isBeingHosted]) { + arg2->itemIsEnabled[26] = [UIApplication.sharedApplication isNetworkActivityIndicatorVisible]; + } + %orig; } %end -void reloadSettings(CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo) -{ - [RASettings.sharedInstance reloadSettings]; +void reloadSettings(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + [RASettings.sharedInstance reloadSettings]; } -%ctor -{ - IF_NOT_SPRINGBOARD { - %init; - $memorized$UITextEffectsWindow$class = objc_getClass("UITextEffectsWindow"); - } +%ctor { + IF_NOT_SPRINGBOARD { + %init; + $memorized$UITextEffectsWindow$class = %c(UITextEffectsWindow); + } - CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &reloadSettings, CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), NULL, 0); - [RASettings sharedInstance]; + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &reloadSettings, CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), NULL, 0); + [RASettings sharedInstance]; } diff --git a/WindowedMultitasking/ActivatorCreateAppWindow.xm b/WindowedMultitasking/ActivatorCreateAppWindow.xm new file mode 100644 index 0000000..3e9a3ff --- /dev/null +++ b/WindowedMultitasking/ActivatorCreateAppWindow.xm @@ -0,0 +1,52 @@ +#import +#import "RABackgrounder.h" +#import "RADesktopManager.h" +#import "RADesktopWindow.h" +#import "RAHostedAppView.h" +#import "RAWindowBar.h" +#import "RAWindowSorter.h" +#import "Multiplexer.h" + +@interface RAActivatorCreateWindowListener : NSObject +@end + +static RAActivatorCreateWindowListener *sharedInstance$RAActivatorCreateWindowListener; + +@implementation RAActivatorCreateWindowListener +- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)levent { + SBApplication *topApp = [[UIApplication sharedApplication] _accessibilityFrontMostApplication]; + RAIconIndicatorViewInfo indicatorInfo = [[%c(RABackgrounder) sharedInstance] allAggregatedIndicatorInfoForIdentifier:topApp.bundleIdentifier]; + + // Close app + [[%c(RABackgrounder) sharedInstance] temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:topApp andCloseForegroundApp:NO]; + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBDeactivationSettings *deactiveSets = [[%c(SBDeactivationSettings) alloc] init]; + [deactiveSets setFlag:YES forDeactivationSetting:20]; + [deactiveSets setFlag:NO forDeactivationSetting:2]; + [topApp _setDeactivationSettings:deactiveSets]; + + SBAppToAppWorkspaceTransaction *transaction = [Multiplexer createSBAppToAppWorkspaceTransactionForExitingApp:topApp]; + [transaction begin]; + + // Open in window + RAWindowBar *windowBar = [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:topApp animated:YES]; + if (!RADesktopManager.sharedInstance.lastUsedWindow) { + RADesktopManager.sharedInstance.lastUsedWindow = windowBar; + } + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; + + // Pop forced foreground backgrounding + [[%c(RABackgrounder) sharedInstance] queueRemoveTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; + [[%c(RABackgrounder) sharedInstance] removeTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; + [[%c(RABackgrounder) sharedInstance] updateIconIndicatorForIdentifier:topApp.bundleIdentifier withInfo:indicatorInfo]; +} +@end + +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance$RAActivatorCreateWindowListener = [[RAActivatorCreateWindowListener alloc] init]; + [[%c(LAActivator) sharedInstance] registerListener:sharedInstance$RAActivatorCreateWindowListener forName:@"com.efrederickson.reachapp.windowedmultitasking.createWindow"]; +} diff --git a/WindowedMultitasking/ActivatorToggleEditModeListener.xm b/WindowedMultitasking/ActivatorToggleEditModeListener.xm index b4a68e6..3be9f58 100644 --- a/WindowedMultitasking/ActivatorToggleEditModeListener.xm +++ b/WindowedMultitasking/ActivatorToggleEditModeListener.xm @@ -10,28 +10,25 @@ static RAActivatorToggleEditModeListener *sharedInstance; @implementation RAActivatorToggleEditModeListener -- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event -{ - RADesktopWindow *desktop = RADesktopManager.sharedInstance.currentDesktop; +- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event { + RADesktopWindow *desktop = RADesktopManager.sharedInstance.currentDesktop; - for (RAWindowBar *view in desktop.subviews) - { - if ([view isKindOfClass:[RAWindowBar class]]) - { - if (view.isOverlayShowing) - [view hideOverlay]; - else - [view showOverlay]; - } - } + for (RAWindowBar *view in desktop.subviews) { + if ([view isKindOfClass:[RAWindowBar class]]) { + if (view.isOverlayShowing) { + [view hideOverlay]; + } else { + [view showOverlay]; + } + } + } } @end -%ctor -{ - if([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.springboard"]) - { - sharedInstance = [[RAActivatorToggleEditModeListener alloc] init]; - [[%c(LAActivator) sharedInstance] registerListener:sharedInstance forName:@"com.efrederickson.reachapp.windowedmultitasking.toggleEditMode"]; - } -} \ No newline at end of file +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance = [[RAActivatorToggleEditModeListener alloc] init]; + [[%c(LAActivator) sharedInstance] registerListener:sharedInstance forName:@"com.efrederickson.reachapp.windowedmultitasking.toggleEditMode"]; +} diff --git a/WindowedMultitasking/LaunchToWindow.xm b/WindowedMultitasking/LaunchToWindow.xm index 5c917c0..ce65b3d 100644 --- a/WindowedMultitasking/LaunchToWindow.xm +++ b/WindowedMultitasking/LaunchToWindow.xm @@ -3,68 +3,52 @@ #import "RADesktopManager.h" #import "RADesktopWindow.h" -#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) -#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) -#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) - BOOL launchNextOpenIntoWindow = NO; BOOL override = NO; BOOL allowOpenApp = NO; %hook SBIconController --(void)iconWasTapped:(__unsafe_unretained SBApplicationIcon*)arg1 -{ - if ([RASettings.sharedInstance windowedMultitaskingEnabled] && [RASettings.sharedInstance launchIntoWindows] && arg1.application) - { +- (void)iconWasTapped:(__unsafe_unretained SBApplicationIcon*)arg1 { + if ([RASettings.sharedInstance windowedMultitaskingEnabled] && [RASettings.sharedInstance launchIntoWindows] && arg1.application) { [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:arg1.application animated:YES]; override = YES; } %orig; } --(void)_launchIcon:(unsafe_id)icon -{ - if (!override) +- (void)_launchIcon:(unsafe_id)icon { + if (!override) { %orig; - else + } else { override = NO; + } } %end %hook SBUIController -- (void)activateApplicationAnimated:(__unsafe_unretained SBApplication*)arg1 -{ +- (void)activateApplicationAnimated:(__unsafe_unretained SBApplication*)arg1 { // Broken //if (launchNextOpenIntoWindow) - if ([RASettings.sharedInstance windowedMultitaskingEnabled] &&[RASettings.sharedInstance launchIntoWindows] && allowOpenApp != YES) - { + if ([RASettings.sharedInstance windowedMultitaskingEnabled] &&[RASettings.sharedInstance launchIntoWindows] && !allowOpenApp) { [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:arg1 animated:YES]; //launchNextOpenIntoWindow = NO; return; - } - else - { + } else { [RADesktopManager.sharedInstance removeAppWithIdentifier:arg1.bundleIdentifier animated:NO forceImmediateUnload:YES]; } %orig; } -- (void)activateApplication:(__unsafe_unretained SBApplication*)arg1 -{ +- (void)activateApplication:(__unsafe_unretained SBApplication*)arg1 { // Broken //if (launchNextOpenIntoWindow) - if ([RASettings.sharedInstance windowedMultitaskingEnabled] &&[RASettings.sharedInstance launchIntoWindows] && allowOpenApp != YES) - { + if ([RASettings.sharedInstance windowedMultitaskingEnabled] &&[RASettings.sharedInstance launchIntoWindows] && !allowOpenApp) { [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:arg1 animated:YES]; //launchNextOpenIntoWindow = NO; return; - } - else - { + } else { [RADesktopManager.sharedInstance removeAppWithIdentifier:arg1.bundleIdentifier animated:NO forceImmediateUnload:YES]; } %orig; diff --git a/WindowedMultitasking/RADesktopManager.h b/WindowedMultitasking/RADesktopManager.h index 20d5917..45b161f 100644 --- a/WindowedMultitasking/RADesktopManager.h +++ b/WindowedMultitasking/RADesktopManager.h @@ -5,31 +5,31 @@ RADesktopWindow *currentDesktop; NSUInteger currentDesktopIndex; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; @property (nonatomic, weak) RAWindowBar *lastUsedWindow; --(void) addDesktop:(BOOL)switchTo; --(void) removeDesktopAtIndex:(NSUInteger)index; --(void) removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated; --(void) removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force; +- (void)addDesktop:(BOOL)switchTo; +- (void)removeDesktopAtIndex:(NSUInteger)index; +- (void)removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated; +- (void)removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force; --(BOOL) isAppOpened:(NSString*)identifier; --(RAWindowBar*) windowForIdentifier:(NSString*)identifier; +- (BOOL)isAppOpened:(NSString*)identifier; +- (RAWindowBar*)windowForIdentifier:(NSString*)identifier; --(NSUInteger) currentDesktopIndex; --(NSUInteger) numberOfDesktops; --(void) switchToDesktop:(NSUInteger)index; --(void) switchToDesktop:(NSUInteger)index actuallyShow:(BOOL)show; --(RADesktopWindow*) currentDesktop; --(NSArray*) availableDesktops; --(RADesktopWindow*) desktopAtIndex:(NSUInteger)index; +- (NSUInteger)currentDesktopIndex; +- (NSUInteger)numberOfDesktops; +- (void)switchToDesktop:(NSUInteger)index; +- (void)switchToDesktop:(NSUInteger)index actuallyShow:(BOOL)show; +- (RADesktopWindow*)currentDesktop; +- (NSArray*)availableDesktops; +- (RADesktopWindow*)desktopAtIndex:(NSUInteger)index; --(void) updateWindowSizeForApplication:(NSString*)identifier; --(void) updateRotationOnClients:(UIInterfaceOrientation)orientation; +- (void)updateWindowSizeForApplication:(NSString*)identifier; +- (void)updateRotationOnClients:(UIInterfaceOrientation)orientation; --(void) hideDesktop; --(void) reshowDesktop; +- (void)hideDesktop; +- (void)reshowDesktop; --(void) findNewForemostApp; -@end \ No newline at end of file +- (void)findNewForemostApp; +@end diff --git a/WindowedMultitasking/RADesktopManager.xm b/WindowedMultitasking/RADesktopManager.xm index 4c99cbd..a78d890 100644 --- a/WindowedMultitasking/RADesktopManager.xm +++ b/WindowedMultitasking/RADesktopManager.xm @@ -5,59 +5,57 @@ BOOL overrideUIWindow = NO; @implementation RADesktopManager -+(instancetype) sharedInstance -{ - SHARED_INSTANCE2(RADesktopManager, ++ (instancetype)sharedInstance { + SHARED_INSTANCE2(RADesktopManager, sharedInstance->windows = [NSMutableArray array]; [sharedInstance addDesktop:YES]; overrideUIWindow = YES; ); } --(void) addDesktop:(BOOL)switchTo -{ +- (void)addDesktop:(BOOL)switchTo { RADesktopWindow *desktopWindow = [[RADesktopWindow alloc] initWithFrame:UIScreen.mainScreen._referenceBounds]; [windows addObject:desktopWindow]; - if (switchTo) + if (switchTo) { [self switchToDesktop:windows.count - 1]; + } [desktopWindow loadInfo:[windows indexOfObject:desktopWindow]]; } --(void) removeDesktopAtIndex:(NSUInteger)index -{ - if (windows.count == 1 && index == 0) +- (void)removeDesktopAtIndex:(NSUInteger)index { + if (windows.count == 1 && index == 0) { return; + } - if (currentDesktopIndex == index) + if (currentDesktopIndex == index) { [self switchToDesktop:0]; + } RADesktopWindow *window = windows[index]; [window saveInfo]; [window closeAllApps]; - [windows removeObjectAtIndex:index]; + [windows removeObjectAtIndex:index]; } --(BOOL) isAppOpened:(NSString*)identifier -{ - for (RADesktopWindow *desktop in windows) - if ([desktop isAppOpened:identifier]) +- (BOOL)isAppOpened:(NSString*)identifier { + for (RADesktopWindow *desktop in windows) { + if ([desktop isAppOpened:identifier]) { return YES; + } + } return NO; } --(NSUInteger) numberOfDesktops -{ +- (NSUInteger)numberOfDesktops { return windows.count; } --(void) switchToDesktop:(NSUInteger)index -{ +- (void)switchToDesktop:(NSUInteger)index { [self switchToDesktop:index actuallyShow:YES]; } --(void) switchToDesktop:(NSUInteger)index actuallyShow:(BOOL)show -{ +- (void)switchToDesktop:(NSUInteger)index actuallyShow:(BOOL)show { RADesktopWindow *newDesktop = windows[index]; currentDesktop.hidden = YES; @@ -65,80 +63,73 @@ BOOL overrideUIWindow = NO; [currentDesktop unloadApps]; [newDesktop loadApps]; - if (show == NO) + if (!show) { newDesktop.hidden = YES; + } overrideUIWindow = NO; [newDesktop makeKeyAndVisible]; overrideUIWindow = YES; - if (show == NO) + if (!show) { newDesktop.hidden = YES; + } currentDesktopIndex = index; currentDesktop = newDesktop; //[newDesktop updateForOrientation:UIApplication.sharedApplication.statusBarOrientation]; } --(void) removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated -{ +- (void)removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated { [self removeAppWithIdentifier:bundleIdentifier animated:animated forceImmediateUnload:NO]; } --(void) removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force -{ - for (RADesktopWindow *window in windows) - { +- (void)removeAppWithIdentifier:(NSString*)bundleIdentifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force { + for (RADesktopWindow *window in windows) { [window removeAppWithIdentifier:bundleIdentifier animated:animated forceImmediateUnload:force]; } } --(RAWindowBar*) windowForIdentifier:(NSString*)identifier -{ - for (RADesktopWindow *desktop in windows) - if ([desktop isAppOpened:identifier]) +- (RAWindowBar*)windowForIdentifier:(NSString*)identifier { + for (RADesktopWindow *desktop in windows) { + if ([desktop isAppOpened:identifier]) { return [desktop windowForIdentifier:identifier]; + } + } return nil; } --(void) hideDesktop -{ +- (void)hideDesktop { currentDesktop.hidden = YES; } --(void) reshowDesktop -{ +- (void)reshowDesktop { currentDesktop.hidden = NO; } --(void) updateRotationOnClients:(UIInterfaceOrientation)orientation -{ - for (RADesktopWindow *w in windows) +- (void)updateRotationOnClients:(UIInterfaceOrientation)orientation { + for (RADesktopWindow *w in windows) { [w updateRotationOnClients:orientation]; + } } --(void) updateWindowSizeForApplication:(NSString*)identifier -{ - for (RADesktopManager *w in windows) +- (void)updateWindowSizeForApplication:(NSString*)identifier { + for (RADesktopManager *w in windows) { [w updateWindowSizeForApplication:identifier]; + } } --(void) setLastUsedWindow:(RAWindowBar*)window -{ - if (_lastUsedWindow) - { +- (void)setLastUsedWindow:(RAWindowBar*)window { + if (_lastUsedWindow) { [_lastUsedWindow resignForemostApp]; } _lastUsedWindow = window; [_lastUsedWindow becomeForemostApp]; } --(void) findNewForemostApp -{ +- (void)findNewForemostApp { RADesktopWindow *desktop = [self currentDesktop]; - for (RAHostedAppView *hostedApp in desktop.hostedWindows) - { + for (RAHostedAppView *hostedApp in desktop.hostedWindows) { RAWindowBar *bar = [desktop windowForIdentifier:hostedApp.app.bundleIdentifier]; - if (bar) - { + if (bar) { self.lastUsedWindow = bar; return; } @@ -146,10 +137,21 @@ BOOL overrideUIWindow = NO; //self.lastUsedWindow = nil; } --(RADesktopWindow*) desktopAtIndex:(NSUInteger)index { return windows[index]; } --(NSArray*) availableDesktops { return windows; } --(NSUInteger) currentDesktopIndex { return currentDesktopIndex; } --(RADesktopWindow*) currentDesktop { return currentDesktop; } +- (RADesktopWindow*)desktopAtIndex:(NSUInteger)index { + return windows[index]; +} + +- (NSArray*)availableDesktops { + return windows; +} + +- (NSUInteger)currentDesktopIndex { + return currentDesktopIndex; +} + +- (RADesktopWindow*)currentDesktop { + return currentDesktop; +} @end /* @@ -186,6 +188,6 @@ BOOL overrideUIWindow = NO; %ctor { - if ([NSBundle.mainBundle.bundleIdentifier isEqual:@"com.apple.springboard"]) + IF_SPRINGBOARD %init; -} \ No newline at end of file +} diff --git a/WindowedMultitasking/RADesktopWindow.h b/WindowedMultitasking/RADesktopWindow.h index 0feba46..a90b4c2 100644 --- a/WindowedMultitasking/RADesktopWindow.h +++ b/WindowedMultitasking/RADesktopWindow.h @@ -9,30 +9,30 @@ BOOL dontClearForcedPhoneState; } --(RAWindowBar*) addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated; --(RAWindowBar*) createAppWindowForSBApplication:(SBApplication*)app animated:(BOOL)animated; --(RAWindowBar*) createAppWindowWithIdentifier:(NSString*)identifier animated:(BOOL)animated; +- (RAWindowBar*)addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated; +- (RAWindowBar*)createAppWindowForSBApplication:(SBApplication*)app animated:(BOOL)animated; +- (RAWindowBar*)createAppWindowWithIdentifier:(NSString*)identifier animated:(BOOL)animated; --(void) addExistingWindow:(RAWindowBar*)window; --(void) removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated; --(void) removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force; +- (void)addExistingWindow:(RAWindowBar*)window; +- (void)removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated; +- (void)removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force; --(NSArray*) hostedWindows; --(BOOL) isAppOpened:(NSString*)identifier; --(RAWindowBar*) windowForIdentifier:(NSString*)identifier; +- (NSArray*)hostedWindows; +- (BOOL)isAppOpened:(NSString*)identifier; +- (RAWindowBar*)windowForIdentifier:(NSString*)identifier; --(UIInterfaceOrientation) currentOrientation; --(CGFloat) baseRotationForOrientation; --(UIInterfaceOrientation) appOrientationRelativeToThisOrientation:(CGFloat)currentRotation; --(void) updateRotationOnClients:(UIInterfaceOrientation)orientation; +- (UIInterfaceOrientation)currentOrientation; +- (CGFloat)baseRotationForOrientation; +- (UIInterfaceOrientation)appOrientationRelativeToThisOrientation:(CGFloat)currentRotation; +- (void)updateRotationOnClients:(UIInterfaceOrientation)orientation; --(void) updateWindowSizeForApplication:(NSString*)identifier; +- (void)updateWindowSizeForApplication:(NSString*)identifier; --(void) unloadApps; --(void) loadApps; --(void) closeAllApps; +- (void)unloadApps; +- (void)loadApps; +- (void)closeAllApps; --(void) saveInfo; --(void) loadInfo; --(void) loadInfo:(NSInteger)index; -@end \ No newline at end of file +- (void)saveInfo; +- (void)loadInfo; +- (void)loadInfo:(NSInteger)index; +@end diff --git a/WindowedMultitasking/RADesktopWindow.mm b/WindowedMultitasking/RADesktopWindow.mm index 941942e..343e5c9 100644 --- a/WindowedMultitasking/RADesktopWindow.mm +++ b/WindowedMultitasking/RADesktopWindow.mm @@ -7,30 +7,27 @@ #import "RAFakePhoneMode.h" @implementation RADesktopWindow --(id) initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) - { +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { appViews = [NSMutableArray array]; self.windowLevel = 1000; } return self; } --(RAWindowBar*) addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated -{ +- (RAWindowBar*)addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated { // Avoid adding duplicates - if it already exists as a window, return the existing window - for (RAWindowBar *bar in self.subviews) - if ([bar isKindOfClass:[RAWindowBar class]]) // Just verify - if (bar.attachedView.app == view.app) - return bar; + for (RAWindowBar *bar in self.subviews) { + if ([bar isKindOfClass:[RAWindowBar class]] && bar.attachedView.app == view.app) {// Just verify + return bar; + } + } - if ([RAFakePhoneMode shouldFakeForAppWithIdentifier:view.app.bundleIdentifier]) - { + if ([RAFakePhoneMode shouldFakeForAppWithIdentifier:view.app.bundleIdentifier]) { view.frame = (CGRect){ { 0, 100 }, [RAFakePhoneMode fakeSizeForAppWithIdentifier:view.app.bundleIdentifier] }; - } - else + } else { view.frame = CGRectMake(0, 100, UIScreen.mainScreen._referenceBounds.size.width, UIScreen.mainScreen._referenceBounds.size.height); + } view.center = self.center; RAWindowBar *windowBar = [[RAWindowBar alloc] init]; @@ -38,26 +35,29 @@ -(RAWindowBar*) addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated [windowBar attachView:view]; [appViews addObject:view]; - if (animated) + if (animated) { windowBar.alpha = 0; + } [self addSubview:windowBar]; - if (animated) + if (animated) { [UIView animateWithDuration:0.5 animations:^{ windowBar.alpha = 1; }]; + } - if (self.hidden == NO) + if (!self.hidden) { [view loadApp]; + } view.hideStatusBar = YES; windowBar.transform = CGAffineTransformMakeScale(0.5, 0.5); - if (![RAFakePhoneMode shouldFakeForAppWithIdentifier:view.app.bundleIdentifier]) + if (![RAFakePhoneMode shouldFakeForAppWithIdentifier:view.app.bundleIdentifier]) { windowBar.transform = CGAffineTransformRotate(windowBar.transform, DEGREES_TO_RADIANS([self baseRotationForOrientation])); + } windowBar.hidden = NO; lastKnownOrientation = -1; //view.shouldUseExternalKeyboard = YES; - if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:view.app.bundleIdentifier]) - { + if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:view.app.bundleIdentifier]) { RAPreservedWindowInformation info = [RAWindowStatePreservationSystemManager.sharedInstance windowInformationForAppIdentifier:view.app.bundleIdentifier]; windowBar.center = info.center; @@ -66,7 +66,7 @@ -(RAWindowBar*) addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated windowBar.center = info.center; windowBar.transform = info.transform; } completion:^(BOOL _) { - [windowBar updateClientRotation]; + [windowBar updateClientRotation]; RADesktopManager.sharedInstance.lastUsedWindow = windowBar; }]; } @@ -77,8 +77,7 @@ -(RAWindowBar*) addAppWithView:(RAHostedAppView*)view animated:(BOOL)animated return windowBar; } --(void) addExistingWindow:(RAWindowBar*)window -{ +- (void)addExistingWindow:(RAWindowBar*)window { [appViews addObject:window.attachedView]; [self addSubview:window]; @@ -86,29 +85,23 @@ -(void) addExistingWindow:(RAWindowBar*)window ((UIView*)self.subviews[self.subviews.count - 1]).transform = window.transform; } --(RAWindowBar*) createAppWindowForSBApplication:(SBApplication*)app animated:(BOOL)animated -{ +- (RAWindowBar*)createAppWindowForSBApplication:(SBApplication*)app animated:(BOOL)animated { return [self createAppWindowWithIdentifier:app.bundleIdentifier animated:animated]; } --(RAWindowBar*) createAppWindowWithIdentifier:(NSString*)identifier animated:(BOOL)animated -{ +- (RAWindowBar*)createAppWindowWithIdentifier:(NSString*)identifier animated:(BOOL)animated { RAHostedAppView *view = [[RAHostedAppView alloc] initWithBundleIdentifier:identifier]; view.renderWallpaper = YES; return [self addAppWithView:view animated:animated]; } --(void) removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated -{ +- (void)removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated { [self removeAppWithIdentifier:identifier animated:animated forceImmediateUnload:NO]; } --(void) removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force -{ - for (RAHostedAppView *view in appViews) - { - if ([view.bundleIdentifier isEqual:identifier]) - { +- (void)removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated forceImmediateUnload:(BOOL)force { + for (RAHostedAppView *view in appViews) { + if ([view.bundleIdentifier isEqual:identifier]) { void (^destructor)() = ^{ //view.shouldUseExternalKeyboard = NO; [view unloadApp:force]; @@ -117,32 +110,32 @@ -(void) removeAppWithIdentifier:(NSString*)identifier animated:(BOOL)animated fo [appViews removeObject:view]; [self saveInfo]; - if (dontClearForcedPhoneState == NO && [RAFakePhoneMode shouldFakeForAppWithIdentifier:identifier]) + if (!dontClearForcedPhoneState && [RAFakePhoneMode shouldFakeForAppWithIdentifier:identifier]) { [RAMessagingServer.sharedInstance forcePhoneMode:NO forIdentifier:identifier andRelaunchApp:YES]; + } }; - if (animated) + if (animated) { [UIView animateWithDuration:0.3 animations:^{ view.superview.layer.transform = CATransform3DMakeScale(0.1, 0.1, 1); view.superview.layer.position = CGPointMake(UIScreen.mainScreen._referenceBounds.size.width / 2, UIScreen.mainScreen._referenceBounds.size.height); view.superview.layer.opacity = 0.0f; [RADesktopManager.sharedInstance findNewForemostApp]; - //view.superview.alpha = 0; - } completion:^(BOOL _) { destructor(); }]; - else + //view.superview.alpha = 0; + } completion:^(BOOL _) { + destructor(); + }]; + } else { destructor(); - + } return; } } } --(void) updateWindowSizeForApplication:(NSString*)identifier -{ +- (void)updateWindowSizeForApplication:(NSString*)identifier { NSArray *tempArrayToAvoidMutationCrash = [appViews copy]; - for (RAHostedAppView *view in tempArrayToAvoidMutationCrash) - { - if ([view.bundleIdentifier isEqual:identifier]) - { + for (RAHostedAppView *view in tempArrayToAvoidMutationCrash) { + if ([view.bundleIdentifier isEqual:identifier]) { dontClearForcedPhoneState = YES; [self removeAppWithIdentifier:identifier animated:NO forceImmediateUnload:YES]; [self createAppWindowWithIdentifier:identifier animated:NO]; @@ -162,94 +155,93 @@ -(void) updateWindowSizeForApplication:(NSString*)identifier } } --(NSArray*) hostedWindows -{ +- (NSArray*)hostedWindows { return appViews; } --(void) unloadApps -{ - for (RAHostedAppView *view in appViews) +- (void)unloadApps { + for (RAHostedAppView *view in appViews) { [view unloadApp]; + } } --(void) loadApps -{ - for (RAHostedAppView *view in appViews) +- (void)loadApps { + for (RAHostedAppView *view in appViews) { [view loadApp]; + } } --(void) closeAllApps -{ +- (void)closeAllApps { //while (appViews.count > 0) int i = appViews.count - 1; - while (i --> 0) // Always wanted to use that 😍 - { + while (i --> 0) { // Always wanted to use that 😍 [self removeAppWithIdentifier:((RAHostedAppView*)appViews[i]).bundleIdentifier animated:YES]; - } + } } --(void) updateRotationOnClients:(UIInterfaceOrientation)orientation -{ +- (void)updateRotationOnClients:(UIInterfaceOrientation)orientation { lastKnownOrientation = orientation; - for (RAWindowBar *app in self.subviews) - if ([app isKindOfClass:[RAWindowBar class]]) // could be a diferent kind of UIView actually - [app updateClientRotation:orientation]; + for (RAWindowBar *app in self.subviews) { + if ([app isKindOfClass:[RAWindowBar class]]){ // could be a diferent kind of UIView actually + [app updateClientRotation:orientation]; + } + } } --(BOOL) isAppOpened:(NSString*)identifier -{ - for (RAHostedAppView *app in appViews) - if ([app.app.bundleIdentifier isEqual:identifier]) +- (BOOL)isAppOpened:(NSString*)identifier { + for (RAHostedAppView *app in appViews) { + if ([app.app.bundleIdentifier isEqual:identifier]) { return YES; + } + } return NO; } --(RAWindowBar*) windowForIdentifier:(NSString*)identifier -{ - for (UIView *view in self.subviews) - if ([view isKindOfClass:[RAWindowBar class]]) - { +- (RAWindowBar*)windowForIdentifier:(NSString*)identifier { + for (UIView *view in self.subviews) { + if ([view isKindOfClass:[RAWindowBar class]]) { RAWindowBar *bar = (RAWindowBar*)view; - if ([bar.attachedView.app.bundleIdentifier isEqual:identifier]) + if ([bar.attachedView.app.bundleIdentifier isEqual:identifier]) { return bar; + } } + } return nil; } --(void) saveInfo -{ +- (void)saveInfo { [RAWindowStatePreservationSystemManager.sharedInstance saveDesktopInformation:self]; [RASnapshotProvider.sharedInstance forceReloadSnapshotOfDesktop:self]; } --(void) loadInfo -{ +- (void)loadInfo { NSInteger index = [RADesktopManager.sharedInstance.availableDesktops indexOfObject:self]; - if ([RAWindowStatePreservationSystemManager.sharedInstance hasDesktopInformationAtIndex:index] == NO) + if (![RAWindowStatePreservationSystemManager.sharedInstance hasDesktopInformationAtIndex:index]) { return; + } RAPreservedDesktopInformation info = [RAWindowStatePreservationSystemManager.sharedInstance desktopInformationForIndex:index]; - for (NSString *bundleIdentifier in info.openApps) + for (NSString *bundleIdentifier in info.openApps) { [self createAppWindowWithIdentifier:bundleIdentifier animated:YES]; + } } --(UIInterfaceOrientation) currentOrientation -{ - if (lastKnownOrientation >= 0) +- (UIInterfaceOrientation)currentOrientation { + if (lastKnownOrientation >= 0) { return lastKnownOrientation; + } return UIApplication.sharedApplication.statusBarOrientation; } --(CGFloat) baseRotationForOrientation -{ +- (CGFloat)baseRotationForOrientation { UIInterfaceOrientation o = [self currentOrientation]; - if (o == UIInterfaceOrientationLandscapeRight) + if (o == UIInterfaceOrientationLandscapeRight) { return 90; - else if (o == UIInterfaceOrientationLandscapeLeft) + } else if (o == UIInterfaceOrientationLandscapeLeft) { return 270; - else if (o == UIInterfaceOrientationPortraitUpsideDown) + } else if (o == UIInterfaceOrientationPortraitUpsideDown) { return 180; + } return 0; } @@ -257,99 +249,97 @@ -(UIInterfaceOrientation) appOrientationRelativeToThisOrientation:(CGFloat)curre { UIInterfaceOrientation base = [self currentOrientation]; - switch (base) - { - case UIInterfaceOrientationLandscapeLeft: - if (currentRotation >= 315 || currentRotation <= 45) - return UIInterfaceOrientationLandscapeLeft; - else if (currentRotation > 45 && currentRotation <= 135) - return UIInterfaceOrientationPortraitUpsideDown; - else if (currentRotation > 135 && currentRotation <= 215) - return UIInterfaceOrientationLandscapeRight; - else - return UIInterfaceOrientationPortrait; - - case UIInterfaceOrientationLandscapeRight: - if (currentRotation >= 315 || currentRotation <= 45) - return UIInterfaceOrientationLandscapeRight; - else if (currentRotation > 45 && currentRotation <= 135) - return UIInterfaceOrientationPortrait; - else if (currentRotation > 135 && currentRotation <= 215) - return UIInterfaceOrientationLandscapeLeft; - else - return UIInterfaceOrientationPortraitUpsideDown; - - case UIInterfaceOrientationPortraitUpsideDown: - if (currentRotation >= 315 || currentRotation <= 45) + switch (base) { + case UIInterfaceOrientationLandscapeLeft: { + if (currentRotation >= 315 || currentRotation <= 45) { + return UIInterfaceOrientationLandscapeLeft; + } else if (currentRotation > 45 && currentRotation <= 135) { return UIInterfaceOrientationPortraitUpsideDown; - else if (currentRotation > 45 && currentRotation <= 135) + } else if (currentRotation > 135 && currentRotation <= 215) { return UIInterfaceOrientationLandscapeRight; - else if (currentRotation > 135 && currentRotation <= 215) + } else { return UIInterfaceOrientationPortrait; - else + } + } + case UIInterfaceOrientationLandscapeRight: { + if (currentRotation >= 315 || currentRotation <= 45) { + return UIInterfaceOrientationLandscapeRight; + } else if (currentRotation > 45 && currentRotation <= 135) { + return UIInterfaceOrientationPortrait; + } else if (currentRotation > 135 && currentRotation <= 215) { return UIInterfaceOrientationLandscapeLeft; - + } else { + return UIInterfaceOrientationPortraitUpsideDown; + } + } + case UIInterfaceOrientationPortraitUpsideDown: { + if (currentRotation >= 315 || currentRotation <= 45) { + return UIInterfaceOrientationPortraitUpsideDown; + } else if (currentRotation > 45 && currentRotation <= 135) { + return UIInterfaceOrientationLandscapeRight; + } else if (currentRotation > 135 && currentRotation <= 215) { + return UIInterfaceOrientationPortrait; + } else { + return UIInterfaceOrientationLandscapeLeft; + } + } case UIInterfaceOrientationPortrait: default: break; } - if (currentRotation >= 315 || currentRotation <= 45) - { + if (currentRotation >= 315 || currentRotation <= 45) { return UIInterfaceOrientationPortrait; - } - else if (currentRotation > 45 && currentRotation <= 135) - { + } else if (currentRotation > 45 && currentRotation <= 135) { return UIInterfaceOrientationLandscapeLeft; - } - else if (currentRotation > 135 && currentRotation <= 215) - { + } else if (currentRotation > 135 && currentRotation <= 215) { return UIInterfaceOrientationPortraitUpsideDown; - } - else - { + } else { return UIInterfaceOrientationLandscapeRight; } } --(void) loadInfo:(NSInteger)index -{ - if ([RAWindowStatePreservationSystemManager.sharedInstance hasDesktopInformationAtIndex:index] == NO) +- (void)loadInfo:(NSInteger)index { + if (![RAWindowStatePreservationSystemManager.sharedInstance hasDesktopInformationAtIndex:index]) { return; + } RAPreservedDesktopInformation info = [RAWindowStatePreservationSystemManager.sharedInstance desktopInformationForIndex:index]; - for (NSString *bundleIdentifier in info.openApps) + for (NSString *bundleIdentifier in info.openApps) { [self createAppWindowWithIdentifier:bundleIdentifier animated:YES]; + } } --(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; - UIView *subview; - while ((subview = [objects nextObject])) - { - if (self.rootViewController && [self.rootViewController.view isEqual:subview]) - continue; - if (subview.hidden) - continue; - UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; - if (success) - return success; - } - return [super hitTest:point withEvent:event]; +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; + UIView *subview; + while ((subview = [objects nextObject])) { + if (self.rootViewController && [self.rootViewController.view isEqual:subview]) { + continue; + } + if (subview.hidden) { + continue; + } + UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; + if (success) { + return success; + } + } + return [super hitTest:point withEvent:event]; } -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL isContained = NO; - for (UIView *view in self.subviews) - { - if (self.rootViewController && [self.rootViewController.view isEqual:view]) - continue; - if (view.hidden) - continue; - if (CGRectContainsPoint(view.frame, point) || CGRectContainsPoint(view.frame, [view convertPoint:point fromView:self])) // [self convertPoint:point toView:view])) + for (UIView *view in self.subviews) { + if (self.rootViewController && [self.rootViewController.view isEqual:view]) { + continue; + } + if (view.hidden) { + continue; + } + if (CGRectContainsPoint(view.frame, point) || CGRectContainsPoint(view.frame, [view convertPoint:point fromView:self])) { // [self convertPoint:point toView:view])) isContained = YES; + } } return isContained; } -@end \ No newline at end of file +@end diff --git a/WindowedMultitasking/RAWindowBar.h b/WindowedMultitasking/RAWindowBar.h index de233bd..9ac0391 100644 --- a/WindowedMultitasking/RAWindowBar.h +++ b/WindowedMultitasking/RAWindowBar.h @@ -3,36 +3,36 @@ @class RADesktopWindow; -@interface RAWindowBar : UIView { +@interface RAWindowBar : UIView { RAHostedAppView *attachedView; } @property (nonatomic, weak) RADesktopWindow *desktop; --(void) close; --(void) maximize; --(void) minimize; --(void) sizingLockButtonTap:(id)arg1; --(BOOL) isLocked; +- (void)close; +- (void)maximize; +- (void)minimize; +- (void)sizingLockButtonTap:(id)arg1; +- (BOOL)isLocked; --(void) showOverlay; --(void) hideOverlay; --(BOOL) isOverlayShowing; +- (void)showOverlay; +- (void)hideOverlay; +- (BOOL)isOverlayShowing; --(RAHostedAppView*) attachedView; --(void) attachView:(RAHostedAppView*)view; +- (RAHostedAppView*)attachedView; +- (void)attachView:(RAHostedAppView*)view; --(void) updateClientRotation; --(void) updateClientRotation:(UIInterfaceOrientation)orientation; +- (void)updateClientRotation; +- (void)updateClientRotation:(UIInterfaceOrientation)orientation; --(void) scaleTo:(CGFloat)scale animated:(BOOL)animate; --(void) scaleTo:(CGFloat)scale animated:(BOOL)animate derotate:(BOOL)derotate; +- (void)scaleTo:(CGFloat)scale animated:(BOOL)animate; +- (void)scaleTo:(CGFloat)scale animated:(BOOL)animate derotate:(BOOL)derotate; --(void) saveWindowInfo; +- (void)saveWindowInfo; --(void) disableLongPress; --(void) enableLongPress; +- (void)disableLongPress; +- (void)enableLongPress; --(void) resignForemostApp; --(void) becomeForemostApp; -@end \ No newline at end of file +- (void)resignForemostApp; +- (void)becomeForemostApp; +@end diff --git a/WindowedMultitasking/RAWindowBar.xm b/WindowedMultitasking/RAWindowBar.xm index c0a0791..9da0bc2 100644 --- a/WindowedMultitasking/RAWindowBar.xm +++ b/WindowedMultitasking/RAWindowBar.xm @@ -44,11 +44,9 @@ extern BOOL allowOpenApp; @end @implementation RAWindowBar --(void) attachView:(RAHostedAppView*)view -{ +- (void)attachView:(RAHostedAppView*)view { height = 40; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - { + if (IS_IPAD) { height = 45; } @@ -64,9 +62,9 @@ extern BOOL allowOpenApp; view.hideStatusBar = YES; [self addSubview:view]; - panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - panGesture.delegate = self; - [self addGestureRecognizer:panGesture]; + panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; + panGesture.delegate = self; + [self addGestureRecognizer:panGesture]; scaleGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)]; scaleGesture.delegate = self; @@ -87,12 +85,12 @@ extern BOOL allowOpenApp; [self addGestureRecognizer:tapGesture]; doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; - doubleTapGesture.numberOfTapsRequired = 2; + doubleTapGesture.numberOfTapsRequired = 2; doubleTapGesture.delegate = self; [self addGestureRecognizer:doubleTapGesture]; tripleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTripleTap:)]; - tripleTapGesture.numberOfTapsRequired = 3; + tripleTapGesture.numberOfTapsRequired = 3; tripleTapGesture.delegate = self; [self addGestureRecognizer:tripleTapGesture]; @@ -104,103 +102,103 @@ extern BOOL allowOpenApp; [doubleTapGesture requireGestureRecognizerToFail:tripleTapGesture]; - self.userInteractionEnabled = YES; - enableDrag = YES; - enableLongPress = YES; - - titleLabel = [[RAInsetLabel alloc] initWithFrame:CGRectMake(0, 0, myFrame.size.width, height)]; - titleLabel.textInset = UIEdgeInsetsMake(0, THEMED(windowedMultitaskingBarTitleTextInset) ?: 5, 0, THEMED(windowedMultitaskingBarTitleTextInset) ?: 5); - titleLabel.textAlignment = THEMED(windowedMultaskingBarTitleTextAlignment); - titleLabel.font = [UIFont systemFontOfSize:18]; - titleLabel.textColor = THEMED(windowedMultitaskingBarTitleColor); - titleLabel.text = [view displayName]; - [self addSubview:titleLabel]; - - CGFloat tmp = 16; - while (tmp + 16 < height) - tmp += 16; - buttonSize = tmp; - spacing = (height - buttonSize) / 2.0; - - if (![RASettings.sharedInstance onlyShowWindowBarIconsOnOverlay]) - { - /* - alignment: - 0 = left - 1 = right - */ - - // This is terribly inefficient.... plz send help - - static id closeItemIdentifier = [[NSObject alloc] init], - maxItemIdentifier = [[NSObject alloc] init], - minItemIdentifier = [[NSObject alloc] init], - rotationItemIdentifier = [[NSObject alloc] init]; - - NSMutableArray *infos = [NSMutableArray array]; - - NSInteger closeAlignment = THEMED(windowedMultitaskingCloseButtonAlignment); - NSInteger maxAlignment = THEMED(windowedMultitaskingMaxButtonAlignment); - NSInteger minAlignment = THEMED(windowedMultitaskingMinButtonAlignment); - NSInteger rotationAlignment = THEMED(windowedMultitaskingRotationAlignment); - - NSInteger closePriority = THEMED(windowedMultitaskingCloseButtonPriority); - NSInteger maxPriority = THEMED(windowedMultitaskingMaxButtonPriority); - NSInteger minPriority = THEMED(windowedMultitaskingMinButtonPriority); - NSInteger rotationPriority = THEMED(windowedMultitaskingRotationPriority); - - RAWindowBarIconInfo *tmpItem = [[RAWindowBarIconInfo alloc] init]; - tmpItem.alignment = closeAlignment; - tmpItem.priority = closePriority; - tmpItem.item = closeItemIdentifier; - [infos addObject:tmpItem]; + self.userInteractionEnabled = YES; + enableDrag = YES; + enableLongPress = YES; + + titleLabel = [[RAInsetLabel alloc] initWithFrame:CGRectMake(0, 0, myFrame.size.width, height)]; + titleLabel.textInset = UIEdgeInsetsMake(0, THEMED(windowedMultitaskingBarTitleTextInset) ?: 5, 0, THEMED(windowedMultitaskingBarTitleTextInset) ?: 5); + titleLabel.textAlignment = THEMED(windowedMultaskingBarTitleTextAlignment); + titleLabel.font = [UIFont systemFontOfSize:18]; + titleLabel.textColor = THEMED(windowedMultitaskingBarTitleColor); + titleLabel.text = [view displayName]; + [self addSubview:titleLabel]; + + CGFloat tmp = 16; + while (tmp + 16 < height) { + tmp += 16; + } + buttonSize = tmp; + spacing = (height - buttonSize) / 2.0; + + if (![RASettings.sharedInstance onlyShowWindowBarIconsOnOverlay]) { + /* + alignment: + 0 = left + 1 = right + */ + + // This is terribly inefficient.... plz send help + + static id closeItemIdentifier = [[NSObject alloc] init], + maxItemIdentifier = [[NSObject alloc] init], + minItemIdentifier = [[NSObject alloc] init], + rotationItemIdentifier = [[NSObject alloc] init]; + + NSMutableArray *infos = [NSMutableArray array]; + + NSInteger closeAlignment = THEMED(windowedMultitaskingCloseButtonAlignment); + NSInteger maxAlignment = THEMED(windowedMultitaskingMaxButtonAlignment); + NSInteger minAlignment = THEMED(windowedMultitaskingMinButtonAlignment); + NSInteger rotationAlignment = THEMED(windowedMultitaskingRotationAlignment); + + NSInteger closePriority = THEMED(windowedMultitaskingCloseButtonPriority); + NSInteger maxPriority = THEMED(windowedMultitaskingMaxButtonPriority); + NSInteger minPriority = THEMED(windowedMultitaskingMinButtonPriority); + NSInteger rotationPriority = THEMED(windowedMultitaskingRotationPriority); + + RAWindowBarIconInfo *tmpItem = [[RAWindowBarIconInfo alloc] init]; + tmpItem.alignment = closeAlignment; + tmpItem.priority = closePriority; + tmpItem.item = closeItemIdentifier; + [infos addObject:tmpItem]; tmpItem = [[RAWindowBarIconInfo alloc] init]; - tmpItem.alignment = maxAlignment; - tmpItem.priority = maxPriority; - tmpItem.item = maxItemIdentifier; - [infos addObject:tmpItem]; - - tmpItem = [[RAWindowBarIconInfo alloc] init]; - tmpItem.alignment = minAlignment; - tmpItem.priority = minPriority; - tmpItem.item = minItemIdentifier; - [infos addObject:tmpItem]; - - tmpItem = [[RAWindowBarIconInfo alloc] init]; - tmpItem.alignment = rotationAlignment; - tmpItem.priority = rotationPriority; - tmpItem.item = rotationItemIdentifier; - [infos addObject:tmpItem]; - - NSMutableArray *leftIconOrder = [NSMutableArray array]; - NSMutableArray *rightIconOrder = [NSMutableArray array]; - - for (int i = 0; i < infos.count; i++) - { + tmpItem.alignment = maxAlignment; + tmpItem.priority = maxPriority; + tmpItem.item = maxItemIdentifier; + [infos addObject:tmpItem]; + + tmpItem = [[RAWindowBarIconInfo alloc] init]; + tmpItem.alignment = minAlignment; + tmpItem.priority = minPriority; + tmpItem.item = minItemIdentifier; + [infos addObject:tmpItem]; + + tmpItem = [[RAWindowBarIconInfo alloc] init]; + tmpItem.alignment = rotationAlignment; + tmpItem.priority = rotationPriority; + tmpItem.item = rotationItemIdentifier; + [infos addObject:tmpItem]; + + NSMutableArray *leftIconOrder = [NSMutableArray array]; + NSMutableArray *rightIconOrder = [NSMutableArray array]; + + for (int i = 0; i < infos.count; i++) { RAWindowBarIconInfo *info = infos[i]; - if (info.alignment == 0) + if (info.alignment == 0) { [leftIconOrder addObject:info]; - else + } else { [rightIconOrder addObject:info]; + } } [leftIconOrder sortUsingComparator:^(RAWindowBarIconInfo *a, RAWindowBarIconInfo *b) { - if (a.priority > b.priority) + if (a.priority > b.priority) { return (NSComparisonResult)NSOrderedDescending; - else if (a.priority < b.priority) + } else if (a.priority < b.priority) { return (NSComparisonResult)NSOrderedAscending; - - return (NSComparisonResult)NSOrderedSame; + } + return (NSComparisonResult)NSOrderedSame; }]; [rightIconOrder sortUsingComparator:^(RAWindowBarIconInfo *a, RAWindowBarIconInfo *b) { - if (a.priority > b.priority) + if (a.priority > b.priority) { return (NSComparisonResult)NSOrderedDescending; - else if (a.priority < b.priority) + } else if (a.priority < b.priority) { return (NSComparisonResult)NSOrderedAscending; - - return (NSComparisonResult)NSOrderedSame; + } + return (NSComparisonResult)NSOrderedSame; }]; @@ -256,39 +254,37 @@ extern BOOL allowOpenApp; return sizingLockButton; }; - for (RAWindowBarIconInfo *item in leftIconOrder) - { + for (RAWindowBarIconInfo *item in leftIconOrder) { UIButton *button = nil; - if (item.item == closeItemIdentifier) + if (item.item == closeItemIdentifier) { button = createCloseButton(); - else if (item.item == maxItemIdentifier) + } else if (item.item == maxItemIdentifier) { button = createMaxButton(); - else if (item.item == minItemIdentifier) + } else if (item.item == minItemIdentifier) { button = createMinButton(); - else if (item.item == rotationItemIdentifier) + } else if (item.item == rotationItemIdentifier) { button = createRotationButton(); + } - if (button) - { + if (button) { button.frame = CGRectMake(leftSpace, spacing, buttonSize, buttonSize); leftSpace += button.frame.size.width + (THEMED(windowedMultitaskingBarTitleTextInset) ?: 5); } } - for (RAWindowBarIconInfo *item in rightIconOrder) - { + for (RAWindowBarIconInfo *item in rightIconOrder) { UIButton *button = nil; - if (item.item == closeItemIdentifier) + if (item.item == closeItemIdentifier) { button = createCloseButton(); - else if (item.item == maxItemIdentifier) + } else if (item.item == maxItemIdentifier) { button = createMaxButton(); - else if (item.item == minItemIdentifier) + } else if (item.item == minItemIdentifier) { button = createMinButton(); - else if (item.item == rotationItemIdentifier) + } else if (item.item == rotationItemIdentifier) { button = createRotationButton(); + } - if (button) - { + if (button) { button.frame = CGRectMake(rightSpace, spacing, buttonSize, buttonSize); rightSpace -= button.frame.size.width + (THEMED(windowedMultitaskingBarTitleTextInset) ?: 5); } @@ -303,227 +299,200 @@ extern BOOL allowOpenApp; self.layer.mask = maskLayer; } --(void) drawRect:(CGRect)rect -{ - CGRect topRect = CGRectMake(0, 0, rect.size.width, height); - // Fill the rectangle with grey - [barBackgroundColor setFill]; - UIRectFill(topRect); +- (void)drawRect:(CGRect)rect { + CGRect topRect = CGRectMake(0, 0, rect.size.width, height); + // Fill the rectangle with grey + [barBackgroundColor setFill]; + UIRectFill(topRect); - [super drawRect:rect]; + [super drawRect:rect]; } --(void) close -{ +- (void)close { [RADesktopManager.sharedInstance removeAppWithIdentifier:self.attachedView.bundleIdentifier animated:YES]; } --(void) maximize -{ +- (void)maximize { allowOpenApp = YES; - if ([%c(SBUIController) respondsToSelector:@selector(activateApplicationAnimated:)]) + if ([%c(SBUIController) respondsToSelector:@selector(activateApplicationAnimated:)]) { [[%c(SBUIController) sharedInstance] activateApplicationAnimated:attachedView.app]; - else + } else { [[%c(SBUIController) sharedInstance] activateApplication:attachedView.app]; + } allowOpenApp = NO; } --(void) minimize -{ +- (void)minimize { [attachedView rotateToOrientation:UIInterfaceOrientationPortrait]; [UIView animateWithDuration:0.7 animations:^{ self.transform = CGAffineTransformMakeScale(0.25, 0.25); }]; } --(void) closeButtonTap:(id)arg1 -{ +- (void)closeButtonTap:(id)arg1 { [self close]; } --(void) maximizeButtonTap:(id)arg1 -{ +- (void)maximizeButtonTap:(id)arg1 { [self maximize]; } --(void) minimizeButtonTap:(id)arg1 -{ +- (void)minimizeButtonTap:(id)arg1 { [self minimize]; } --(void) saveWindowInfo -{ +- (void)saveWindowInfo { [RAWindowStatePreservationSystemManager.sharedInstance saveWindowInformation:self]; - if (self.desktop) - { + if (self.desktop) { [self.desktop saveInfo]; } } --(BOOL) isLocked -{ - if ([RASettings.sharedInstance windowRotationLockMode] == 0) - { +- (BOOL)isLocked { + if ([RASettings.sharedInstance windowRotationLockMode] == 0) { return sizingLocked; - } - else - { + } else { return appRotationLocked; } } --(void) sizingLockButtonTap:(id)arg1 -{ - if ([RASettings.sharedInstance windowRotationLockMode] == 0) - { +- (void)sizingLockButtonTap:(id)arg1 { + if ([RASettings.sharedInstance windowRotationLockMode] == 0) { sizingLocked = !sizingLocked; - } - else - { + } else { appRotationLocked = !appRotationLocked; } - if (sizingLocked || appRotationLocked) - { + if (sizingLocked || appRotationLocked) { [sizingLockButton setImage:[RAResourceImageProvider imageForFilename:@"Lock" size:CGSizeMake(16, 16) tintedTo:THEMED(windowedMultitaskingRotationIconTint)] forState:UIControlStateNormal]; - } - else - { + } else { [sizingLockButton setImage:[RAResourceImageProvider imageForFilename:@"Unlocked" size:CGSizeMake(16, 16) tintedTo:THEMED(windowedMultitaskingRotationIconTint)] forState:UIControlStateNormal]; [self updateClientRotation]; } } --(void) scaleTo:(CGFloat)scale animated:(BOOL)animate -{ +- (void)scaleTo:(CGFloat)scale animated:(BOOL)animate { [self scaleTo:scale animated:animate derotate:NO]; } --(void) scaleTo:(CGFloat)scale animated:(BOOL)animate derotate:(BOOL)derotate -{ +- (void)scaleTo:(CGFloat)scale animated:(BOOL)animate derotate:(BOOL)derotate { CGFloat rotation = atan2(self.transform.b, self.transform.a); CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale); - if (derotate == NO) + if (!derotate) { transform = CGAffineTransformRotate(transform, rotation); + } - if (animate) + if (animate) { [UIView animateWithDuration:0.2 animations:^{ - [self setTransform:transform]; - }]; - else + [self setTransform:transform]; + }]; + } else { [self setTransform:transform]; + } [self saveWindowInfo]; } --(void) addRotation:(CGFloat)rads updateApp:(BOOL)update -{ - if (sizingLocked) +- (void)addRotation:(CGFloat)rads updateApp:(BOOL)update { + if (sizingLocked) { return; - - if (rads != 0) + } + + if (rads != 0) { self.transform = CGAffineTransformRotate(self.transform, rads); + } + + if (update) { + CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); + CGFloat rotateSnapDegrees = 0; + + if (currentRotation < 0) { + currentRotation = 360 + currentRotation; + } + + if (currentRotation >= 315 || currentRotation <= 45) { + rotateSnapDegrees = 360 - currentRotation; + } else if (currentRotation > 45 && currentRotation <= 135) { + rotateSnapDegrees = 90 - currentRotation; + } else if (currentRotation > 135 && currentRotation <= 215) { + rotateSnapDegrees = 180 - currentRotation; + } else { + rotateSnapDegrees = 270 - currentRotation; + } + + if ([RASettings.sharedInstance snapRotation]) { + [UIView animateWithDuration:0.2 animations:^{ + self.transform = CGAffineTransformRotate(self.transform, DEGREES_TO_RADIANS(rotateSnapDegrees)); + }]; + } + + if (!appRotationLocked) { + [attachedView rotateToOrientation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; + } - if (update) - { - CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); - CGFloat rotateSnapDegrees = 0; - - if (currentRotation < 0) - currentRotation = 360 + currentRotation; - - if (currentRotation >= 315 || currentRotation <= 45) - rotateSnapDegrees = 360 - currentRotation; - else if (currentRotation > 45 && currentRotation <= 135) - rotateSnapDegrees = 90 - currentRotation; - else if (currentRotation > 135 && currentRotation <= 215) - rotateSnapDegrees = 180 - currentRotation; - else - rotateSnapDegrees = 270 - currentRotation; - - if ([RASettings.sharedInstance snapRotation]) - [UIView animateWithDuration:0.2 animations:^{ - self.transform = CGAffineTransformRotate(self.transform, DEGREES_TO_RADIANS(rotateSnapDegrees)); - }]; - - if (!appRotationLocked) - [attachedView rotateToOrientation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; - - if ([RASettings.sharedInstance snapWindows] && [RAWindowSnapDataProvider shouldSnapWindow:self]) - { + if ([RASettings.sharedInstance snapWindows] && [RAWindowSnapDataProvider shouldSnapWindow:self]) { [RAWindowSnapDataProvider snapWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self] animated:YES]; isSnapped = YES; } [self saveWindowInfo]; - } + } } --(void) updateClientRotation -{ - if (!appRotationLocked) - { - CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); - [self updateClientRotation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; +- (void)updateClientRotation { + if (appRotationLocked) { + return; } + CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); + [self updateClientRotation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; } --(void) updateClientRotation:(UIInterfaceOrientation)orientation -{ - if (!appRotationLocked) - { - CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); - [attachedView rotateToOrientation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; +- (void)updateClientRotation:(UIInterfaceOrientation)orientation { + if (appRotationLocked) { + return; } + CGFloat currentRotation = RADIANS_TO_DEGREES(atan2(self.transform.b, self.transform.a)); + [attachedView rotateToOrientation:[self.desktop appOrientationRelativeToThisOrientation:currentRotation]]; } --(void) disableLongPress -{ +- (void)disableLongPress { enableLongPress = NO; longPressGesture.enabled = NO; longPressGesture.enabled = YES; } --(void) enableLongPress -{ +- (void)enableLongPress { enableLongPress = YES; } --(void) swapOrientationButtonTap:(id)arg1 -{ +- (void)swapOrientationButtonTap:(id)arg1 { [self addRotation:DEGREES_TO_RADIANS(90) updateApp:YES]; } -- (void)handleRotate:(UIRotationGestureRecognizer *)gesture -{ - if ([RASettings.sharedInstance alwaysEnableGestures] == NO && self.isOverlayShowing == NO) +- (void)handleRotate:(UIRotationGestureRecognizer *)gesture { + if (![RASettings.sharedInstance alwaysEnableGestures] && !self.isOverlayShowing) { return; + } - if (gesture.state == UIGestureRecognizerStateChanged) - { - [self addRotation:gesture.rotation updateApp:NO]; - //[self setTransform:CGAffineTransformRotate(self.transform, gesture.rotation)]; - gesture.rotation = 0.0; - } - else if (gesture.state == UIGestureRecognizerStateEnded) - { - [self addRotation:0 updateApp:YES]; - } -} - --(void) handleLongPress:(UILongPressGestureRecognizer*)sender -{ - if (!enableLongPress) - { + if (gesture.state == UIGestureRecognizerStateChanged) { + [self addRotation:gesture.rotation updateApp:NO]; + //[self setTransform:CGAffineTransformRotate(self.transform, gesture.rotation)]; + gesture.rotation = 0.0; + } else if (gesture.state == UIGestureRecognizerStateEnded) { + [self addRotation:0 updateApp:YES]; + } +} + +- (void)handleLongPress:(UILongPressGestureRecognizer*)sender { + if (!enableLongPress) { return; } [self close]; } --(void) showOverlay -{ +- (void)showOverlay { RAWindowOverlayView *overlay = [[RAWindowOverlayView alloc] initWithFrame:CGRectMake(0, height, self.bounds.size.width, self.bounds.size.height - height)]; overlay.alpha = 0; overlay.tag = 465982; @@ -540,8 +509,7 @@ extern BOOL allowOpenApp; }]; } --(void) hideOverlay -{ +- (void)hideOverlay { [(RAWindowOverlayView*)[self viewWithTag:465982] dismiss]; [UIView animateWithDuration:0.5 animations:^{ closeButton.alpha = 1; @@ -551,52 +519,47 @@ extern BOOL allowOpenApp; }]; } --(BOOL) isOverlayShowing { return [self viewWithTag:465982] != nil; } +- (BOOL)isOverlayShowing { + return [self viewWithTag:465982] != nil; +} --(void) handleTap:(UITapGestureRecognizer*)tap -{ - if (!self.isOverlayShowing) - [self showOverlay]; +- (void)handleTap:(UITapGestureRecognizer*)tap { + if (self.isOverlayShowing) { + return; + } + [self showOverlay]; } --(void) handleDoubleTap:(UITapGestureRecognizer*)tap -{ +- (void)handleDoubleTap:(UITapGestureRecognizer*)tap { [attachedView rotateToOrientation:UIInterfaceOrientationPortrait]; [UIView animateWithDuration:0.7 animations:^{ self.transform = CGAffineTransformMakeScale(0.6, 0.6); }]; } --(void) handleTripleTap:(UITapGestureRecognizer*)tap -{ - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) - [RAMessagingServer.sharedInstance forcePhoneMode:![RAFakePhoneMode shouldFakeForAppWithIdentifier:attachedView.app.bundleIdentifier] forIdentifier:attachedView.app.bundleIdentifier andRelaunchApp:YES]; +- (void)handleTripleTap:(UITapGestureRecognizer*)tap { + if (!IS_IPAD) { + return; + } + [RAMessagingServer.sharedInstance forcePhoneMode:![RAFakePhoneMode shouldFakeForAppWithIdentifier:attachedView.app.bundleIdentifier] forIdentifier:attachedView.app.bundleIdentifier andRelaunchApp:YES]; } --(void) handlePan:(UIPanGestureRecognizer*)sender -{ - if (!enableDrag) - { +- (void)handlePan:(UIPanGestureRecognizer*)sender { + if (!enableDrag) { [self removePotentialSnapShadow]; return; } - if (sender.state == UIGestureRecognizerStateBegan) - { + if (sender.state == UIGestureRecognizerStateBegan) { [self.superview bringSubviewToFront:self]; initialPoint = sender.view.center; - } - else if (sender.state == UIGestureRecognizerStateChanged) - { + } else if (sender.state == UIGestureRecognizerStateChanged) { enableLongPress = NO; - } - else if (sender.state == UIGestureRecognizerStateEnded) - { + } else if (sender.state == UIGestureRecognizerStateEnded) { enableLongPress = YES; [self saveWindowInfo]; - if ([RASettings.sharedInstance snapWindows] && [RAWindowSnapDataProvider shouldSnapWindow:self]) - { + if ([RASettings.sharedInstance snapWindows] && [RAWindowSnapDataProvider shouldSnapWindow:self]) { [RAWindowSnapDataProvider snapWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self] animated:YES completion:^{ [self removePotentialSnapShadow]; [self saveWindowInfo]; @@ -606,42 +569,43 @@ extern BOOL allowOpenApp; tapGesture.enabled = NO; tapGesture.enabled = YES; return; - } - else + } else { [self removePotentialSnapShadow]; + } return; } isSnapped = NO; - UIView *view = sender.view; - CGPoint point = [sender translationInView:view.superview]; + UIView *view = sender.view; + CGPoint point = [sender translationInView:view.superview]; - CGPoint translatedPoint = CGPointMake(initialPoint.x + point.x, initialPoint.y + point.y); - view.center = translatedPoint; + CGPoint translatedPoint = CGPointMake(initialPoint.x + point.x, initialPoint.y + point.y); + view.center = translatedPoint; - [self updatePotentialSnapShadow]; + [self updatePotentialSnapShadow]; } -- (void)handlePinch:(UIPinchGestureRecognizer *)gesture -{ - if ([RASettings.sharedInstance alwaysEnableGestures] == NO && self.isOverlayShowing == NO) +- (void)handlePinch:(UIPinchGestureRecognizer *)gesture { + if (![RASettings.sharedInstance alwaysEnableGestures] && !self.isOverlayShowing) { return; + } + + switch (gesture.state) { + case UIGestureRecognizerStateBegan: { + enableDrag = NO; enableLongPress = NO; + break; + } + case UIGestureRecognizerStateChanged: { + [self setTransform:CGAffineTransformScale(self.transform, gesture.scale, gesture.scale)]; + //self.bounds = (CGRect){ self.bounds.origin, {self.bounds.size.width * gesture.scale, self.bounds.size.height * gesture.scale} }; + + gesture.scale = 1.0; + break; + } + case UIGestureRecognizerStateEnded: { + enableDrag = YES; enableLongPress = YES; - switch (gesture.state) { - case UIGestureRecognizerStateBegan: - enableDrag = NO; enableLongPress = NO; - break; - case UIGestureRecognizerStateChanged: - [self setTransform:CGAffineTransformScale(self.transform, gesture.scale, gesture.scale)]; - //self.bounds = (CGRect){ self.bounds.origin, {self.bounds.size.width * gesture.scale, self.bounds.size.height * gesture.scale} }; - - gesture.scale = 1.0; - break; - case UIGestureRecognizerStateEnded: - enableDrag = YES; enableLongPress = YES; - - if ([RAWindowSnapDataProvider shouldSnapWindow:self]) - { + if ([RAWindowSnapDataProvider shouldSnapWindow:self]) { [RAWindowSnapDataProvider snapWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self] animated:YES]; isSnapped = YES; // Force tap to fail @@ -650,15 +614,14 @@ extern BOOL allowOpenApp; return; } [self saveWindowInfo]; - - break; - default: - break; - } + break; + } + default: + break; + } } --(void) setTransform:(CGAffineTransform)trans -{ +- (void)setTransform:(CGAffineTransform)trans { CGFloat scale = sqrt(trans.a * trans.a + trans.c * trans.c); CGFloat max = 1.0; scale = MIN(max, MAX(0.15, scale)); @@ -667,123 +630,97 @@ extern BOOL allowOpenApp; [super setTransform:trans]; - if (isBeingTouched == NO) - { - if ([RAWindowSnapDataProvider shouldSnapWindow:self]) - [RAWindowSnapDataProvider snapWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self] animated:YES]; - - /*CGPoint origin = self.frame.origin; - CGPoint endPoint = CGPointMake(origin.x + self.frame.size.width, origin.y + self.frame.size.height); - - if (endPoint.x > self.desktop.frame.size.width) - origin.x -= (endPoint.x - self.desktop.frame.size.width); - if (endPoint.y > self.desktop.frame.size.height) - origin.y -= (endPoint.y - self.desktop.frame.size.height); - - if (origin.x < 0) - origin.x = 0; - if (origin.y < 0) - origin.y = 0; - - CGRect adjustedFrame = CGRectMake(origin.x, origin.y, self.frame.size.width, self.frame.size.height); - self.frame = adjustedFrame;*/ - + if (!isBeingTouched && [RAWindowSnapDataProvider shouldSnapWindow:self]) { + [RAWindowSnapDataProvider snapWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self] animated:YES]; } } --(void) updatePotentialSnapShadow -{ - if (![RASettings.sharedInstance snapWindows]) +- (void)updatePotentialSnapShadow { + if (![RASettings.sharedInstance snapWindows]) { return; + } - if (![RASettings.sharedInstance showSnapHelper]) + if (![RASettings.sharedInstance showSnapHelper]) { return; - - if (!snapShadowView) - { + } + + if (!snapShadowView) { snapShadowView = [[UIView alloc] initWithFrame:self.bounds]; snapShadowView.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.1]; // [UIColor.blackColor colorWithAlphaComponent:0.5]; snapShadowView.layer.borderColor = [UIColor whiteColor].CGColor; snapShadowView.layer.shadowRadius = 20; snapShadowView.layer.shadowOpacity = 0.8; snapShadowView.layer.shadowOffset = CGSizeMake(0, 0); - snapShadowView.layer.borderWidth = 1.5f; - snapShadowView.layer.cornerRadius = 6; - snapShadowView.clipsToBounds = YES; - snapShadowView.layer.masksToBounds = YES; + snapShadowView.layer.borderWidth = 1.5f; + snapShadowView.layer.cornerRadius = 6; + snapShadowView.clipsToBounds = YES; + snapShadowView.layer.masksToBounds = YES; [self.superview insertSubview:snapShadowView belowSubview:self]; } - if ([RAWindowSnapDataProvider shouldSnapWindow:self]) - { + if ([RAWindowSnapDataProvider shouldSnapWindow:self]) { snapShadowView.hidden = NO; snapShadowView.transform = self.transform; snapShadowView.center = [RAWindowSnapDataProvider snapCenterForWindow:self toLocation:[RAWindowSnapDataProvider snapLocationForWindow:self]]; - } - else - { + } else { snapShadowView.hidden = YES; } } --(void) removePotentialSnapShadow -{ +- (void)removePotentialSnapShadow { [snapShadowView removeFromSuperview]; snapShadowView = nil; } -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event -{ +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { isBeingTouched = YES; RADesktopManager.sharedInstance.lastUsedWindow = self; } -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event -{ +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { isBeingTouched = NO; } --(void) resignForemostApp -{ - titleLabel.font = [UIFont systemFontOfSize:18]; +- (void)resignForemostApp { + titleLabel.font = [UIFont systemFontOfSize:18]; } --(void) becomeForemostApp -{ - titleLabel.font = [UIFont boldSystemFontOfSize:20]; +- (void)becomeForemostApp { + titleLabel.font = [UIFont boldSystemFontOfSize:20]; [self.superview bringSubviewToFront:self]; } --(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; - UIView *subview; - while ((subview = [objects nextObject])) - { - UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; - if (success) - return success; - } - return [super hitTest:point withEvent:event]; +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + NSEnumerator *objects = [self.subviews reverseObjectEnumerator]; + UIView *subview; + while (subview = [objects nextObject]) { + UIView *success = [subview hitTest:[self convertPoint:point toView:subview] withEvent:event]; + if (success) { + return success; + } + } + return [super hitTest:point withEvent:event]; } -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL isContained = NO; - for (UIView *view in self.subviews) - { - if (CGRectContainsPoint(view.frame, point) || CGRectContainsPoint(view.frame, [view convertPoint:point fromView:self])) // [self convertPoint:point toView:view])) + for (UIView *view in self.subviews) { + if (CGRectContainsPoint(view.frame, point) || CGRectContainsPoint(view.frame, [view convertPoint:point fromView:self])) { // [self convertPoint:point toView:view])) isContained = YES; + } } return isContained || [super pointInside:point withEvent:event]; } -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ - if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { return NO; - return YES; + } + return YES; } --(RAHostedAppView*) attachedView { return attachedView; } -@end \ No newline at end of file + +- (RAHostedAppView*)attachedView { + return attachedView; +} +@end diff --git a/WindowedMultitasking/RAWindowOverlayView.h b/WindowedMultitasking/RAWindowOverlayView.h index b99039d..a6e1030 100644 --- a/WindowedMultitasking/RAWindowOverlayView.h +++ b/WindowedMultitasking/RAWindowOverlayView.h @@ -3,6 +3,6 @@ @interface RAWindowOverlayView : UIView @property (nonatomic, weak) RAWindowBar *appWindow; --(void) show; --(void) dismiss; -@end \ No newline at end of file +- (void)show; +- (void)dismiss; +@end diff --git a/WindowedMultitasking/RAWindowOverlayView.xm b/WindowedMultitasking/RAWindowOverlayView.xm index 0f70783..64202e5 100644 --- a/WindowedMultitasking/RAWindowOverlayView.xm +++ b/WindowedMultitasking/RAWindowOverlayView.xm @@ -12,8 +12,7 @@ @end @implementation RAWindowOverlayView --(void) show -{ +- (void)show { probablyAnimating = NO; UIVisualEffect *effect = [UIBlurEffect effectWithStyle:THEMED(windowedMultitaskingBlurStyle)]; @@ -96,20 +95,17 @@ rotationLockButton.layer.cornerRadius = buttonSize/2; [self addSubview:rotationLockButton]; - if (self.appWindow.isLocked) - { + if (self.appWindow.isLocked) { [rotationLockButton setImage:[RAResourceImageProvider imageForFilename:@"Lock" size:CGSizeMake(imageSize, imageSize) tintedTo:THEMED(windowedMultitaskingRotationIconOverlayColor)] forState:UIControlStateNormal]; - } - else - { + } else { [rotationLockButton setImage:[RAResourceImageProvider imageForFilename:@"Unlocked" size:CGSizeMake(imageSize, imageSize) tintedTo:THEMED(windowedMultitaskingRotationIconOverlayColor)] forState:UIControlStateNormal]; } } -- (void) buttonPress:(UIButton*)button -{ - if ([RASettings.sharedInstance windowedMultitaskingCompleteAnimations]) +- (void)buttonPress:(UIButton*)button { + if ([RASettings.sharedInstance windowedMultitaskingCompleteAnimations]) { probablyAnimating = YES; + } //[UIView animateWithDuration:0.2 animations:^{ // button.transform = CGAffineTransformMakeScale(1.1, 1.1); //}]; @@ -124,19 +120,19 @@ sizeAnimation.duration = 0.5f; sizeAnimation.numberOfBounces = 2; sizeAnimation.shouldOvershoot = YES; - + [button.layer addAnimation:sizeAnimation forKey:@"bliss"]; [button.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1.0)] forKeyPath:@"transform"]; - + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ probablyAnimating = NO; }); } -- (void) buttonRelease:(UIButton*)button -{ - if ([RASettings.sharedInstance windowedMultitaskingCompleteAnimations]) +- (void)buttonRelease:(UIButton*)button { + if ([RASettings.sharedInstance windowedMultitaskingCompleteAnimations]) { probablyAnimating = YES; + } //[UIView animateWithDuration:0.2 animations:^{ // button.transform = CGAffineTransformMakeScale(1, 1); //}]; @@ -149,7 +145,7 @@ sizeAnimation.duration = 0.3f; sizeAnimation.numberOfBounces = 2; sizeAnimation.shouldOvershoot = YES; - + [button.layer addAnimation:sizeAnimation forKey:@"bliss"]; [button.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)] forKeyPath:@"transform"]; @@ -160,13 +156,11 @@ }); } --(void) dismiss_ -{ +- (void)dismiss_ { [self.appWindow hideOverlay]; } --(void) dismiss -{ +- (void)dismiss { [UIView animateWithDuration:0.5 animations:^{ self.alpha = 0; } completion:^(BOOL _) { @@ -174,40 +168,36 @@ }]; } --(void) closeButtonTap -{ - if (probablyAnimating) +- (void)closeButtonTap { + if (probablyAnimating) { [self performSelector:@selector(closeButtonTap) withObject:nil afterDelay:0.1]; - else + } else { [self.appWindow close]; + } } --(void) maximizeButtonTap -{ - if (probablyAnimating) +- (void)maximizeButtonTap { + if (probablyAnimating) { [self performSelector:@selector(maximizeButtonTap) withObject:nil afterDelay:0.1]; - else + } else { [self.appWindow maximize]; + } } --(void) minimizeButtonTap -{ - if (probablyAnimating) +- (void)minimizeButtonTap { + if (probablyAnimating) { [self performSelector:@selector(minimizeButtonTap) withObject:nil afterDelay:0.1]; - else + } else { [self.appWindow minimize]; + } } --(void) rotationLockButtonTap -{ +- (void)rotationLockButtonTap { [self.appWindow sizingLockButtonTap:nil]; - if (self.appWindow.isLocked) - { + if (self.appWindow.isLocked) { [rotationLockButton setImage:[RAResourceImageProvider imageForFilename:@"Lock" size:CGSizeMake(imageSize, imageSize) tintedTo:THEMED(windowedMultitaskingRotationIconOverlayColor)] forState:UIControlStateNormal]; - } - else - { + } else { [rotationLockButton setImage:[RAResourceImageProvider imageForFilename:@"Unlocked" size:CGSizeMake(imageSize, imageSize) tintedTo:THEMED(windowedMultitaskingRotationIconOverlayColor)] forState:UIControlStateNormal]; } } diff --git a/WindowedMultitasking/RAWindowSnapDataProvider.h b/WindowedMultitasking/RAWindowSnapDataProvider.h index f06bb1a..ecb80ce 100644 --- a/WindowedMultitasking/RAWindowSnapDataProvider.h +++ b/WindowedMultitasking/RAWindowSnapDataProvider.h @@ -1,13 +1,13 @@ #import "RAWindowBar.h" #import "RADesktopWindow.h" -enum RAWindowSnapLocation { +typedef NS_ENUM(NSInteger, RAWindowSnapLocation) { RAWindowSnapLocationInvalid = 0, RAWindowSnapLocationLeftTop, RAWindowSnapLocationLeftMiddle, RAWindowSnapLocationLeftBottom, - + RAWindowSnapLocationRightTop, RAWindowSnapLocationRightMiddle, RAWindowSnapLocationRightBottom, @@ -25,11 +25,11 @@ enum RAWindowSnapLocation { }; @interface RAWindowSnapDataProvider : NSObject -+(BOOL) shouldSnapWindow:(RAWindowBar*)bar; -+(RAWindowSnapLocation) snapLocationForWindow:(RAWindowBar*)windowBar; -+(CGPoint) snapCenterForWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location; -+(void) snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated; -+(void) snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated completion:(dispatch_block_t)completionBlock; ++ (BOOL)shouldSnapWindow:(RAWindowBar*)bar; ++ (RAWindowSnapLocation)snapLocationForWindow:(RAWindowBar*)windowBar; ++ (CGPoint)snapCenterForWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location; ++ (void)snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated; ++ (void)snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated completion:(dispatch_block_t)completionBlock; @end RAWindowSnapLocation RAWindowSnapLocationGetLeftOfScreen(); diff --git a/WindowedMultitasking/RAWindowSnapDataProvider.xm b/WindowedMultitasking/RAWindowSnapDataProvider.xm index 31937cd..b5c85b6 100644 --- a/WindowedMultitasking/RAWindowSnapDataProvider.xm +++ b/WindowedMultitasking/RAWindowSnapDataProvider.xm @@ -1,13 +1,11 @@ #import "RAWindowSnapDataProvider.h" @implementation RAWindowSnapDataProvider -+(BOOL) shouldSnapWindow:(RAWindowBar*)bar -{ ++ (BOOL)shouldSnapWindow:(RAWindowBar*)bar { return [RAWindowSnapDataProvider snapLocationForWindow:bar] != RAWindowSnapLocationInvalid; } -+(RAWindowSnapLocation) snapLocationForWindow:(RAWindowBar*)windowBar -{ ++ (RAWindowSnapLocation)snapLocationForWindow:(RAWindowBar*)windowBar { CGRect location = windowBar.frame; // Convienence values @@ -39,70 +37,82 @@ bottomRight.x += location.size.width / 2; bottomRight.y += location.size.height / 2; //bottomRight = CGPointApplyAffineTransform(bottomRight, theView.transform); - + // I am not proud of the below jumps, however i do believe it is the best solution to the problem apart from making weird blocks, which would be a considerable amount of work. BOOL didLeft = NO; BOOL didRight = NO; - if (topLeft.x > bottomLeft.x) + if (topLeft.x > bottomLeft.x) { goto try_right; + } - if (topLeft.y > bottomLeft.y) + if (topLeft.y > bottomLeft.y) { goto try_bottom; + } try_left: didLeft = YES; // Left - if (location.origin.x < leftXBuffer && location.origin.y < height / 8) + if (location.origin.x < leftXBuffer && location.origin.y < height / 8) { return RAWindowSnapLocationLeftTop; - if (location.origin.x < leftXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) + } + if (location.origin.x < leftXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) { return RAWindowSnapLocationLeftBottom; - if (location.origin.x < leftXBuffer && location.origin.y >= height / 8 && location.origin.y < twoThirdsHeight) + } + if (location.origin.x < leftXBuffer && location.origin.y >= height / 8 && location.origin.y < twoThirdsHeight) { return RAWindowSnapLocationLeftMiddle; + } try_right: didRight = YES; // Right - if (location.origin.x + location.size.width > rightXBuffer && location.origin.y < height / 8) + if (location.origin.x + location.size.width > rightXBuffer && location.origin.y < height / 8) { return RAWindowSnapLocationRightTop; - if (location.origin.x + location.size.width > rightXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) + } + if (location.origin.x + location.size.width > rightXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) { return RAWindowSnapLocationRightBottom; - if (location.origin.x + location.size.width > rightXBuffer && location.origin.y >= height / 8 && location.origin.y < twoThirdsHeight) + } + if (location.origin.x + location.size.width > rightXBuffer && location.origin.y >= height / 8 && location.origin.y < twoThirdsHeight) { return RAWindowSnapLocationRightMiddle; + } - if (!didLeft) + if (!didLeft) { goto try_left; - else if (!didRight) + } else if (!didRight) { goto try_right; + } try_bottom: // Jumps through this off slightly, so we re-check (which may or may not actually be needed, depending on the path it takes) - if (location.origin.x + location.size.width > rightXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) + if (location.origin.x + location.size.width > rightXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) { return RAWindowSnapLocationRightBottom; - if (location.origin.x < leftXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) + } + if (location.origin.x < leftXBuffer && (location.origin.y >= twoThirdsHeight || location.origin.y + location.size.height > height)) { return RAWindowSnapLocationLeftBottom; - - if (location.origin.y + location.size.height > bottomBuffer) + } + if (location.origin.y + location.size.height > bottomBuffer) { return RAWindowSnapLocationBottom; + } //try_top: - if (location.origin.y < 20 + 25) + if (location.origin.y < 20 + 25) { return RAWindowSnapLocationTop; + } // Second time possible verify - if (!didLeft) + if (!didLeft) { goto try_left; - else if (!didRight) + } else if (!didRight) { goto try_right; + } return RAWindowSnapLocationNone; } -+(CGPoint) snapCenterForWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location -{ ++ (CGPoint)snapCenterForWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location { // Convienence values CGFloat width = UIScreen.mainScreen._referenceBounds.size.width; CGFloat height = UIScreen.mainScreen._referenceBounds.size.height; @@ -113,70 +123,63 @@ try_bottom: BOOL adjustStatusBar = NO; - switch (location) - { - case RAWindowSnapLocationLeftTop: + switch (location) { + case RAWindowSnapLocationLeftTop: { newCenter = CGPointMake(frame.size.width / 2, (frame.size.height / 2) + 20); adjustStatusBar = YES; break; + } case RAWindowSnapLocationLeftMiddle: newCenter.x = frame.size.width / 2; break; case RAWindowSnapLocationLeftBottom: newCenter = CGPointMake(frame.size.width / 2, height - (frame.size.height / 2)); break; - - case RAWindowSnapLocationRightTop: + case RAWindowSnapLocationRightTop: { newCenter = CGPointMake(width - (frame.size.width / 2), (frame.size.height / 2) + 20); adjustStatusBar = YES; break; + } case RAWindowSnapLocationRightMiddle: newCenter.x = width - (frame.size.width / 2); break; case RAWindowSnapLocationRightBottom: newCenter = CGPointMake(width - (frame.size.width / 2), height - (frame.size.height / 2)); break; - - case RAWindowSnapLocationTop: + case RAWindowSnapLocationTop: { newCenter.y = (frame.size.height / 2) + 20; adjustStatusBar = YES; break; + } case RAWindowSnapLocationBottom: newCenter.y = height - (frame.size.height / 2); break; - - case RAWindowSnapLocationBottomCenter: + case RAWindowSnapLocationBottomCenter: { newCenter.x = width / 2.0; newCenter.y = height - (frame.size.height / 2); break; - + } case RAWindowSnapLocationInvalid: default: break; } - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight && adjustStatusBar) - { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight && adjustStatusBar) { newCenter.y -= 20; } - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight && (location == RAWindowSnapLocationRightMiddle || location == RAWindowSnapLocationRightBottom || location == RAWindowSnapLocationRightTop)) - { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeRight && (location == RAWindowSnapLocationRightMiddle || location == RAWindowSnapLocationRightBottom || location == RAWindowSnapLocationRightTop)) { newCenter.x -= 20; - } - else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && adjustStatusBar) - { + } else if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && adjustStatusBar) { newCenter.y -= 20; } - if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location == RAWindowSnapLocationLeftMiddle || location == RAWindowSnapLocationLeftBottom || location == RAWindowSnapLocationLeftTop)) - { + if (UIApplication.sharedApplication.statusBarOrientation == UIInterfaceOrientationLandscapeLeft && (location == RAWindowSnapLocationLeftMiddle || location == RAWindowSnapLocationLeftBottom || location == RAWindowSnapLocationLeftTop)) { newCenter.x += 20; } return newCenter; } -+(void) snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated -{ ++ (void)snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated { /* // Convienence values CGFloat width = UIScreen.mainScreen.bounds.size.width; @@ -233,32 +236,28 @@ try_bottom: [self snapWindow:window toLocation:location animated:animated completion:nil]; } -+(void) snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated completion:(dispatch_block_t)completionBlock -{ ++ (void)snapWindow:(RAWindowBar*)window toLocation:(RAWindowSnapLocation)location animated:(BOOL)animated completion:(dispatch_block_t)completionBlock { CGPoint newCenter = [RAWindowSnapDataProvider snapCenterForWindow:window toLocation:location]; - if (animated) - { + if (animated) { [UIView animateWithDuration:0.2 animations:^{ window.center = newCenter; } completion:^(BOOL _) { - if (completionBlock) + if (completionBlock) { completionBlock(); + } }]; - } - else - { + } else { window.center = newCenter; - if (completionBlock) + if (completionBlock) { completionBlock(); + } } } @end -RAWindowSnapLocation RAWindowSnapLocationGetLeftOfScreen() -{ - switch (UIApplication.sharedApplication.statusBarOrientation) - { +RAWindowSnapLocation RAWindowSnapLocationGetLeftOfScreen() { + switch (UIApplication.sharedApplication.statusBarOrientation) { case UIInterfaceOrientationPortrait: return RAWindowSnapLocationLeft; case UIInterfaceOrientationLandscapeRight: @@ -271,10 +270,8 @@ RAWindowSnapLocation RAWindowSnapLocationGetLeftOfScreen() return RAWindowSnapLocationLeft; } -RAWindowSnapLocation RAWindowSnapLocationGetRightOfScreen() -{ - switch (UIApplication.sharedApplication.statusBarOrientation) - { +RAWindowSnapLocation RAWindowSnapLocationGetRightOfScreen() { + switch (UIApplication.sharedApplication.statusBarOrientation) { case UIInterfaceOrientationPortrait: return RAWindowSnapLocationRight; case UIInterfaceOrientationLandscapeRight: @@ -286,4 +283,3 @@ RAWindowSnapLocation RAWindowSnapLocationGetRightOfScreen() } return RAWindowSnapLocationRight; } - diff --git a/WindowedMultitasking/RAWindowSorter.h b/WindowedMultitasking/RAWindowSorter.h index 268c9db..b549c1a 100644 --- a/WindowedMultitasking/RAWindowSorter.h +++ b/WindowedMultitasking/RAWindowSorter.h @@ -1,5 +1,5 @@ #import "RADesktopWindow.h" @interface RAWindowSorter : NSObject -+(void) sortWindowsOnDesktop:(RADesktopWindow*)desktop resizeIfNecessary:(BOOL)resize; -@end \ No newline at end of file ++ (void)sortWindowsOnDesktop:(RADesktopWindow*)desktop resizeIfNecessary:(BOOL)resize; +@end diff --git a/WindowedMultitasking/RAWindowSorter.xm b/WindowedMultitasking/RAWindowSorter.xm index 044a18e..4f47532 100644 --- a/WindowedMultitasking/RAWindowSorter.xm +++ b/WindowedMultitasking/RAWindowSorter.xm @@ -4,46 +4,42 @@ #import "RAWindowSnapDataProvider.h" @implementation RAWindowSorter -+(void) sortWindowsOnDesktop:(RADesktopWindow*)desktop resizeIfNecessary:(BOOL)resize -{ ++ (void)sortWindowsOnDesktop:(RADesktopWindow*)desktop resizeIfNecessary:(BOOL)resize { NSInteger numberOfWindows = desktop.hostedWindows.count; - if (numberOfWindows == 0) + if (numberOfWindows == 0) { return; + } NSMutableArray *windows = [NSMutableArray array]; - for (UIView *view in desktop.subviews) - if ([view isKindOfClass:[RAWindowBar class]]) + for (UIView *view in desktop.subviews) { + if ([view isKindOfClass:[RAWindowBar class]]) { [windows addObject:view]; + } + } - if (numberOfWindows == 1) - { - if (resize) + if (numberOfWindows == 1) { + if (resize) { [windows[0] scaleTo:0.7 animated:YES derotate:YES]; + } [RAWindowSnapDataProvider snapWindow:windows[0] toLocation:RAWindowSnapLocationLeftTop animated:YES]; - } - else if (numberOfWindows == 2) - { + } else if (numberOfWindows == 2) { RAWindowBar *window1 = windows[0]; RAWindowBar *window2 = windows[1]; - if (resize) - { + if (resize) { [window1 scaleTo:0.5 animated:YES derotate:YES]; [window2 scaleTo:0.5 animated:YES derotate:YES]; } [RAWindowSnapDataProvider snapWindow:window1 toLocation:RAWindowSnapLocationLeftTop animated:YES]; [RAWindowSnapDataProvider snapWindow:window2 toLocation:RAWindowSnapLocationRightTop animated:YES]; - } - else if (numberOfWindows == 3) - { + } else if (numberOfWindows == 3) { RAWindowBar *window1 = windows[0]; RAWindowBar *window2 = windows[1]; RAWindowBar *window3 = windows[2]; - if (resize) - { + if (resize) { [window1 scaleTo:0.5 animated:YES derotate:YES]; [window2 scaleTo:0.5 animated:YES derotate:YES]; [window3 scaleTo:0.4 animated:YES derotate:YES]; @@ -52,68 +48,59 @@ [RAWindowSnapDataProvider snapWindow:window1 toLocation:RAWindowSnapLocationLeftTop animated:YES]; [RAWindowSnapDataProvider snapWindow:window2 toLocation:RAWindowSnapLocationRightTop animated:YES]; [RAWindowSnapDataProvider snapWindow:window3 toLocation:RAWindowSnapLocationBottomCenter animated:YES]; - } - else if (NO && numberOfWindows == 4) - { + } else if (NO && numberOfWindows == 4) { RAWindowBar *window1 = windows[0]; RAWindowBar *window2 = windows[1]; RAWindowBar *window3 = windows[2]; RAWindowBar *window4 = windows[3]; - if (resize) - { + if (resize) { [window1 scaleTo:0.45 animated:YES derotate:YES]; [window2 scaleTo:0.45 animated:YES derotate:YES]; [window3 scaleTo:0.45 animated:YES derotate:YES]; [window4 scaleTo:0.45 animated:YES derotate:YES]; } - + [RAWindowSnapDataProvider snapWindow:window1 toLocation:RAWindowSnapLocationLeftTop animated:YES]; [RAWindowSnapDataProvider snapWindow:window2 toLocation:RAWindowSnapLocationRightTop animated:YES]; [RAWindowSnapDataProvider snapWindow:window3 toLocation:RAWindowSnapLocationBottomLeft animated:YES]; [RAWindowSnapDataProvider snapWindow:window4 toLocation:RAWindowSnapLocationBottomRight animated:YES]; - } - else - { - if (resize) - { + } else { + if (resize) { //CGFloat maxScale = 1.0 / numberOfWindows; // (numberOfWindows / 2.0); //CGFloat maxScale = (desktop.frame.size.width / (numberOfWindows/2.0)) / desktop.frame.size.width; CGFloat factor = desktop.frame.size.height - 20; CGFloat maxScale = factor / (ceil(sqrt(numberOfWindows)) * [windows[0] bounds].size.height); - + CGFloat x = 0, y = 0; int panesPerLine = floor(1.0 / maxScale);// (numberOfWindows & ~1) /* round down to nearest even number */ int currentPane = 0; - for (RAWindowBar *bar in windows) - { + for (RAWindowBar *bar in windows) { [bar scaleTo:maxScale animated:YES derotate:YES]; - if (y == 0) // 20 = statusbar + if (y == 0) { // 20 = statusbar y = 20 + (bar.frame.size.height / 2.0); - if (x == 0) + } + if (x == 0) { x = bar.frame.size.width / 2.0; + } bar.center = CGPointMake(x, y); - if (++currentPane == panesPerLine) - { + if (++currentPane == panesPerLine) { currentPane = 0; x = 0; y += bar.frame.size.height; - } - else + } else { x += bar.frame.size.width; + } } } - else - { - - } } - for (RAWindowBar *bar in windows) + for (RAWindowBar *bar in windows) { [bar saveWindowInfo]; + } } -@end \ No newline at end of file +@end diff --git a/WindowedMultitasking/RAWindowStatePreservationSystemManager.h b/WindowedMultitasking/RAWindowStatePreservationSystemManager.h index 7ec4429..fef145c 100644 --- a/WindowedMultitasking/RAWindowStatePreservationSystemManager.h +++ b/WindowedMultitasking/RAWindowStatePreservationSystemManager.h @@ -2,32 +2,32 @@ #import "RADesktopWindow.h" #import "RAWindowBar.h" -struct RAPreservedWindowInformation { +typedef struct { CGPoint center; CGAffineTransform transform; -}; +} RAPreservedWindowInformation; -struct RAPreservedDesktopInformation { +typedef struct { NSUInteger index; NSArray *openApps; //NSArray -}; +} RAPreservedDesktopInformation; @interface RAWindowStatePreservationSystemManager : NSObject { NSMutableDictionary *dict; } -+(id) sharedInstance; ++ (instancetype)sharedInstance; --(void) loadInfo; --(void) saveInfo; +- (void)loadInfo; +- (void)saveInfo; // Desktop --(void) saveDesktopInformation:(RADesktopWindow*)desktop; --(BOOL) hasDesktopInformationAtIndex:(NSInteger)index; --(RAPreservedDesktopInformation) desktopInformationForIndex:(NSInteger)index; +- (void)saveDesktopInformation:(RADesktopWindow*)desktop; +- (BOOL)hasDesktopInformationAtIndex:(NSInteger)index; +- (RAPreservedDesktopInformation)desktopInformationForIndex:(NSInteger)index; // Window --(void) saveWindowInformation:(RAWindowBar*)window; --(BOOL) hasWindowInformationForIdentifier:(NSString*)appIdentifier; --(RAPreservedWindowInformation) windowInformationForAppIdentifier:(NSString*)identifier; --(void) removeWindowInformationForIdentifier:(NSString*)appIdentifier; -@end \ No newline at end of file +- (void)saveWindowInformation:(RAWindowBar*)window; +- (BOOL)hasWindowInformationForIdentifier:(NSString*)appIdentifier; +- (RAPreservedWindowInformation) windowInformationForAppIdentifier:(NSString*)identifier; +- (void)removeWindowInformationForIdentifier:(NSString*)appIdentifier; +@end diff --git a/WindowedMultitasking/RAWindowStatePreservationSystemManager.xm b/WindowedMultitasking/RAWindowStatePreservationSystemManager.xm index e3d56d0..ce977ee 100644 --- a/WindowedMultitasking/RAWindowStatePreservationSystemManager.xm +++ b/WindowedMultitasking/RAWindowStatePreservationSystemManager.xm @@ -5,28 +5,23 @@ #define FILE_PATH @"/User/Library/Preferences/com.efrederickson.empoleon.windowstates.plist" @implementation RAWindowStatePreservationSystemManager -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(RAWindowStatePreservationSystemManager, [sharedInstance loadInfo]); } --(void) loadInfo -{ +- (void)loadInfo { dict = [NSMutableDictionary dictionaryWithContentsOfFile:FILE_PATH] ?: [NSMutableDictionary dictionary]; } --(void) saveInfo -{ +- (void)saveInfo { [dict writeToFile:FILE_PATH atomically:YES]; } --(void) saveDesktopInformation:(RADesktopWindow*)desktop -{ +- (void)saveDesktopInformation:(RADesktopWindow*)desktop { NSUInteger index = [RADesktopManager.sharedInstance.availableDesktops indexOfObject:desktop]; NSString *key = [NSString stringWithFormat:@"%lu",(unsigned long)index]; NSMutableArray *openApps = [NSMutableArray array]; - for (RAHostedAppView *app in desktop.hostedWindows) - { + for (RAHostedAppView *app in desktop.hostedWindows) { [openApps addObject:app.app.bundleIdentifier]; } @@ -35,21 +30,20 @@ [self saveInfo]; } --(BOOL) hasDesktopInformationAtIndex:(NSInteger)index -{ +- (BOOL)hasDesktopInformationAtIndex:(NSInteger)index { NSString *key = [NSString stringWithFormat:@"%lu",(unsigned long)index]; return [dict objectForKey:key] != nil; } --(RAPreservedDesktopInformation) desktopInformationForIndex:(NSInteger)index -{ +- (RAPreservedDesktopInformation)desktopInformationForIndex:(NSInteger)index { RAPreservedDesktopInformation info; info.index = index; NSString *key = [NSString stringWithFormat:@"%lu",(unsigned long)index]; NSMutableArray *apps = [NSMutableArray array]; - for (NSString *ident in dict[key]) + for (NSString *ident in dict[key]) { [apps addObject:ident]; + } info.openApps = apps; @@ -57,8 +51,7 @@ } // Window --(void) saveWindowInformation:(RAWindowBar*)window -{ +- (void)saveWindowInformation:(RAWindowBar*)window { CGPoint center = window.center; CGAffineTransform transform = window.transform; NSString *appIdent = window.attachedView.app.bundleIdentifier; @@ -71,18 +64,17 @@ [self saveInfo]; } --(BOOL) hasWindowInformationForIdentifier:(NSString*)appIdentifier -{ +- (BOOL)hasWindowInformationForIdentifier:(NSString*)appIdentifier { return [dict objectForKey:appIdentifier] != nil; } --(RAPreservedWindowInformation) windowInformationForAppIdentifier:(NSString*)identifier -{ +- (RAPreservedWindowInformation)windowInformationForAppIdentifier:(NSString*)identifier { RAPreservedWindowInformation info = (RAPreservedWindowInformation) { CGPointZero, CGAffineTransformIdentity }; NSDictionary *appInfo = dict[identifier]; - if (!appInfo) + if (!appInfo) { return info; + } info.center = CGPointFromString(appInfo[@"center"]); info.transform = CGAffineTransformFromString(appInfo[@"transform"]); @@ -90,9 +82,8 @@ return info; } --(void) removeWindowInformationForIdentifier:(NSString*)appIdentifier -{ +- (void)removeWindowInformationForIdentifier:(NSString*)appIdentifier { [dict removeObjectForKey:appIdentifier]; [self saveInfo]; } -@end \ No newline at end of file +@end diff --git a/WindowedMultitasking/StartMultitaskingGesture.xm b/WindowedMultitasking/StartMultitaskingGesture.xm index 1a5ea71..5a8f57f 100644 --- a/WindowedMultitasking/StartMultitaskingGesture.xm +++ b/WindowedMultitasking/StartMultitaskingGesture.xm @@ -9,142 +9,133 @@ #import "RAControlCenterInhibitor.h" #import "Multiplexer.h" -BOOL locationIsInValidArea(CGFloat x) -{ - if (x == 0) return YES; // more than likely, UIGestureRecognizerStateEnded - - switch ([RASettings.sharedInstance windowedMultitaskingGrabArea]) - { - case RAGrabAreaBottomLeftThird: - NSLog(@"[ReachApp] StartMultitaskingGesture: %f %f", x, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width); - return x <= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0; - case RAGrabAreaBottomMiddleThird: - return x >= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0 && x <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0) * 2; - case RAGrabAreaBottomRightThird: - return x >= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0) * 2; - default: - return NO; - } +BOOL locationIsInValidArea(CGFloat x) { + if (x == 0) { // more than likely, UIGestureRecognizerStateEnded + return YES; + } + + switch ([RASettings.sharedInstance windowedMultitaskingGrabArea]) { + case RAGrabAreaBottomLeftThird: + LogDebug(@"[ReachApp] StartMultitaskingGesture: %f %f", x, UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width); + return x <= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0; + case RAGrabAreaBottomMiddleThird: + return x >= UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0 && x <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0) * 2; + case RAGrabAreaBottomRightThird: + return x >= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.width / 3.0) * 2; + default: + return NO; + } } -%ctor -{ - if (!IS_SPRINGBOARD) - return; - __weak __block UIView *appView = nil; - __block CGFloat lastY = 0; - __block CGPoint originalCenter; - [[RAGestureManager sharedInstance] addGestureRecognizer:^RAGestureCallbackResult(UIGestureRecognizerState state, CGPoint location, CGPoint velocity) { - - SBApplication *topApp = [[UIApplication sharedApplication] _accessibilityFrontMostApplication]; - - // Dismiss potential CC - //[[%c(SBUIController) sharedInstance] _showControlCenterGestureEndedWithLocation:CGPointMake(0, UIScreen.mainScreen.bounds.size.height - 1) velocity:CGPointZero]; - - if (state == UIGestureRecognizerStateBegan) - { - [RAControlCenterInhibitor setInhibited:YES]; - - // Show HS/Wallpaper - [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; - [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; - - // Assign view - appView = [RAHostManager systemHostViewForApplication:topApp].superview; - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"9.0")) - appView = appView.superview; - originalCenter = appView.center; - } - else if (state == UIGestureRecognizerStateChanged) - { - lastY = location.y; - CGFloat scale = location.y / UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height; - - if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:topApp.bundleIdentifier]) - { - scale = MIN(MAX(scale, 0.01), 1); - CGFloat actualScale = scale; - scale = 1 - scale; - RAPreservedWindowInformation info = [RAWindowStatePreservationSystemManager.sharedInstance windowInformationForAppIdentifier:topApp.bundleIdentifier]; - - // Interpolates between A and B with percentage T (T% between state A and state B) - CGFloat (^interpolate)(CGFloat, CGFloat, CGFloat) = ^CGFloat(CGFloat a, CGFloat b, CGFloat t){ - return a + (b - a) * t; - }; - - CGPoint center = CGPointMake( - interpolate(info.center.x, originalCenter.x, actualScale), - interpolate(info.center.y, originalCenter.y, actualScale) - ); - - CGFloat currentRotation = (atan2(info.transform.b, info.transform.a) * scale); - //CGFloat currentScale = 1 - (sqrt(info.transform.a * info.transform.a + info.transform.c * info.transform.c) * scale); - CGFloat currentScale = interpolate(1, sqrt(info.transform.a * info.transform.a + info.transform.c * info.transform.c), scale); - CGAffineTransform transform = CGAffineTransformRotate(CGAffineTransformMakeScale(currentScale, currentScale), currentRotation); - - appView.center = center; - appView.transform = transform; - } - else - { - scale = MIN(MAX(scale, 0.3), 1); - appView.transform = CGAffineTransformMakeScale(scale, scale); - } - } - else if (state == UIGestureRecognizerStateEnded) - { - [RAControlCenterInhibitor setInhibited:NO]; - - if (lastY <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 4) * 3 && lastY != 0) // 75% down, 0 == gesture ended in most situations - { - [UIView animateWithDuration:.3 animations:^{ - - if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:topApp.bundleIdentifier]) - { - RAPreservedWindowInformation info = [RAWindowStatePreservationSystemManager.sharedInstance windowInformationForAppIdentifier:topApp.bundleIdentifier]; - appView.center = info.center; - appView.transform = info.transform; - } - else - { - appView.transform = CGAffineTransformMakeScale(0.5, 0.5); - appView.center = originalCenter; - } - } completion:^(BOOL _) { - RAIconIndicatorViewInfo indicatorInfo = [[%c(RABackgrounder) sharedInstance] allAggregatedIndicatorInfoForIdentifier:topApp.bundleIdentifier]; - - // Close app - [[%c(RABackgrounder) sharedInstance] temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:topApp andCloseForegroundApp:NO]; - FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ - SBAppToAppWorkspaceTransaction *transaction = [Multiplexer createSBAppToAppWorkspaceTransactionForExitingApp:topApp]; - [transaction begin]; - - // Open in window - RAWindowBar *windowBar = [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:topApp animated:YES]; - if (RADesktopManager.sharedInstance.lastUsedWindow == nil) - RADesktopManager.sharedInstance.lastUsedWindow = windowBar; - }]; - [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; - [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; - - // Pop forced foreground backgrounding - [[%c(RABackgrounder) sharedInstance] queueRemoveTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; - [[%c(RABackgrounder) sharedInstance] removeTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; - [[%c(RABackgrounder) sharedInstance] updateIconIndicatorForIdentifier:topApp.bundleIdentifier withInfo:indicatorInfo]; - }]; - } - else - { - appView.center = originalCenter; - [UIView animateWithDuration:0.2 animations:^{ appView.transform = CGAffineTransformIdentity; } completion:^(BOOL _) { - [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; - }]; +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + __weak __block UIView *appView = nil; + __block CGFloat lastY = 0; + __block CGPoint originalCenter; + [[RAGestureManager sharedInstance] addGestureRecognizer:^RAGestureCallbackResult(UIGestureRecognizerState state, CGPoint location, CGPoint velocity) { + SBApplication *topApp = [[UIApplication sharedApplication] _accessibilityFrontMostApplication]; + + // Dismiss potential CC + //[[%c(SBUIController) sharedInstance] _showControlCenterGestureEndedWithLocation:CGPointMake(0, UIScreen.mainScreen.bounds.size.height - 1) velocity:CGPointZero]; + + if (state == UIGestureRecognizerStateBegan) { + [RAControlCenterInhibitor setInhibited:YES]; + + // Show HS/Wallpaper + [[%c(SBWallpaperController) sharedInstance] beginRequiringWithReason:@"BeautifulAnimation"]; + [[%c(SBUIController) sharedInstance] restoreContentAndUnscatterIconsAnimated:NO]; + + // Assign view + appView = [RAHostManager systemHostViewForApplication:topApp].superview; + if (IS_IOS_OR_NEWER(iOS_9_0)) { + appView = appView.superview; + } + originalCenter = appView.center; + } else if (state == UIGestureRecognizerStateChanged) { + lastY = location.y; + CGFloat scale = location.y / UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height; + + if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:topApp.bundleIdentifier]) { + scale = MIN(MAX(scale, 0.01), 1); + CGFloat actualScale = scale; + scale = 1 - scale; + RAPreservedWindowInformation info = [RAWindowStatePreservationSystemManager.sharedInstance windowInformationForAppIdentifier:topApp.bundleIdentifier]; + + // Interpolates between A and B with percentage T (T% between state A and state B) + CGFloat (^interpolate)(CGFloat, CGFloat, CGFloat) = ^CGFloat(CGFloat a, CGFloat b, CGFloat t){ + return a + (b - a) * t; + }; + + CGPoint center = CGPointMake( + interpolate(info.center.x, originalCenter.x, actualScale), + interpolate(info.center.y, originalCenter.y, actualScale) + ); + + CGFloat currentRotation = (atan2(info.transform.b, info.transform.a) * scale); + //CGFloat currentScale = 1 - (sqrt(info.transform.a * info.transform.a + info.transform.c * info.transform.c) * scale); + CGFloat currentScale = interpolate(1, sqrt(info.transform.a * info.transform.a + info.transform.c * info.transform.c), scale); + CGAffineTransform transform = CGAffineTransformRotate(CGAffineTransformMakeScale(currentScale, currentScale), currentRotation); + + appView.center = center; + appView.transform = transform; + } else { + scale = MIN(MAX(scale, 0.3), 1); + appView.transform = CGAffineTransformMakeScale(scale, scale); + } + } else if (state == UIGestureRecognizerStateEnded) { + [RAControlCenterInhibitor setInhibited:NO]; + + if (lastY <= (UIScreen.mainScreen.RA_interfaceOrientedBounds.size.height / 4) * 3 && lastY != 0) { // 75% down, 0 == gesture ended in most situations + [UIView animateWithDuration:.3 animations:^{ + if ([RAWindowStatePreservationSystemManager.sharedInstance hasWindowInformationForIdentifier:topApp.bundleIdentifier]) { + RAPreservedWindowInformation info = [RAWindowStatePreservationSystemManager.sharedInstance windowInformationForAppIdentifier:topApp.bundleIdentifier]; + appView.center = info.center; + appView.transform = info.transform; + } else { + appView.transform = CGAffineTransformMakeScale(0.5, 0.5); + appView.center = originalCenter; + } + } completion:^(BOOL _) { + RAIconIndicatorViewInfo indicatorInfo = [[%c(RABackgrounder) sharedInstance] allAggregatedIndicatorInfoForIdentifier:topApp.bundleIdentifier]; + + // Close app + [[%c(RABackgrounder) sharedInstance] temporarilyApplyBackgroundingMode:RABackgroundModeForcedForeground forApplication:topApp andCloseForegroundApp:NO]; + FBWorkspaceEvent *event = [%c(FBWorkspaceEvent) eventWithName:@"ActivateSpringBoard" handler:^{ + SBDeactivationSettings *deactiveSets = [[%c(SBDeactivationSettings) alloc] init]; + [deactiveSets setFlag:YES forDeactivationSetting:20]; + [deactiveSets setFlag:NO forDeactivationSetting:2]; + [topApp _setDeactivationSettings:deactiveSets]; + + SBAppToAppWorkspaceTransaction *transaction = [Multiplexer createSBAppToAppWorkspaceTransactionForExitingApp:topApp]; + [transaction begin]; + + // Open in window + RAWindowBar *windowBar = [RADesktopManager.sharedInstance.currentDesktop createAppWindowForSBApplication:topApp animated:YES]; + if (!RADesktopManager.sharedInstance.lastUsedWindow) { + RADesktopManager.sharedInstance.lastUsedWindow = windowBar; } - appView = nil; - } - - return RAGestureCallbackResultSuccess; - } withCondition:^BOOL(CGPoint location, CGPoint velocity) { - return [RASettings.sharedInstance windowedMultitaskingEnabled] && (locationIsInValidArea(location.x) || appView) && ![[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver] && ![[%c(SBUIController) sharedInstance] isAppSwitcherShowing] && ![[%c(SBLockScreenManager) sharedInstance] isUILocked] && [UIApplication.sharedApplication _accessibilityFrontMostApplication] != nil && ![[%c(SBNotificationCenterController) sharedInstance] isVisible]; - } forEdge:UIRectEdgeBottom identifier:@"com.efrederickson.reachapp.windowedmultitasking.systemgesture" priority:RAGesturePriorityDefault]; -} \ No newline at end of file + }]; + [(FBWorkspaceEventQueue*)[%c(FBWorkspaceEventQueue) sharedInstance] executeOrAppendEvent:event]; + [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; + + // Pop forced foreground backgrounding + [[%c(RABackgrounder) sharedInstance] queueRemoveTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; + [[%c(RABackgrounder) sharedInstance] removeTemporaryOverrideForIdentifier:topApp.bundleIdentifier]; + [[%c(RABackgrounder) sharedInstance] updateIconIndicatorForIdentifier:topApp.bundleIdentifier withInfo:indicatorInfo]; + }]; + } else { + appView.center = originalCenter; + [UIView animateWithDuration:0.2 animations:^{ appView.transform = CGAffineTransformIdentity; } completion:^(BOOL _) { + [[%c(SBWallpaperController) sharedInstance] endRequiringWithReason:@"BeautifulAnimation"]; + }]; + } + appView = nil; + } + + return RAGestureCallbackResultSuccess; + } withCondition:^BOOL(CGPoint location, CGPoint velocity) { + return [RASettings.sharedInstance windowedMultitaskingEnabled] && (locationIsInValidArea(location.x) || appView) && ![[%c(RASwipeOverManager) sharedInstance] isUsingSwipeOver] && ![[%c(SBUIController) sharedInstance] isAppSwitcherShowing] && ![[%c(SBLockScreenManager) sharedInstance] isUILocked] && [UIApplication.sharedApplication _accessibilityFrontMostApplication] && ![[%c(SBNotificationCenterController) sharedInstance] isVisible]; + } forEdge:UIRectEdgeBottom identifier:@"com.efrederickson.reachapp.windowedmultitasking.systemgesture" priority:RAGesturePriorityDefault]; +} diff --git a/WindowedMultitasking/WindowSorterActivator.xm b/WindowedMultitasking/WindowSorterActivator.xm index 17d5a52..dfcbed2 100644 --- a/WindowedMultitasking/WindowSorterActivator.xm +++ b/WindowedMultitasking/WindowSorterActivator.xm @@ -11,21 +11,17 @@ static RAActivatorSortWindowsListener *sharedInstance$RAActivatorSortWindowsListener; @implementation RAActivatorSortWindowsListener -- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event -{ - RADesktopWindow *desktop = RADesktopManager.sharedInstance.currentDesktop; +- (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event { + RADesktopWindow *desktop = RADesktopManager.sharedInstance.currentDesktop; - [RAWindowSorter sortWindowsOnDesktop:desktop resizeIfNecessary:YES]; + [RAWindowSorter sortWindowsOnDesktop:desktop resizeIfNecessary:YES]; } @end -%ctor -{ - if([[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.springboard"]) - { - sharedInstance$RAActivatorSortWindowsListener = [[RAActivatorSortWindowsListener alloc] init]; - [[%c(LAActivator) sharedInstance] registerListener:sharedInstance$RAActivatorSortWindowsListener forName:@"com.efrederickson.reachapp.windowedmultitasking.sortWindows"]; - } +%ctor { + IF_NOT_SPRINGBOARD { + return; + } + sharedInstance$RAActivatorSortWindowsListener = [[RAActivatorSortWindowsListener alloc] init]; + [[%c(LAActivator) sharedInstance] registerListener:sharedInstance$RAActivatorSortWindowsListener forName:@"com.efrederickson.reachapp.windowedmultitasking.sortWindows"]; } - - diff --git a/dispatch_after_cancel.m b/dispatch_after_cancel.m index a6ba379..d8263c5 100644 --- a/dispatch_after_cancel.m +++ b/dispatch_after_cancel.m @@ -1,35 +1,32 @@ #include "dispatch_after_cancel.h" -struct dispatch_async_handle *dispatch_after_cancellable(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t payload) -{ - struct dispatch_async_handle *handle = malloc(sizeof(struct dispatch_async_handle)); +struct dispatch_async_handle *dispatch_after_cancellable(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t payload) { + struct dispatch_async_handle *handle = malloc(sizeof(struct dispatch_async_handle)); - handle->didFire = 0; - handle->shouldCall = 1; // initially, payload should be called - handle->shouldFree = 0; // and handles belong to owner + handle->didFire = 0; + handle->shouldCall = 1; // initially, payload should be called + handle->shouldFree = 0; // and handles belong to owner - dispatch_after(when, queue, ^{ + dispatch_after(when, queue, ^{ - //NSLog(@"[ReachApp][%p] (control block) call=%d, free=%d, didfree=%d", handle, handle->shouldCall, handle->shouldFree, handle->didFree); + //NSLog(@"[ReachApp][%p] (control block) call=%d, free=%d, didfree=%d", handle, handle->shouldCall, handle->shouldFree, handle->didFree); - handle->didFire = 1; - if (handle->shouldCall) payload(); - if (handle->shouldFree && handle->didFree == 0) free(handle); - }); + handle->didFire = 1; + if (handle->shouldCall) payload(); + if (handle->shouldFree && handle->didFree == 0) free(handle); + }); - return handle; // to owner + return handle; // to owner } -void dispatch_after_cancel(struct dispatch_async_handle *handle) -{ - if (handle->didFire && handle->shouldFree == 0) { - //printf("[%p] (owner) too late, freeing myself\n", handle); - handle->didFree = 1; - free(handle); - } - else { - //printf("[%p] (owner) set call=0, free=1\n", handle); - handle->shouldCall = 0; - handle->shouldFree = 1; // control block is owner now - } -} \ No newline at end of file +void dispatch_after_cancel(struct dispatch_async_handle *handle) { + if (handle->didFire && handle->shouldFree == 0) { + //printf("[%p] (owner) too late, freeing myself\n", handle); + handle->didFree = 1; + free(handle); + } else { + //printf("[%p] (owner) set call=0, free=1\n", handle); + handle->shouldCall = 0; + handle->shouldFree = 1; // control block is owner now + } +} diff --git a/headers.h b/headers.h index 826b1ce..435646b 100644 --- a/headers.h +++ b/headers.h @@ -3,7 +3,6 @@ #import #import #import -#import #import #import #import @@ -19,6 +18,15 @@ #include #import #import +#import +#import +#import +#import +#import +#import +#import +#import +#import #define RA_BASE_PATH @"/Library/Multiplexer" @@ -32,28 +40,35 @@ #import "RASBWorkspaceFetcher.h" #define GET_SBWORKSPACE [RASBWorkspaceFetcher getCurrentSBWorkspaceImplementationInstanceForThisOS] -#define GET_STATUSBAR_ORIENTATION (UIApplication.sharedApplication._accessibilityFrontMostApplication == nil ? UIApplication.sharedApplication.statusBarOrientation : UIApplication.sharedApplication._accessibilityFrontMostApplication.statusBarOrientation) +#define GET_STATUSBAR_ORIENTATION (![UIApplication sharedApplication]._accessibilityFrontMostApplication ? UIApplication.sharedApplication.statusBarOrientation : UIApplication.sharedApplication._accessibilityFrontMostApplication.statusBarOrientation) #if DEBUG -#define NSLog NSLog +#define LogDebug HBLogDebug +#define LogInfo HBLogInfo +#define LogWarn HBLogWarn +#define LogError HBLogError #else -#define NSLog(...) +#define LogDebug(...) +#define LogInfo(...) +#define LogWarn(...) +#define LogError(...) #endif #if MULTIPLEXER_CORE extern BOOL $__IS_SPRINGBOARD; #define IS_SPRINGBOARD $__IS_SPRINGBOARD #else -#define IS_SPRINGBOARD [NSBundle.mainBundle.bundleIdentifier isEqual:@"com.apple.springboard"] +#define IS_SPRINGBOARD IN_SPRINGBOARD #endif #define ON_MAIN_THREAD(block) \ { \ - dispatch_block_t _blk = block; \ - if (NSThread.isMainThread) \ - _blk(); \ - else \ - dispatch_sync(dispatch_get_main_queue(), _blk); \ + dispatch_block_t _blk = block; \ + if (NSThread.isMainThread) { \ + _blk(); \ + } else { \ + dispatch_sync(dispatch_get_main_queue(), _blk); \ + } \ } #define IF_SPRINGBOARD if (IS_SPRINGBOARD) @@ -63,19 +78,16 @@ extern BOOL $__IS_SPRINGBOARD; // ugh, i got so tired of typing this in by hand, plus it expands method declarations by a LOT. #define unsafe_id __unsafe_unretained id -#define kBGModeUnboundedTaskCompletion @"unboundedTaskCompletion" -#define kBGModeContinuous @"continuous" -#define kBGModeFetch @"fetch" -#define kBGModeRemoteNotification @"remote-notification" -#define kBGModeExternalAccessory @"external-accessory" -#define kBGModeVoIP @"voip" -#define kBGModeLocation @"location" -#define kBGModeAudio @"audio" -#define kBGModeBluetoothCentral @"bluetooth-central" -#define kBGModeBluetoothPeripheral @"bluetooth-peripheral" -// newsstand-content +#ifdef __cplusplus +extern "C" { +#endif -extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); +CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); +void BKSHIDServicesCancelTouchesOnMainDisplay(); + +#ifdef __cplusplus +} +#endif #define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI)) #define DEGREES_TO_RADIANS(radians) ((radians) * (M_PI / 180)) @@ -84,7 +96,7 @@ void SET_BACKGROUNDED(id settings, BOOL val); #define SHARED_INSTANCE2(cls, extracode) \ static cls *sharedInstance = nil; \ -static dispatch_once_t onceToken = 0; \ +static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ sharedInstance = [[cls alloc] init]; \ extracode; \ @@ -93,14 +105,6 @@ return sharedInstance; #define SHARED_INSTANCE(cls) SHARED_INSTANCE2(cls, ); -#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) -#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) -#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) -#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) - -extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); - //////////////////////////////////////////////////////////////////////////////////////////////// @interface UIRemoteKeyboardWindow : UIWindow //UITextEffectsWindow @@ -113,6 +117,52 @@ extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); - (void)_lockOrientation; @end +@interface SBIconImageView : UIView { + UIImageView *_overlayView; + //SBIconProgressView *_progressView; + _Bool _isPaused; + UIImage *_cachedSquareContentsImage; + _Bool _showsSquareCorners; + SBIcon *_icon; + double _brightness; + double _overlayAlpha; +} + ++ (id)dequeueRecycledIconImageViewOfClass:(Class)arg1; ++ (void)recycleIconImageView:(id)arg1; ++ (double)cornerRadius; +@property(nonatomic) _Bool showsSquareCorners; // @synthesize showsSquareCorners=_showsSquareCorners; +@property(nonatomic) double overlayAlpha; // @synthesize overlayAlpha=_overlayAlpha; +@property(nonatomic) double brightness; // @synthesize brightness=_brightness; +@property(retain, nonatomic) SBIcon *icon; // @synthesize icon=_icon; +- (_Bool)_shouldAnimatePropertyWithKey:(id)arg1; +- (void)iconImageDidUpdate:(id)arg1; +- (struct CGRect)visibleBounds; +- (struct CGSize)sizeThatFits:(struct CGSize)arg1; +- (id)squareDarkeningOverlayImage; +- (id)darkeningOverlayImage; +- (id)squareContentsImage; +- (UIImage*)contentsImage; +- (void)_clearCachedImages; +- (id)_generateSquareContentsImage; +- (void)_updateProgressMask; +- (void)_updateOverlayImage; +- (id)_currentOverlayImage; +- (void)updateImageAnimated:(_Bool)arg1; +- (id)snapshot; +- (void)prepareForReuse; +- (void)layoutSubviews; +- (void)setPaused:(_Bool)arg1; +- (void)setProgressAlpha:(double)arg1; +- (void)_clearProgressView; +- (void)progressViewCanBeRemoved:(id)arg1; +- (void)setProgressState:(long long)arg1 paused:(_Bool)arg2 percent:(double)arg3 animated:(_Bool)arg4; +- (void)_updateOverlayAlpha; +- (void)setIcon:(id)arg1 animated:(_Bool)arg2; +- (void)dealloc; +- (id)initWithFrame:(struct CGRect)arg1; +@end + @interface SBOrientationLockManager : NSObject { NSMutableSet *_lockOverrideReasons; @@ -184,11 +234,16 @@ extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); @end @interface SBFWallpaperView : UIView +@property (nonatomic,readonly) UIImage *wallpaperImage; - (void)setGeneratesBlurredImages:(BOOL)arg1; - (void)_startGeneratingBlurredImages; - (void)prepareToAppear; @end +@interface SBFStaticWallpaperView : SBFWallpaperView +@property (setter=_setDisplayedImage:,getter=_displayedImage,nonatomic,retain) UIImage *displayedImage; +@end + @interface SBControlCenterController : UIViewController + (id)sharedInstance; @property(nonatomic, getter=isPresented) _Bool presented; // @synthesize presented=_presented; @@ -219,7 +274,6 @@ extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); @interface BKSProcess : NSObject { //BSBaseXPCClient { int _pid; NSString *_bundlePath; - NSObject *_clientQueue; bool _workspaceLocked; bool _connectedToExternalAccessories; bool _nowPlayingWithAudio; @@ -325,7 +379,7 @@ extern "C" void BKSHIDServicesCancelTouchesOnMainDisplay(); @end typedef struct { - BOOL itemIsEnabled[25]; + BOOL itemIsEnabled[29]; char timeString[64]; int gsmSignalStrengthRaw; int gsmSignalStrengthBars; @@ -352,6 +406,11 @@ typedef struct { unsigned locationIconType : 1; unsigned quietModeInactive : 1; unsigned tetheringConnectionCount; + unsigned batterySaverModeActive : 1; + unsigned deviceIsRTL : 1; + char breadcrumbTitle[256]; + char breadcrumbSecondaryTitle[256]; + char personName[100]; } StatusBarData; @interface UIStatusBar : UIView @@ -365,9 +424,36 @@ typedef struct { +(StatusBarData*) getStatusBarData; @end +@interface SBNotificationCenterViewController : UIViewController +@property (nonatomic,readonly) CGRect contentFrame; +-(CGRect)_containerFrame; +-(void)_setContainerFrame:(CGRect)arg1 ; +-(void)prepareLayoutForDefaultPresentation; +-(void)_loadContainerView; +-(void)_loadContentView; +@end + +@interface SBSearchEtceteraLayoutContentView : UIView +@end + +@interface SBSearchEtceteraLayoutView : UIView +@property (getter=_visibleView,nonatomic,retain,readonly) SBSearchEtceteraLayoutContentView * visibleView; +-(id)_visibleView; +@end + @interface SBNotificationCenterController : NSObject +(id) sharedInstance; +-(SBNotificationCenterViewController *)viewController; -(BOOL) isVisible; +-(double)percentComplete; +-(BOOL)isTransitioning; +-(BOOL)isPresentingControllerTransitioning; +@end + +@interface SBSearchEtceteraIsolatedViewController : UIViewController +@property (nonatomic,retain,readonly) SBSearchEtceteraLayoutView * contentView; +-(SBSearchEtceteraLayoutView *)contentView; ++(id)sharedInstance; @end @interface UIStatusBarItem : NSObject @@ -375,6 +461,7 @@ typedef struct { @end @interface UIScreen (ohBoy) +- (CGRect)_gkBounds; -(CGRect) _referenceBounds; - (CGPoint)convertPoint:(CGPoint)arg1 toCoordinateSpace:(id)arg2; + (CGPoint)convertPoint:(CGPoint)arg1 toView:(id)arg2; @@ -403,6 +490,7 @@ typedef struct { @end @interface SBWallpaperController +@property (nonatomic,retain) SBFStaticWallpaperView *sharedWallpaperView; +(id) sharedInstance; -(void) beginRequiringWithReason:(NSString*)reason; -(void) endRequiringWithReason:(NSString*)reason; @@ -517,6 +605,13 @@ typedef enum @property(readonly, nonatomic) NSString *type; // @synthesize type=_type; @end +@interface SBHomeScreenViewController : UIViewController +@end + +@interface SBHomeScreenWindow : UIWindow +@property (nonatomic, weak,readonly) SBHomeScreenViewController *homeScreenViewController; +@end + @interface SBLockScreenManager +(id) sharedInstance; -(BOOL) isUILocked; @@ -587,12 +682,15 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { @interface _UIBackdropView : UIView @property (retain, nonatomic) _UIBackdropViewSettings *outputSettings; @property (retain, nonatomic) _UIBackdropViewSettings *inputSettings; +@property (assign,nonatomic) double _blurRadius; @property (nonatomic) int blurHardEdges; +- (void)_applyCornerRadiusToSubviews; +- (void)_setCornerRadius:(double)arg1 ; - (void) setBlursWithHardEdges:(BOOL)arg1; - (void)setBlurQuality:(id)arg1; --(void) setBlurRadius:(CGFloat)radius; --(void) setBlurRadiusSetOnce:(BOOL)v; --(id) initWithStyle:(NSInteger)style; +- (void)setBlurRadius:(CGFloat)radius; +- (void)setBlurRadiusSetOnce:(BOOL)v; +- (id)initWithStyle:(NSInteger)style; @property (nonatomic) BOOL autosizesToFitSuperview; @property (nonatomic) BOOL blursBackground; - (void)_setBlursBackground:(BOOL)arg1; @@ -655,7 +753,9 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { + (instancetype)eventWithName:(NSString *)label handler:(id)handler; @end -@interface FBSceneManager : NSObject +@interface FBDisplayManager : NSObject ++(id)sharedInstance; ++(id)mainDisplay; @end @interface SBWorkspaceApplicationTransitionContext : NSObject @@ -673,6 +773,7 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { @interface SBMainWorkspaceTransitionRequest : NSObject - (id)initWithDisplay:(id)arg1; +- (void)setApplicationContext:(SBWorkspaceApplicationTransitionContext *)arg1 ; @end @interface SBAppToAppWorkspaceTransaction @@ -713,9 +814,9 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { @end @interface SBDisplayLayout : NSObject { - int _layoutSize; - NSMutableArray* _displayItems; - NSString* _uniqueStringRepresentation; + int _layoutSize; + NSMutableArray* _displayItems; + NSString* _uniqueStringRepresentation; } @property(readonly, assign, nonatomic) NSArray* displayItems; @property(readonly, assign, nonatomic) int layoutSize; @@ -739,8 +840,7 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { -(id)initWithLayoutSize:(int)layoutSize displayItems:(id)items; @end -@interface FBProcessManager : NSObject -+ (id)sharedInstance; +@interface FBProcessManager () - (void)_updateWorkspaceLockedState; - (void)applicationProcessWillLaunch:(id)arg1; - (void)noteProcess:(id)arg1 didUpdateState:(id)arg2; @@ -752,7 +852,6 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { - (id)createApplicationProcessForBundleID:(id)arg1 withExecutionContext:(id)arg2; - (id)createApplicationProcessForBundleID:(id)arg1; - (id)applicationProcessForPID:(int)arg1; -- (id)processForPID:(int)arg1; - (id)applicationProcessesForBundleIdentifier:(id)arg1; - (id)processesForBundleIdentifier:(id)arg1; - (id)allApplicationProcesses; @@ -760,55 +859,10 @@ typedef NS_ENUM(NSInteger, UIScreenEdgePanRecognizerType) { @end @interface UIGestureRecognizerTarget : NSObject { - id _target; + id _target; } @end -typedef NS_ENUM(NSUInteger, BKSProcessAssertionReason) -{ - kProcessAssertionReasonNone = 0, - kProcessAssertionReasonAudio = 1, - kProcessAssertionReasonLocation = 2, - kProcessAssertionReasonExternalAccessory = 3, - kProcessAssertionReasonFinishTask = 4, - kProcessAssertionReasonBluetooth = 5, - kProcessAssertionReasonNetworkAuthentication = 6, - kProcessAssertionReasonBackgroundUI = 7, - kProcessAssertionReasonInterAppAudioStreaming = 8, - kProcessAssertionReasonViewServices = 9, - kProcessAssertionReasonNewsstandDownload = 10, - kProcessAssertionReasonBackgroundDownload = 11, - kProcessAssertionReasonVOiP = 12, - kProcessAssertionReasonExtension = 13, - kProcessAssertionReasonContinuityStreams = 14, - // 15-9999 unknown - kProcessAssertionReasonActivation = 10000, - kProcessAssertionReasonSuspend = 10001, - kProcessAssertionReasonTransientWakeup = 10002, - kProcessAssertionReasonVOiP_PreiOS8 = 10003, - kProcessAssertionReasonPeriodicTask_iOS8 = kProcessAssertionReasonVOiP_PreiOS8, - kProcessAssertionReasonFinishTaskUnbounded = 10004, - kProcessAssertionReasonContinuous = 10005, - kProcessAssertionReasonBackgroundContentFetching = 10006, - kProcessAssertionReasonNotificationAction = 10007, - // 10008-49999 unknown - kProcessAssertionReasonFinishTaskAfterBackgroundContentFetching = 50000, - kProcessAssertionReasonFinishTaskAfterBackgroundDownload = 50001, - kProcessAssertionReasonFinishTaskAfterPeriodicTask = 50002, - kProcessAssertionReasonAFterNoficationAction = 50003, - // 50004+ unknown -}; - -typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) -{ - ProcessAssertionFlagNone = 0, - ProcessAssertionFlagPreventSuspend = 1 << 0, - ProcessAssertionFlagPreventThrottleDownCPU = 1 << 1, - ProcessAssertionFlagAllowIdleSleep = 1 << 2, - ProcessAssertionFlagWantsForegroundResourcePriority = 1 << 3 -}; - - @interface FBWindowContextHostManager - (id)hostViewForRequester:(id)arg1 enableAndOrderFront:(BOOL)arg2; - (void)resumeContextHosting; @@ -888,17 +942,9 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) @interface UIMutableApplicationSceneSettings : FBSMutableSceneSettings @end - -@interface FBProcess : NSObject -@end - -@interface FBScene +@interface FBScene () -(FBWindowContextHostManager*) contextHostManager; -@property(readonly, retain, nonatomic) FBSMutableSceneSettings *mutableSettings; // @synthesize mutableSettings=_mutableSettings; - (void)updateSettings:(id)arg1 withTransitionContext:(id)arg2; -- (void)_applyMutableSettings:(id)arg1 withTransitionContext:(id)arg2 completion:(id)arg3; -@property (nonatomic, readonly) NSString *identifier; -@property (nonatomic, readonly, retain) FBProcess *clientProcess; @end @interface SBApplication () @@ -916,7 +962,7 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) - (void)_sendDidLaunchNotification:(_Bool)arg1; - (void)notifyResumeActiveForReason:(long long)arg1; -@property(readonly, nonatomic) int pid; +@property(readwrite, nonatomic) int pid; @end @interface SBApplicationController : NSObject @@ -956,8 +1002,7 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) - (void)minimize; @end -@interface BKSProcessAssertion -- (id)initWithPID:(int)arg1 flags:(unsigned int)arg2 reason:(unsigned int)arg3 name:(id)arg4 withHandler:(id)arg5; +@interface BKSProcessAssertion () - (id)initWithBundleIdentifier:(id)arg1 flags:(unsigned int)arg2 reason:(unsigned int)arg3 name:(id)arg4 withHandler:(id)arg5; - (void)invalidate; @property(readonly, nonatomic) BOOL valid; @@ -1017,7 +1062,7 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) - (unsigned int)contextID; @end -@interface UIWindow () +@interface UIWindow () +(instancetype) keyWindow; -(id) firstResponder; + (void)setAllWindowsKeepContextInBackground:(BOOL)arg1; @@ -1029,6 +1074,7 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) @end @interface UIApplication () +@property (nonatomic) BOOL RA_networkActivity; - (void)_handleKeyUIEvent:(id)arg1; -(UIStatusBar*) statusBar; - (id)_mainScene; @@ -1147,49 +1193,49 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) @end @interface SBIconView : UIView { - SBIcon *_icon; - id _delegate; - id _locker; - SBIconImageContainerView *_iconImageContainer; - SBIconImageView *_iconImageView; - UIImageView *_iconDarkeningOverlay; - UIImageView *_ghostlyImageView; - UIImageView *_reflection; - UIImageView *_shadow; - SBIconBadgeImage *_badgeImage; - UIImageView *_badgeView; - SBIconLabel *_label; - BOOL _labelHidden; - BOOL _labelOnWallpaper; - UIView *_closeBox; - int _closeBoxType; - UIImageView *_dropGlow; - unsigned _drawsLabel : 1; - unsigned _isHidden : 1; - unsigned _isGrabbed : 1; - unsigned _isOverlapping : 1; - unsigned _refusesRecipientStatus : 1; - unsigned _highlighted : 1; - unsigned _launchDisabled : 1; - unsigned _isJittering : 1; - unsigned _allowJitter : 1; - unsigned _touchDownInIcon : 1; - unsigned _hideShadow : 1; - NSTimer *_delayedUnhighlightTimer; - unsigned _onWallpaper : 1; - unsigned _ghostlyRequesters; - int _iconLocation; - float _iconImageAlpha; - float _iconImageBrightness; - float _iconLabelAlpha; - float _accessoryAlpha; - CGPoint _unjitterPoint; - CGPoint _grabPoint; - NSTimer *_longPressTimer; - unsigned _ghostlyTag; - UIImage *_ghostlyImage; - BOOL _ghostlyPending; -} + SBIcon *_icon; + id _delegate; + id _locker; + SBIconImageContainerView *_iconImageContainer; + SBIconImageView *_iconImageView; + UIImageView *_iconDarkeningOverlay; + UIImageView *_ghostlyImageView; + UIImageView *_reflection; + UIImageView *_shadow; + SBIconBadgeImage *_badgeImage; + UIImageView *_badgeView; + SBIconLabel *_label; + BOOL _labelHidden; + BOOL _labelOnWallpaper; + UIView *_closeBox; + int _closeBoxType; + UIImageView *_dropGlow; + unsigned _drawsLabel : 1; + unsigned _isHidden : 1; + unsigned _isGrabbed : 1; + unsigned _isOverlapping : 1; + unsigned _refusesRecipientStatus : 1; + unsigned _highlighted : 1; + unsigned _launchDisabled : 1; + unsigned _isJittering : 1; + unsigned _allowJitter : 1; + unsigned _touchDownInIcon : 1; + unsigned _hideShadow : 1; + NSTimer *_delayedUnhighlightTimer; + unsigned _onWallpaper : 1; + unsigned _ghostlyRequesters; + int _iconLocation; + float _iconImageAlpha; + float _iconImageBrightness; + float _iconLabelAlpha; + float _accessoryAlpha; + CGPoint _unjitterPoint; + CGPoint _grabPoint; + NSTimer *_longPressTimer; + unsigned _ghostlyTag; + UIImage *_ghostlyImage; + BOOL _ghostlyPending; + } -(void) RA_updateIndicatorView:(NSInteger)info; @@ -1319,23 +1365,27 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) @end +@interface SBIconView () +@property (nonatomic, assign) BOOL RA_isIconIndicatorInhibited; +@end + @class NSMapTable; @interface SBIconViewMap : NSObject { - NSMapTable* _iconViewsForIcons; - id _iconViewdelegate; - NSMapTable* _recycledIconViewsByType; - NSMapTable* _labels; - NSMapTable* _badges; + NSMapTable* _iconViewsForIcons; + id _iconViewdelegate; + NSMapTable* _recycledIconViewsByType; + NSMapTable* _labels; + NSMapTable* _badges; } + (SBIconViewMap *)switcherMap; +(SBIconViewMap *)homescreenMap; +(Class)iconViewClassForIcon:(SBIcon *)icon location:(int)location; -(id)init; -(void)dealloc; --(SBIconView *)mappedIconViewForIcon:(SBIcon *)icon; --(SBIconView *)_iconViewForIcon:(SBIcon *)icon; --(SBIconView *)iconViewForIcon:(SBIcon *)icon; +-(SBIconView *)mappedIconViewForIcon:(SBApplicationIcon *)icon; +-(SBIconView *)_iconViewForIcon:(SBApplicationIcon *)icon; +-(SBIconView *)iconViewForIcon:(SBApplicationIcon *)icon; -(void)_addIconView:(SBIconView *)iconView forIcon:(SBIcon *)icon; -(void)purgeIconFromMap:(SBIcon *)icon; -(void)_recycleIconView:(SBIconView *)iconView; @@ -1355,6 +1405,11 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) @property (nonatomic, readonly) SBIconModel *iconModel; @end +@interface SBIconController (iOS90) +@property (nonatomic,readonly) SBIconViewMap *homescreenIconViewMap; ++ (id)sharedInstance; +@end + @interface SBApplication (iOS6) - (BOOL)isRunning; - (id)badgeNumberOrString; @@ -1389,53 +1444,6 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) - (id)initWithDefaultSize; @end -@interface SBIconImageView () -{ - UIImageView *_overlayView; - //SBIconProgressView *_progressView; - _Bool _isPaused; - UIImage *_cachedSquareContentsImage; - _Bool _showsSquareCorners; - SBIcon *_icon; - double _brightness; - double _overlayAlpha; -} - -+ (id)dequeueRecycledIconImageViewOfClass:(Class)arg1; -+ (void)recycleIconImageView:(id)arg1; -+ (double)cornerRadius; -@property(nonatomic) _Bool showsSquareCorners; // @synthesize showsSquareCorners=_showsSquareCorners; -@property(nonatomic) double overlayAlpha; // @synthesize overlayAlpha=_overlayAlpha; -@property(nonatomic) double brightness; // @synthesize brightness=_brightness; -@property(retain, nonatomic) SBIcon *icon; // @synthesize icon=_icon; -- (_Bool)_shouldAnimatePropertyWithKey:(id)arg1; -- (void)iconImageDidUpdate:(id)arg1; -- (struct CGRect)visibleBounds; -- (struct CGSize)sizeThatFits:(struct CGSize)arg1; -- (id)squareDarkeningOverlayImage; -- (id)darkeningOverlayImage; -- (id)squareContentsImage; -- (UIImage*)contentsImage; -- (void)_clearCachedImages; -- (id)_generateSquareContentsImage; -- (void)_updateProgressMask; -- (void)_updateOverlayImage; -- (id)_currentOverlayImage; -- (void)updateImageAnimated:(_Bool)arg1; -- (id)snapshot; -- (void)prepareForReuse; -- (void)layoutSubviews; -- (void)setPaused:(_Bool)arg1; -- (void)setProgressAlpha:(double)arg1; -- (void)_clearProgressView; -- (void)progressViewCanBeRemoved:(id)arg1; -- (void)setProgressState:(long long)arg1 paused:(_Bool)arg2 percent:(double)arg3 animated:(_Bool)arg4; -- (void)_updateOverlayAlpha; -- (void)setIcon:(id)arg1 animated:(_Bool)arg2; -- (void)dealloc; -- (id)initWithFrame:(struct CGRect)arg1; -@end - @interface BBBulletin @property(copy, nonatomic) NSString *bulletinID; // @synthesize bulletinID=_bulletinID; @property(copy, nonatomic) NSString *sectionID; // @synthesize sectionID=_sectionID; @@ -1455,3 +1463,51 @@ typedef NS_ENUM(NSUInteger, ProcessAssertionFlags) - (id)bulletinIDsForSectionID:(id)arg1 inFeed:(unsigned long long)arg2; @end +@interface FBSystemService : NSObject +- (id)sharedInstance; +- (void)exitAndRelaunch:(bool)arg1; +@end + +@interface SBSwitcherSnapshotImageView : UIView +@property (nonatomic,readonly) UIImage * image; +- (UIImage *)image; +@end + +@interface _SBAppSwitcherSnapshotContext : NSObject { + SBSwitcherSnapshotImageView* _snapshotImageView; +} +@property (nonatomic,retain) SBSwitcherSnapshotImageView * snapshotImageView; //@synthesize snapshotImageView=_snapshotImageView - In the implementation block +- (SBSwitcherSnapshotImageView *)snapshotImageView; +- (void)setSnapshotImageView:(SBSwitcherSnapshotImageView *)arg1 ; +- (CGRect)snapshotReferenceFrame; +- (void)setSnapshotReferenceFrame:(CGRect)arg1 ; +@end + +@interface SBMainSwitcherViewController : UIViewController ++ (id)sharedInstance; +- (BOOL)dismissSwitcherNoninteractively; +- (BOOL)isVisible; +- (BOOL)activateSwitcherNoninteractively; +- (void)RA_dismissSwitcherUnanimated; +@end + +@interface SBSwitcherContainerView : UIView +@property (nonatomic,retain) UIView * contentView; +- (void)layoutSubviews; +- (UIView *)contentView; +@end + +@interface SBUIChevronView : UIView +@property (assign,nonatomic) long long state; +@property (nonatomic,retain) UIColor * color; +-(id)initWithFrame:(CGRect)arg1; +-(id)initWithColor:(id)arg1 ; +-(void)setColor:(UIColor *)arg1 ; +-(void)setState:(long long)arg1 animated:(BOOL)arg2; +-(void)setBackgroundView:(id)arg1; +@end + +@interface SBPagedScrollView : UIScrollView +- (NSArray *)pageViews; +- (void)setPageViews:(NSArray *)arg1; +@end diff --git a/layout/DEBIAN/control b/layout/DEBIAN/control index d8377d1..b58d9d1 100644 --- a/layout/DEBIAN/control +++ b/layout/DEBIAN/control @@ -1,12 +1,12 @@ Package: org.thebigboss.multiplexer Name: Multiplexer -Depends: mobilesubstrate, applist, preferenceloader, com.elijahandandrew.MultiplexerTutorial, com.rpetrich.rocketbootstrap +Depends: mobilesubstrate, applist, preferenceloader, com.rpetrich.rocketbootstrap Conflicts: cc.tweak.statushud Replaces: com.efrederickson.reachapp Version: 0.1 Architecture: iphoneos-arm -Description: All sorts of multitasking. -Depiction: http://elijahandandrew.com/repo/depictions/Multiplexer/index.html -Maintainer: Elijah and Andrew -Author: Elijah and Andrew +Description: All sorts of multitasking. +Depiction: https://shade-zepheri.github.io/depic/index.html?p=com.shade.multiplexer +Maintainer: Shade Zepheri +Author: Shade Zepheri Section: Tweaks diff --git a/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/Info.plist b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/Info.plist new file mode 100644 index 0000000..7d88b9b --- /dev/null +++ b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/Info.plist @@ -0,0 +1,16 @@ + + + + + compatible-modes + + springboard + application + lockscreen + + description + Create window for currently open app. + title + Create Window + + diff --git a/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small.png b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small.png new file mode 100644 index 0000000..1c8a825 Binary files /dev/null and b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small.png differ diff --git a/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@2x.png b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@2x.png new file mode 100644 index 0000000..5fbb37f Binary files /dev/null and b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@2x.png differ diff --git a/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@3x.png b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@3x.png new file mode 100644 index 0000000..42b36d2 Binary files /dev/null and b/layout/Library/Activator/Listeners/com.efrederickson.reachapp.windowedmultitasking.createWindow/icon-small@3x.png differ diff --git a/layout/Library/LaunchDaemons/com.efrederickson.reachapp.fsdaemon.plist b/layout/Library/LaunchDaemons/com.efrederickson.reachapp.fsdaemon.plist index c82ec6d..c2991a0 100644 --- a/layout/Library/LaunchDaemons/com.efrederickson.reachapp.fsdaemon.plist +++ b/layout/Library/LaunchDaemons/com.efrederickson.reachapp.fsdaemon.plist @@ -8,6 +8,8 @@ /usr/bin/ReachAppFSDaemon RunAtLoad + ExecuteAllowed + StandardErrorPath /dev/null WatchPaths @@ -19,4 +21,4 @@ group wheel - \ No newline at end of file + diff --git a/layout/Library/Multiplexer/Localizations/en.strings b/layout/Library/Multiplexer/Localizations/en.strings index 732efd9..8157433 100644 --- a/layout/Library/Multiplexer/Localizations/en.strings +++ b/layout/Library/Multiplexer/Localizations/en.strings @@ -19,6 +19,6 @@ "FAVORITES" = "Favorites"; "RECENTS" = "Recent"; "ACTIVE_APP_WARNING" = "%@\n is currently open"; -"ASPHALEIA2_AUTH_FAILED" = "Asphaleia 2\n authentication failed for\n %@.\nTap to try again."; +"ASPHALEIA_AUTH_FAILED" = "Asphaleia \n authentication failed for\n %@.\nTap to try again."; "UNLIMITED_BACKGROUNDING_TIME" = "Unlimited Backgrounding Time"; -"KILL_ALL" = "Kill All"; \ No newline at end of file +"KILL_ALL" = "Kill All"; diff --git a/layout/Library/Multiplexer/Localizations/es.strings b/layout/Library/Multiplexer/Localizations/es.strings new file mode 100644 index 0000000..25c88bd --- /dev/null +++ b/layout/Library/Multiplexer/Localizations/es.strings @@ -0,0 +1,24 @@ +"BIOLOCKDOWN_AUTH_DESCRIPTION" = "Multiplexer necesita autenticación"; +"BIOLOCKDOWN_AUTH_FAILED" = "Autenticación de BioLockdown falló para %@. Toca para tratar otra vez."; +"MULTIPLEXER" = "Multiplexer"; +"BACKGROUNDER_POPUP_SWITCHER_TEXT" = "Cual modo de fondo quieres usar par %@ (Ahorita es %@)?"; +"CANCEL" = "Cancela"; +"FORCE_FOREGROUND" = "Forzar primer plano"; +"NATIVE" = "Nativo"; +"SUSPEND_IMMEDIATELY" = "Suspende inmediatamente"; +"DISABLE" = "Inhabilitar"; +"THANK_YOU_TEXT" = "Gracias por instalando Multiplexer! Toca aquí para ver el tutorial."; +"DESKTOPS" = "Escritorio"; +"ON_THIS_DESKTOP" = "En este Escritorio"; +"RUNNING_ELSEWHERE" = "Corriendo en otra parte"; +"NO_APPS" = "Ningun Aplicaciones"; +"APP" = "Aplicacion"; +"UNLOCK_FOR_NCAPP" = "Desbloquear para usar\nQuick Access"; +"ALL_APPS" = "All Apps"; +"WIDGETS" = "Widgets"; +"FAVORITES" = "Favoritos"; +"RECENTS" = "Reciente"; +"ACTIVE_APP_WARNING" = "%@\n está abierto"; +"ASPHALEIA_AUTH_FAILED" = "Asphaleia \n Autenticación falló para\n %@.\nToca para tratar otra vez."; +"UNLIMITED_BACKGROUNDING_TIME" = "Ilimitado tiemp en el fondo"; +"KILL_ALL" = "Mata Todos"; diff --git a/reachappassertiondhooks/Makefile b/reachappassertiondhooks/Makefile index 3f531be..54b7675 100644 --- a/reachappassertiondhooks/Makefile +++ b/reachappassertiondhooks/Makefile @@ -1,6 +1,5 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -fno-objc-arc -LDFLAGS += -Wl,-segalign,4000 +CFLAGS = -fno-objc-arc -O2 include $(THEOS)/makefiles/common.mk diff --git a/reachappassertiondhooks/Tweak.xm b/reachappassertiondhooks/Tweak.xm index a656765..cb73906 100644 --- a/reachappassertiondhooks/Tweak.xm +++ b/reachappassertiondhooks/Tweak.xm @@ -1,29 +1,35 @@ #import -#import #import +#import -extern const char *__progname; +%group iOS8 +%hookf(int, BSAuditTokenTaskHasEntitlement, id connection, NSString *entitlement) { + if ([entitlement isEqualToString:@"com.apple.multitasking.unlimitedassertions"]) { + return true; + } -static int (*orig_BSAuditTokenTaskHasEntitlement)(id connection, NSString *entitlement); -static int hax_BSAuditTokenTaskHasEntitlement(__unsafe_unretained id connection, __unsafe_unretained NSString *entitlement) -{ - if ([entitlement isEqualToString:@"com.apple.multitasking.unlimitedassertions"]) - { - // We could check if the connection's pid matches SpringBoard's pid, but at this point I don't think it really matters - // I mean, what could be the worst thing a process can do by making BKSProcessAssertions? slaughtering battery? suspending/keeping apps running? - return true; - } + return %orig; +} +%end + +%group iOS9andUp +%hookf(int, BSXPCConnectionHasEntitlement, id connection, NSString *entitlement) { + if ([entitlement isEqualToString:@"com.apple.multitasking.unlimitedassertions"]) { + return true; + } - return orig_BSAuditTokenTaskHasEntitlement(connection, entitlement); + return %orig; } +%end -%ctor -{ - // We can never be too sure - if (strcmp(__progname, "assertiond") == 0) - { - dlopen("/System/Library/PrivateFrameworks/XPCObjects.framework/XPCObjects", RTLD_LAZY); - void *xpcFunction = MSFindSymbol(NULL, "_BSAuditTokenTaskHasEntitlement"); - MSHookFunction(xpcFunction, (void *)hax_BSAuditTokenTaskHasEntitlement, (void **)&orig_BSAuditTokenTaskHasEntitlement); - } -} \ No newline at end of file +%ctor { + // We can never be too sure (im pretty sure we can) + dlopen("/System/Library/PrivateFrameworks/XPCObjects.framework/XPCObjects", RTLD_LAZY); + if (IS_IOS_OR_NEWER(iOS_9_0)) { + void *BSXPCConnectionHasEntitlement = MSFindSymbol(NULL, "_BSXPCConnectionHasEntitlement"); + %init(iOS9andUp); + } else { + void *BSAuditTokenTaskHasEntitlement = MSFindSymbol(NULL, "_BSAuditTokenTaskHasEntitlement"); + %init(iOS8); + } +} diff --git a/reachappbackboarddhooks/Makefile b/reachappbackboarddhooks/Makefile index 96cb14f..1c7690e 100644 --- a/reachappbackboarddhooks/Makefile +++ b/reachappbackboarddhooks/Makefile @@ -1,13 +1,13 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../Messaging/ +CFLAGS = -I../Messaging/ -O2 #CFLAGS += -fno-objc-arc -LDFLAGS += -Wl,-segalign,4000 include $(THEOS)/makefiles/common.mk TWEAK_NAME = ReachAppBackboarddHooks ReachAppBackboarddHooks_FILES = Tweak.xm -ReachAppBackboarddHooks_LIBRARIES = IOKit +ReachAppBackboarddHooks_PRIVATE_FRAMEWORKS = AppSupport IOKit +ReachAppBackboarddHooks_LIBRARIES = rocketbootstrap include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/reachappbackboarddhooks/Tweak.xm b/reachappbackboarddhooks/Tweak.xm index 98c4298..237888c 100644 --- a/reachappbackboarddhooks/Tweak.xm +++ b/reachappbackboarddhooks/Tweak.xm @@ -1,15 +1,16 @@ #import -#import +#import #import #import "RAMessaging.h" #import +#import #define CTRL_KEY 224 -#define CMD_KEY 231 +#define CMD_KEY 231 #define CMD_KEY2 227 #define SHIFT_KEY 229 #define SHIFT_KEY2 225 -#define ALT_KEY 226 +#define ALT_KEY 226 #define ALT_KEY2 230 #define D_KEY 7 #define P_KEY 19 @@ -31,60 +32,40 @@ CPDistributedMessagingCenter *center; // TODO: Ensure all keyboard commands do not conflict with // https://support.apple.com/en-us/HT201236 -void handle_event(void *target, void *refcon, IOHIDServiceRef service, IOHIDEventRef event) -{ - if (IOHIDEventGetType(event) == kIOHIDEventTypeKeyboard) - { +void handle_event(void *target, void *refcon, IOHIDServiceRef service, IOHIDEventRef event) { + if (IOHIDEventGetType(event) == kIOHIDEventTypeKeyboard) { IOHIDEventRef event2 = IOHIDEventCreateCopy(kCFAllocatorDefault, event); BOOL isDown = IOHIDEventGetIntegerValue(event2, kIOHIDEventFieldKeyboardDown); int key = IOHIDEventGetIntegerValue(event2, kIOHIDEventFieldKeyboardUsage); - if (key == CTRL_KEY) + if (key == CTRL_KEY) { isControlKeyDown = isDown; - else if (key == CMD_KEY || key == CMD_KEY2) + } else if (key == CMD_KEY || key == CMD_KEY2) { isWindowsKeyDown = isDown; - else if (key == SHIFT_KEY || key == SHIFT_KEY2) + } else if (key == SHIFT_KEY || key == SHIFT_KEY2) { isShiftKeyDown = isDown; - else if (key == ALT_KEY || key == ALT_KEY2) + } else if (key == ALT_KEY || key == ALT_KEY2) { isAltKeyDown = isDown; - else if (isDown && isWindowsKeyDown && isControlKeyDown) - { - if (key == ARROW_LEFT_KEY) - { + } else if (isDown && isWindowsKeyDown && isControlKeyDown) { + if (key == ARROW_LEFT_KEY) { [center sendMessageName:RAMessagingGoToDesktopOnTheLeftMessageName userInfo:nil]; - } - else if (key == ARROW_RIGHT_KEY) - { + } else if (key == ARROW_RIGHT_KEY) { [center sendMessageName:RAMessagingGoToDesktopOnTheRightMessageName userInfo:nil]; - } - else if (key == BKSPCE_KEY) - { + } else if (key == BKSPCE_KEY) { [center sendMessageName:RAMessagingDetachCurrentAppMessageName userInfo:nil]; - } - else if (key == D_KEY || key == EQUALS_OR_PLUS_KEY) - { - + } else if (key == D_KEY || key == EQUALS_OR_PLUS_KEY) { [center sendMessageName:RAMessagingAddNewDesktopMessageName userInfo:nil]; } - } - else if (isDown && isWindowsKeyDown && isAltKeyDown) - { - if (key == ARROW_LEFT_KEY) - { + } else if (isDown && isWindowsKeyDown && isAltKeyDown) { + if (key == ARROW_LEFT_KEY) { [center sendMessageName:RAMessagingSnapFrontMostWindowLeftMessageName userInfo:nil]; - } - else if (key == ARROW_RIGHT_KEY) - { + } else if (key == ARROW_RIGHT_KEY) { [center sendMessageName:RAMessagingSnapFrontMostWindowRightMessageName userInfo:nil]; - } - else if (key == ARROW_UP_KEY) - { + } else if (key == ARROW_UP_KEY) { [center sendMessageName:RAMessagingMaximizeAppMessageName userInfo:nil]; - } - else if (key == ARROW_DOWN_KEY) - { - [center sendMessageName:RAMessagingCloseAppMessageName userInfo:nil]; + } else if (key == ARROW_DOWN_KEY) { + [center sendMessageName:RAMessagingCloseAppMessageName userInfo:nil]; } } } @@ -92,29 +73,26 @@ void handle_event(void *target, void *refcon, IOHIDServiceRef service, IOHIDEven eventCallback(target, refcon, service, event); } -Boolean (*orig$IOHIDEventSystemOpen)(IOHIDEventSystemRef system, IOHIDEventSystemCallback callback, void* target, void* refcon, void* unused); -Boolean hook$IOHIDEventSystemOpen(IOHIDEventSystemRef system, IOHIDEventSystemCallback callback, void* target, void* refcon, void* unused) -{ +%hookf(Boolean, "_IOHIDEventSystemOpen", IOHIDEventSystemRef system, IOHIDEventSystemCallback callback, void* target, void* refcon, void* unused) { eventCallback = callback; - return orig$IOHIDEventSystemOpen(system, handle_event, target, refcon, unused); + return %orig; } %hook BKEventFocusManager @interface BKEventDestination --(id ) initWithPid:(unsigned int)arg1 clientID:(NSString*)arg2; +- (instancetype)initWithPid:(NSUInteger)arg1 clientID:(NSString*)arg2; @end --(id) destinationForFocusedEventWithDisplay:(__unsafe_unretained id)arg1 -{ +- (id)destinationForFocusedEventWithDisplay:(__unsafe_unretained id)arg1 { NSDictionary *response = [center sendMessageAndReceiveReplyName:RAMessagingGetFrontMostAppInfoMessageName userInfo:nil]; - if (response) - { + if (response) { int pid = [response[@"pid"] unsignedIntValue]; NSString *clientId = response[@"bundleIdentifier"]; - if (pid && clientId) - return [[[objc_getClass("BKEventDestination") alloc] initWithPid:pid clientID:clientId] autorelease]; + if (pid && clientId) { + return [[[%c(BKEventDestination) alloc] initWithPid:pid clientID:clientId] autorelease]; + } } return %orig; } @@ -144,7 +122,7 @@ Boolean hook$IOHIDEventSystemOpen(IOHIDEventSystemRef system, IOHIDEventSystemCa UIGraphicsPopContext(); CGContextRelease(context); CGFloat alpha = pixel[0]/255.0f; - BOOL transparent = alpha < 1.f; + BOOL transparent = alpha < 1.f; if (!transparent) return cid; } @@ -154,18 +132,13 @@ Boolean hook$IOHIDEventSystemOpen(IOHIDEventSystemRef system, IOHIDEventSystemCa %end */ -%ctor -{ - MSHookFunction(&IOHIDEventSystemOpen, hook$IOHIDEventSystemOpen, &orig$IOHIDEventSystemOpen); - - center = [objc_getClass("CPDistributedMessagingCenter") centerNamed:@"com.efrederickson.reachapp.messaging.server"]; +%ctor { + center = [%c(CPDistributedMessagingCenter) centerNamed:@"com.efrederickson.reachapp.messaging.server"]; void* handle = dlopen("/usr/lib/librocketbootstrap.dylib", RTLD_LAZY); - if(handle) - { - void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*); - rocketbootstrap_distributedmessagingcenter_apply = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); - rocketbootstrap_distributedmessagingcenter_apply(center); - dlclose(handle); + if (handle) { + void (*rocketbootstrap_distributedmessagingcenter_apply)(CPDistributedMessagingCenter*) = (void(*)(CPDistributedMessagingCenter*))dlsym(handle, "rocketbootstrap_distributedmessagingcenter_apply"); + rocketbootstrap_distributedmessagingcenter_apply(center); + dlclose(handle); } -} \ No newline at end of file +} diff --git a/reachappfakephonemode/Makefile b/reachappfakephonemode/Makefile index 9664d58..8e0e720 100644 --- a/reachappfakephonemode/Makefile +++ b/reachappfakephonemode/Makefile @@ -1,7 +1,6 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../ -I../Theming -LDFLAGS += -Wl,-segalign,4000 +CFLAGS = -I../ -I../Theming -O2 include $(THEOS)/makefiles/common.mk diff --git a/reachappfakephonemode/Tweak.xm b/reachappfakephonemode/Tweak.xm index bee13af..48cc3d4 100644 --- a/reachappfakephonemode/Tweak.xm +++ b/reachappfakephonemode/Tweak.xm @@ -11,78 +11,68 @@ } %hook UIDevice --(UIUserInterfaceIdiom) userInterfaceIdiom -{ - UIUserInterfaceIdiom origIdiom = %orig; +- (UIUserInterfaceIdiom)userInterfaceIdiom { + UIUserInterfaceIdiom origIdiom = %orig; - //if (IS_SPRINGBOARD || ignorePhoneMode) - // return origIdiom; + //if (IS_SPRINGBOARD || ignorePhoneMode) + // return origIdiom; - if (origIdiom != UIUserInterfaceIdiomPhone && [%c(RAFakePhoneMode) shouldFakeForThisProcess]) - return UIUserInterfaceIdiomPhone; + if (origIdiom != UIUserInterfaceIdiomPhone && [%c(RAFakePhoneMode) shouldFakeForThisProcess]) { + return UIUserInterfaceIdiomPhone; + } - return origIdiom; + return origIdiom; } %end %hook UIScreen -- (CGRect)_unjailedReferenceBounds -{ - FAKE; - return %orig; +- (CGRect)_unjailedReferenceBounds { + FAKE; + return %orig; } -- (CGRect)_referenceBounds -{ - FAKE; - return %orig; +- (CGRect)_referenceBounds { + FAKE; + return %orig; } -- (CGRect)_interfaceOrientedBounds -{ - FAKE; - return %orig; +- (CGRect)_interfaceOrientedBounds { + FAKE; + return %orig; } -- (CGRect)bounds -{ - FAKE; - return %orig; +- (CGRect)bounds { + FAKE; + return %orig; } -- (CGRect)nativeBounds -{ - FAKE; - return %orig; +- (CGRect)nativeBounds { + FAKE; + return %orig; } -- (CGRect)applicationFrame -{ - FAKE; - return %orig; +- (CGRect)applicationFrame { + FAKE; + return %orig; } -- (CGRect)_boundsForInterfaceOrientation:(int)arg1 -{ - FAKE; - return %orig; +- (CGRect)_boundsForInterfaceOrientation:(int)arg1 { + FAKE; + return %orig; } -- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 usingStatusbarHeight:(CGFloat)arg2 ignoreStatusBar:(BOOL)arg3 -{ - FAKE; - return %orig; +- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 usingStatusbarHeight:(CGFloat)arg2 ignoreStatusBar:(BOOL)arg3 { + FAKE; + return %orig; } -- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 usingStatusbarHeight:(CGFloat)arg2 -{ - FAKE; - return %orig; +- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 usingStatusbarHeight:(CGFloat)arg2 { + FAKE; + return %orig; } -- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 -{ - FAKE; - return %orig; +- (CGRect)_applicationFrameForInterfaceOrientation:(int)arg1 { + FAKE; + return %orig; } %end diff --git a/reachappflipswitch/Switch.x b/reachappflipswitch/Switch.x index ca186b8..ae2e16d 100644 --- a/reachappflipswitch/Switch.x +++ b/reachappflipswitch/Switch.x @@ -7,21 +7,20 @@ @implementation ReachAppFlipswitchSwitch -- (FSSwitchState)stateForSwitchIdentifier:(NSString *)switchIdentifier -{ +- (FSSwitchState)stateForSwitchIdentifier:(NSString *)switchIdentifier { Boolean keyExistsAndHasValidFormat; BOOL enabled = CFPreferencesGetAppBooleanValue(CFSTR("enabled"), CFSTR("com.efrederickson.reachapp.settings"), &keyExistsAndHasValidFormat); return enabled ? FSSwitchStateOn : FSSwitchStateOff; } -- (void)applyState:(FSSwitchState)newState forSwitchIdentifier:(NSString *)switchIdentifier -{ - if (newState == FSSwitchStateIndeterminate) +- (void)applyState:(FSSwitchState)newState forSwitchIdentifier:(NSString *)switchIdentifier { + if (newState == FSSwitchStateIndeterminate) { return; + } CFPreferencesSetAppValue(CFSTR("enabled"), (CFPropertyListRef)(newState == FSSwitchStateOn ? @YES : @NO), CFSTR("com.efrederickson.reachapp.settings")); notify_post("com.efrederickson.reachapp.settings/reloadSettings"); } -@end \ No newline at end of file +@end diff --git a/reachappfsdaemon/Makefile b/reachappfsdaemon/Makefile index febea2b..1e9647b 100644 --- a/reachappfsdaemon/Makefile +++ b/reachappfsdaemon/Makefile @@ -1,6 +1,5 @@ ARCHS = armv7 armv7s arm64 -CFLAGS = -I../ -I../Theming -LDFLAGS += -Wl,-segalign,4000 +CFLAGS = -I../ -I../Theming -O2 include $(THEOS)/makefiles/common.mk diff --git a/reachappfsdaemon/main.mm b/reachappfsdaemon/main.mm index f3aa58c..893ab0e 100644 --- a/reachappfsdaemon/main.mm +++ b/reachappfsdaemon/main.mm @@ -7,28 +7,26 @@ #import int main(int argc, char **argv, char **envp) { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; + @autoreleasepool { + NSString *filePath = @"/var/mobile/Library/.reachapp.uiappexitsonsuspend.wantstochangerootapp"; + if (![NSFileManager.defaultManager fileExistsAtPath:filePath]) { + LogError(@"[ReachApp] FS Daemon: plist does not exist"); + return 0; + } - NSString *filePath = @"/var/mobile/Library/.reachapp.uiappexitsonsuspend.wantstochangerootapp"; - if ([NSFileManager.defaultManager fileExistsAtPath:filePath] == NO) - { - NSLog(@"[ReachApp] FS Daemon: plist does not exist"); - return 0; - } + NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:filePath]; - NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:filePath]; + LSApplicationProxy *appInfo = [objc_getClass("LSApplicationProxy") applicationProxyForIdentifier:contents[@"bundleIdentifier"]]; + NSString *path = [NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]; + NSMutableDictionary *infoPlist = [NSMutableDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:path]]; + infoPlist[@"UIApplicationExitsOnSuspend"] = contents[@"UIApplicationExitsOnSuspend"]; + BOOL success = [infoPlist writeToURL:[NSURL URLWithString:path] atomically:YES]; - LSApplicationProxy *appInfo = [objc_getClass("LSApplicationProxy") applicationProxyForIdentifier:contents[@"bundleIdentifier"]]; - NSString *path = [NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]; - NSMutableDictionary *infoPlist = [NSMutableDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:path]]; - infoPlist[@"UIApplicationExitsOnSuspend"] = contents[@"UIApplicationExitsOnSuspend"]; - BOOL success = [infoPlist writeToURL:[NSURL URLWithString:path] atomically:YES]; - - if (!success) - NSLog(@"[ReachApp] FS Daemon: error writing to plist: %@", path); - else - [NSFileManager.defaultManager removeItemAtPath:filePath error:nil]; - - [pool release]; + if (!success) { + LogError(@"[ReachApp] FS Daemon: error writing to plist: %@", path); + } else { + [NSFileManager.defaultManager removeItemAtPath:filePath error:nil]; + } + } return 0; -} \ No newline at end of file +} diff --git a/reachappsettings/BackgroundPerAppDetailsController.h b/reachappsettings/BackgroundPerAppDetailsController.h index 84b1a22..3b2ce18 100644 --- a/reachappsettings/BackgroundPerAppDetailsController.h +++ b/reachappsettings/BackgroundPerAppDetailsController.h @@ -1,10 +1,10 @@ #import "headers.h" #import +#import -@interface RABGPerAppDetailsController : SKTintedListController -{ +@interface RABGPerAppDetailsController : SKTintedListController { NSString* _appName; NSString* _identifier; } --(id)initWithAppName:(NSString*)appName identifier:(NSString*)identifier; -@end \ No newline at end of file +- (instancetype)initWithAppName:(NSString*)appName identifier:(NSString*)identifier; +@end diff --git a/reachappsettings/BackgroundPerAppDetailsController.xm b/reachappsettings/BackgroundPerAppDetailsController.xm index 64d6214..62e72e6 100644 --- a/reachappsettings/BackgroundPerAppDetailsController.xm +++ b/reachappsettings/BackgroundPerAppDetailsController.xm @@ -6,254 +6,257 @@ extern void RA_BGAppsControllerNeedsToReload(); @implementation RABGPerAppDetailsController --(id)initWithAppName:(NSString*)appName identifier:(NSString*)identifier -{ +- (instancetype)initWithAppName:(NSString*)appName identifier:(NSString*)identifier { _appName = appName; _identifier = identifier; return [self init]; } --(NSString*) customTitle { return _appName; } --(BOOL) showHeartImage { return NO; } --(UIColor*) navigationTintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } +- (NSString*)customTitle { + return _appName; +} + +- (BOOL)showHeartImage { + return NO; +} + +- (UIColor*)navigationTintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} --(id) isBackgroundModeActive:(NSString*)mode withAppInfo:(NSArray*)info -{ - return [info containsObject:mode] ? @YES : @NO; +- (id)isBackgroundModeActive:(NSString*)mode withAppInfo:(NSArray*)info { + return [info containsObject:mode] ? @YES : @NO; } --(NSArray*) customSpecifiers -{ - LSApplicationProxy *appInfo = [%c(LSApplicationProxy) applicationProxyForIdentifier:_identifier]; - NSArray *bgModes = appInfo.UIBackgroundModes; +- (NSArray*)customSpecifiers { + LSApplicationProxy *appInfo = [%c(LSApplicationProxy) applicationProxyForIdentifier:_identifier]; + NSArray *bgModes = appInfo.UIBackgroundModes; + + BOOL exitsOnSuspend = [[NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]]][@"UIApplicationExitsOnSuspend"] boolValue]; - BOOL exitsOnSuspend = [[NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]]][@"UIApplicationExitsOnSuspend"] boolValue]; + BOOL preventDeath = [[self getActualPrefValue:@"preventDeath"] boolValue]; // Default is NO so it should work fine - BOOL preventDeath = [[self getActualPrefValue:@"preventDeath"] boolValue]; // Default is NO so it should work fine + return @[ + @{ + @"cell": @"PSSwitchCell", + @"label": @"Enabled", + @"key": @"enabled", + @"default": @NO, + }, - return @[ - @{ - @"cell": @"PSSwitchCell", - @"label": @"Enabled", - @"key": @"enabled", - @"default": @NO, - }, + @{ @"label": @""}, + @{ + @"cell": @"PSLinkListCell", + @"label": @"Background Mode", + @"key": @"backgroundMode", + @"validTitles": @[ @"Native", @"Unlimited Backgrounding Time", @"Force Foreground", @"Kill on Exit", @"Suspend Immediately" ], + @"validValues": @[ @(RABackgroundModeNative), @(RABackgroundModeUnlimitedBackgroundingTime), @(RABackgroundModeForcedForeground), @(RABackgroundModeForceNone), @(RABackgroundModeSuspendImmediately)], + @"shortTitles": @[ @"Native", @"∞", @"Forced", @"Disabled", @"SmartClose" ], + @"default": @(RABackgroundModeNative), + @"detail": @"RABackgroundingListItemsController" + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Auto Launch (On Boot)", + @"key": @"autoLaunch", + @"default": @NO, + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Auto Relaunch", + @"key": @"autoRelaunch", + @"default": @NO, + }, - @{ @"label": @""}, - @{ - @"cell": @"PSLinkListCell", - @"label": @"Background Mode", - @"key": @"backgroundMode", - @"validTitles": @[ @"Native", @"Unlimited Backgrounding Time", @"Force Foreground", @"Kill on Exit", @"Suspend Immediately" ], - @"validValues": @[ @(RABackgroundModeNative), @(RABackgroundModeUnlimitedBackgroundingTime), @(RABackgroundModeForcedForeground), @(RABackgroundModeForceNone), @(RABackgroundModeSuspendImmediately)], - @"shortTitles": @[ @"Native", @"∞", @"Forced", @"Disabled", @"SmartClose" ], - @"default": @(RABackgroundModeNative), - @"detail": @"RABackgroundingListItemsController" - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Auto Launch", - @"key": @"autoLaunch", - @"default": @NO, - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Auto Relaunch", - @"key": @"autoRelaunch", - @"default": @NO, - }, - - @{ @"footerText": @"If the app's background mode is Disabled, this will remove the app from the switcher in addition to killing it." }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Remove from Switcher", - @"key": @"removeFromSwitcher", - @"default": @NO, - }, + @{ @"footerText": @"If the app's background mode is Disabled, this will remove the app from the switcher in addition to killing it." }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Remove from Switcher", + @"key": @"removeFromSwitcher", + @"default": @NO, + }, - @{ @"footerText": @"This will prevent most cases of the app being terminated (app switcher, low memory, etc). Please note that if you enable this option, and your system runs low on memory or some other situation, it may yield unpredictable results. Enabling both this and \"Exit on Suspend\" (see below) will cause this switch to have no effect." }, - @{ - @"cell": @"PSSwitchCell", - @"key": @"preventDeath", - @"default": @NO, - @"label": @"Prevent Death", - @"enabled": @(!exitsOnSuspend), - @"reloadSpecifiersXX": @YES, - }, - @{ @"footerText": @"This switch causes applications to completely disable their backgrounding, natively. Apps such as BatteryLife, FinalFantasy2, and a certain Solitaire do this. This switch will not revert upon the uninstallation of Multiplexer because it actually writes to the app's data. A respring may be required to apply." }, - @{ - @"cell": @"PSSwitchCell", - @"key": @"UIApplicationExitsOnSuspend", - @"default": @(exitsOnSuspend), - @"label": @"Exit on Suspend", - @"enabled": @(!preventDeath), - @"reloadSpecifiersXX": @YES, - }, - @{ - @"cell": @"PSGroupCell", - @"label": @"Native Backgrounding Modes", - @"footerText": @"A respring is required to apply changes to these values. Just because a mode has been enabled does not necessarily mean it will be used by the app.", - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Unbounded Task Completion", - @"key": kBGModeUnboundedTaskCompletion, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeUnboundedTaskCompletion withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Continuous", - @"key": kBGModeContinuous, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeContinuous withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Fetch", - @"key": kBGModeFetch, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeFetch withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Remote Notification", - @"key": kBGModeRemoteNotification, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeRemoteNotification withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"External Accessory", - @"key": kBGModeExternalAccessory, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeExternalAccessory withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"VoIP", - @"key": kBGModeVoIP, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeVoIP withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Location", - @"key": kBGModeLocation, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeLocation withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Audio", - @"key": kBGModeAudio, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeAudio withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Bluetooth (Central)", - @"key": kBGModeBluetoothCentral, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeBluetoothCentral withAppInfo:bgModes], - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Bluetooth (Peripheral)", - @"key": kBGModeBluetoothPeripheral, - @"prefix": @"backgroundmodes", - @"default": [self isBackgroundModeActive:kBGModeBluetoothPeripheral withAppInfo:bgModes], - }, + @{ @"footerText": @"This will prevent most cases of the app being terminated (app switcher, low memory, etc). Please note that if you enable this option, and your system runs low on memory or some other situation, it may yield unpredictable results. Enabling both this and \"Exit on Suspend\" (see below) will cause this switch to have no effect." }, + @{ + @"cell": @"PSSwitchCell", + @"key": @"preventDeath", + @"default": @NO, + @"label": @"Prevent Death", + @"enabled": @(!exitsOnSuspend), + @"reloadSpecifiersXX": @YES, + }, + @{ @"footerText": @"This switch causes applications to completely disable their backgrounding, natively. Apps such as BatteryLife, FinalFantasy2, and a certain Solitaire do this. This switch will not revert upon the uninstallation of Multiplexer because it actually writes to the app's data. A respring may be required to apply." }, + @{ + @"cell": @"PSSwitchCell", + @"key": @"UIApplicationExitsOnSuspend", + @"default": @(exitsOnSuspend), + @"label": @"Exit on Suspend", + @"enabled": @(!preventDeath), + @"reloadSpecifiersXX": @YES, + }, + @{ + @"cell": @"PSGroupCell", + @"label": @"Native Backgrounding Modes", + @"footerText": @"A respring is required to apply changes to these values. Just because a mode has been enabled does not necessarily mean it will be used by the app.", + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Unbounded Task Completion", + @"key": kBKSBackgroundModeUnboundedTaskCompletion, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeUnboundedTaskCompletion withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Continuous", + @"key": kBKSBackgroundModeContinuous, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeContinuous withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Fetch", + @"key": kBKSBackgroundModeFetch, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeFetch withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Remote Notification", + @"key": kBKSBackgroundModeRemoteNotification, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeRemoteNotification withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"External Accessory", + @"key": kBKSBackgroundModeExternalAccessory, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeExternalAccessory withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"VoIP", + @"key": kBKSBackgroundModeVoIP, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeVoIP withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Location", + @"key": kBKSBackgroundModeLocation, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeLocation withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Audio", + @"key": kBKSBackgroundModeAudio, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeAudio withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Bluetooth (Central)", + @"key": kBKSBackgroundModeBluetoothCentral, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeBluetoothCentral withAppInfo:bgModes], + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Bluetooth (Peripheral)", + @"key": kBKSBackgroundModeBluetoothPeripheral, + @"prefix": @"backgroundmodes", + @"default": [self isBackgroundModeActive:kBKSBackgroundModeBluetoothPeripheral withAppInfo:bgModes], + }, - @{ @"footerText": @"Description of icon letters: \n\ -N - Native\n\ -∞ - Unlimited Backgrounding Time\n\ -F - Force Foreground\n" -//D - Kill on Exit\n\ -"ll - Suspend Immediately\n\ -U - Unkillable\n\ -\n\ -The status bar icon is simply the app icon.", }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show Icon Indicators", - @"key": @"showIndicatorOnIcon", - @"default": @YES, - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show in Status Bar", - @"key": @"showStatusBarIcon", - @"default": @YES, - }, - ]; + @{ @"footerText": @"Description of icon letters: \n\ + N - Native\n\ + ∞ - Unlimited Backgrounding Time\n\ + F - Force Foreground\n" + //D - Kill on Exit\n\ + "ll - Suspend Immediately\n\ + U - Unkillable\n\ + \n\ + The status bar icon is simply the app icon.", }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show Icon Indicators", + @"key": @"showIndicatorOnIcon", + @"default": @YES, + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show in Status Bar", + @"key": @"showStatusBarIcon", + @"default": @YES, + }, + ]; } --(void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier -{ - //[super setPreferenceValue:value specifier:specifier]; +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { + //[super setPreferenceValue:value specifier:specifier]; - if ([[specifier propertyForKey:@"key"] isEqualToString:@"UIApplicationExitsOnSuspend"]) - { - LSApplicationProxy *appInfo = [%c(LSApplicationProxy) applicationProxyForIdentifier:_identifier]; - NSString *path = [NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]; - NSMutableDictionary *infoPlist = [NSMutableDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:path]]; - infoPlist[@"UIApplicationExitsOnSuspend"] = value; - BOOL success = [infoPlist writeToURL:[NSURL URLWithString:path] atomically:YES]; + if ([[specifier propertyForKey:@"key"] isEqualToString:@"UIApplicationExitsOnSuspend"]) { + LSApplicationProxy *appInfo = [%c(LSApplicationProxy) applicationProxyForIdentifier:_identifier]; + NSString *path = [NSString stringWithFormat:@"%@/Info.plist",appInfo.bundleURL.absoluteString]; + NSMutableDictionary *infoPlist = [NSMutableDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:path]]; + infoPlist[@"UIApplicationExitsOnSuspend"] = value; + BOOL success = [infoPlist writeToURL:[NSURL URLWithString:path] atomically:YES]; - if (!success) - { - NSMutableDictionary *daemonDict = [NSMutableDictionary dictionary]; - daemonDict[@"bundleIdentifier"] = _identifier; - daemonDict[@"UIApplicationExitsOnSuspend"] = value; - [daemonDict writeToFile:@"/var/mobile/Library/.reachapp.uiappexitsonsuspend.wantstochangerootapp" atomically:YES]; - } + if (!success) { + NSMutableDictionary *daemonDict = [NSMutableDictionary dictionary]; + daemonDict[@"bundleIdentifier"] = _identifier; + daemonDict[@"UIApplicationExitsOnSuspend"] = value; + [daemonDict writeToFile:@"/var/mobile/Library/.reachapp.uiappexitsonsuspend.wantstochangerootapp" atomically:YES]; + } - if ([[specifier propertyForKey:@"reloadSpecifiers"] boolValue]) - [self reloadSpecifiers]; + if ([[specifier propertyForKey:@"reloadSpecifiers"] boolValue]) { + [self reloadSpecifiers]; + } - return; - } + return; + } CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - NSString *key = [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,[specifier propertyForKey:@"key"]]; - if ([specifier propertyForKey:@"prefix"]) - key = [NSString stringWithFormat:@"backgrounder-%@-%@-%@",_identifier,[specifier propertyForKey:@"prefix"],[specifier propertyForKey:@"key"]]; - CFPreferencesSetAppValue((__bridge CFStringRef)key, (const void*)value, appID); + NSString *key = [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,[specifier propertyForKey:@"key"]]; + if ([specifier propertyForKey:@"prefix"]) { + key = [NSString stringWithFormat:@"backgrounder-%@-%@-%@",_identifier,[specifier propertyForKey:@"prefix"],[specifier propertyForKey:@"key"]]; + } + CFPreferencesSetAppValue((__bridge CFStringRef)key, (const void*)value, appID); - CFPreferencesAppSynchronize(appID); - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); - RA_BGAppsControllerNeedsToReload(); + CFPreferencesAppSynchronize(appID); + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); + RA_BGAppsControllerNeedsToReload(); - if ([[specifier propertyForKey:@"reloadSpecifiers"] boolValue]) - [self reloadSpecifiers]; + if ([[specifier propertyForKey:@"reloadSpecifiers"] boolValue]) { + [self reloadSpecifiers]; + } } --(id) getActualPrefValue:(NSString*)basename -{ - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - NSString *key = [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,basename]; +- (id)getActualPrefValue:(NSString*)basename { + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + NSString *key = [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,basename]; - CFPropertyListRef value = CFPreferencesCopyValue((__bridge CFStringRef)key, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFPropertyListRef value = CFPreferencesCopyValue((__bridge CFStringRef)key, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - return (__bridge id)value; + return (__bridge id)value; } --(id)readPreferenceValue:(PSSpecifier*)specifier -{ - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!keyList) { - return [specifier propertyForKey:@"default"]; - } - NSDictionary *_settings = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - CFRelease(keyList); - if (!_settings) { - return [specifier propertyForKey:@"default"]; - } +- (id)readPreferenceValue:(PSSpecifier*)specifier { + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!keyList) { + return [specifier propertyForKey:@"default"]; + } + NSDictionary *_settings = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFRelease(keyList); + if (!_settings) { + return [specifier propertyForKey:@"default"]; + } - NSString *key = [specifier propertyForKey:@"prefix"] ? [NSString stringWithFormat:@"backgrounder-%@-%@-%@",_identifier,[specifier propertyForKey:@"prefix"],[specifier propertyForKey:@"key"]] : [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,[specifier propertyForKey:@"key"]]; - return [_settings objectForKey:key] == nil ? [specifier propertyForKey:@"default"] : _settings[key]; + NSString *key = [specifier propertyForKey:@"prefix"] ? [NSString stringWithFormat:@"backgrounder-%@-%@-%@",_identifier,[specifier propertyForKey:@"prefix"],[specifier propertyForKey:@"key"]] : [NSString stringWithFormat:@"backgrounder-%@-%@",_identifier,[specifier propertyForKey:@"key"]]; + return ![_settings objectForKey:key] ? [specifier propertyForKey:@"default"] : _settings[key]; } -@end \ No newline at end of file +@end diff --git a/reachappsettings/BackgrounderPerApp.xm b/reachappsettings/BackgrounderPerApp.xm index 3e1ffb6..8b3e8be 100644 --- a/reachappsettings/BackgrounderPerApp.xm +++ b/reachappsettings/BackgrounderPerApp.xm @@ -1,14 +1,17 @@ -#import +#import +#import +#import +#import #import -#import +#import #import #import #import "BackgroundPerAppDetailsController.h" @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -19,28 +22,27 @@ @end @implementation ALLinkCell --(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - if (!(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil; - self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } return self; } @end @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end BOOL reload = NO; -void RA_BGAppsControllerNeedsToReload() -{ - reload = YES; +void RA_BGAppsControllerNeedsToReload() { + reload = YES; } -@interface RABGPerAppController : PSViewController -{ +@interface RABGPerAppController : PSViewController { UITableView* _tableView; ALApplicationTableDataSource* _dataSource; } @@ -48,148 +50,134 @@ void RA_BGAppsControllerNeedsToReload() @implementation RABGPerAppController --(void)updateDataSource:(NSString*)searchText -{ +- (void)updateDataSource:(NSString*)searchText { NSNumber *iconSize = [NSNumber numberWithUnsignedInteger:ALApplicationIconSizeSmall]; - + NSString *enabledList = @""; - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (keyList) - { - NSDictionary *prefs = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - CFRelease(keyList); - if (prefs) - { - NSArray *apps = [[ALApplicationList sharedApplicationList] applications].allKeys; - for (NSString* identifier in apps) - { - if ([prefs[[NSString stringWithFormat:@"backgrounder-%@-enabled",identifier]] boolValue]) - { - enabledList = [enabledList stringByAppendingString:[NSString stringWithFormat:@"'%@',", identifier]]; - } - } - } - } - enabledList = [enabledList stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (keyList) { + NSDictionary *prefs = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFRelease(keyList); + if (prefs) { + NSArray *apps = [[ALApplicationList sharedApplicationList] applications].allKeys; + for (NSString* identifier in apps) { + if ([prefs[[NSString stringWithFormat:@"backgrounder-%@-enabled",identifier]] boolValue]) { + enabledList = [enabledList stringByAppendingString:[NSString stringWithFormat:@"'%@',", identifier]]; + } + } + } + } + enabledList = [enabledList stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; NSString* filter = (searchText && searchText.length > 0) ? [NSString stringWithFormat:@"displayName beginsWith[cd] '%@'", searchText] : nil; - - if (filter) - { + + if (filter) { _dataSource.sectionDescriptors = [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - @"Search Results", ALSectionDescriptorTitleKey, - @"ALLinkCell", ALSectionDescriptorCellClassNameKey, - iconSize, ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - filter, ALSectionDescriptorPredicateKey - , nil] - , nil]; - } - else - { - if ([enabledList isEqual:@""]) - { - _dataSource.sectionDescriptors = [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - @"", ALSectionDescriptorTitleKey, - @"ALLinkCell", ALSectionDescriptorCellClassNameKey, - iconSize, ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - [NSString stringWithFormat:@"not bundleIdentifier in {%@}", enabledList], - ALSectionDescriptorPredicateKey - , nil], - nil]; - } - else - { - _dataSource.sectionDescriptors = [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - @"Enabled Applications", ALSectionDescriptorTitleKey, - @"ALLinkCell", ALSectionDescriptorCellClassNameKey, - iconSize, ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - [NSString stringWithFormat:@"bundleIdentifier in {%@}", enabledList], - ALSectionDescriptorPredicateKey - , nil], - [NSDictionary dictionaryWithObjectsAndKeys: - @"Other Applications", ALSectionDescriptorTitleKey, - @"ALLinkCell", ALSectionDescriptorCellClassNameKey, - iconSize, ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - [NSString stringWithFormat:@"not bundleIdentifier in {%@}", enabledList], - ALSectionDescriptorPredicateKey - , nil], - nil]; - } + [NSDictionary dictionaryWithObjectsAndKeys: + @"Search Results", ALSectionDescriptorTitleKey, + @"ALLinkCell", ALSectionDescriptorCellClassNameKey, + iconSize, ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + filter, ALSectionDescriptorPredicateKey + , nil] + , nil]; + } else { + if ([enabledList isEqual:@""]) { + _dataSource.sectionDescriptors = [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"", ALSectionDescriptorTitleKey, + @"ALLinkCell", ALSectionDescriptorCellClassNameKey, + iconSize, ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + [NSString stringWithFormat:@"not bundleIdentifier in {%@}", enabledList], + ALSectionDescriptorPredicateKey + , nil], + nil]; + } else { + _dataSource.sectionDescriptors = [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"Enabled Applications", ALSectionDescriptorTitleKey, + @"ALLinkCell", ALSectionDescriptorCellClassNameKey, + iconSize, ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + [NSString stringWithFormat:@"bundleIdentifier in {%@}", enabledList], + ALSectionDescriptorPredicateKey + , nil], + [NSDictionary dictionaryWithObjectsAndKeys: + @"Other Applications", ALSectionDescriptorTitleKey, + @"ALLinkCell", ALSectionDescriptorCellClassNameKey, + iconSize, ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + [NSString stringWithFormat:@"not bundleIdentifier in {%@}", enabledList], + ALSectionDescriptorPredicateKey + , nil], + nil]; + } } - [_tableView reloadData]; + [_tableView reloadData]; } --(id)init -{ - if (!(self = [super init])) return nil; - - CGRect bounds = [[UIScreen mainScreen] bounds]; - - _dataSource = [[ALApplicationTableDataSource alloc] init]; - - _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height) style:UITableViewStyleGrouped]; - _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _tableView.delegate = self; - _tableView.dataSource = _dataSource; - _dataSource.tableView = _tableView; - [self updateDataSource:nil]; - +- (instancetype)init { + self = [super init]; + if (self) { + CGRect bounds = [[UIScreen mainScreen] bounds]; + + _dataSource = [[ALApplicationTableDataSource alloc] init]; + + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height) style:UITableViewStyleGrouped]; + _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _tableView.delegate = self; + _tableView.dataSource = _dataSource; + _dataSource.tableView = _tableView; + [self updateDataSource:nil]; + } return self; } --(void)viewDidLoad -{ +- (void)viewDidLoad { ((UIViewController *)self).title = @"Applications"; - + [self.view addSubview:_tableView]; - + [super viewDidLoad]; } --(void) viewWillAppear:(BOOL) animated -{ - if (reload) - { - [self updateDataSource:nil]; - reload = NO; - } - - ((UIView*)self.view).tintColor = self.tintColor; - self.navigationController.navigationBar.tintColor = self.tintColor; - - [super viewWillAppear:animated]; +- (void)viewWillAppear:(BOOL)animated { + if (reload) { + [self updateDataSource:nil]; + reload = NO; + } + + ((UIView*)self.view).tintColor = self.tintColor; + self.navigationController.navigationBar.tintColor = self.tintColor; + + [super viewWillAppear:animated]; } --(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath -{ +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath]; - + // Need to mimic what PSListController does when it handles didSelectRowAtIndexPath // otherwise the child controller won't load RABGPerAppDetailsController *controller = [[RABGPerAppDetailsController alloc] initWithAppName:cell.textLabel.text identifier:[_dataSource displayIdentifierForIndexPath:indexPath]]; controller.rootController = self.rootController; controller.parentController = self; - + [self pushController:controller]; [tableView deselectRowAtIndexPath:indexPath animated:true]; } --(UIColor*) tintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } +- (UIColor*)tintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} - (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - ((UIView*)self.view).tintColor = nil; - self.navigationController.navigationBar.tintColor = nil; + [super viewWillDisappear:animated]; + + ((UIView*)self.view).tintColor = nil; + self.navigationController.navigationBar.tintColor = nil; } -@end \ No newline at end of file +@end diff --git a/reachappsettings/BackgrounderSettings.xm b/reachappsettings/BackgrounderSettings.xm index 758f6ee..ecf8fb4 100644 --- a/reachappsettings/BackgrounderSettings.xm +++ b/reachappsettings/BackgrounderSettings.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -14,15 +17,15 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -33,169 +36,184 @@ @end @implementation ReachAppBackgrounderSettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:255/255.0f green:111/255.0f blue:124/255.0f alpha:1.0f].CGColor - ]; - header.shouldBlend = NO; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/BackgrounderHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(15, 33)]]; - - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; - [notHeader addSubview:header]; - - return notHeader; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:255/255.0f green:111/255.0f blue:124/255.0f alpha:1.0f].CGColor + ]; + header.shouldBlend = NO; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/BackgrounderHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(15, 33)]]; + + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; + [notHeader addSubview:header]; + + return notHeader; } --(UIColor*) tintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } +- (UIColor*)tintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; +} --(NSString*) customTitle { return @"Aura"; } --(BOOL) showHeartImage { return NO; } +- (NSString*)customTitle { + return @"Aura"; +} --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; +- (BOOL)showHeartImage { + return NO; } --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"Quickly enable or disable Aura. Relaunch apps to apply changes." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"backgrounderEnabled", - @"label": @"Enabled", - }, - - @{ @"label": @"Activator", - @"footerText": @"If enabled, the current app will be closed after performing the activation method.", - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"showActivatorAction", - @"label": @"Activation Method", - //@"enabled": objc_getClass("LAEventSettingsController") != nil, - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Exit App After Menu", - @"default": @YES, - @"key": @"exitAppAfterUsingActivatorAction", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"label": @"Global", @"footerText": @"" }, - - @{ - @"cell": @"PSLinkListCell", - @"label": @"Background Mode", - @"key": @"globalBackgroundMode", - @"validTitles": @[ @"Native", @"Unlimited Backgrounding Time", @"Force Foreground", @"Kill on Exit", @"Suspend Immediately" ], - @"validValues": @[ @(RABackgroundModeNative), @(RABackgroundModeUnlimitedBackgroundingTime), @(RABackgroundModeForcedForeground), @(RABackgroundModeForceNone), @(RABackgroundModeSuspendImmediately)], - @"shortTitles": @[ @"Native", @"∞", @"Forced", @"Disabled", @"SmartClose" ], - @"default": @(RABackgroundModeNative), - @"detail": @"RABackgroundingListItemsController", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - @"staticTextMessage": @"Does not apply to apps enabled with differing options in the “Per App” section." - }, - @{ - @"cell": @"PSLinkListCell", - @"detail": @"RABackgrounderIconIndicatorOptionsListController", - @"label": @"Icon Indicator Options", - }, - @{ - @"cell": @"PSLinkListCell", - @"detail": @"RABackgrounderStatusbarOptionsListController", - @"label": @"Status Bar Indicator Options", - }, - @{ @"label": @"Specific" }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Per App", - @"detail": @"RABGPerAppController", - }, - ]; +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; } --(void) showActivatorAction -{ - id activator = objc_getClass("LAListenerSettingsViewController"); - if (!activator) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - } - else - { - LAListenerSettingsViewController *vc = [[objc_getClass("LAListenerSettingsViewController") alloc] init]; - vc.listenerName = @"com.efrederickson.reachapp.backgrounder.togglemode"; - [self.rootController pushViewController:vc animated:YES]; - } +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"Quickly enable or disable Aura. Relaunch apps to apply changes." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"backgrounderEnabled", + @"label": @"Enabled", + }, + + @{ @"label": @"Activator", + @"footerText": @"If enabled, the current app will be closed after performing the activation method.", + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"showActivatorAction", + @"label": @"Activation Method", + //@"enabled": objc_getClass("LAEventSettingsController") != nil, + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Exit App After Menu", + @"default": @YES, + @"key": @"exitAppAfterUsingActivatorAction", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"label": @"Global", @"footerText": @"" }, + + @{ + @"cell": @"PSLinkListCell", + @"label": @"Background Mode", + @"key": @"globalBackgroundMode", + @"validTitles": @[ @"Native", @"Unlimited Backgrounding Time", @"Force Foreground", @"Kill on Exit", @"Suspend Immediately" ], + @"validValues": @[ @(RABackgroundModeNative), @(RABackgroundModeUnlimitedBackgroundingTime), @(RABackgroundModeForcedForeground), @(RABackgroundModeForceNone), @(RABackgroundModeSuspendImmediately)], + @"shortTitles": @[ @"Native", @"∞", @"Forced", @"Disabled", @"SmartClose" ], + @"default": @(RABackgroundModeNative), + @"detail": @"RABackgroundingListItemsController", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + @"staticTextMessage": @"Does not apply to apps enabled with differing options in the “Per App” section." + }, + @{ + @"cell": @"PSLinkListCell", + @"detail": @"RABackgrounderIconIndicatorOptionsListController", + @"label": @"Icon Indicator Options", + }, + @{ + @"cell": @"PSLinkListCell", + @"detail": @"RABackgrounderStatusbarOptionsListController", + @"label": @"Status Bar Indicator Options", + }, + @{ @"label": @"Specific" }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Per App", + @"detail": @"RABGPerAppController", + }, + ]; +} + +- (void)showActivatorAction { + id activator = %c(LAListenerSettingsViewController); + if (!activator) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + } else { + LAListenerSettingsViewController *vc = [[%c(LAListenerSettingsViewController) alloc] init]; + vc.listenerName = @"com.efrederickson.reachapp.backgrounder.togglemode"; + [self.rootController pushController:vc animate:YES]; + } } @end -@interface RABackgrounderIconIndicatorOptionsListController : SKTintedListController +@interface RABackgrounderIconIndicatorOptionsListController : SKTintedListController @end @implementation RABackgrounderIconIndicatorOptionsListController --(UIColor*) navigationTintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } --(BOOL) showHeartImage { return NO; } --(NSArray*) customSpecifiers -{ - return @[ - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show Icon Indicators", - @"default": @YES, - @"key": @"showIconIndicators", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show Native Mode Indicators", - @"default": @NO, - @"key": @"showNativeStateIconIndicators", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - ]; +- (UIColor*)navigationTintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} + +- (BOOL)showHeartImage { + return NO; +} + +- (NSArray*)customSpecifiers { + return @[ + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show Icon Indicators", + @"default": @YES, + @"key": @"showIconIndicators", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show Native Mode Indicators", + @"default": @NO, + @"key": @"showNativeStateIconIndicators", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + ]; } @end -@interface RABackgrounderStatusbarOptionsListController : SKTintedListController +@interface RABackgrounderStatusbarOptionsListController : SKTintedListController @end @implementation RABackgrounderStatusbarOptionsListController --(UIColor*) navigationTintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } --(BOOL) showHeartImage { return NO; } --(NSArray*) customSpecifiers -{ - return @[ - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show on Status Bar", - @"default": @YES, - @"key": @"shouldShowStatusBarIcons", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"label": @"Show Native in Status Bar", - @"default": @NO, - @"key": @"shouldShowStatusBarNativeIcons", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - ]; +- (UIColor*)navigationTintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} + +- (BOOL)showHeartImage { + return NO; +} + +- (NSArray*)customSpecifiers { + return @[ + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show on Status Bar", + @"default": @YES, + @"key": @"shouldShowStatusBarIcons", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"label": @"Show Native in Status Bar", + @"default": @NO, + @"key": @"shouldShowStatusBarNativeIcons", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + ]; } @end diff --git a/reachappsettings/Makefile b/reachappsettings/Makefile index de71efd..af7cc72 100644 --- a/reachappsettings/Makefile +++ b/reachappsettings/Makefile @@ -1,13 +1,12 @@ ARCHS = armv7 armv7s arm64 -TARGET = iPhone:clang:latest:latest -CFLAGS = -fobjc-arc -I../ -I../Backgrounding/ -I../Theming/ -I../NotificationCenterApp +TARGET = iphone:9.2 +CFLAGS = -fobjc-arc -I../ -I../Backgrounding/ -I../Theming/ -I../NotificationCenterApp -Wno-deprecated-declarations -O2 LDFLAGS = -F$(THEOS)/frameworks -LDFLAGS += -Wl,-segalign,4000 include $(THEOS)/makefiles/common.mk BUNDLE_NAME = ReachAppSettings -ReachAppSettings_FILES = ReachAppSettings.mm $(shell find $(THEOS)/include/SettingsKit -name '*.m') $(wildcard *.xm) RAHeaderView.mm ../PDFImageOptions.m ../PDFImage.m ../RALocalizer.mm ../RASettings.mm $(wildcard ../Theming/*.mm) +ReachAppSettings_FILES = ReachAppSettings.mm $(shell find $(THEOS)/include/SettingsKit -name '*.m') $(wildcard *.xm) RAHeaderView.mm ../PDFImageOptions.m ../PDFImage.m ../RALocalizer.mm ../RASettings.mm $(wildcard ../Theming/*.mm) ReachAppSettings_INSTALL_PATH = /Library/PreferenceBundles ReachAppSettings_FRAMEWORKS = UIKit MessageUI Social QuartzCore CoreGraphics ReachAppSettings_LIBRARIES = applist substrate diff --git a/reachappsettings/MissionControlSettings.xm b/reachappsettings/MissionControlSettings.xm index 2a03fb4..8ae442e 100644 --- a/reachappsettings/MissionControlSettings.xm +++ b/reachappsettings/MissionControlSettings.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -12,15 +15,15 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -31,34 +34,43 @@ @end @implementation ReachAppMCSettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:255/255.0f green:205/255.0f blue:2/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:255/255.0f green:227/255.0f blue:113/255.0f alpha:1.0f].CGColor, - ]; - header.shouldBlend = NO; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/MissionControlHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(32, 32)]]; - - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; - [notHeader addSubview:header]; - - return notHeader; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:255/255.0f green:205/255.0f blue:2/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:255/255.0f green:227/255.0f blue:113/255.0f alpha:1.0f].CGColor, + ]; + header.shouldBlend = NO; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/MissionControlHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(32, 32)]]; + + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; + [notHeader addSubview:header]; + + return notHeader; +} + +- (UIColor*)tintColor { + return [UIColor colorWithRed:255/255.0f green:205/255.0f blue:2/255.0f alpha:1.0f]; } --(UIColor*) tintColor { return [UIColor colorWithRed:255/255.0f green:205/255.0f blue:2/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } --(NSString*) customTitle { return @"Mission Control"; } --(BOOL) showHeartImage { return NO; } - --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; +} + +- (NSString*)customTitle { + return @"Mission Control"; } --(NSArray*) customSpecifiers -{ +- (BOOL)showHeartImage { + return NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; +} + +- (NSArray*)customSpecifiers { return @[ @{ @"footerText": @"Quickly enable or disable Mission Control." }, @{ @@ -70,7 +82,7 @@ @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", }, - @{ @"footerText": @"If enabled the App Switcher will be replaced with the Mission Control view."}, + @{ @"footerText": @"If enabled the App Switcher will be replaced with the Mission Control view."}, @{ @"cell": @"PSSwitchCell", @"default": @NO, @@ -117,19 +129,18 @@ }, ]; } --(void) showActivatorAction -{ - id activator = objc_getClass("LAListenerSettingsViewController"); - if (!activator) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - } - else - { - LAListenerSettingsViewController *vc = [[objc_getClass("LAListenerSettingsViewController") alloc] init]; - vc.listenerName = @"com.efrederickson.reachapp.missioncontrol.activatorlistener"; - [self.rootController pushViewController:vc animated:YES]; - } + +- (void)showActivatorAction { + id activator = %c(LAListenerSettingsViewController); + if (!activator) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + } else { + LAListenerSettingsViewController *vc = [[%c(LAListenerSettingsViewController) alloc] init]; + vc.listenerName = @"com.efrederickson.reachapp.missioncontrol.activatorlistener"; + [self.rootController pushController:vc animate:YES]; + } } -@end \ No newline at end of file +@end diff --git a/reachappsettings/NCApp.xm b/reachappsettings/NCApp.xm index 5a6629a..574e310 100644 --- a/reachappsettings/NCApp.xm +++ b/reachappsettings/NCApp.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -11,97 +14,104 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) - (void)sectionRequestedSectionReload:(id)section animated:(BOOL)animated; @end -@interface ReachAppNCAppSettingsListController: SKTintedListController +@interface ReachAppNCAppSettingsListController: SKTintedListController @end @implementation ReachAppNCAppSettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:90/255.0f green:212/255.0f blue:39/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:164/255.0f green:231/255.0f blue:134/255.0f alpha:1.0f].CGColor, - ]; - header.shouldBlend = NO; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/NCAppHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(53, 32)]]; - - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 70)]; - [notHeader addSubview:header]; - - return notHeader; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:90/255.0f green:212/255.0f blue:39/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:164/255.0f green:231/255.0f blue:134/255.0f alpha:1.0f].CGColor, + ]; + header.shouldBlend = NO; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/NCAppHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(53, 32)]]; + + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 70)]; + [notHeader addSubview:header]; + + return notHeader; } --(UIColor*) tintColor { return [UIColor colorWithRed:90/255.0f green:212/255.0f blue:39/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } --(NSString*) customTitle { return @"Quick Access"; } --(BOOL) showHeartImage { return NO; } +- (UIColor*)tintColor { + return [UIColor colorWithRed:90/255.0f green:212/255.0f blue:39/255.0f alpha:1.0f]; +} + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; +} + +- (NSString*)customTitle { + return @"Quick Access"; +} + +- (BOOL)showHeartImage { + return NO; +} --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; } --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"Quickly enable or disable Quick Access." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"ncAppEnabled", - @"label": @"Enabled", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ @"footerText": @"Instead of using the app's name, the tab label will simply show \"App\"." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"quickAccessUseGenericTabLabel", - @"label": @"Use Generic Tab Label", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ @"footerText": @"Instead of displaying a label, this will completely hide the Quick Access tab on the Lock Screen." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"ncAppHideOnLS", - @"label": @"Hide on Lock Screen", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ }, - @{ - @"cell": @"PSLinkListCell", - @"detail": @"RANCAppSelectorView", - @"label": @"Selected App", - }, - ]; +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"Quickly enable or disable Quick Access." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"ncAppEnabled", + @"label": @"Enabled", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ @"footerText": @"Instead of using the app's name, the tab label will simply show \"App\". Only Works on iOS 9 and below" }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"quickAccessUseGenericTabLabel", + @"label": @"Use Generic Tab Label", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ @"footerText": @"Instead of displaying a label, this will completely hide the Quick Access tab on the Lock Screen." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"ncAppHideOnLS", + @"label": @"Hide on Lock Screen", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ }, + @{ + @"cell": @"PSLinkListCell", + @"detail": @"RANCAppSelectorView", + @"label": @"Selected App", + }, + ]; } @end -@interface RANCAppSelectorView : PSViewController -{ - UITableView* _tableView; - ALApplicationTableDataSource* _dataSource; +@interface RANCAppSelectorView : PSViewController { + UITableView* _tableView; + ALApplicationTableDataSource* _dataSource; } @end @@ -114,106 +124,100 @@ @end @implementation RANCApplicationTableDataSource -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - //NSInteger row = indexPath.row; - UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; - - NSDictionary *prefs = nil; - - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!keyList) { - return cell; - } - prefs = (__bridge NSDictionary*)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!prefs) { - return cell; - } - CFRelease(keyList); - - if ([cell isKindOfClass:[ALCheckCell class]]) - { - NSString *dn = [self displayIdentifierForIndexPath:indexPath]; - NSString *key = @"NCApp";// [NSString stringWithFormat:@"NCApp-%@",dn]; - //BOOL value = [prefs[key] boolValue]; - BOOL value = [dn isEqualToString:prefs[key] ?: @"com.apple.Preferences"]; - [(ALCheckCell*)cell loadValue:@(value)]; - } +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + //NSInteger row = indexPath.row; + UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; + + NSDictionary *prefs = nil; + + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!keyList) { + return cell; + } + prefs = (__bridge NSDictionary*)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!prefs) { return cell; + } + CFRelease(keyList); + + if ([cell isKindOfClass:[ALCheckCell class]]) { + NSString *dn = [self displayIdentifierForIndexPath:indexPath]; + NSString *key = @"NCApp";// [NSString stringWithFormat:@"NCApp-%@",dn]; + //BOOL value = [prefs[key] boolValue]; + BOOL value = [dn isEqualToString:prefs[key] ?: @"com.apple.Preferences"]; + [(ALCheckCell*)cell loadValue:@(value)]; + } + return cell; } @end @implementation RANCAppSelectorView --(void)updateDataSource:(NSString*)searchText -{ - _dataSource.sectionDescriptors = [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - @"", ALSectionDescriptorTitleKey, - @"ALCheckCell", ALSectionDescriptorCellClassNameKey, - @(29), ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - [NSString stringWithFormat:@"not bundleIdentifier in { }"],ALSectionDescriptorPredicateKey, - @YES,@"ALSingleEnabledMode" - , nil], - nil]; - [_tableView reloadData]; +- (void)updateDataSource:(NSString*)searchText { + _dataSource.sectionDescriptors = [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"", ALSectionDescriptorTitleKey, + @"ALCheckCell", ALSectionDescriptorCellClassNameKey, + @(29), ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + [NSString stringWithFormat:@"not bundleIdentifier in { }"],ALSectionDescriptorPredicateKey, + @YES,@"ALSingleEnabledMode" + , nil], + nil]; + [_tableView reloadData]; } --(id)init -{ - if (!(self = [super init])) return nil; - +- (instancetype)init { + self = [super init]; + if (self) { CGRect bounds = [[UIScreen mainScreen] bounds]; - + _dataSource = [[RANCApplicationTableDataSource alloc] init]; - + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height) style:UITableViewStyleGrouped]; _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _tableView.delegate = self; _tableView.dataSource = _dataSource; _dataSource.tableView = _tableView; [self updateDataSource:nil]; - - return self; + } + return self; } --(void)viewDidLoad -{ - ((UIViewController *)self).title = @"Applications"; - [self.view addSubview:_tableView]; - [super viewDidLoad]; +- (void)viewDidLoad { + ((UIViewController *)self).title = @"Applications"; + [self.view addSubview:_tableView]; + [super viewDidLoad]; } --(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath -{ - [tableView deselectRowAtIndexPath:indexPath animated:true]; - ALCheckCell* cell = (ALCheckCell*)[tableView cellForRowAtIndexPath:indexPath]; - [cell didSelect]; +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + [tableView deselectRowAtIndexPath:indexPath animated:true]; + ALCheckCell* cell = (ALCheckCell*)[tableView cellForRowAtIndexPath:indexPath]; + [cell didSelect]; - UITableViewCellAccessoryType type = [cell accessoryType]; - BOOL selected = type == UITableViewCellAccessoryCheckmark; - - NSString *identifier = [_dataSource displayIdentifierForIndexPath:indexPath]; - if (selected) - CFPreferencesSetAppValue((__bridge CFStringRef)@"NCApp", (CFPropertyListRef)(identifier), CFSTR("com.efrederickson.reachapp.settings")); + UITableViewCellAccessoryType type = [cell accessoryType]; + BOOL selected = type == UITableViewCellAccessoryCheckmark; - [self updateDataSource:nil]; + NSString *identifier = [_dataSource displayIdentifierForIndexPath:indexPath]; + if (selected) { + CFPreferencesSetAppValue((__bridge CFStringRef)@"NCApp", (CFPropertyListRef)(identifier), CFSTR("com.efrederickson.reachapp.settings")); + } - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); - }); + [self updateDataSource:nil]; - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Quick Access" message:@"A respring is required to apply changes. Would you like to respring now?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil]; - [alert show]; -} + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); + }); -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex -{ - if (buttonIndex == 1) - { - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.respring"), nil, nil, YES); - } + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Quick Access" message:@"A respring is required to apply changes. Would you like to respring now?" preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *respringAction = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.respring"), nil, nil, YES); + }]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]; + + [alert addAction:respringAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; } -@end \ No newline at end of file +@end diff --git a/reachappsettings/RAHeaderView.h b/reachappsettings/RAHeaderView.h index 084be15..d4884de 100644 --- a/reachappsettings/RAHeaderView.h +++ b/reachappsettings/RAHeaderView.h @@ -6,7 +6,7 @@ } @property (nonatomic) CGBlendMode blendMode; @property (nonatomic) BOOL shouldBlend; --(void) setColors:(NSArray*)colors; --(void) setTitle:(NSString*)title; --(void) setImage:(UIImage*)image; -@end \ No newline at end of file +- (void)setColors:(NSArray*)colors; +- (void)setTitle:(NSString*)title; +- (void)setImage:(UIImage*)image; +@end diff --git a/reachappsettings/RAHeaderView.mm b/reachappsettings/RAHeaderView.mm index be2d78a..25d027b 100644 --- a/reachappsettings/RAHeaderView.mm +++ b/reachappsettings/RAHeaderView.mm @@ -1,82 +1,76 @@ #import "RAHeaderView.h" @implementation UIImage (ext) -- (UIImage *)tintedImageWithColor:(UIColor *)tintColor blendingMode:(CGBlendMode)blendMode -{ - UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); - [tintColor setFill]; - CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height); - UIRectFill(bounds); - [self drawInRect:bounds blendMode:blendMode alpha:1.0f]; +- (UIImage *)tintedImageWithColor:(UIColor *)tintColor blendingMode:(CGBlendMode)blendMode { + UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); + [tintColor setFill]; + CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height); + UIRectFill(bounds); + [self drawInRect:bounds blendMode:blendMode alpha:1.0f]; - if (blendMode != kCGBlendModeDestinationIn) - [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0]; + if (blendMode != kCGBlendModeDestinationIn) { + [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0]; + } - UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); + UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); - return tintedImage; + return tintedImage; } @end @implementation RAHeaderView -+ (Class)layerClass -{ - return [CAGradientLayer class]; ++ (Class)layerClass { + return [CAGradientLayer class]; } --(id) initWithFrame:(CGRect)frame -{ - if (self = [super initWithFrame:frame]) - { - CAGradientLayer *gradient = (CAGradientLayer*)self.layer; - gradient.colors = @[ (id)[UIColor colorWithRed:255/255.0f green:124/255.0f blue:111/255.0f alpha:1.0f].CGColor, (id)[UIColor colorWithRed:231/255.0f green:76/255.0f blue:60/255.0f alpha:1.0f].CGColor ]; - gradient.locations = @[ @0, @1 ]; - gradient.bounds = CGRectMake(0, 0, frame.size.width, frame.size.height); +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + CAGradientLayer *gradient = (CAGradientLayer*)self.layer; + gradient.colors = @[ (id)[UIColor colorWithRed:255/255.0f green:124/255.0f blue:111/255.0f alpha:1.0f].CGColor, (id)[UIColor colorWithRed:231/255.0f green:76/255.0f blue:60/255.0f alpha:1.0f].CGColor ]; + gradient.locations = @[ @0, @1 ]; + gradient.bounds = CGRectMake(0, 0, frame.size.width, frame.size.height); - label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, frame.size.height - 20)]; - label.textColor = [UIColor whiteColor]; - label.font = [UIFont systemFontOfSize:36]; - label.adjustsFontSizeToFitWidth = YES; - label.clipsToBounds = NO; - [self addSubview:label]; + label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, frame.size.height - 20)]; + label.textColor = [UIColor whiteColor]; + label.font = [UIFont systemFontOfSize:36]; + label.adjustsFontSizeToFitWidth = YES; + label.clipsToBounds = NO; + [self addSubview:label]; - imageView = [[UIImageView alloc] initWithFrame:CGRectMake(frame.size.width - 210, 0, 200, 75)]; - [self addSubview:imageView]; + imageView = [[UIImageView alloc] initWithFrame:CGRectMake(frame.size.width - 210, 0, 200, 75)]; + [self addSubview:imageView]; - self.blendMode = kCGBlendModeOverlay; - self.shouldBlend = YES; - } - return self; + self.blendMode = kCGBlendModeOverlay; + self.shouldBlend = YES; + } + return self; } --(void) setFrame:(CGRect)frame -{ - [super setFrame:frame]; - ((CAGradientLayer*)self.layer).frame = CGRectMake(0, 0, frame.size.width, frame.size.height); +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + ((CAGradientLayer*)self.layer).frame = CGRectMake(0, 0, frame.size.width, frame.size.height); } --(void) setColors:(NSArray*)c -{ - ((CAGradientLayer*)self.layer).colors = c; +- (void)setColors:(NSArray*)c { + ((CAGradientLayer*)self.layer).colors = c; } --(void) setTitle:(NSString*)title -{ - label.text = title; +- (void)setTitle:(NSString*)title { + label.text = title; } --(void) setImage:(UIImage*)image -{ - if (label.text.length > 0) - imageView.frame = (CGRect) { { self.frame.size.width - image.size.width - 20, (self.frame.size.height - image.size.height) / 2.0 }, image.size }; - else - imageView.frame = (CGRect) { { (self.frame.size.width - image.size.width) / 2.0, (self.frame.size.height - image.size.height) / 2.0 }, image.size }; - if (self.shouldBlend) - { - UIColor *color = [UIColor colorWithCGColor:(CGColorRef)((CAGradientLayer*)self.layer).colors[0]]; - image = [image tintedImageWithColor:color blendingMode:self.blendMode]; - } - imageView.image = image; +- (void)setImage:(UIImage*)image { + if (label.text.length > 0) { + imageView.frame = (CGRect) { { self.frame.size.width - image.size.width - 20, (self.frame.size.height - image.size.height) / 2.0 }, image.size }; + } else { + imageView.frame = (CGRect) { { (self.frame.size.width - image.size.width) / 2.0, (self.frame.size.height - image.size.height) / 2.0 }, image.size }; + } + if (self.shouldBlend) { + UIColor *color = [UIColor colorWithCGColor:(CGColorRef)((CAGradientLayer*)self.layer).colors[0]]; + image = [image tintedImageWithColor:color blendingMode:self.blendMode]; + } + imageView.image = image; } @end diff --git a/reachappsettings/RAListItemsController.xm b/reachappsettings/RAListItemsController.xm index e3191bf..60dff5f 100644 --- a/reachappsettings/RAListItemsController.xm +++ b/reachappsettings/RAListItemsController.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import @interface PSListItemsController (tableView) @@ -12,57 +15,53 @@ @end @implementation RAListItemsController --(UIColor*) navigationTintColor { return [UIColor blackColor]; } +- (UIColor*)navigationTintColor { + return [UIColor blackColor]; +} -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; - self.navigationController.navigationBar.tintColor = self.navigationTintColor; - [[UIApplication sharedApplication] keyWindow].tintColor = self.navigationTintColor; + self.navigationController.navigationBar.tintColor = self.navigationTintColor; + [[UIApplication sharedApplication] keyWindow].tintColor = self.navigationTintColor; } -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - [[UIApplication sharedApplication] keyWindow].tintColor = nil; - self.navigationController.navigationBar.tintColor = nil; +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[UIApplication sharedApplication] keyWindow].tintColor = nil; + self.navigationController.navigationBar.tintColor = nil; } --(NSArray*) specifiers -{ - if (!_specifiers) { - PSSpecifier* themeSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Documentation" - target:self - set:NULL - get:NULL - detail:Nil - cell:PSButtonCell - edit:Nil]; - [themeSpecifier setProperty:RSIMG(@"tutorial.png") forKey:@"iconImage"]; - [themeSpecifier setProperty:@"poop" forKey:@"isTheming"]; - _specifiers = [super specifiers]; - [(NSMutableArray*)_specifiers addObject:[PSSpecifier emptyGroupSpecifier]]; - [(NSMutableArray*)_specifiers addObject:themeSpecifier]; - } - return _specifiers; +- (NSArray*)specifiers { + if (!_specifiers) { + PSSpecifier* themeSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Documentation" + target:self + set:NULL + get:NULL + detail:Nil + cell:PSButtonCell + edit:Nil]; + [themeSpecifier setProperty:SK_RSIMG(@"tutorial.png") forKey:@"iconImage"]; + [themeSpecifier setProperty:@"poop" forKey:@"isTheming"]; + _specifiers = [super specifiers]; + [(NSMutableArray*)_specifiers addObject:[PSSpecifier emptyGroupSpecifier]]; + [(NSMutableArray*)_specifiers addObject:themeSpecifier]; + } + return _specifiers; } --(void) openThemingDocumentation -{ - [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com/multiplexer/ThemingDocumentation.html"]]; +- (void)openThemingDocumentation { + [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com/multiplexer/ThemingDocumentation.html"]]; } --(void) tableView:(id)arg1 didSelectRowAtIndexPath:(id)arg2 -{ - [super tableView:arg1 didSelectRowAtIndexPath:arg2]; +- (void)tableView:(id)arg1 didSelectRowAtIndexPath:(id)arg2 { + [super tableView:arg1 didSelectRowAtIndexPath:arg2]; - PSTableCell *cell = [self tableView:arg1 cellForRowAtIndexPath:arg2]; - if ([cell.specifier propertyForKey:@"isTheming"] != nil) - { - [self openThemingDocumentation]; - } + PSTableCell *cell = [self tableView:arg1 cellForRowAtIndexPath:arg2]; + if ([cell.specifier propertyForKey:@"isTheming"]) { + [self openThemingDocumentation]; + } } @end @@ -72,21 +71,21 @@ @end @implementation RABackgroundingListItemsController --(UIColor*) navigationTintColor { return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; } +- (UIColor*)navigationTintColor { + return [UIColor colorWithRed:248/255.0f green:73/255.0f blue:88/255.0f alpha:1.0f]; +} -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; - self.navigationController.navigationBar.tintColor = self.navigationTintColor; - [[UIApplication sharedApplication] keyWindow].tintColor = self.navigationTintColor; + self.navigationController.navigationBar.tintColor = self.navigationTintColor; + [[UIApplication sharedApplication] keyWindow].tintColor = self.navigationTintColor; } -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - [[UIApplication sharedApplication] keyWindow].tintColor = nil; - self.navigationController.navigationBar.tintColor = nil; +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[UIApplication sharedApplication] keyWindow].tintColor = nil; + self.navigationController.navigationBar.tintColor = nil; } -@end \ No newline at end of file +@end diff --git a/reachappsettings/RASupportController.xm b/reachappsettings/RASupportController.xm index 0ed679b..b635c70 100644 --- a/reachappsettings/RASupportController.xm +++ b/reachappsettings/RASupportController.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -9,119 +12,136 @@ @end @implementation RAMakersController --(BOOL) showHeartImage { return NO; } --(UIColor*) navigationTintColor { return [UIColor blackColor]; } --(UIColor*) switchOnTintColor { return self.navigationTintColor; } +- (BOOL)showHeartImage { + return NO; +} + +- (UIColor*)navigationTintColor { + return [UIColor blackColor]; +} + +- (UIColor*)switchOnTintColor { + return self.navigationTintColor; +} //-(UIColor*) iconColor { return self.navigationTintColor; } --(NSString*) customTitle { return @"Creators"; } +- (NSString*)customTitle { + return @"Creators"; +} -- (id)customSpecifiers { - return @[ - @{ @"cell": @"PSGroupCell", @"label": @"Developed and Designed by" }, - @{ - @"cell": @"PSLinkCell", - //@"cellClass": @"RAElijahPersonCell", - @"height": @45, - @"action": @"openElijahTwitter", - @"label": @"Elijah Frederickson", - @"icon": @"elijah" - }, - @{ - @"cell": @"PSLinkCell", - //@"cellClass": @"RAAndrewPersonCell", - @"height": @45, - @"action": @"openAndrewTwitter", - @"label": @"Andrew Abosh", - @"icon": @"andrew" - }, +- (NSArray*)customSpecifiers { + return @[ + @{ @"cell": @"PSGroupCell", @"label": @"Developed and Designed by" }, + @{ + @"cell": @"PSLinkCell", + //@"cellClass": @"RAElijahPersonCell", + @"height": @45, + @"action": @"openElijahTwitter", + @"label": @"Elijah Frederickson", + @"icon": @"elijah" + }, + @{ + @"cell": @"PSLinkCell", + //@"cellClass": @"RAAndrewPersonCell", + @"height": @45, + @"action": @"openAndrewTwitter", + @"label": @"Andrew Abosh", + @"icon": @"andrew" + }, + @{ + @"cell": @"PSLinkCell", + @"height": @45, + @"action": @"openShadeTwitter", + @"label": @"Shade Zepheri", + @"icon": @"shade" + }, - @{ @"label": @"Beta tested by" }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openAndiTwitter", - @"label": @"Andi Andreas", - @"icon": @"Andi" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openBetaPage", - @"label": @"Beta382", - @"icon": @"beta382" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openBindersPAge", - @"label": @"BindersFullOfWomen", - @"icon": @"Binders" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openDavidTwitter", - @"label": @"David", - @"icon": @"David" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openJackTwitter", - @"label": @"Jack Haal", - @"icon": @"Jack" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openMosheTwitter", - @"label": @"Moshe Dancykier", - @"icon": @"Moshe" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openWilsonTwitter", - @"label": @"Wilson (TM3Dev)", - @"icon": @"Wilson" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openZiph0nTwitter", - @"label": @"Ziph0n", - @"icon": @"Ziphon" - }, + @{ @"label": @"Beta tested by" }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openAndiTwitter", + @"label": @"Andi Andreas", + @"icon": @"Andi" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openBetaPage", + @"label": @"Beta382", + @"icon": @"beta382" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openBindersPAge", + @"label": @"BindersFullOfWomen", + @"icon": @"Binders" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openDavidTwitter", + @"label": @"David", + @"icon": @"David" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openJackTwitter", + @"label": @"Jack Haal", + @"icon": @"Jack" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openMosheTwitter", + @"label": @"Moshe Dancykier", + @"icon": @"Moshe" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openWilsonTwitter", + @"label": @"Wilson (TM3Dev)", + @"icon": @"Wilson" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openZiph0nTwitter", + @"label": @"Ziph0n", + @"icon": @"Ziphon" + }, - @{ @"label": @"Special Thanks To" }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openChonTwitter", - @"label": @"Chon Lee", - @"icon": @"Chon" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openEthanTwitter", - @"label": @"Ethan Arbuckle", - @"icon": @"EthanArbuckle" - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"openSharedRoutineTwitter", - @"label": @"sharedRoutine", - @"icon": @"SharedRoutine" - }, + @{ @"label": @"Special Thanks To" }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openChonTwitter", + @"label": @"Chon Lee", + @"icon": @"Chon" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openEthanTwitter", + @"label": @"Ethan Arbuckle", + @"icon": @"EthanArbuckle" + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"openSharedRoutineTwitter", + @"label": @"sharedRoutine", + @"icon": @"SharedRoutine" + }, - @{ @"cell": @"PSGroupCell" }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Site", - @"action": @"openSite", - @"icon": @"ra_makers.png" - }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Source Code", - @"action": @"openGithub", - @"icon": @"github.png" - }, + @{ @"cell": @"PSGroupCell" }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Site", + @"action": @"openSite", + @"icon": @"ra_makers.png" + }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Source Code", + @"action": @"openGithub", + @"icon": @"github.png" + }, - @{ @"cell": @"PSGroupCell", - @"footerText": @"Acknowledgments: \n\ + @{ @"cell": @"PSGroupCell", + @"footerText": @"Acknowledgments: \n\ \n\ This code thanks: \n\ ForceReach, Reference, MessageBox \n\ @@ -133,27 +153,27 @@ A special thanks goes to those who contributed ideas, feature enhancements, bug \n\ Crafted with love in 🇨🇦 and 🇺🇸. \n\ \n", - }, - ]; + }, + ]; } --(void) openGithub -{ - [SKSharedHelper openGitHub:@"mlnlover11/Multiplexer"]; +- (void)openGithub { + [SKSharedHelper openGitHub:@"mlnlover11/Multiplexer"]; } --(void) openElijahTwitter { [SKSharedHelper openTwitter:@"daementor"]; } --(void) openAndrewTwitter { [SKSharedHelper openTwitter:@"drewplex"]; } --(void) openAndiTwitter { [SKSharedHelper openTwitter:@"Nexuist"]; } --(void) openBetaPage { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://www.reddit.com/user/beta382"]]; } --(void) openChonTwitter { [SKSharedHelper openTwitter:@"HikoMitsuketa"]; } --(void) openDavidTwitter { [SKSharedHelper openTwitter:@"djaovx"]; } --(void) openJackTwitter { [SKSharedHelper openTwitter:@"JackHaal"]; } --(void) openMosheTwitter { [SKSharedHelper openTwitter:@"oniconpack"]; } --(void) openBindersPAge { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://www.reddit.com/user/_BindersFullOfWomen_"]]; } --(void) openWilsonTwitter { [SKSharedHelper openTwitter:@"xTM3x"]; } --(void) openZiph0nTwitter { [SKSharedHelper openTwitter:@"ziph0n"]; } --(void) openSharedRoutineTwitter { [SKSharedHelper openTwitter:@"sharedRoutine"]; } --(void) openEthanTwitter { [SKSharedHelper openTwitter:@"its_not_herpes"]; } --(void) openSite { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com"]]; } -@end \ No newline at end of file +- (void)openElijahTwitter { [SKSharedHelper openTwitter:@"daementor"]; } +- (void)openAndrewTwitter { [SKSharedHelper openTwitter:@"drewplex"]; } +- (void)openShadeTwitter { [SKSharedHelper openTwitter:@"ShadeZepheri"]; } +- (void)openAndiTwitter { [SKSharedHelper openTwitter:@"Nexuist"]; } +- (void)openBetaPage { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://www.reddit.com/user/beta382"]]; } +- (void)openChonTwitter { [SKSharedHelper openTwitter:@"HikoMitsuketa"]; } +- (void)openDavidTwitter { [SKSharedHelper openTwitter:@"djaovx"]; } +- (void)openJackTwitter { [SKSharedHelper openTwitter:@"JackHaal"]; } +- (void)openMosheTwitter { [SKSharedHelper openTwitter:@"oniconpack"]; } +- (void)openBindersPAge { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://www.reddit.com/user/_BindersFullOfWomen_"]]; } +- (void)openWilsonTwitter { [SKSharedHelper openTwitter:@"xTM3x"]; } +- (void)openZiph0nTwitter { [SKSharedHelper openTwitter:@"ziph0n"]; } +- (void)openSharedRoutineTwitter { [SKSharedHelper openTwitter:@"sharedRoutine"]; } +- (void)openEthanTwitter { [SKSharedHelper openTwitter:@"its_not_herpes"]; } +- (void)openSite { [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com"]]; } +@end diff --git a/reachappsettings/ReachAppSettings.mm b/reachappsettings/ReachAppSettings.mm index 83ec02e..9f7e960 100644 --- a/reachappsettings/ReachAppSettings.mm +++ b/reachappsettings/ReachAppSettings.mm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -17,15 +20,15 @@ #import "RASettings.h" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -36,254 +39,255 @@ @interface ReachAppSettingsListController: SKTintedListController= 300000) - header.title = @"dank memes"; + if (arc4random_uniform(1000000) == 11) { + header.title = @"卐卐 TWEAK SUPREMACY 卍卍"; + } else if (arc4random_uniform(1000000) >= 300000) { + header.title = @"dank memes"; + } #endif - header.blendMode = kCGBlendModeSoftLight; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/MainHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(109.33, 41)]]; + header.blendMode = kCGBlendModeSoftLight; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/MainHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(109.33, 41)]]; - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 115)]; - [notHeader addSubview:header]; + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 115)]; + [notHeader addSubview:header]; - return notHeader; + return notHeader; } --(UIColor*) navigationTintColor { return [UIColor colorWithRed:190/255.0f green:83/255.0f blue:184/255.0f alpha:1.0f]; } --(NSString*) customTitle { return @"Multiplexer"; } --(BOOL) showHeartImage { return YES; } --(NSString*) shareMessage { return @"I'm multitasking with Multiplexer, by @daementor and @drewplex"; } +- (UIColor*)navigationTintColor { + return [UIColor colorWithRed:190/255.0f green:83/255.0f blue:184/255.0f alpha:1.0f]; +} + +- (NSString*)customTitle { + return @"Multiplexer"; +} --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"Quickly enable or disable Multiplexer." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"enabled", - @"label": @"Enabled", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - @"icon": @"ra_enabled.png", - }, +- (BOOL)showHeartImage { + return YES; +} + +- (NSString*)shareMessage { + return @"I'm multitasking with Multiplexer, by @daementor and @drewplex"; +} + +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"Quickly enable or disable Multiplexer." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"enabled", + @"label": @"Enabled", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + @"icon": @"ra_enabled.png", + }, #if DEBUG - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"debug_showIPCMessages", - @"label": @"Show IPC communication messages", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - @"icon": @"ra_enabled.png", - }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"debug_showIPCMessages", + @"label": @"Show IPC communication messages", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + @"icon": @"ra_enabled.png", + }, #endif - @{ @"footerText": @"Customize the look of Multiplexer." }, + @{ @"footerText": @"Customize the look of Multiplexer." }, - @{ - @"cell": @"PSLinkListCell", - @"default": [RASettings.sharedInstance currentThemeIdentifier], - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - @"label": @"Theme", - @"icon": @"theme.png", - @"key": @"currentThemeIdentifier", - @"detail": @"RAListItemsController", - @"valuesDataSource": @"getThemeValues:", - @"titlesDataSource": @"getThemeTitles:", - @"enabled": @([self getEnabled]) - }, + @{ + @"cell": @"PSLinkListCell", + @"default": [RASettings.sharedInstance currentThemeIdentifier], + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + @"label": @"Theme", + @"icon": @"theme.png", + @"key": @"currentThemeIdentifier", + @"detail": @"RAListItemsController", + @"valuesDataSource": @"getThemeValues:", + @"titlesDataSource": @"getThemeTitles:", + @"enabled": @([self getEnabled]) + }, - @{ @"footerText": @"Let apps run in the background." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Aura", - @"detail": @"ReachAppBackgrounderSettingsListController", - @"icon": @"aura.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": @"Windowed multitasking." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Empoleon", - @"detail": @"ReachAppWindowSettingsListController", - @"icon": @"empoleon.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": @"Manage multiple desktops and their windows." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Mission Control", - @"detail": @"ReachAppMCSettingsListController", - @"icon": @"missioncontrol.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": @"Have an app in Notification Center." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Quick Access", - @"detail": @"ReachAppNCAppSettingsListController", - @"icon": @"quickaccess.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": @"Use an app in Reachability alongside another." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Reach App", - @"detail": @"ReachAppReachabilitySettingsListController", - @"icon": @"reachapp.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": @"Access another app simply by swiping in from the right side of the screen." }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Swipe Over", - @"detail": @"ReachAppSwipeOverSettingsListController", - @"icon": @"swipeover.png", - @"enabled": @([self getEnabled]) - }, - @{ @"footerText": [NSString stringWithFormat:@"%@%@", + @{ @"footerText": @"Let apps run in the background." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Aura", + @"detail": @"ReachAppBackgrounderSettingsListController", + @"icon": @"aura.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": @"Windowed multitasking." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Empoleon", + @"detail": @"ReachAppWindowSettingsListController", + @"icon": @"empoleon.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": @"Manage multiple desktops and their windows." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Mission Control", + @"detail": @"ReachAppMCSettingsListController", + @"icon": @"missioncontrol.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": @"Have an app in Notification Center." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Quick Access", + @"detail": @"ReachAppNCAppSettingsListController", + @"icon": @"quickaccess.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": @"Use an app in Reachability alongside another." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Reach App", + @"detail": @"ReachAppReachabilitySettingsListController", + @"icon": @"reachapp.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": @"Access another app simply by swiping in from the right side of the screen." }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Swipe Over", + @"detail": @"ReachAppSwipeOverSettingsListController", + @"icon": @"swipeover.png", + @"enabled": @([self getEnabled]) + }, + @{ @"footerText": [NSString stringWithFormat:@"%@%@", #if DEBUG - arc4random_uniform(10000) == 9901 ? @"2fast5me" : + arc4random_uniform(10000) == 9901 ? @"2fast5me" : #endif - @"© 2015 Elijah Frederickson & Andrew Abosh.", + @"© 2015 Elijah Frederickson & Andrew Abosh.", #if DEBUG - @"\n**DEBUG** " + @"\n**DEBUG** " #else - @"" + @"" #endif - ]}, - @{ - @"cell": @"PSLinkCell", - @"label": @"Creators", - @"detail": @"RAMakersController", - @"icon": @"ra_makers.png" - }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Support", - @"action": @"showSupportDialog", - @"icon": @"ra_support.png" - }, + ]}, + @{ + @"cell": @"PSLinkCell", + @"label": @"Creators", + @"detail": @"RAMakersController", + @"icon": @"ra_makers.png" + }, + @{ + @"cell": @"PSLinkCell", + @"label": @"Support", + @"action": @"showSupportDialog", + @"icon": @"ra_support.png" + }, - @{ - @"cell": @"PSLinkCell", - @"label": @"Tutorial", - @"action": @"showTutorial", - @"icon": @"tutorial.png", - //@"enabled": @NO, - },/* - @{ - @"cell": @"PSLinkCell", - @"label": @"Theming Documentation", - @"action": @"openThemingDocumentation", - @"icon": @"tutorial.png", - },*/ - @{ - @"cell": @"PSButtonCell", - @"action": @"resetData", - @"label": @"Reset All Settings & Respring", - @"icon": @"Reset.png" - } - ]; + @{ + @"cell": @"PSLinkCell", + @"label": @"Tutorial", + @"action": @"showTutorial", + @"icon": @"tutorial.png", + //@"enabled": @NO, + },/* + @{ + @"cell": @"PSLinkCell", + @"label": @"Theming Documentation", + @"action": @"openThemingDocumentation", + @"icon": @"tutorial.png", + },*/ + @{ + @"cell": @"PSButtonCell", + @"action": @"resetData", + @"label": @"Reset All Settings & Respring", + @"icon": @"Reset.png" + } + ]; } --(void) resetData -{ - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Multiplexer" message:@"Please confirm your choice to reset all settings & respring." delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil]; - [alert addButtonWithTitle:@"Yes"]; - [alert show]; -} +- (void)resetData { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Please confirm your choice to reset all settings & respring.." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.resetSettings"), nil, nil, YES); + }]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex -{ - if (buttonIndex == 1) - { - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.resetSettings"), nil, nil, YES); - } + [alert addAction:resetAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; } --(void) openThemingDocumentation -{ - [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com/multiplexer/ThemingDocumentation.html"]]; +- (void)openThemingDocumentation { + [UIApplication.sharedApplication openURL:[NSURL URLWithString:@"https://elijahandandrew.com/multiplexer/ThemingDocumentation.html"]]; } --(NSArray*) getThemeTitles:(id)target -{ - NSArray *themes = [RAThemeManager.sharedInstance allThemes]; - NSMutableArray *ret = [NSMutableArray array]; - for (RATheme *theme in themes) - [ret addObject:theme.themeName]; - return ret; +- (NSArray*)getThemeTitles:(id)target { + NSArray *themes = [RAThemeManager.sharedInstance allThemes]; + NSMutableArray *ret = [NSMutableArray array]; + for (RATheme *theme in themes) { + [ret addObject:theme.themeName]; + } + return ret; } --(NSArray*) getThemeValues:(id)target -{ - NSArray *themes = [RAThemeManager.sharedInstance allThemes]; - NSMutableArray *ret = [NSMutableArray array]; - for (RATheme *theme in themes) - [ret addObject:theme.themeIdentifier]; - return ret; +- (NSArray*)getThemeValues:(id)target { + NSArray *themes = [RAThemeManager.sharedInstance allThemes]; + NSMutableArray *ret = [NSMutableArray array]; + for (RATheme *theme in themes) { + [ret addObject:theme.themeIdentifier]; + } + return ret; } --(void) showSupportDialog -{ - MFMailComposeViewController *mailViewController; - if ([MFMailComposeViewController canSendMail]) - { - mailViewController = [[MFMailComposeViewController alloc] init]; - mailViewController.mailComposeDelegate = self; - [mailViewController setSubject:@"Multiplexer"]; - - struct utsname systemInfo; - uname(&systemInfo); - NSString *sysInfo = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; - - NSString *msg = [NSString stringWithFormat:@"\n\n%@ %@\nModel: %@\n", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion, sysInfo]; - [mailViewController setMessageBody:msg isHTML:NO]; - [mailViewController setToRecipients:@[@"elijahandandrew@gmail.com"]]; - - [self.rootController presentViewController:mailViewController animated:YES completion:nil]; - } +- (void)showSupportDialog { + MFMailComposeViewController *mailViewController; + if ([MFMailComposeViewController canSendMail]) { + mailViewController = [[MFMailComposeViewController alloc] init]; + mailViewController.mailComposeDelegate = self; + [mailViewController setSubject:@"Multiplexer"]; + + struct utsname systemInfo; + uname(&systemInfo); + NSString *sysInfo = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + + NSString *msg = [NSString stringWithFormat:@"\n\n%@ %@\nModel: %@\n", [UIDevice currentDevice].systemName, [UIDevice currentDevice].systemVersion, sysInfo]; + [mailViewController setMessageBody:msg isHTML:NO]; + [mailViewController setToRecipients:@[@"elijahandandrew@gmail.com"]]; + + [self.rootController presentViewController:mailViewController animated:YES completion:nil]; + } } --(void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier -{ - [super setPreferenceValue:value specifier:specifier]; - [self reloadSpecifiers]; +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { + [super setPreferenceValue:value specifier:specifier]; + [self reloadSpecifiers]; } --(BOOL) getEnabled -{ - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!keyList) { - return YES; - } - NSDictionary *_settings = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - CFRelease(keyList); - if (!_settings) { - return YES; - } +- (BOOL)getEnabled { + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!keyList) { + return YES; + } + NSDictionary *_settings = (__bridge NSDictionary *)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + CFRelease(keyList); + if (!_settings) { + return YES; + } - return [_settings objectForKey:@"enabled"] == nil ? YES : [_settings[@"enabled"] boolValue]; + return ![_settings objectForKey:@"enabled"] ? YES : [_settings[@"enabled"] boolValue]; } --(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error{ - [self dismissViewControllerAnimated:YES completion:NULL]; +- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { + [self dismissViewControllerAnimated:YES completion:NULL]; } --(void) showTutorial -{ - [UIApplication.sharedApplication launchApplicationWithIdentifier:@"com.andrewabosh.Multiplexer" suspended:NO]; +- (void)showTutorial { + [UIApplication.sharedApplication launchApplicationWithIdentifier:@"com.andrewabosh.Multiplexer" suspended:NO]; } @end diff --git a/reachappsettings/Reachability.xm b/reachappsettings/Reachability.xm index 3319028..c079ec3 100644 --- a/reachappsettings/Reachability.xm +++ b/reachappsettings/Reachability.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -11,15 +14,15 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void) viewDidLoad; +- (void) viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -30,233 +33,242 @@ @end @implementation ReachAppReachabilitySettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:29/255.0f green:119/255.0f blue:239/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:82/255.0f green:191/255.0f blue:232/255.0f alpha:1.0f].CGColor - ]; - header.shouldBlend = NO; - //header.title = @"ReachApp"; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/ReachAppHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(27.15, 32)]]; - - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; - [notHeader addSubview:header]; - - return notHeader; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:29/255.0f green:119/255.0f blue:239/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:82/255.0f green:191/255.0f blue:232/255.0f alpha:1.0f].CGColor + ]; + header.shouldBlend = NO; + //header.title = @"ReachApp"; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/ReachAppHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(27.15, 32)]]; + + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; + [notHeader addSubview:header]; + + return notHeader; } --(UIColor*) tintColor { return [UIColor colorWithRed:29/255.0f green:119/255.0f blue:239/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } --(NSString*) customTitle { return @"Reach App"; } --(BOOL) showHeartImage { return NO; } - --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; + +- (UIColor*)tintColor { + return [UIColor colorWithRed:29/255.0f green:119/255.0f blue:239/255.0f alpha:1.0f]; +} + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; } --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"Quickly enable or disable ReachApp." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"reachabilityEnabled", - @"label": @"Enabled", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"If enabled, the Notification Center view is displayed in Reachability." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showNCInstead", - @"label": @"Show NC Instead of App", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"Disables the default duration that Reachability closes after." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"disableAutoDismiss", - @"label": @"Disable Auto-dismiss", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, +- (NSString*)customTitle { + return @"Reach App"; +} + +- (BOOL)showHeartImage { + return NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; +} + +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"Quickly enable or disable ReachApp." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"reachabilityEnabled", + @"label": @"Enabled", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"If enabled, the Notification Center view is displayed in Reachability." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showNCInstead", + @"label": @"Show NC Instead of App", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"Disables the default duration that Reachability closes after." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"disableAutoDismiss", + @"label": @"Disable Auto-dismiss", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, /* - @{ @"footerText": @"Forces apps to rotate to the current orientation" }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"enableRotation", - @"label": @"Enable Rotation", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, + @{ @"footerText": @"Forces apps to rotate to the current orientation" }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"enableRotation", + @"label": @"Enable Rotation", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, */ - @{ @"footerText": @"If enabled, the home button will no longer return to the home screen when Reachability is displayed." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"homeButtonClosesReachability", - @"label": @"Home Button Closes Reachability", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, + @{ @"footerText": @"If enabled, the home button will no longer return to the home screen when Reachability is displayed." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"homeButtonClosesReachability", + @"label": @"Home Button Closes Reachability", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, /* - @{ @"footerText": @"Shows the bottom half of the resizing grabber" }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showBottomGrabber", - @"label": @"Show Bottom Grabber", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"This attempts to hide the lower status bar and force the upper status bar." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"unifyStatusBar", - @"label": @"Unify Status Bar", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, + @{ @"footerText": @"Shows the bottom half of the resizing grabber" }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showBottomGrabber", + @"label": @"Show Bottom Grabber", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"This attempts to hide the lower status bar and force the upper status bar." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"unifyStatusBar", + @"label": @"Unify Status Bar", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, */ - @{ @"footerText": @"If enabled, a widget selector will be displayed. If disabled, the last used app will be show in Reachability." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showAppSelector", - @"label": @"Display Widget Selector", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSLinkListCell", - @"detail": @"RAAppChooserOptionsListController", - @"label": @"Options", - }, + @{ @"footerText": @"If enabled, a widget selector will be displayed. If disabled, the last used app will be show in Reachability." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showAppSelector", + @"label": @"Display Widget Selector", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSLinkListCell", + @"detail": @"RAAppChooserOptionsListController", + @"label": @"Options", + }, /* - @{ @"footerText": @"PLEASE NOTE THESE ARE BETA OPTIONS, STILL UNDER WORK OR TEMPORARILY BEING IGNORED. DO NOT SEND EMAILS RELATING TO THIS FEATURE. THEY WILL BE IGNORED. \n\nThat said, one will force applications into portrait and scale them to the screen size in landscape mode\nand the other will flip the top and bottom panes" }, - @{ - @"cell": @"PSSwitchCell", - @"default": @0, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"rotationMode", - @"label": @"Use Scaling Rotation Mode", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - @"cellClass": @"RASwitchCell", - }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"flipTopAndBottom", - @"label": @"Appear at Bottom", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - */ - ]; - + @{ @"footerText": @"PLEASE NOTE THESE ARE BETA OPTIONS, STILL UNDER WORK OR TEMPORARILY BEING IGNORED. DO NOT SEND EMAILS RELATING TO THIS FEATURE. THEY WILL BE IGNORED. \n\nThat said, one will force applications into portrait and scale them to the screen size in landscape mode\nand the other will flip the top and bottom panes" }, + @{ + @"cell": @"PSSwitchCell", + @"default": @0, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"rotationMode", + @"label": @"Use Scaling Rotation Mode", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + @"cellClass": @"RASwitchCell", + }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"flipTopAndBottom", + @"label": @"Appear at Bottom", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + */ + ]; } @end -@interface RAAppChooserOptionsListController : SKTintedListController +@interface RAAppChooserOptionsListController : SKTintedListController @end @implementation RAAppChooserOptionsListController --(BOOL) showHeartImage { return NO; } --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"If enabled, the app selector will scale to the size of available apps." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"autoSizeAppChooser", - @"label": @"Auto-size Widget Chooser", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"If enabled, a list of your recent apps will display in the app selector." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showRecents", - @"label": @"Display Recent Apps", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"Apps that will be displayed in the favorites section of the app selector." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showFavorites", - @"label": @"Display Favorite Apps", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSLinkListCell", - @"detail": @"RAFavoritesAppSelectorView", - @"label": @"Favorites", - }, - - @{ @"footerText": @"If enabled, a section with all your apps will display in the app selector." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showAllAppsInAppChooser", - @"label": @"Display All Apps", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"If enabled, apps will be divided into discrete pages." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"pagingEnabled", - @"label": @"Pagination", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - ]; +- (BOOL)showHeartImage { + return NO; +} + +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"If enabled, the app selector will scale to the size of available apps." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"autoSizeAppChooser", + @"label": @"Auto-size Widget Chooser", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"If enabled, a list of your recent apps will display in the app selector." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showRecents", + @"label": @"Display Recent Apps", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"Apps that will be displayed in the favorites section of the app selector." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showFavorites", + @"label": @"Display Favorite Apps", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSLinkListCell", + @"detail": @"RAFavoritesAppSelectorView", + @"label": @"Favorites", + }, + + @{ @"footerText": @"If enabled, a section with all your apps will display in the app selector." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showAllAppsInAppChooser", + @"label": @"Display All Apps", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"If enabled, apps will be divided into discrete pages." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"pagingEnabled", + @"label": @"Pagination", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + ]; } @end @interface RASwitchCell : PSSwitchTableCell //our class @end - + @implementation RASwitchCell --(id)initWithStyle:(int)arg1 reuseIdentifier:(id)arg2 specifier:(id)arg3 { //init method - self = [super initWithStyle:arg1 reuseIdentifier:arg2 specifier:arg3]; //call the super init method - if (self) { - [((UISwitch *)[self control]) setOnTintColor:[UIColor redColor]]; //change the switch color - } - return self; +- (instancetype)initWithStyle:(int)arg1 reuseIdentifier:(id)arg2 specifier:(id)arg3 { //init method + self = [super initWithStyle:arg1 reuseIdentifier:arg2 specifier:arg3]; //call the super init method + if (self) { + [((UISwitch *)[self control]) setOnTintColor:[UIColor redColor]]; //change the switch color + } + return self; } @end -@interface RAFavoritesAppSelectorView : PSViewController -{ - UITableView* _tableView; - ALApplicationTableDataSource* _dataSource; +@interface RAFavoritesAppSelectorView : PSViewController { + UITableView* _tableView; + ALApplicationTableDataSource* _dataSource; } @end @@ -269,91 +281,84 @@ @end @implementation RAApplicationTableDataSource -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //NSInteger row = indexPath.row; - UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; - - NSDictionary *prefs = nil; - - CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); - CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!keyList) { - return cell; - } - prefs = (__bridge NSDictionary*)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - if (!prefs) { - return cell; - } - CFRelease(keyList); - - if ([cell isKindOfClass:[ALCheckCell class]]) - { - NSString *dn = [self displayIdentifierForIndexPath:indexPath]; - NSString *key = [NSString stringWithFormat:@"Favorites-%@",dn]; - BOOL value = [prefs[key] boolValue]; - [(ALCheckCell*)cell loadValue:@(value)]; - } + UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; + + NSDictionary *prefs = nil; + + CFStringRef appID = CFSTR("com.efrederickson.reachapp.settings"); + CFArrayRef keyList = CFPreferencesCopyKeyList(appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!keyList) { + return cell; + } + prefs = (__bridge NSDictionary*)CFPreferencesCopyMultiple(keyList, appID, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); + if (!prefs) { return cell; + } + CFRelease(keyList); + + if ([cell isKindOfClass:[ALCheckCell class]]) { + NSString *dn = [self displayIdentifierForIndexPath:indexPath]; + NSString *key = [NSString stringWithFormat:@"Favorites-%@",dn]; + BOOL value = [prefs[key] boolValue]; + [(ALCheckCell*)cell loadValue:@(value)]; + } + return cell; } @end @implementation RAFavoritesAppSelectorView --(void)updateDataSource:(NSString*)searchText -{ - _dataSource.sectionDescriptors = [NSArray arrayWithObjects: - [NSDictionary dictionaryWithObjectsAndKeys: - @"", ALSectionDescriptorTitleKey, - @"ALCheckCell", ALSectionDescriptorCellClassNameKey, - @(29), ALSectionDescriptorIconSizeKey, - @YES, ALSectionDescriptorSuppressHiddenAppsKey, - [NSString stringWithFormat:@"not bundleIdentifier in { }"], - ALSectionDescriptorPredicateKey - , nil], - nil]; - [_tableView reloadData]; +-(void)updateDataSource:(NSString*)searchText { + _dataSource.sectionDescriptors = [NSArray arrayWithObjects: + [NSDictionary dictionaryWithObjectsAndKeys: + @"", ALSectionDescriptorTitleKey, + @"ALCheckCell", ALSectionDescriptorCellClassNameKey, + @(29), ALSectionDescriptorIconSizeKey, + @YES, ALSectionDescriptorSuppressHiddenAppsKey, + [NSString stringWithFormat:@"not bundleIdentifier in { }"], + ALSectionDescriptorPredicateKey + , nil], + nil]; + [_tableView reloadData]; } --(id)init -{ - if (!(self = [super init])) return nil; - +- (instancetype)init { + if (self = [super init]) { CGRect bounds = [[UIScreen mainScreen] bounds]; - + _dataSource = [[RAApplicationTableDataSource alloc] init]; - + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height) style:UITableViewStyleGrouped]; _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _tableView.delegate = self; _tableView.dataSource = _dataSource; _dataSource.tableView = _tableView; [self updateDataSource:nil]; - - return self; + } + return self; } --(void)viewDidLoad -{ - ((UIViewController *)self).title = @"Applications"; - [self.view addSubview:_tableView]; - [super viewDidLoad]; +- (void)viewDidLoad { + ((UIViewController *)self).title = @"Applications"; + [self.view addSubview:_tableView]; + [super viewDidLoad]; } --(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath -{ - [tableView deselectRowAtIndexPath:indexPath animated:true]; - ALCheckCell* cell = (ALCheckCell*)[tableView cellForRowAtIndexPath:indexPath]; - [cell didSelect]; - - UITableViewCellAccessoryType type = [cell accessoryType]; - BOOL selected = type == UITableViewCellAccessoryCheckmark; - - NSString *identifier = [_dataSource displayIdentifierForIndexPath:indexPath]; - CFPreferencesSetAppValue((__bridge CFStringRef)[NSString stringWithFormat:@"Favorites-%@", identifier], (CFPropertyListRef)(@(selected)), CFSTR("com.efrederickson.reachapp.settings")); - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); - }); +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + [tableView deselectRowAtIndexPath:indexPath animated:true]; + ALCheckCell* cell = (ALCheckCell*)[tableView cellForRowAtIndexPath:indexPath]; + [cell didSelect]; + + UITableViewCellAccessoryType type = [cell accessoryType]; + BOOL selected = type == UITableViewCellAccessoryCheckmark; + + NSString *identifier = [_dataSource displayIdentifierForIndexPath:indexPath]; + CFPreferencesSetAppValue((__bridge CFStringRef)[NSString stringWithFormat:@"Favorites-%@", identifier], (CFPropertyListRef)(@(selected)), CFSTR("com.efrederickson.reachapp.settings")); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.efrederickson.reachapp.settings/reloadSettings"), nil, nil, YES); + }); } -@end \ No newline at end of file +@end diff --git a/reachappsettings/SwipeOver.xm b/reachappsettings/SwipeOver.xm index 18cf1fd..1b95b7b 100644 --- a/reachappsettings/SwipeOver.xm +++ b/reachappsettings/SwipeOver.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -12,49 +15,57 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ReachAppSwipeOverSettingsListController: SKTintedListController @end @implementation ReachAppSwipeOverSettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:88/255.0f green:86/255.0f blue:214/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:198/255.0f green:68/255.0f blue:252/255.0f alpha:1.0f].CGColor, - ]; - header.shouldBlend = NO; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/SwipeOverHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(54, 32)]]; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:88/255.0f green:86/255.0f blue:214/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:198/255.0f green:68/255.0f blue:252/255.0f alpha:1.0f].CGColor, + ]; + header.shouldBlend = NO; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/SwipeOverHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(54, 32)]]; - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; - [notHeader addSubview:header]; + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; + [notHeader addSubview:header]; - return notHeader; + return notHeader; +} +- (NSString*)customTitle { + return @"Swipe Over"; +} + +- (UIColor*)tintColor { + return [UIColor colorWithRed:88/255.0f green:86/255.0f blue:214/255.0f alpha:1.0f]; +} + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; +} + +- (BOOL)showHeartImage { + return NO; } --(NSString*) customTitle { return @"Swipe Over"; } --(UIColor*) tintColor { return [UIColor colorWithRed:88/255.0f green:86/255.0f blue:214/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } --(BOOL) showHeartImage { return NO; } --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; } --(NSArray*) customSpecifiers -{ +- (NSArray*)customSpecifiers { return @[ @{ @"footerText": @"Quickly enable or disable Swipe Over." }, @{ @@ -89,4 +100,3 @@ ]; } @end - diff --git a/reachappsettings/WindowedMultitasking.xm b/reachappsettings/WindowedMultitasking.xm index 268b539..d045a00 100644 --- a/reachappsettings/WindowedMultitasking.xm +++ b/reachappsettings/WindowedMultitasking.xm @@ -1,4 +1,7 @@ -#import +#import +#import +#import +#import #import #import #import @@ -13,15 +16,15 @@ #define PLIST_NAME @"/var/mobile/Library/Preferences/com.efrederickson.reachapp.settings.plist" @interface PSViewController (Protean) --(void) viewDidLoad; --(void) viewWillDisappear:(BOOL)animated; +- (void)viewDidLoad; +- (void)viewWillDisappear:(BOOL)animated; - (void)viewDidAppear:(BOOL)animated; @end @interface PSViewController (SettingsKit2) --(UINavigationController*)navigationController; --(void)viewWillAppear:(BOOL)animated; --(void)viewWillDisappear:(BOOL)animated; +- (UINavigationController*)navigationController; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; @end @interface ALApplicationTableDataSource (Private) @@ -32,185 +35,210 @@ @end @implementation ReachAppWindowSettingsListController --(UIView*) headerView -{ - RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; - header.colors = @[ - (id) [UIColor colorWithRed:255/255.0f green:94/255.0f blue:58/255.0f alpha:1.0f].CGColor, - (id) [UIColor colorWithRed:255/255.0f green:149/255.0f blue:0/255.0f alpha:1.0f].CGColor, - ]; - header.shouldBlend = NO; - header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/EmpoleonHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(32, 32)]]; - - UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; - [notHeader addSubview:header]; - - return notHeader; +- (UIView*)headerView { + RAHeaderView *header = [[RAHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)]; + header.colors = @[ + (id) [UIColor colorWithRed:255/255.0f green:94/255.0f blue:58/255.0f alpha:1.0f].CGColor, + (id) [UIColor colorWithRed:255/255.0f green:149/255.0f blue:0/255.0f alpha:1.0f].CGColor, + ]; + header.shouldBlend = NO; + header.image = [[RAPDFImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ReachAppSettings.bundle/EmpoleonHeader.pdf"] imageWithOptions:[RAPDFImageOptions optionsWithSize:CGSizeMake(32, 32)]]; + + UIView *notHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)]; + [notHeader addSubview:header]; + + return notHeader; } --(UIColor*) tintColor { return [UIColor colorWithRed:255/255.0f green:94/255.0f blue:58/255.0f alpha:1.0f]; } --(UIColor*) switchTintColor { return [[UISwitch alloc] init].tintColor; } --(NSString*) customTitle { return @"Empoleon"; } --(BOOL) showHeartImage { return NO; } - --(void) viewDidAppear:(BOOL)arg1 -{ - [super viewDidAppear:arg1]; - [super performSelector:@selector(setupHeader)]; + +- (UIColor*)tintColor { + return [UIColor colorWithRed:255/255.0f green:94/255.0f blue:58/255.0f alpha:1.0f]; +} + +- (UIColor*)switchTintColor { + return [[UISwitch alloc] init].tintColor; +} + +- (NSString*)customTitle { + return @"Empoleon"; +} + +- (BOOL)showHeartImage { + return NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [super performSelector:@selector(setupHeader)]; } --(NSArray*) customSpecifiers -{ - return @[ - @{ @"footerText": @"Quickly enable or disable Empoleon." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"windowedMultitaskingEnabled", - @"label": @"Enabled", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"label": @"Swipe Up From Bottom...", @"footerText": @"Launches all apps into windows rather than fullscreen." }, - @{ - @"cell": @"PSSegmentCell", - @"validTitles": @[ @"Left", @"Middle", @"Right" ], - @"validValues": @[ @(RAGrabAreaBottomLeftThird), @(RAGrabAreaBottomMiddleThird), @(RAGrabAreaBottomRightThird), ], - @"default": @(RAGrabAreaBottomLeftThird), - @"key": @"windowedMultitaskingGrabArea", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"launchIntoWindows", - @"label": @"Launch Into Window", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"If disabled, you will not be able to resize and rotate windows unless the easy-tap-mode overlay is displayed." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"alwaysEnableGestures", - @"label": @"Always Enable Gestures", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"onlyShowWindowBarIconsOnOverlay", - @"label": @"Only Show Icons in Easy-Tap-Mode", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"footerText": @"If enabled, tapping an icon on the easy-tap-mode overlay will be delayed until the bounce animation is complete." }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"windowedMultitaskingCompleteAnimations", - @"label": @"Complete Animations", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"label": @"Snapping" }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"snapWindows", - @"label": @"Snap Windows", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"default": @YES, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"snapRotation", - @"label": @"Rotation Snapping", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"showSnapHelper", - @"label": @"Show Snap Helper", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"label": @"Lock button action" }, - @{ - @"cell": @"PSSegmentCell", - @"validTitles": @[ @"Lock All Rotation", @"Lock App Rotation" ], - @"validValues": @[ @0, @1 ], - @"default": @0, - @"key": @"windowRotationLockMode", - @"defaults": @"com.efrederickson.reachapp.settings", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - - @{ @"label": @"Activator" }, - @{ - @"cell": @"PSLinkCell", - @"action": @"showActivatorAction", - @"label": @"Sort Windows Activation", - //@"enabled": objc_getClass("LAEventSettingsController") != nil, - }, - @{ - @"cell": @"PSLinkCell", - @"action": @"showActivatorAction2", - @"label": @"Easy-Tap-Mode Activation", - //@"enabled": objc_getClass("LAEventSettingsController") != nil, - }, - - /* - @{ - @"cell": @"PSSwitchCell", - @"default": @NO, - @"defaults": @"com.efrederickson.reachapp.settings", - @"key": @"openLinksInWindows", - @"label": @"Open links in windows", - @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", - }, - */ - ]; +- (NSArray*)customSpecifiers { + return @[ + @{ @"footerText": @"Quickly enable or disable Empoleon." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"windowedMultitaskingEnabled", + @"label": @"Enabled", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"label": @"Swipe Up From Bottom...", @"footerText": @"Launches all apps into windows rather than fullscreen." }, + @{ + @"cell": @"PSSegmentCell", + @"validTitles": @[ @"Left", @"Middle", @"Right" ], + @"validValues": @[ @(RAGrabAreaBottomLeftThird), @(RAGrabAreaBottomMiddleThird), @(RAGrabAreaBottomRightThird), ], + @"default": @(RAGrabAreaBottomLeftThird), + @"key": @"windowedMultitaskingGrabArea", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"launchIntoWindows", + @"label": @"Launch Into Window", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"If disabled, you will not be able to resize and rotate windows unless the easy-tap-mode overlay is displayed." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"alwaysEnableGestures", + @"label": @"Always Enable Gestures", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"onlyShowWindowBarIconsOnOverlay", + @"label": @"Only Show Icons in Easy-Tap-Mode", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"footerText": @"If enabled, tapping an icon on the easy-tap-mode overlay will be delayed until the bounce animation is complete." }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"windowedMultitaskingCompleteAnimations", + @"label": @"Complete Animations", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"label": @"Snapping" }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"snapWindows", + @"label": @"Snap Windows", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"default": @YES, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"snapRotation", + @"label": @"Rotation Snapping", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"showSnapHelper", + @"label": @"Show Snap Helper", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"label": @"Lock button action" }, + @{ + @"cell": @"PSSegmentCell", + @"validTitles": @[ @"Lock All Rotation", @"Lock App Rotation" ], + @"validValues": @[ @0, @1 ], + @"default": @0, + @"key": @"windowRotationLockMode", + @"defaults": @"com.efrederickson.reachapp.settings", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + + @{ @"label": @"Activator" }, + @{ + @"cell": @"PSLinkCell", + @"action": @"showActivatorAction", + @"label": @"Sort Windows Activation", + //@"enabled": objc_getClass("LAEventSettingsController") != nil, + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"showActivatorAction2", + @"label": @"Easy-Tap-Mode Activation", + //@"enabled": objc_getClass("LAEventSettingsController") != nil, + }, + @{ + @"cell": @"PSLinkCell", + @"action": @"showActivatorAction3", + @"label": @"Create App Window Activation", + //@"enabled": objc_getClass("LAEventSettingsController") != nil, + }, + + /* + @{ + @"cell": @"PSSwitchCell", + @"default": @NO, + @"defaults": @"com.efrederickson.reachapp.settings", + @"key": @"openLinksInWindows", + @"label": @"Open links in windows", + @"PostNotification": @"com.efrederickson.reachapp.settings/reloadSettings", + }, + */ + ]; } --(void) showActivatorAction -{ - id activator = objc_getClass("LAListenerSettingsViewController"); - if (!activator) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - } - else - { - LAListenerSettingsViewController *vc = [[objc_getClass("LAListenerSettingsViewController") alloc] init]; - vc.listenerName = @"com.efrederickson.reachapp.windowedmultitasking.sortWindows"; - [self.rootController pushViewController:vc animated:YES]; - } +- (void)showActivatorAction { + id activator = %c(LAListenerSettingsViewController); + if (!activator) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + } else { + LAListenerSettingsViewController *vc = [[%c(LAListenerSettingsViewController) alloc] init]; + vc.listenerName = @"com.efrederickson.reachapp.windowedmultitasking.sortWindows"; + [self.rootController pushController:vc animate:YES]; + } } --(void) showActivatorAction2 -{ - id activator = objc_getClass("LAListenerSettingsViewController"); - if (!activator) - { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; - } - else - { - LAListenerSettingsViewController *vc = [[objc_getClass("LAListenerSettingsViewController") alloc] init]; - vc.listenerName = @"com.efrederickson.reachapp.windowedmultitasking.toggleEditMode"; - [self.rootController pushViewController:vc animated:YES]; - } +- (void)showActivatorAction2 { + id activator = %c(LAListenerSettingsViewController); + if (!activator) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + } else { + LAListenerSettingsViewController *vc = [[%c(LAListenerSettingsViewController) alloc] init]; + vc.listenerName = @"com.efrederickson.reachapp.windowedmultitasking.toggleEditMode"; + [self.rootController pushController:vc animate:YES]; + } } -@end \ No newline at end of file + +- (void)showActivatorAction3 { + id activator = %c(LAListenerSettingsViewController); + if (!activator) { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:LOCALIZE(@"Multiplexer") message:@"Activator must be installed to use this feature." preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + } else { + LAListenerSettingsViewController *vc = [[%c(LAListenerSettingsViewController) alloc] init]; + vc.listenerName = @"com.efrederickson.reachapp.windowedmultitasking.createWindow"; + [self.rootController pushController:vc animate:YES]; + } +} +@end diff --git a/update_status b/update_status index e3c4b39..b9454df 100644 --- a/update_status +++ b/update_status @@ -3,21 +3,36 @@ update status: Windowed: working fs daemon: working SwipeOver: working (replace with native slide over(?)) -Reachability: fixed +Reachability: working (show NC broken in 10.x) GestureSupport: fixed -Backgrounding: fixed +Backgrounding: working KeyboardSupport: hackily fixed but it works now -MissionControl: initialization broken, otherwise fixed -NCApp: fixed on phone, not working right on ipad (misplaced view & no title) -assertiond hooks: unknown +MissionControl: working +NCApp: working (not tested on ipad); +assertiond hooks: working backboardd hooks: unknown fake phone mode: working - -- adding items to SBAppSwitcherModel is broken +Bugs: +- Individual app force foregrounding is broken when used in conjunction with auto (re)launch; +- Invoking keyboard in reachapp closes view (I think reachability dismisses when using KB) +- Showing NC with reachapp doesnt properly resize (not even sure if possible) +- CC inhibitor not reliable on 9.x+? +- adding items to SBAppSwitcherModel is broken (fixed now?) - SwipeOver sliding off screen animation is broken (RASwipeOverManager.xm:L62) - icons and apps do not show up in RASnapshotProvider - GestureSupport: LandscapeLeft is, once again, broken +Minor Things/Bugs to note: +- (some of these are leftover from the original release lol: eg MC lag) +- Some say it causes serious lag (probably because logs werent disabled/due to MC)? +- Startup bug still isnt fixed (apparently caused by gesture support?) +- Check iPad support/lower iOS versions + +Things to do/Features to add: +- 3D Touch actions? +- (Soon) split all 6 features into seperate tweaks +- General Code Cleanup/conform to standards, feels to messy RN (at least indents are fine) + notes: use _referenceBounds instead of bounds on UIScreen to get physical bounds. Makes landscape support easier? diff --git a/widgets/Core/RAWidgetBase.h b/widgets/Core/RAWidgetBase.h index c2f4e0f..144d0ba 100644 --- a/widgets/Core/RAWidgetBase.h +++ b/widgets/Core/RAWidgetBase.h @@ -1,9 +1,9 @@ #import "headers.h" @interface RAWidgetBase : UIView --(NSString*) identifier; --(NSString*) displayName; +- (NSString*)identifier; +- (NSString*)displayName; --(void) didAppear; --(void) didDisappear; -@end \ No newline at end of file +- (void)didAppear; +- (void)didDisappear; +@end diff --git a/widgets/Core/RAWidgetBase.xm b/widgets/Core/RAWidgetBase.xm index 4e922a5..90c04d0 100644 --- a/widgets/Core/RAWidgetBase.xm +++ b/widgets/Core/RAWidgetBase.xm @@ -1,16 +1,19 @@ #import "RAWidgetBase.h" @implementation RAWidgetBase --(NSString*) identifier { return nil; } --(NSString*) displayName { return nil; } +- (NSString*)identifier { + return nil; +} + +- (NSString*)displayName { + return nil; +} --(void) didAppear -{ +- (void)didAppear { } --(void) didDisappear -{ +- (void)didDisappear { } -@end \ No newline at end of file +@end diff --git a/widgets/Core/RAWidgetHostManager.h b/widgets/Core/RAWidgetHostManager.h index 07bcb73..792cd19 100644 --- a/widgets/Core/RAWidgetHostManager.h +++ b/widgets/Core/RAWidgetHostManager.h @@ -4,10 +4,10 @@ @interface RAWidgetHostManager : NSObject { NSMutableArray *widgets; } -+(id) sharedInstance; ++ (instancetype)sharedInstance; --(void) addWidget:(RAWidgetBase*)widget; --(void) removeWidget:(RAWidgetBase*)widget; --(void) removeWidgetWithIdentifier:(NSString*)identifier; --(RAWidgetBase*) widgetForIdentifier:(NSString*)identifier; -@end \ No newline at end of file +- (void)addWidget:(RAWidgetBase*)widget; +- (void)removeWidget:(RAWidgetBase*)widget; +- (void)removeWidgetWithIdentifier:(NSString*)identifier; +- (RAWidgetBase*)widgetForIdentifier:(NSString*)identifier; +@end diff --git a/widgets/Core/RAWidgetHostManager.xm b/widgets/Core/RAWidgetHostManager.xm index 3f3bcbf..c4731cc 100644 --- a/widgets/Core/RAWidgetHostManager.xm +++ b/widgets/Core/RAWidgetHostManager.xm @@ -1,43 +1,36 @@ #import "RAWidgetHostManager.h" @implementation RAWidgetHostManager -+(id) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE2(RAWidgetHostManager, sharedInstance->widgets = [NSMutableArray array]); } --(void) addWidget:(RAWidgetBase*)widget -{ - if ([widgets containsObject:widget] == NO) - [widgets addObject:widget]; +- (void)addWidget:(RAWidgetBase*)widget { + if ([widgets containsObject:widget]) { + return; + } + [widgets addObject:widget]; } --(void) removeWidget:(RAWidgetBase*)widget -{ +- (void)removeWidget:(RAWidgetBase*)widget { [self removeWidgetWithIdentifier:widget.identifier]; } --(void) removeWidgetWithIdentifier:(NSString*)identifier -{ - for (RAWidgetBase *w in widgets) - { - if ([w.identifier isEqual:identifier]) - { +- (void)removeWidgetWithIdentifier:(NSString*)identifier { + for (RAWidgetBase *w in widgets) { + if ([w.identifier isEqual:identifier]) { [widgets removeObject:w]; return; } } } --(RAWidgetBase*) widgetForIdentifier:(NSString*)identifier -{ - for (RAWidgetBase *w in widgets) - { - if ([w.identifier isEqual:identifier]) - { +- (RAWidgetBase*)widgetForIdentifier:(NSString*)identifier { + for (RAWidgetBase *w in widgets) { + if ([w.identifier isEqual:identifier]) { return w; } } return nil; } -@end \ No newline at end of file +@end diff --git a/widgets/Reachability/RAAllAppsWidget.xm b/widgets/Reachability/RAAllAppsWidget.xm index e4b1228..910f960 100644 --- a/widgets/Reachability/RAAllAppsWidget.xm +++ b/widgets/Reachability/RAAllAppsWidget.xm @@ -10,16 +10,27 @@ @end @implementation RAAllAppsWidget --(BOOL) enabled { return [RASettings.sharedInstance showAllAppsInWidgetSelector]; } +- (BOOL)enabled { + return [RASettings.sharedInstance showAllAppsInWidgetSelector]; +} + +- (NSInteger)sortOrder { + return 3; +} --(NSInteger) sortOrder { return 3; } +- (NSString*)displayName { + return LOCALIZE(@"ALL_APPS"); +} --(NSString*) displayName { return LOCALIZE(@"ALL_APPS"); } --(NSString*) identifier { return @"com.efrederickson.reachapp.widgets.sections.allapps"; } --(CGFloat) titleOffset { return savedX; } +- (NSString*)identifier { + return @"com.efrederickson.reachapp.widgets.sections.allapps"; +} + +- (CGFloat)titleOffset { + return savedX; +} --(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing -{ +- (UIView*)viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing { UIScrollView *allAppsView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 200)]; CGSize size = [%c(SBIconView) defaultIconSize]; @@ -40,13 +51,16 @@ allAppsView.pagingEnabled = [RASettings.sharedInstance pagingEnabled]; static NSMutableArray *allApps = nil; - if (!allApps) - { - allApps = [[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] mutableCopy]; - [allApps sortUsingComparator: ^(NSString* a, NSString* b) { - NSString *a_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:a].displayName; - NSString *b_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:b].displayName; - return [a_ caseInsensitiveCompare:b_]; + if (!allApps) { + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + allApps = [[[[%c(SBIconViewMap) homescreenMap] iconModel] visibleIconIdentifiers] mutableCopy]; + } else { + allApps = [[[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] visibleIconIdentifiers] mutableCopy]; + } + [allApps sortUsingComparator: ^(NSString* a, NSString* b) { + NSString *a_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:a].displayName; + NSString *b_ = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:b].displayName; + return [a_ caseInsensitiveCompare:b_]; }]; //[allApps removeObject:currentBundleIdentifier]; } @@ -54,23 +68,26 @@ isTop = YES; intervalCount = 1; hasSecondRow = NO; - for (NSString *str in allApps) - { + for (NSString *str in allApps) { app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:str]; - SBIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; - SBIconView *iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - if (!iconView || [icon isKindOfClass:[%c(SBApplicationIcon) class]] == NO) - continue; - - if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) - { - if (isTop) - { + SBApplicationIcon *icon = nil; + SBIconView *iconView = nil; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + } else { + icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] _iconViewForIcon:icon]; + } + if (!iconView || ![icon isKindOfClass:[%c(SBApplicationIcon) class]]) { + continue; + } + + if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) { + if (isTop) { contentSize.height += size.height + 10; contentSize.width -= interval; - } - else - { + } else { intervalCount++; contentSize.height -= (size.height + 10); width += interval; @@ -79,15 +96,15 @@ isTop = !isTop; } - iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); - iconView.tag = app.pid; - iconView.restorationIdentifier = app.bundleIdentifier; - UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; - [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; + iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); + iconView.tag = app.pid; + iconView.restorationIdentifier = app.bundleIdentifier; + UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; + [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; - [allAppsView addSubview:iconView]; + [allAppsView addSubview:iconView]; - contentSize.width += iconView.frame.size.width + spacing; + contentSize.width += iconView.frame.size.width + spacing; } contentSize.width = width; contentSize.height = 10 + ((size.height + 10) * (hasSecondRow ? 2 : 1)); @@ -98,15 +115,13 @@ return allAppsView; } --(void) appViewItemTap:(UIGestureRecognizer*)gesture -{ +- (void)appViewItemTap:(UIGestureRecognizer*)gesture { [GET_SBWORKSPACE appViewItemTap:gesture]; //[[RAReachabilityManager sharedInstance] launchTopAppWithIdentifier:gesture.view.restorationIdentifier]; } @end -%ctor -{ +%ctor { static id _widget = [[RAAllAppsWidget alloc] init]; [RAWidgetSectionManager.sharedInstance registerSection:_widget]; -} \ No newline at end of file +} diff --git a/widgets/Reachability/RADefaultWidgetSection.h b/widgets/Reachability/RADefaultWidgetSection.h index cac3d36..7ebaff4 100644 --- a/widgets/Reachability/RADefaultWidgetSection.h +++ b/widgets/Reachability/RADefaultWidgetSection.h @@ -2,5 +2,5 @@ #import "RAWidget.h" @interface RADefaultWidgetSection : RAWidgetSection -+(id) sharedDefaultWidgetSection; -@end \ No newline at end of file ++ (instancetype)sharedDefaultWidgetSection; +@end diff --git a/widgets/Reachability/RADefaultWidgetSection.mm b/widgets/Reachability/RADefaultWidgetSection.mm index 1a686db..76dd71c 100644 --- a/widgets/Reachability/RADefaultWidgetSection.mm +++ b/widgets/Reachability/RADefaultWidgetSection.mm @@ -4,24 +4,20 @@ #import "headers.h" @implementation RADefaultWidgetSection -+(id) sharedDefaultWidgetSection -{ ++ (instancetype)sharedDefaultWidgetSection { SHARED_INSTANCE2(RADefaultWidgetSection, [[RAWidgetSectionManager sharedInstance] registerSection:sharedInstance]); } --(NSString*) displayName -{ +- (NSString*)displayName { return LOCALIZE(@"WIDGETS"); } --(NSString*) identifier -{ +- (NSString*)identifier { return @"com.efrederickson.reachapp.widgets.sections.default"; } @end -static __attribute__((constructor)) void cant_believe_i_forgot_this_before() -{ +static __attribute__((constructor)) void cant_believe_i_forgot_this_before() { static id _widget = [RADefaultWidgetSection sharedDefaultWidgetSection]; [RAWidgetSectionManager.sharedInstance registerSection:_widget]; -} \ No newline at end of file +} diff --git a/widgets/Reachability/RAFavoriteAppsWidget.xm b/widgets/Reachability/RAFavoriteAppsWidget.xm index 3678f27..9148451 100644 --- a/widgets/Reachability/RAFavoriteAppsWidget.xm +++ b/widgets/Reachability/RAFavoriteAppsWidget.xm @@ -10,21 +10,34 @@ @end @implementation RAFavoriteAppsWidget --(BOOL) enabled { return [RASettings.sharedInstance showFavorites]; } +- (BOOL)enabled { + return [RASettings.sharedInstance showFavorites]; +} + +- (NSInteger)sortOrder { + return 2; +} + +- (NSString*)displayName { + return LOCALIZE(@"FAVORITES"); +} + +- (NSString*)identifier { + return @"com.efrederickson.reachapp.widgets.sections.favoriteapps"; +} --(NSInteger) sortOrder { return 2; } --(NSString*) displayName { return LOCALIZE(@"FAVORITES"); } --(NSString*) identifier { return @"com.efrederickson.reachapp.widgets.sections.favoriteapps"; } --(CGFloat) titleOffset { return savedX; } +- (CGFloat)titleOffset { + return savedX; +} --(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing -{ +- (UIView*)viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing { CGSize size = [%c(SBIconView) defaultIconSize]; spacing = (frame.size.width - (iconsPerLine * size.width)) / iconsPerLine; NSString *currentBundleIdentifier = [[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier; - if (!currentBundleIdentifier) + if (!currentBundleIdentifier) { return nil; - CGSize contentSize = CGSizeMake(spacing / 2.0, 10); + } + CGSize contentSize = CGSizeMake((spacing / 2.0), 10); CGFloat interval = (size.width + spacing) * iconsPerLine; NSInteger intervalCount = 1; BOOL isTop = YES; @@ -35,29 +48,33 @@ NSMutableArray *favorites = [RASettings.sharedInstance favoriteApps]; [favorites removeObject:currentBundleIdentifier]; - if (favorites.count == 0) + if (favorites.count == 0) { return nil; + } UIScrollView *favoritesView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 200)]; favoritesView.backgroundColor = [UIColor clearColor]; favoritesView.pagingEnabled = [RASettings.sharedInstance pagingEnabled]; - for (NSString *str in favorites) - { + for (NSString *str in favorites) { app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:str]; - SBIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; - SBIconView *iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - if (!iconView) - continue; - - if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) - { - if (isTop) - { + SBApplicationIcon *icon = nil; + SBIconView *iconView = nil; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + } else { + icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] _iconViewForIcon:icon]; + } + if (!iconView) { + continue; + } + + if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) { + if (isTop) { contentSize.height += size.height + 10; contentSize.width -= interval; - } - else - { + } else { intervalCount++; contentSize.height -= (size.height + 10); width += interval; @@ -66,16 +83,16 @@ isTop = !isTop; } - iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); + iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); - iconView.tag = app.pid; - iconView.restorationIdentifier = app.bundleIdentifier; - UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; - [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; + iconView.tag = app.pid; + iconView.restorationIdentifier = app.bundleIdentifier; + UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; + [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; - [favoritesView addSubview:iconView]; + [favoritesView addSubview:iconView]; - contentSize.width += iconView.frame.size.width + spacing; + contentSize.width += iconView.frame.size.width + spacing; } contentSize.width = width; contentSize.height = 10 + ((size.height + 10) * (hasSecondRow ? 2 : 1)); @@ -86,15 +103,13 @@ return favoritesView; } --(void) appViewItemTap:(UIGestureRecognizer*)gesture -{ +- (void)appViewItemTap:(UIGestureRecognizer*)gesture { [GET_SBWORKSPACE appViewItemTap:gesture]; //[[RAReachabilityManager sharedInstance] launchTopAppWithIdentifier:gesture.view.restorationIdentifier]; } @end -%ctor -{ +%ctor { static id _widget = [[RAFavoriteAppsWidget alloc] init]; [RAWidgetSectionManager.sharedInstance registerSection:_widget]; -} \ No newline at end of file +} diff --git a/widgets/Reachability/RARecentAppsWidget.xm b/widgets/Reachability/RARecentAppsWidget.xm index 19da1a3..3c56407 100644 --- a/widgets/Reachability/RARecentAppsWidget.xm +++ b/widgets/Reachability/RARecentAppsWidget.xm @@ -15,21 +15,34 @@ @end @implementation RARecentAppsWidget --(BOOL) enabled { return [RASettings.sharedInstance showRecentAppsInWidgetSelector]; } +- (BOOL)enabled { + return [RASettings.sharedInstance showRecentAppsInWidgetSelector]; +} + +- (NSInteger)sortOrder { + return 1; +} + +- (NSString*)displayName { + return LOCALIZE(@"RECENTS"); +} + +- (NSString*)identifier { + return @"com.efrederickson.reachapp.widgets.sections.recentapps"; +} --(NSInteger) sortOrder { return 1; } --(NSString*) displayName { return LOCALIZE(@"RECENTS"); } --(NSString*) identifier { return @"com.efrederickson.reachapp.widgets.sections.recentapps"; } --(CGFloat) titleOffset { return savedX; } +- (CGFloat)titleOffset { + return savedX; +} --(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing -{ +- (UIView*)viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size_ iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing { viewFrame = frame; CGSize size = [%c(SBIconView) defaultIconSize]; spacing = (frame.size.width - (iconsPerLine * size.width)) / (iconsPerLine + 0); NSString *currentBundleIdentifier = [[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier; - if (!currentBundleIdentifier) + if (!currentBundleIdentifier) { return nil; + } CGSize contentSize = CGSizeMake((spacing / 2.0), 10); CGFloat interval = ((size.width + spacing) * iconsPerLine); NSInteger intervalCount = 1; @@ -41,8 +54,9 @@ NSMutableArray *recents = [[RAAppSwitcherModelWrapper appSwitcherAppIdentiferList] mutableCopy]; [recents removeObject:currentBundleIdentifier]; - if (recents.count == 0) + if (recents.count == 0) { return nil; + } BOOL hasSecondRow = recents.count >= iconsPerLine; @@ -50,23 +64,26 @@ recentsView.backgroundColor = [UIColor clearColor]; recentsView.pagingEnabled = [RASettings.sharedInstance pagingEnabled]; - for (NSString *str in recents) - { + for (NSString *str in recents) { app = [[%c(SBApplicationController) sharedInstance] applicationWithBundleIdentifier:str]; - SBIcon *icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; - SBIconView *iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; - if (!iconView) - continue; - - if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) - { - if (isTop) - { + SBApplicationIcon *icon = nil; + SBIconView *iconView = nil; + if ([%c(SBIconViewMap) respondsToSelector:@selector(homescreenMap)]) { + icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[%c(SBIconViewMap) homescreenMap] _iconViewForIcon:icon]; + } else { + icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] applicationIconForBundleIdentifier:app.bundleIdentifier]; + iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] _iconViewForIcon:icon]; + } + if (!iconView) { + continue; + } + + if (interval != 0 && contentSize.width + iconView.frame.size.width > interval * intervalCount) { + if (isTop) { contentSize.height += size.height + 10; contentSize.width -= interval; - } - else - { + } else { intervalCount++; contentSize.height -= (size.height + 10); width += interval; @@ -74,16 +91,16 @@ isTop = !isTop; } - iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); + iconView.frame = CGRectMake(contentSize.width, contentSize.height, iconView.frame.size.width, iconView.frame.size.height); - iconView.tag = index++; - iconView.restorationIdentifier = app.bundleIdentifier; - UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; - [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; + iconView.tag = index++; + iconView.restorationIdentifier = app.bundleIdentifier; + UITapGestureRecognizer *iconViewTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(appViewItemTap:)]; + [iconView addGestureRecognizer:iconViewTapGestureRecognizer]; - [recentsView addSubview:iconView]; + [recentsView addSubview:iconView]; - contentSize.width += iconView.frame.size.width + spacing; + contentSize.width += iconView.frame.size.width + spacing; } contentSize.width = width; contentSize.height = 10 + ((size.height + 10) * (hasSecondRow ? 2 : 1)); @@ -94,11 +111,10 @@ return recentsView; } --(void) appViewItemTap:(UIGestureRecognizer*)gesture -{ +- (void)appViewItemTap:(UIGestureRecognizer*)gesture { @autoreleasepool { //[[%c(SBWorkspace) sharedInstance] appViewItemTap:gesture]; - + RAAppSliderProvider *provider = [[RAAppSliderProvider alloc] init]; provider.availableIdentifiers = [[RAAppSwitcherModelWrapper appSwitcherAppIdentiferList] mutableCopy]; [((NSMutableArray*)provider.availableIdentifiers) removeObject:[[UIApplication sharedApplication] _accessibilityFrontMostApplication].bundleIdentifier]; @@ -113,8 +129,7 @@ } @end -%ctor -{ +%ctor { static id _widget = [[RARecentAppsWidget alloc] init]; [RAWidgetSectionManager.sharedInstance registerSection:_widget]; -} \ No newline at end of file +} diff --git a/widgets/Reachability/RAWidget.h b/widgets/Reachability/RAWidget.h index f0f1b27..6929a82 100644 --- a/widgets/Reachability/RAWidget.h +++ b/widgets/Reachability/RAWidget.h @@ -2,13 +2,13 @@ @interface RAWidget : NSObject --(NSString*) identifier; +- (NSString*)identifier; // actual view for showing in Reachability --(UIView*) view; +- (UIView*)view; // Similar to an app icon with the image/title --(UIView*) iconForSize:(CGSize)size; +- (UIView*)iconForSize:(CGSize)size; --(CGFloat) preferredHeight; -@end \ No newline at end of file +- (CGFloat)preferredHeight; +@end diff --git a/widgets/Reachability/RAWidget.mm b/widgets/Reachability/RAWidget.mm index 608b2c1..3f24a0a 100644 --- a/widgets/Reachability/RAWidget.mm +++ b/widgets/Reachability/RAWidget.mm @@ -2,23 +2,19 @@ @implementation RAWidget --(NSString*)identifier -{ +- (NSString*)identifier { @throw @"This is an abstract method and must be overriden"; } --(UIView*) view -{ +- (UIView*)view { @throw @"This is an abstract method and must be overriden"; } --(UIView*) iconForSize:(CGSize)size -{ +- (UIView*)iconForSize:(CGSize)size { @throw @"This is an abstract method and must be overriden"; } --(CGFloat) preferredHeight -{ +- (CGFloat)preferredHeight { return self.view.frame.size.height; } -@end \ No newline at end of file +@end diff --git a/widgets/Reachability/RAWidgetSection.h b/widgets/Reachability/RAWidgetSection.h index ea7cd34..afd7dac 100644 --- a/widgets/Reachability/RAWidgetSection.h +++ b/widgets/Reachability/RAWidgetSection.h @@ -5,17 +5,17 @@ NSMutableArray *_widgets; } --(BOOL) enabled; +- (BOOL)enabled; --(NSInteger) sortOrder; --(BOOL) showTitle; --(NSString*) displayName; --(NSString*) identifier; --(CGFloat) titleOffset; +- (NSInteger)sortOrder; +- (BOOL)showTitle; +- (NSString*)displayName; +- (NSString*)identifier; +- (CGFloat)titleOffset; -// The view should cache, if possible, to speed up loading times. -// It should NOT show the title view. --(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing; +// The view should cache, if possible, to speed up loading times. +// It should NOT show the title view. +- (UIView*)viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing; --(void) addWidget:(RAWidget*)widget; -@end \ No newline at end of file +- (void)addWidget:(RAWidget*)widget; +@end diff --git a/widgets/Reachability/RAWidgetSection.mm b/widgets/Reachability/RAWidgetSection.mm index 0fa7bef..8977b60 100644 --- a/widgets/Reachability/RAWidgetSection.mm +++ b/widgets/Reachability/RAWidgetSection.mm @@ -3,43 +3,43 @@ @implementation RAWidgetSection --(id) init -{ - if (self = [super init]) - { +- (instancetype)init { + if (self = [super init]) { _widgets = [NSMutableArray array]; } return self; } --(BOOL) enabled { return _widgets.count > 0; } --(BOOL) showTitle { return YES; } +- (BOOL)enabled { + return _widgets.count > 0; +} + +- (BOOL)showTitle { + return YES; +} --(NSInteger) sortOrder { return 10; } +- (NSInteger)sortOrder { + return 10; +} --(NSString*) displayName -{ - @throw @"This is an abstract method and should be overriden."; +- (NSString*)displayName { + @throw @"This is an abstract method and should be overriden."; } --(NSString*) identifier -{ +- (NSString*)identifier { @throw @"This is an abstract method and should be overriden."; } --(void) addWidget:(RAWidget*)widget -{ +- (void)addWidget:(RAWidget*)widget { [_widgets addObject:widget]; } --(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing -{ +- (UIView*)viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing { UIView *view = [[UIView alloc] initWithFrame:frame]; view.userInteractionEnabled = YES; CGPoint origin = CGPointMake(10, 10); - for (NSInteger index = 0; index < _widgets.count; index++) - { + for (NSInteger index = 0; index < _widgets.count; index++) { RAWidget *widget = _widgets[index]; UIView *subView = [widget iconForSize:size]; @@ -61,14 +61,12 @@ -(UIView*) viewForFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFi return view; } --(void) widgetIconTap:(UITapGestureRecognizer*)gesture -{ +- (void)widgetIconTap:(UITapGestureRecognizer*)gesture { NSInteger widgetIndex = gesture.view.tag; [[RAReachabilityManager sharedInstance] launchWidget:_widgets[widgetIndex]]; } --(CGFloat) titleOffset -{ +- (CGFloat)titleOffset { return 10; } -@end \ No newline at end of file +@end diff --git a/widgets/Reachability/RAWidgetSectionManager.h b/widgets/Reachability/RAWidgetSectionManager.h index fecb99d..8a3b243 100644 --- a/widgets/Reachability/RAWidgetSectionManager.h +++ b/widgets/Reachability/RAWidgetSectionManager.h @@ -5,12 +5,12 @@ NSMutableDictionary *_sections; } -+(instancetype) sharedInstance; ++ (instancetype)sharedInstance; --(void) registerSection:(RAWidgetSection*)section; +- (void)registerSection:(RAWidgetSection*)section; --(NSArray*) sections; --(NSArray*) enabledSections; +- (NSArray*)sections; +- (NSArray*)enabledSections; --(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing; -@end \ No newline at end of file +- (UIView*)createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIconSize:(CGSize)size iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing; +@end diff --git a/widgets/Reachability/RAWidgetSectionManager.mm b/widgets/Reachability/RAWidgetSectionManager.mm index 9d8e634..fbee16f 100644 --- a/widgets/Reachability/RAWidgetSectionManager.mm +++ b/widgets/Reachability/RAWidgetSectionManager.mm @@ -6,63 +6,59 @@ @implementation RAWidgetSectionManager -+(instancetype) sharedInstance -{ ++ (instancetype)sharedInstance { SHARED_INSTANCE(RAWidgetSectionManager); } --(id) init -{ - if (self = [super init]) - { +- (instancetype)init { + if (self = [super init]) { _sections = [NSMutableDictionary dictionary]; } return self; } --(void) registerSection:(RAWidgetSection*)section -{ - if (!section || !section.identifier) +- (void)registerSection:(RAWidgetSection*)section { + if (!section || !section.identifier) { return; - if ([_sections.allKeys containsObject:section.identifier]) + } + if ([_sections.allKeys containsObject:section.identifier]) { return; + } //NSLog(@"[ReachApp] registering section %@", section.identifier); _sections[section.identifier] = section; } --(NSArray*) sections -{ +- (NSArray*)sections { return _sections.allValues; } --(NSArray*) enabledSections -{ +- (NSArray*)enabledSections { NSMutableArray *arr = [NSMutableArray array]; - for (RAWidgetSection* section in _sections.allValues) - { - if ([section enabled]) + for (RAWidgetSection* section in _sections.allValues) { + if ([section enabled]) { [arr addObject:section]; + } } //[arr sortUsingComparator:^(RAWidgetSection *a, RAWidgetSection *b) { // return [@(a.sortOrder) compare:@(b.sortOrder)]; //}]; - + [arr sortUsingComparator:^NSComparisonResult(RAWidgetSection *a, RAWidgetSection *b) { - if (a.sortOrder < b.sortOrder) + if (a.sortOrder < b.sortOrder) { return NSOrderedAscending; - else if (a.sortOrder > b.sortOrder) + } else if (a.sortOrder > b.sortOrder) { return NSOrderedDescending; - else + } else { return NSOrderedSame; + } }]; return arr; } --(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIconSize:(CGSize)iconSize iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing -{ +- (UIView*)createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIconSize:(CGSize)iconSize iconsThatFitPerLine:(NSInteger)iconsPerLine spacing:(CGFloat)spacing { // vertical scroll view? UIView *view = [[UIView alloc] initWithFrame:frame]; view.backgroundColor = [UIColor clearColor]; @@ -71,17 +67,14 @@ -(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIcon CGFloat currentY = VERTICAL_PADDING; - for (RAWidgetSection* section in [self enabledSections]) - { - if (section.enabled == NO) + for (RAWidgetSection* section in [self enabledSections]) { + if (!section.enabled) { continue; - @try - { + } + @try { UIView *sectionView = [section viewForFrame:CGRectMake(0, currentY, view.frame.size.width, iconSize.height + VERTICAL_PADDING) preferredIconSize:iconSize iconsThatFitPerLine:iconsPerLine spacing:spacing]; - if (sectionView) - { - if (section.showTitle) - { + if (sectionView) { + if (section.showTitle) { CGFloat x = [section respondsToSelector:@selector(titleOffset)] ? section.titleOffset : 10; UILabel *titleView = [[UILabel alloc] initWithFrame:CGRectMake(x, currentY, 300, 20)]; titleView.text = section.displayName; @@ -91,7 +84,7 @@ -(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIcon [view addSubview:titleView]; currentY += titleView.frame.size.height + VERTICAL_PADDING; } - + //sectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; sectionView.backgroundColor = [UIColor clearColor]; sectionView.clipsToBounds = YES; @@ -106,9 +99,8 @@ -(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIcon [view addSubview:sectionView]; } } - @catch (NSException *ex) - { - NSLog(@"[ReachApp] an error occurred creating the view for section '%@': %@", section.identifier, ex); + @catch (NSException *ex) { + LogError(@"[ReachApp] an error occurred creating the view for section '%@': %@", section.identifier, ex); } } @@ -119,4 +111,4 @@ -(UIView*) createViewForEnabledSectionsWithBaseFrame:(CGRect)frame preferredIcon return view; } -@end \ No newline at end of file +@end