├── ScreenshotXI.plist ├── README.md ├── Resources ├── redo@2x.png ├── redo@3x.png ├── save@2x.png ├── save@3x.png ├── undo@2x.png ├── undo@3x.png ├── close@2x.png ├── close@3x.png ├── share@2x.png └── share@3x.png ├── screenshotxi ├── Resources │ ├── icon@2x.png │ ├── icon@3x.png │ └── Info.plist ├── SXIConfigurationListController.h ├── SXIAppearanceListController.h ├── SXIPriorityListController.h ├── SXISliderCell.h ├── SXIRootListController.h ├── entry.plist ├── Makefile ├── SXISliderCell.xm ├── SXIPriorityListController.xm ├── SXIRootListController.xm ├── SXIAppearanceListController.xm └── SXIConfigurationListController.xm ├── control ├── Makefile ├── ESSWindow.xm ├── ESSContainerView.xm ├── SXIPreferences.xm ├── headers.h ├── Tweak.xm └── ESSController.xm /ScreenshotXI.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScreenshotXI 2 | Bring iOS 11 style screenshotting to iOS 9 and 10 devices. 3 | -------------------------------------------------------------------------------- /Resources/redo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/redo@2x.png -------------------------------------------------------------------------------- /Resources/redo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/redo@3x.png -------------------------------------------------------------------------------- /Resources/save@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/save@2x.png -------------------------------------------------------------------------------- /Resources/save@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/save@3x.png -------------------------------------------------------------------------------- /Resources/undo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/undo@2x.png -------------------------------------------------------------------------------- /Resources/undo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/undo@3x.png -------------------------------------------------------------------------------- /Resources/close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/close@2x.png -------------------------------------------------------------------------------- /Resources/close@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/close@3x.png -------------------------------------------------------------------------------- /Resources/share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/share@2x.png -------------------------------------------------------------------------------- /Resources/share@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/Resources/share@3x.png -------------------------------------------------------------------------------- /screenshotxi/Resources/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/screenshotxi/Resources/icon@2x.png -------------------------------------------------------------------------------- /screenshotxi/Resources/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DGh0st/ScreenshotXI/HEAD/screenshotxi/Resources/icon@3x.png -------------------------------------------------------------------------------- /screenshotxi/SXIConfigurationListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface SXIConfigurationListController : PSListController 5 | 6 | @end -------------------------------------------------------------------------------- /screenshotxi/SXIAppearanceListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // needed for libcolorpicker 5 | @interface PSListController (Private) 6 | -(void)clearCache; 7 | -(void)reload; 8 | @end 9 | 10 | @interface SXIAppearanceListController : PSListController 11 | 12 | @end -------------------------------------------------------------------------------- /screenshotxi/SXIPriorityListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface SXIPriorityListController : PSViewController 5 | @property (nonatomic, strong) UITableView *tableView; 6 | @property (nonatomic, strong) NSMutableArray *currentPriority; 7 | @end -------------------------------------------------------------------------------- /screenshotxi/SXISliderCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface PSRootController 5 | +(void)setPreferenceValue:(id)value specifier:(id)specifier; 6 | @end 7 | 8 | @interface SXISliderCell : PSSliderTableCell 9 | -(void)presentAlert; 10 | @end -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.dgh0st.screenshotxi 2 | Name: ScreenshotXI 3 | Depends: mobilesubstrate, preferenceloader, org.thebigboss.libcolorpicker 4 | Version: 1.0 5 | Architecture: iphoneos-arm 6 | Description: iOS 11 screenshot feature on older iOS versions 7 | Maintainer: DGh0st 8 | Author: DGh0st 9 | Section: Tweaks 10 | -------------------------------------------------------------------------------- /screenshotxi/SXIRootListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface SXIRootListController : PSListController 6 | 7 | @end 8 | 9 | 10 | @interface UIImage (SXIPrivate) 11 | +(UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier format:(NSInteger)format scale:(CGFloat)scale; 12 | @end -------------------------------------------------------------------------------- /screenshotxi/entry.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | ScreenshotXI 9 | cell 10 | PSLinkCell 11 | detail 12 | SXIRootListController 13 | icon 14 | icon.png 15 | isController 16 | 17 | label 18 | ScreenshotXI 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /screenshotxi/Makefile: -------------------------------------------------------------------------------- 1 | export TARGET = iphone:clang:8.1:latest 2 | 3 | include $(THEOS)/makefiles/common.mk 4 | 5 | BUNDLE_NAME = ScreenshotXI 6 | ScreenshotXI_FILES = $(wildcard *.xm) 7 | ScreenshotXI_INSTALL_PATH = /Library/PreferenceBundles 8 | ScreenshotXI_FRAMEWORKS = UIKit MessageUI 9 | ScreenshotXI_PRIVATE_FRAMEWORKS = Preferences 10 | ScreenshotXI_LIBRARIES = colorpicker 11 | 12 | include $(THEOS_MAKE_PATH)/bundle.mk 13 | 14 | internal-stage:: 15 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 16 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/ScreenshotXI.plist$(ECHO_END) 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export ARCHS = armv7 arm64 2 | export TARGET = iphone:clang:9.3:latest 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | TWEAK_NAME = ScreenshotXI 7 | ScreenshotXI_FILES = $(wildcard *.xm) 8 | ScreenshotXI_FRAMEWORKS = UIKit CoreGraphics QuartzCore Photos 9 | ScreenshotXI_PRIVATE_FRAMEWORKS = PhotoLibrary MarkupUI AudioToolbox 10 | ScreenshotXI_LIBRARIES = colorpicker 11 | 12 | include $(THEOS_MAKE_PATH)/tweak.mk 13 | 14 | BUNDLE_NAME = ImageAssets 15 | ImageAssets_INSTALL_PATH = /Library/Application Support/ScreenshotXI 16 | 17 | include $(THEOS_MAKE_PATH)/bundle.mk 18 | 19 | after-install:: 20 | install.exec "killall -9 SpringBoard" 21 | SUBPROJECTS += screenshotxi 22 | include $(THEOS_MAKE_PATH)/aggregate.mk 23 | -------------------------------------------------------------------------------- /screenshotxi/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ScreenshotXI 9 | CFBundleIdentifier 10 | com.dgh0st.screenshotxi 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | NSPrincipalClass 22 | SXIRootListController 23 | 24 | 25 | -------------------------------------------------------------------------------- /ESSWindow.xm: -------------------------------------------------------------------------------- 1 | #import "headers.h" 2 | 3 | @implementation ESSWindow 4 | -(id)initWithFrame:(CGRect)frame { 5 | self = [super initWithFrame:frame]; 6 | if (self != nil) { 7 | self.windowLevel = [SXIPreferences sharedInstance].currentTweakLevel; 8 | [self _setSecure:YES]; // make it work on lockscreen as well 9 | self.rootViewController = [[ESSController alloc] init]; 10 | self.rootViewController.view.frame = frame; 11 | self.opaque = NO; 12 | self.hidden = NO; 13 | self.clipsToBounds = YES; 14 | self.layer.masksToBounds = YES; 15 | } 16 | return self; 17 | } 18 | 19 | -(void)dealloc { 20 | [self.rootViewController release]; 21 | [super dealloc]; 22 | } 23 | 24 | -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // to make touches pass through 25 | ESSController *viewController = (ESSController *)(self.rootViewController); 26 | UIView *result = [super hitTest:point withEvent:event]; 27 | if ([viewController presentedViewController] == nil) { 28 | for (ESSContainerView *view in viewController.containerViews) 29 | if (CGRectContainsPoint(view.frame, point)) 30 | return result; 31 | return nil; 32 | } else { 33 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 34 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 35 | return result; 36 | } 37 | } 38 | @end -------------------------------------------------------------------------------- /screenshotxi/SXISliderCell.xm: -------------------------------------------------------------------------------- 1 | #import "SXISliderCell.h" 2 | 3 | @implementation SXISliderCell 4 | 5 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)identifier specifier:(PSSpecifier *)specifier { 6 | self = [super initWithStyle:style reuseIdentifier:identifier specifier:specifier]; 7 | if (self != nil) { 8 | CGRect frame = [self frame]; 9 | UIButton *alertButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 10 | alertButton.frame = CGRectMake(frame.size.width - 50, 0, 50, frame.size.height); 11 | alertButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; 12 | [alertButton setTitle:@"" forState:UIControlStateNormal]; 13 | [alertButton addTarget:self action:@selector(presentAlert) forControlEvents:UIControlEventTouchUpInside]; 14 | [self addSubview:alertButton]; 15 | } 16 | return self; 17 | } 18 | 19 | - (void)presentAlert { 20 | NSString *rangeString = [NSString stringWithFormat:@"Please enter a value between %.2f and %.2f", [[self.specifier propertyForKey:@"min"] floatValue], [[self.specifier propertyForKey:@"max"] floatValue]]; 21 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:self.specifier.name message:rangeString delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Enter", nil]; 22 | alert.alertViewStyle = UIAlertViewStylePlainTextInput; 23 | alert.tag = 342879; 24 | [alert show]; 25 | 26 | [[alert textFieldAtIndex:0] setDelegate:self]; 27 | [[alert textFieldAtIndex:0] resignFirstResponder]; 28 | [[alert textFieldAtIndex:0] setKeyboardType:UIKeyboardTypeDecimalPad]; 29 | [[alert textFieldAtIndex:0] becomeFirstResponder]; 30 | [alert release]; 31 | } 32 | 33 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 34 | if (alertView.tag == 342879 && buttonIndex == 1) { 35 | CGFloat value = [[alertView textFieldAtIndex:0].text floatValue]; 36 | [[alertView textFieldAtIndex:0] resignFirstResponder]; 37 | 38 | if (value <= [[self.specifier propertyForKey:@"max"] floatValue] && value >= [[self.specifier propertyForKey:@"min"] floatValue]) { 39 | [self setValue:[NSNumber numberWithFloat:value]]; 40 | [PSRootController setPreferenceValue:[NSNumber numberWithFloat:value] specifier:self.specifier]; 41 | } else { 42 | UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"The value entered is not valid. Try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; 43 | errorAlert.tag = 85230234; 44 | [errorAlert show]; 45 | [errorAlert release]; 46 | } 47 | } else if (alertView.tag == 85230234) { 48 | [self presentAlert]; 49 | } 50 | } 51 | 52 | @end -------------------------------------------------------------------------------- /ESSContainerView.xm: -------------------------------------------------------------------------------- 1 | #import "headers.h" 2 | 3 | extern ESSWindow *window; 4 | 5 | @implementation ESSContainerView 6 | -(id)initWithFrame:(CGRect)frame withColor:(UIColor *)color { 7 | self = [super initWithFrame:frame]; 8 | if (self != nil) { 9 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 10 | 11 | self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin; 12 | self.layer.cornerRadius = 0.0; 13 | self.layer.borderColor = color.CGColor; 14 | self.layer.borderWidth = preferenceManager.miniImageWhitePadding; 15 | self.layer.masksToBounds = YES; 16 | self.backgroundColor = color; 17 | self.clipsToBounds = YES; 18 | self.center = CGPointMake(window.frame.size.width / 2, window.frame.size.height / 2); 19 | [self setTransform:CGAffineTransformMakeScale(1 / preferenceManager.miniImageScale, 1 / preferenceManager.miniImageScale)]; 20 | 21 | // corner radius animation 22 | CABasicAnimation *cornerRadiusAnimation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"]; 23 | cornerRadiusAnimation.duration = preferenceManager.animationSpeed; 24 | cornerRadiusAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 25 | cornerRadiusAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 26 | cornerRadiusAnimation.toValue = [NSNumber numberWithFloat:preferenceManager.miniImageRoundness]; 27 | cornerRadiusAnimation.fillMode = kCAFillModeForwards; 28 | cornerRadiusAnimation.removedOnCompletion = NO; 29 | [self.layer addAnimation:cornerRadiusAnimation forKey:@"setCornerRadius"]; 30 | 31 | self.image = nil; 32 | _color = color; 33 | } 34 | return self; 35 | } 36 | 37 | -(void)dealloc { 38 | [self.layer removeAnimationForKey:@"setCornerRadius"]; 39 | [self.layer removeAnimationForKey:@"setBorderColor"]; 40 | self.image = nil; 41 | if (_color != nil) 42 | [_color release]; 43 | _color = nil; 44 | [super dealloc]; 45 | } 46 | 47 | -(void)highlightViewWithCompletion:(id)completion { 48 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 49 | 50 | [self.layer removeAnimationForKey:@"setBorderColor"]; 51 | 52 | // border color animation 53 | CABasicAnimation *borderColorAnimation = [CABasicAnimation animationWithKeyPath:@"borderColor"]; 54 | borderColorAnimation.duration = preferenceManager.previewAnimationSpeed; 55 | borderColorAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 56 | borderColorAnimation.fromValue = (id)_color.CGColor; 57 | borderColorAnimation.toValue = (id)[_color colorWithAlphaComponent:preferenceManager.previewAlpha].CGColor; 58 | borderColorAnimation.fillMode = kCAFillModeForwards; 59 | borderColorAnimation.removedOnCompletion = YES; 60 | [self.layer addAnimation:borderColorAnimation forKey:@"setBorderColor"]; 61 | 62 | [UIView animateWithDuration:preferenceManager.previewAnimationSpeed animations:^{ 63 | self.layer.borderColor = [_color colorWithAlphaComponent:preferenceManager.previewAlpha].CGColor; // I don't think this value matters because CABasicAnimation takes care of it 64 | self.backgroundColor = [_color colorWithAlphaComponent:preferenceManager.previewAlpha]; 65 | [self setTransform:CGAffineTransformMakeScale(preferenceManager.previewScale, preferenceManager.previewScale)]; 66 | } completion:completion]; 67 | } 68 | 69 | -(void)unhighlightViewWithCompletion:(id)completion { 70 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 71 | 72 | [self.layer removeAnimationForKey:@"setBorderColor"]; 73 | 74 | // border color animation 75 | CABasicAnimation *borderColorAnimation = [CABasicAnimation animationWithKeyPath:@"borderColor"]; 76 | borderColorAnimation.duration = preferenceManager.previewAnimationSpeed; 77 | borderColorAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 78 | borderColorAnimation.fromValue = (id)[_color colorWithAlphaComponent:preferenceManager.previewAlpha].CGColor; 79 | borderColorAnimation.toValue = (id)_color.CGColor; 80 | borderColorAnimation.fillMode = kCAFillModeForwards; 81 | borderColorAnimation.removedOnCompletion = YES; 82 | [self.layer addAnimation:borderColorAnimation forKey:@"setBorderColor"]; 83 | 84 | [UIView animateWithDuration:preferenceManager.previewAnimationSpeed animations:^{ 85 | self.layer.borderColor = _color.CGColor; // I don't think this value matters because CABasicAnimation takes care of it 86 | self.backgroundColor = _color; 87 | [self setTransform:CGAffineTransformMakeScale(1, 1)]; 88 | } completion:completion]; 89 | } 90 | 91 | // Code stolen from one of the answers to https://stackoverflow.com/questions/3844557/uiview-shake-animation 92 | -(void)shake { 93 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 94 | 95 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; 96 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 97 | animation.duration = preferenceManager.previewAnimationSpeed; 98 | animation.values = @[ @(-12), @(12), @(-12), @(12), @(-10), @(10), @(-7.5), @(7.5), @(-5), @(5), @(-3), @(0) ]; 99 | [self.layer addAnimation:animation forKey:@"shake"]; 100 | } 101 | @end -------------------------------------------------------------------------------- /screenshotxi/SXIPriorityListController.xm: -------------------------------------------------------------------------------- 1 | #import "SXIPriorityListController.h" 2 | #import "../headers.h" 3 | 4 | @implementation SXIPriorityListController 5 | 6 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 7 | return 1; 8 | } 9 | 10 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 11 | switch (section) { 12 | case 0: 13 | return @"Window Priority"; 14 | default: 15 | return @""; 16 | } 17 | } 18 | 19 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 20 | switch (section) { 21 | case 0: 22 | return [self.currentPriority count]; 23 | default: 24 | return 0; 25 | } 26 | } 27 | 28 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 29 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ScreenshotXICell" forIndexPath:indexPath]; 30 | 31 | if (self.currentPriority == nil || [self.currentPriority count] <= indexPath.row) 32 | return nil; 33 | 34 | if (cell == nil) 35 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ScreenshotXICell"]; 36 | 37 | cell.textLabel.text = [self.currentPriority objectAtIndex:indexPath.row]; 38 | 39 | return cell; 40 | } 41 | 42 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { 43 | if (self.tableView == nil) 44 | return; 45 | 46 | if (self.currentPriority == nil) 47 | [self updatePriority]; 48 | 49 | if (sourceIndexPath == nil || destinationIndexPath == nil || sourceIndexPath.row < 0 || sourceIndexPath.row >= [self.currentPriority count] || destinationIndexPath.row <= 0 || destinationIndexPath.row >= [self.currentPriority count]) { 50 | [self.tableView reloadData]; 51 | return; 52 | } 53 | 54 | NSString *objectToMove = [self.currentPriority objectAtIndex:sourceIndexPath.row]; 55 | [self.currentPriority removeObjectAtIndex:sourceIndexPath.row]; 56 | [self.currentPriority insertObject:objectToMove atIndex:destinationIndexPath.row]; 57 | 58 | [self writeToFile]; 59 | [self.tableView reloadData]; 60 | } 61 | 62 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 63 | return [[self.currentPriority objectAtIndex:indexPath.row] isEqualToString:@"ScreenshotXI"]; 64 | } 65 | 66 | - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 67 | return UITableViewCellEditingStyleNone; 68 | } 69 | 70 | - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath { 71 | return NO; 72 | } 73 | 74 | - (void)writeToFile { 75 | DisplayWindowLevel currentTweakLevel = kAboveHomeAppsLockScreens; 76 | 77 | for (NSInteger i = 1; i < [self.currentPriority count]; i++) { // can never be 0 (below lockscreen/homescreen/application) 78 | if ([[self.currentPriority objectAtIndex:i] isEqualToString:@"ScreenshotXI"]) { 79 | currentTweakLevel = (DisplayWindowLevel)i; 80 | break; 81 | } 82 | } 83 | 84 | PSSpecifier *screenshotxiWindowLevel = [PSSpecifier preferenceSpecifierNamed:@"" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSLinkListCell edit:nil]; 85 | [screenshotxiWindowLevel setProperty:[NSNumber numberWithInt:kAboveHomeAppsLockScreens] forKey:@"default"]; 86 | [screenshotxiWindowLevel setProperty:kTweakIdentifier forKey:@"defaults"]; 87 | [screenshotxiWindowLevel setProperty:@"windowPriority" forKey:@"key"]; 88 | [screenshotxiWindowLevel setProperty:@"" forKey:@"label"]; 89 | [screenshotxiWindowLevel setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 90 | [self setPreferenceValue:[NSNumber numberWithInt:currentTweakLevel] specifier:screenshotxiWindowLevel]; 91 | } 92 | 93 | - (void)updatePriority { 94 | NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:kSettingsPath] ?: [NSMutableDictionary dictionary]; 95 | DisplayWindowLevel currentTweakLevel = [prefs objectForKey:@"windowPriority"] ? (DisplayWindowLevel)[[prefs objectForKey:@"windowPriority"] intValue] : kAboveHomeAppsLockScreens; 96 | NSArray *defaultWindowLevels = @[@"Lockscreen, HomeScreen and Applications", @"Control Center", @"Notification Center", @"Notification Banners", @"SpringBoard Alerts", @"Screenshot Flash"]; 97 | 98 | self.currentPriority = [NSMutableArray array]; 99 | 100 | for (NSInteger i = 0; i < currentTweakLevel; i++) 101 | [self.currentPriority addObject:[defaultWindowLevels objectAtIndex:i]]; 102 | 103 | [self.currentPriority addObject:@"ScreenshotXI"]; 104 | 105 | for (NSInteger i = currentTweakLevel; i < [defaultWindowLevels count]; i++) 106 | [self.currentPriority addObject:[defaultWindowLevels objectAtIndex:i]]; 107 | } 108 | 109 | - (void)viewWillDisappear:(BOOL)animated { 110 | [super viewWillDisappear:animated]; 111 | [self writeToFile]; 112 | } 113 | 114 | - (void)viewWillAppear:(BOOL)animated { 115 | [super viewWillAppear:animated]; 116 | [self updatePriority]; 117 | } 118 | 119 | - (void)viewDidLoad { 120 | [super viewDidLoad]; 121 | 122 | self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStyleGrouped]; 123 | self.tableView.delegate = self; 124 | self.tableView.dataSource = self; 125 | [self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 126 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ScreenshotXICell"]; 127 | [self.tableView setEditing:YES]; 128 | [self.tableView setAllowsSelection:NO]; 129 | 130 | ((UIViewController *)self).title = @"Priority"; 131 | self.view = self.tableView; 132 | } 133 | 134 | - (void)dealloc { 135 | [self.tableView release]; 136 | [super dealloc]; 137 | } 138 | 139 | @end -------------------------------------------------------------------------------- /screenshotxi/SXIRootListController.xm: -------------------------------------------------------------------------------- 1 | #import "SXIRootListController.h" 2 | #import "../headers.h" 3 | 4 | @implementation SXIRootListController 5 | 6 | - (id)initForContentSize:(CGSize)size { 7 | self = [super initForContentSize:size]; 8 | 9 | if (self != nil) { 10 | UIImageView *iconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon" inBundle:[self bundle] compatibleWithTraitCollection:nil]]; 11 | iconView.contentMode = UIViewContentModeScaleAspectFit; 12 | iconView.frame = CGRectMake(0, 0, 29, 29); 13 | 14 | [self.navigationItem setTitleView:iconView]; 15 | [iconView release]; 16 | } 17 | 18 | return self; 19 | } 20 | 21 | - (NSArray *)specifiers { 22 | if (_specifiers == nil) { 23 | PSSpecifier *enableGroup = [PSSpecifier emptyGroupSpecifier]; 24 | PSSpecifier *enableSwitch = [PSSpecifier preferenceSpecifierNamed:@"Enable" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 25 | [enableSwitch setProperty:@YES forKey:@"default"]; 26 | [enableSwitch setProperty:kTweakIdentifier forKey:@"defaults"]; 27 | [enableSwitch setProperty:@"isEnabled" forKey:@"key"]; 28 | [enableSwitch setProperty:@"Enable" forKey:@"label"]; 29 | [enableSwitch setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 30 | 31 | PSSpecifier *optionsGroup = [PSSpecifier emptyGroupSpecifier]; 32 | PSSpecifier *configuration = [PSSpecifier preferenceSpecifierNamed:@"Configuration" target:self set:NULL get:NULL detail:%c(SXIConfigurationListController) cell:PSLinkCell edit:nil]; 33 | [configuration setProperty:@YES forKey:@"isController"]; 34 | [configuration setProperty:@"Configuration" forKey:@"label"]; 35 | PSSpecifier *priority = [PSSpecifier preferenceSpecifierNamed:@"Priority" target:self set:NULL get:NULL detail:%c(SXIPriorityListController) cell:PSLinkCell edit:nil]; 36 | [priority setProperty:@YES forKey:@"isController"]; 37 | [priority setProperty:@"Priority" forKey:@"label"]; 38 | PSSpecifier *appearance = [PSSpecifier preferenceSpecifierNamed:@"Appearance" target:self set:NULL get:NULL detail:%c(SXIAppearanceListController) cell:PSLinkCell edit:nil]; 39 | [appearance setProperty:@YES forKey:@"isController"]; 40 | [appearance setProperty:@"Appearance" forKey:@"label"]; 41 | 42 | PSSpecifier *creditGroup = [PSSpecifier emptyGroupSpecifier]; 43 | [creditGroup setProperty:@"Credits" forKey:@"label"]; 44 | [creditGroup setProperty:@"Enjoy the tweak :)" forKey:@"footerText"]; 45 | PSSpecifier *email = [PSSpecifier preferenceSpecifierNamed:@"Email Support" target:self set:NULL get:NULL detail:nil cell:PSButtonCell edit:nil]; 46 | email->action = @selector(emailSupport); 47 | [email setProperty:@"Email Support" forKey:@"label"]; 48 | [email setProperty:[UIImage _applicationIconImageForBundleIdentifier:@"com.apple.mobilemail" format:0 scale:[UIScreen mainScreen].scale] forKey:@"iconImage"]; 49 | [email setProperty:@YES forKey:@"hasIcon"]; 50 | PSSpecifier *twitter = [PSSpecifier preferenceSpecifierNamed:@"Follow on twitter (@D_Gh0st)" target:self set:NULL get:NULL detail:nil cell:PSButtonCell edit:nil]; 51 | twitter->action = @selector(follow); 52 | [twitter setProperty:@"Follow on twitter" forKey:@"label"]; 53 | [twitter setProperty:[UIImage _applicationIconImageForBundleIdentifier:@"com.atebits.Tweetie2" format:0 scale:[UIScreen mainScreen].scale] forKey:@"iconImage"]; 54 | [twitter setProperty:@YES forKey:@"hasIcon"]; 55 | 56 | PSSpecifier *copyrightGroup = [PSSpecifier emptyGroupSpecifier]; 57 | [copyrightGroup setProperty:@1 forKey:@"footerAlignment"]; 58 | [copyrightGroup setProperty:@"ScreenshotXI © 2017 DGh0st" forKey:@"footerText"]; 59 | 60 | _specifiers = [@[enableGroup, enableSwitch, optionsGroup, configuration, priority, appearance, creditGroup, email, twitter, copyrightGroup] mutableCopy]; 61 | } 62 | 63 | return _specifiers; 64 | } 65 | 66 | - (void)emailSupport { 67 | if ([MFMailComposeViewController canSendMail]) { 68 | MFMailComposeViewController *emailController = [[MFMailComposeViewController alloc] initWithNibName:nil bundle:nil]; 69 | [emailController setSubject:@"ScreenshotXI Support"]; 70 | [emailController setToRecipients:[NSArray arrayWithObjects:@"deeppwnage@yahoo.com", nil]]; 71 | [emailController addAttachmentData:[NSData dataWithContentsOfFile:kSettingsPath] mimeType:@"application/xml" fileName:@"Prefs.plist"]; 72 | [emailController addAttachmentData:[NSData dataWithContentsOfFile:kColorPath] mimeType:@"application/xml" fileName:@"Color.plist"]; 73 | #pragma GCC diagnostic push 74 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 75 | system("/usr/bin/dpkg -l > /tmp/dpkgl.log"); 76 | #pragma GCC diagnostic pop 77 | [emailController addAttachmentData:[NSData dataWithContentsOfFile:@"/tmp/dpkgl.log"] mimeType:@"text/plain" fileName:@"dpkgl.txt"]; 78 | [self.navigationController presentViewController:emailController animated:YES completion:nil]; 79 | [emailController setMailComposeDelegate:self]; 80 | [emailController release]; 81 | } 82 | } 83 | 84 | - (void)mailComposeController:(id)controller didFinishWithResult:(MFMailComposeResult)result error:(id)error { 85 | [self dismissViewControllerAnimated:YES completion:nil]; 86 | } 87 | 88 | - (void)follow { 89 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://mobile.twitter.com/D_Gh0st"]]; 90 | } 91 | 92 | - (void)viewDidLoad { 93 | [super viewDidLoad]; 94 | 95 | UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.table.bounds.size.width, 100)]; 96 | [headerView setBackgroundColor:[UIColor clearColor]]; 97 | [headerView setContentMode:UIViewContentModeCenter]; 98 | [headerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 99 | 100 | CGRect frame = CGRectMake(0, 16, self.table.bounds.size.width, 32); 101 | CGRect underFrame = CGRectMake(0, 56, self.table.bounds.size.width, 24); 102 | 103 | UILabel *label = [[UILabel alloc] initWithFrame:frame]; 104 | [label setNumberOfLines:1]; 105 | label.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:42]; 106 | [label setText:@"ScreenshotXI"]; 107 | [label setBackgroundColor:[UIColor clearColor]]; 108 | label.textColor = [UIColor blackColor]; 109 | label.textAlignment = NSTextAlignmentCenter; 110 | label.autoresizingMask = UIViewAutoresizingFlexibleWidth; 111 | label.contentMode = UIViewContentModeScaleToFill; 112 | 113 | UILabel *underLabel = [[UILabel alloc] initWithFrame:underFrame]; 114 | [underLabel setNumberOfLines:1]; 115 | underLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:18]; 116 | [underLabel setText:@"Bring iOS 11 screenshotting to iOS 9 and 10"]; 117 | [underLabel setBackgroundColor:[UIColor clearColor]]; 118 | underLabel.textColor = [UIColor blackColor]; 119 | underLabel.textAlignment = NSTextAlignmentCenter; 120 | underLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; 121 | underLabel.contentMode = UIViewContentModeScaleToFill; 122 | 123 | [headerView addSubview:label]; 124 | [headerView addSubview:underLabel]; 125 | 126 | self.table.tableHeaderView = headerView; 127 | 128 | [label release]; 129 | [underLabel release]; 130 | [headerView release]; 131 | } 132 | 133 | @end -------------------------------------------------------------------------------- /SXIPreferences.xm: -------------------------------------------------------------------------------- 1 | #import "headers.h" 2 | 3 | @implementation SXIPreferences 4 | +(SXIPreferences *)sharedInstance { 5 | static SXIPreferences *sharedObject = nil; 6 | static dispatch_once_t token = 0; 7 | dispatch_once(&token, ^{ 8 | sharedObject = [self new]; 9 | }); 10 | return sharedObject; 11 | } 12 | 13 | -(id)init { 14 | self = [super init]; 15 | if (self != nil) { 16 | [self updatePreferences]; 17 | 18 | self.aboveHomeAndAppsWindowLevel = 1048; 19 | self.aboveLockscreenWindowLevel = 1051; 20 | self.aboveControlCenterWindowLevel = 1091; 21 | self.aboveNotificationCenterWindowLevel = 1096; 22 | self.aboveNotificationBannerWindowLevel = 1101; 23 | self.aboveSpringboardAlertWindowLevel = 2001; 24 | self.screenFlashWindowLevel = 2200; 25 | } 26 | return self; 27 | } 28 | 29 | -(void)updatePreferences { 30 | CFPreferencesAppSynchronize((CFStringRef)kTweakIdentifier); 31 | 32 | NSMutableDictionary *prefs = nil; 33 | if ([NSHomeDirectory() isEqualToString:@"/var/mobile"]) { 34 | CFArrayRef keyList = CFPreferencesCopyKeyList((CFStringRef)kTweakIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 35 | if (keyList != nil) { 36 | prefs = (NSMutableDictionary *)CFPreferencesCopyMultiple(keyList, (CFStringRef)kTweakIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 37 | if (prefs == nil) 38 | prefs = [NSMutableDictionary new]; 39 | CFRelease(keyList); 40 | } 41 | } else { 42 | prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:kSettingsPath]; 43 | } 44 | 45 | _isEnabled = [prefs objectForKey:@"isEnabled"] ? [[prefs objectForKey:@"isEnabled"] boolValue] : YES; 46 | _isRightSwipeEnabled = [prefs objectForKey:@"isRightSwipeEnabled"] ? [[prefs objectForKey:@"isRightSwipeEnabled"] boolValue] : NO; 47 | _isNotifyApplicationsEnabled = [prefs objectForKey:@"isNotifyApplicationsEnabled"] ? [[prefs objectForKey:@"isNotifyApplicationsEnabled"] boolValue] : YES; 48 | _dismissTime = [prefs objectForKey:@"dismissTime"] ? [[prefs objectForKey:@"dismissTime"] floatValue] : 5.0; 49 | _isUnlimitedDismissTimeEnabled = [prefs objectForKey:@"isUnlimitedDismissTimeEnabled"] ? [[prefs objectForKey:@"isUnlimitedDismissTimeEnabled"] boolValue] : NO; 50 | _isShutterSoundDisabled = [prefs objectForKey:@"isShutterSoundDisabled"] ? [[prefs objectForKey:@"isShutterSoundDisabled"] boolValue] : NO; 51 | _isSaveOnSwipeDismissEnabled = [prefs objectForKey:@"isSaveOnSwipeDismissEnabled"] ? [[prefs objectForKey:@"isSaveOnSwipeDismissEnabled"] boolValue] : YES; 52 | _isSaveOnRightSwipeDismissEnabled = [prefs objectForKey:@"isSaveOnRightSwipeDismissEnabled"] ? [[prefs objectForKey:@"isSaveOnRightSwipeDismissEnabled"] boolValue] : NO; 53 | _isSaveOnAutoDismissEnabled = [prefs objectForKey:@"isSaveOnAutoDismissEnabled"] ? [[prefs objectForKey:@"isSaveOnAutoDismissEnabled"] boolValue] : YES; 54 | _isSaveOnShareEnabled = [prefs objectForKey:@"isSaveOnShareEnabled"] ? [[prefs objectForKey:@"isSaveOnShareEnabled"] boolValue] : YES; 55 | _isSaveUneditedEnabled = [prefs objectForKey:@"isSaveUneditedEnabled"] ? [[prefs objectForKey:@"isSaveUneditedEnabled"] boolValue] : NO; 56 | _isSaveUneditedOnCancelEnabled = [prefs objectForKey:@"isSaveUneditedOnCancelEnabled"] ? [[prefs objectForKey:@"isSaveUneditedOnCancelEnabled"] boolValue] : YES; 57 | _isSaveUneditedOnShareEnabled = [prefs objectForKey:@"isSaveUneditedOnShareEnabled"] ? [[prefs objectForKey:@"isSaveUneditedOnShareEnabled"] boolValue] : YES; 58 | _isSpamSaveEnabled = [prefs objectForKey:@"isSpamSaveEnabled"] ? [[prefs objectForKey:@"isSpamSaveEnabled"] boolValue] : YES; 59 | _isCopyToPasteBoardEnabled = [prefs objectForKey:@"isCopyToPasteBoardEnabled"] ? [[prefs objectForKey:@"isCopyToPasteBoardEnabled"] boolValue] : NO; 60 | _isDismissOnLockEnabled = [prefs objectForKey:@"isDismissOnLockEnabled"] ? [[prefs objectForKey:@"isDismissOnLockEnabled"] boolValue] : NO; 61 | _isDismissOnCallEnabled = [prefs objectForKey:@"isDismissOnCallEnabled"] ? [[prefs objectForKey:@"isDismissOnCallEnabled"] boolValue] : YES; 62 | _isLockscreenShareDisabled = [prefs objectForKey:@"isLockscreenShareDisabled"] ? [[prefs objectForKey:@"isLockscreenShareDisabled"] boolValue] : YES; 63 | _isLockscreenEditDisabled = [prefs objectForKey:@"isLockscreenEditDisabled"] ? [[prefs objectForKey:@"isLockscreenEditDisabled"] boolValue] : NO; 64 | 65 | DisplayWindowLevel windowPriority = [prefs objectForKey:@"windowPriority"] ? (DisplayWindowLevel)[[prefs objectForKey:@"windowPriority"] intValue] : kAboveHomeAppsLockScreens; 66 | switch (windowPriority) { 67 | case kAboveHomeAppsLockScreens: 68 | _currentTweakLevel = self.aboveLockscreenWindowLevel; 69 | break; 70 | case kAboveControlCenter: 71 | _currentTweakLevel = self.aboveControlCenterWindowLevel; 72 | break; 73 | case kAboveNotificationCenter: 74 | _currentTweakLevel = self.aboveNotificationCenterWindowLevel; 75 | break; 76 | case kAboveNotificationBanners: 77 | _currentTweakLevel = self.aboveNotificationBannerWindowLevel; 78 | break; 79 | case kAboveSpringBoardAlerts: 80 | _currentTweakLevel = self.aboveSpringboardAlertWindowLevel; 81 | break; 82 | case kScreenshotFlash: 83 | _currentTweakLevel = self.screenFlashWindowLevel; 84 | break; 85 | default: 86 | _currentTweakLevel = self.aboveLockscreenWindowLevel; 87 | break; 88 | } 89 | 90 | _animationSpeed = [prefs objectForKey:@"animationSpeed"] ? [[prefs objectForKey:@"animationSpeed"] floatValue] : 0.5; 91 | _miniImageScale = [prefs objectForKey:@"miniImageScale"] ? [[prefs objectForKey:@"miniImageScale"] floatValue] : 0.2; 92 | _miniImageWhitePadding = [prefs objectForKey:@"miniImageWhitePadding"] ? [[prefs objectForKey:@"miniImageWhitePadding"] floatValue] : 6.0; 93 | _miniImageMargin = [prefs objectForKey:@"miniImageMargin"] ? [[prefs objectForKey:@"miniImageMargin"] floatValue] : 10.0; 94 | _miniImageRoundness = [prefs objectForKey:@"miniImageRoundness"] ? [[prefs objectForKey:@"miniImageRoundness"] floatValue] : 4.0; 95 | _dismissAnimationSpeed = [prefs objectForKey:@"dismissAnimationSpeed"] ? [[prefs objectForKey:@"dismissAnimationSpeed"] floatValue] : 0.5; 96 | _previewAnimationSpeed = [prefs objectForKey:@"previewAnimationSpeed"] ? [[prefs objectForKey:@"previewAnimationSpeed"] floatValue] : 0.15; 97 | _previewAlpha = [prefs objectForKey:@"previewAlpha"] ? [[prefs objectForKey:@"previewAlpha"] floatValue] : 0.25; 98 | _previewScale = [prefs objectForKey:@"previewScale"] ? [[prefs objectForKey:@"previewScale"] floatValue] : 1.05; 99 | 100 | [prefs release]; 101 | } 102 | 103 | -(void)updatePriority { 104 | CFPreferencesAppSynchronize((CFStringRef)kTweakIdentifier); 105 | 106 | NSMutableDictionary *prefs = nil; 107 | if ([NSHomeDirectory() isEqualToString:@"/var/mobile"]) { 108 | CFArrayRef keyList = CFPreferencesCopyKeyList((CFStringRef)kTweakIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 109 | if (keyList != nil) { 110 | prefs = (NSMutableDictionary *)CFPreferencesCopyMultiple(keyList, (CFStringRef)kTweakIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 111 | if (prefs == nil) 112 | prefs = [NSMutableDictionary new]; 113 | CFRelease(keyList); 114 | } 115 | } else { 116 | prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:kSettingsPath]; 117 | } 118 | 119 | DisplayWindowLevel windowPriority = [prefs objectForKey:@"windowPriority"] ? (DisplayWindowLevel)[[prefs objectForKey:@"windowPriority"] intValue] : kAboveHomeAppsLockScreens; 120 | switch (windowPriority) { 121 | case kAboveHomeAppsLockScreens: 122 | _currentTweakLevel = self.aboveLockscreenWindowLevel; 123 | break; 124 | case kAboveControlCenter: 125 | _currentTweakLevel = self.aboveControlCenterWindowLevel; 126 | break; 127 | case kAboveNotificationCenter: 128 | _currentTweakLevel = self.aboveNotificationCenterWindowLevel; 129 | break; 130 | case kAboveNotificationBanners: 131 | _currentTweakLevel = self.aboveNotificationBannerWindowLevel; 132 | break; 133 | case kAboveSpringBoardAlerts: 134 | _currentTweakLevel = self.aboveSpringboardAlertWindowLevel; 135 | break; 136 | case kScreenshotFlash: 137 | _currentTweakLevel = self.screenFlashWindowLevel; 138 | break; 139 | default: 140 | _currentTweakLevel = self.aboveLockscreenWindowLevel; 141 | break; 142 | } 143 | 144 | [prefs release]; 145 | } 146 | 147 | -(NSString *)uiHexColor { 148 | CFPreferencesAppSynchronize((CFStringRef)kColorIdentifier); // not needed 149 | 150 | NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:kColorPath]; 151 | if (prefs != nil) { 152 | return [prefs objectForKey:@"color"]; 153 | } 154 | return nil; 155 | } 156 | @end -------------------------------------------------------------------------------- /headers.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | 6 | #define kLongPressStartDuration 0.15 // time till long press starts 7 | #define kLongPressEndDuration 0.33 // additional duration after long press starts 8 | #define kLongPressRange 7.5 // finger movement allowed for long press 9 | 10 | #define kTweakIdentifier @"com.dgh0st.screenshotxi" 11 | #define kSettingsChangedIdentifier @"com.dgh0st.screenshotxi/settingschanged" 12 | #define kSettingsPath @"/var/mobile/Library/Preferences/com.dgh0st.screenshotxi.plist" 13 | #define kColorIdentifier @"com.dgh0st.screenshotxi.color" 14 | #define kColorChangedIdentifier @"com.dgh0st.screenshotxi/colorchanged" 15 | #define kColorPath @"/var/mobile/Library/Preferences/com.dgh0st.screenshotxi.color.plist" 16 | #define kBundlePath @"/Library/Application Support/ScreenshotXI/ImageAssets.bundle" 17 | #define kPhotoShutterSystemSound 0x454 18 | #define kImageMinimumScaleMultiplier 0.75 19 | 20 | /* 21 | ------------------------------ iOS's Window Level (Atleast on iOS 10 iPhone 6+) ------------------------------ 22 | HomeScreen Wallpaper = -3 23 | HomeScreen = -2 24 | Application = 0 25 | (alerts in applications are displayed in same window, UIAlertController are presented from UIViewController) 26 | LockScreen Wallpaper = 1049 27 | LockScreen = 1050 28 | Control Center = 1090 29 | Notification Center = 1095 30 | Notification Banners = 1100 31 | SpringBoard Alert = 2000 32 | Screenshot Flash = 2200 33 | -------------------------------------------------------------------------------------------------------------- 34 | */ 35 | 36 | typedef enum { 37 | kAboveHomeAppsLockScreens = 1, 38 | kAboveControlCenter = 2, 39 | kAboveNotificationCenter = 3, 40 | kAboveNotificationBanners = 4, 41 | kAboveSpringBoardAlerts = 5, 42 | kScreenshotFlash = 6 43 | } DisplayWindowLevel; 44 | 45 | typedef enum { 46 | kNone = 0, 47 | kShareSheet, 48 | kEditor 49 | } DisplayedControllerType; 50 | 51 | @interface _SBScreenshotPersistenceCoordinator : NSObject 52 | -(void)saveScreenshot:(id)arg1 withCompletion:(id)arg2; 53 | @end 54 | 55 | @interface SBScreenshotManager : NSObject 56 | -(void)saveScreenshotsWithCompletion:(id)arg1; 57 | -(_SBScreenshotPersistenceCoordinator *)_persistenceCoordinator; 58 | @end 59 | 60 | @interface SBScreenShotter : NSObject 61 | +(id)sharedInstance; 62 | -(void)saveScreenshot:(BOOL)arg1; 63 | @end 64 | 65 | @interface PLPhotoLibrary : NSObject 66 | @property (nonatomic,copy,readonly) NSArray * albums; 67 | +(id)sharedPhotoLibrary; 68 | @end 69 | 70 | @interface PLManagedAsset : NSObject 71 | @property (nonatomic,copy,readonly) NSURL * mainFileURL; 72 | @end 73 | 74 | @interface PLManagedAlbum : NSObject 75 | @property (nonatomic,retain) NSOrderedSet * assets; 76 | @end 77 | 78 | @interface AKUndoController : NSObject 79 | @end 80 | 81 | @interface AKOverlayView : UIView 82 | @end 83 | 84 | @interface AKPageController : NSObject 85 | @property (nonatomic,retain) UIView *overlayView; 86 | @property (assign) BOOL shouldPixelate; 87 | @end 88 | 89 | @interface AKModelController 90 | -(void)deselectAllAnnotations; 91 | @end 92 | 93 | @interface AKController : NSObject 94 | @property (retain) AKUndoController *undoController; 95 | @property (retain) AKModelController *modelController; 96 | @property (assign, nonatomic) BOOL overlayShouldPixelate; 97 | -(AKPageController *)currentPageController; 98 | @end 99 | 100 | @interface MUImageContentViewController : UIViewController 101 | @end 102 | 103 | @protocol MarkupViewControllerDelegate 104 | @end 105 | 106 | @interface MarkupViewController : UIViewController 107 | @property (retain) MUImageContentViewController *contentViewController; 108 | @property (nonatomic,retain) UINavigationBar *navBar; 109 | @property (nonatomic,retain) NSUndoManager *akUndoManager; 110 | @property (retain) AKController *annotationController; 111 | @property (nonatomic, retain) id sourceContent; 112 | -(void)setImage:(id)arg1; 113 | -(void)setShapeDetectionEnabled:(BOOL)arg1; 114 | -(void)setAnnotationEditingEnabled:(BOOL)arg1; // iOS 10.0 + 115 | -(void)setDelegate:(id)arg1; 116 | @end 117 | 118 | @interface SBScreenFlash : NSObject 119 | +(id)mainScreenFlasher; 120 | -(void)setScreenshotImage:(id)image; 121 | -(UIImage *)screenshotImage; 122 | -(void)flashColor:(id)arg1 withCompletion:(id)arg2; 123 | -(void)screenshotwithCompletion:(id)arg2; 124 | @end 125 | 126 | @interface UIWindow (SXIPrivate) 127 | -(void)_setSecure:(BOOL)arg1; 128 | -(void)_updateToInterfaceOrientation:(UIInterfaceOrientation)arg1 animated:(BOOL)arg2; 129 | @end 130 | 131 | @interface UIScreen (SXIPrivate) 132 | -(id)_snapshotExcludingWindows:(id)arg1 withRect:(CGRect)arg2; 133 | -(id)snapshotViewAfterScreenUpdates:(BOOL)arg1; 134 | @end 135 | 136 | @interface UIApplication (SXIPrivate) 137 | -(void)setStatusBarHidden:(BOOL)arg1; 138 | @end 139 | 140 | @interface UIActivityViewController (SXIPrivate) 141 | @property (assign,nonatomic) BOOL showKeyboardAutomatically; 142 | -(void)setDismissCompletionHandler:(id)arg1; 143 | @end 144 | 145 | @interface UIBarButtonItem (SXIPrivate) 146 | -(id)view; 147 | @end 148 | 149 | @interface SBAlert : UIViewController 150 | @end 151 | 152 | @interface SBLockScreenViewControllerBase : SBAlert 153 | @end 154 | 155 | @interface SBLockScreenViewController : SBLockScreenViewControllerBase 156 | -(id)lockScreenView; 157 | @end 158 | 159 | @interface SBDashBoardViewController : SBLockScreenViewControllerBase 160 | -(id)dashBoardView; 161 | @end 162 | 163 | @interface SBLockScreenManager : NSObject 164 | @property (nonatomic,readonly) SBLockScreenViewControllerBase *lockScreenViewController; 165 | +(id)sharedInstance; 166 | @end 167 | 168 | @interface SBBacklightController 169 | +(id)sharedInstance; 170 | -(void)resetLockScreenIdleTimer; 171 | @end 172 | 173 | @interface UIRemoteApplication : NSObject 174 | -(void)didTakeScreenshot; 175 | @end 176 | 177 | @interface SBApplication 178 | -(UIRemoteApplication *)remoteApplication; 179 | @end 180 | 181 | @interface SpringBoard : UIApplication 182 | @property (nonatomic,readonly) SBScreenshotManager *screenshotManager; 183 | -(BOOL)isLocked; 184 | -(UIInterfaceOrientation)activeInterfaceOrientation; 185 | -(SBApplication *)_accessibilityFrontMostApplication; 186 | @end 187 | 188 | @interface SBUIController : NSObject 189 | +(id)sharedInstance; 190 | -(void)_hideKeyboard; 191 | @end 192 | 193 | @interface ESSContainerView : UIView { 194 | UIColor *_color; 195 | } 196 | @property (nonatomic, strong) UIImage *image; 197 | -(id)initWithFrame:(CGRect)frame withColor:(UIColor *)color; 198 | -(void)highlightViewWithCompletion:(id)completion; 199 | -(void)unhighlightViewWithCompletion:(id)completion; 200 | -(void)shake; 201 | @end 202 | 203 | @interface ESSController : UIViewController { 204 | UIActivityViewController *_activityViewController; 205 | MarkupViewController *_markUpEditor; 206 | NSTimeInterval pressStartTime; 207 | CGPoint pressStartLocation; 208 | BOOL useLongPressAsPan; 209 | BOOL timerDidTrigger; 210 | UIBarButtonItem *redoButton; 211 | UIBarButtonItem *undoButton; 212 | UIBarButtonItem *saveButton; 213 | UIBarButtonItem *shareButton; 214 | BOOL didHideStatusBar; 215 | UIImage *resultEditedImage; 216 | } 217 | @property (nonatomic, assign) BOOL rotationEnabled; 218 | @property (nonatomic, strong) NSMutableArray *containerViews; 219 | +(UIImage *)imageFromView:(UIView *)view andView:(UIView *)secondView; 220 | -(DisplayedControllerType)currentlyHostingViewControllerType; 221 | -(void)saveScreenshot:(UIImage *)image; 222 | -(void)autoHide:(UIView *)view; 223 | -(void)forceHide:(UIView *)view; 224 | -(void)forceHideWithoutAnimations:(UIView *)view; 225 | -(void)updateUndoAndRedoButtons; 226 | -(BOOL)isEqualToMarkUpEditor:(id)editor; 227 | -(BOOL)isEqualToUndoController:(id)undoController; 228 | -(BOOL)isEqualToImageContentViewController:(id)imageContentViewController; 229 | -(BOOL)isEqualToSourceContent:(id)sourceContent; 230 | -(BOOL)isPresentingEditor; 231 | -(void)forceSaveMarkUpWithCompletion:(void (^)())completion; 232 | -(void)dismissMarkUpEditorAnimated:(BOOL)animated completion:(void (^)())completion; 233 | -(void)dismissShareSheetAnimated:(BOOL)animated completion:(void (^)(void))completion; 234 | @end 235 | 236 | @interface ESSWindow : UIWindow 237 | @end 238 | 239 | // anemone fix 240 | @interface ANEMSettingsManager : NSObject 241 | +(instancetype)sharedManager; 242 | -(void)setCGImageHookEnabled:(BOOL)enabled; 243 | @end 244 | 245 | @interface SXIPreferences : NSObject 246 | @property (nonatomic, assign, readonly) BOOL isEnabled; 247 | @property (nonatomic, assign, readonly) BOOL isRightSwipeEnabled; 248 | @property (nonatomic, assign, readonly) BOOL isNotifyApplicationsEnabled; 249 | @property (nonatomic, assign, readonly) CGFloat dismissTime; 250 | @property (nonatomic, assign, readonly) BOOL isUnlimitedDismissTimeEnabled; 251 | @property (nonatomic, assign, readonly) BOOL isShutterSoundDisabled; 252 | @property (nonatomic, assign, readonly) BOOL isSaveOnSwipeDismissEnabled; 253 | @property (nonatomic, assign, readonly) BOOL isSaveOnRightSwipeDismissEnabled; 254 | @property (nonatomic, assign, readonly) BOOL isSaveOnAutoDismissEnabled; 255 | @property (nonatomic, assign, readonly) BOOL isSaveOnShareEnabled; 256 | @property (nonatomic, assign, readonly) BOOL isSaveUneditedEnabled; 257 | @property (nonatomic, assign, readonly) BOOL isSaveUneditedOnCancelEnabled; 258 | @property (nonatomic, assign, readonly) BOOL isSaveUneditedOnShareEnabled; 259 | @property (nonatomic, assign, readonly) BOOL isSpamSaveEnabled; 260 | @property (nonatomic, assign, readonly) BOOL isCopyToPasteBoardEnabled; 261 | @property (nonatomic, assign, readonly) BOOL isDismissOnLockEnabled; 262 | @property (nonatomic, assign, readonly) BOOL isDismissOnCallEnabled; 263 | @property (nonatomic, assign, readonly) BOOL isLockscreenShareDisabled; 264 | @property (nonatomic, assign, readonly) BOOL isLockscreenEditDisabled; 265 | @property (nonatomic, assign, readonly) UIWindowLevel currentTweakLevel; 266 | @property (nonatomic, assign, readonly) CGFloat animationSpeed; 267 | @property (nonatomic, assign, readonly) CGFloat miniImageScale; 268 | @property (nonatomic, assign, readonly) CGFloat miniImageWhitePadding; 269 | @property (nonatomic, assign, readonly) CGFloat miniImageMargin; 270 | @property (nonatomic, assign, readonly) CGFloat miniImageRoundness; 271 | @property (nonatomic, assign, readonly) CGFloat dismissAnimationSpeed; 272 | @property (nonatomic, assign, readonly) CGFloat previewAnimationSpeed; 273 | @property (nonatomic, assign, readonly) CGFloat previewAlpha; 274 | @property (nonatomic, assign, readonly) CGFloat previewScale; 275 | @property (nonatomic, assign) UIWindowLevel aboveHomeAndAppsWindowLevel; 276 | @property (nonatomic, assign) UIWindowLevel aboveLockscreenWindowLevel; 277 | @property (nonatomic, assign) UIWindowLevel aboveControlCenterWindowLevel; 278 | @property (nonatomic, assign) UIWindowLevel aboveNotificationCenterWindowLevel; 279 | @property (nonatomic, assign) UIWindowLevel aboveNotificationBannerWindowLevel; 280 | @property (nonatomic, assign) UIWindowLevel aboveSpringboardAlertWindowLevel; 281 | @property (nonatomic, assign) UIWindowLevel screenFlashWindowLevel; 282 | +(SXIPreferences *)sharedInstance; 283 | -(void)updatePreferences; 284 | -(void)updatePriority; 285 | -(NSString *)uiHexColor; 286 | @end 287 | -------------------------------------------------------------------------------- /screenshotxi/SXIAppearanceListController.xm: -------------------------------------------------------------------------------- 1 | #import "SXIAppearanceListController.h" 2 | #import "../headers.h" 3 | 4 | @implementation SXIAppearanceListController 5 | 6 | - (NSArray *)specifiers { 7 | if (_specifiers == nil) { // copy pasted code... can probably make a function... 8 | PSSpecifier *animationSpeedGroup = [PSSpecifier groupSpecifierWithName:@"Animation Speed"]; 9 | [animationSpeedGroup setProperty:@"Animation Speed" forKey:@"label"]; 10 | PSSpecifier *animationSpeedSlider = [PSSpecifier preferenceSpecifierNamed:@"Flash Animation Speed" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 11 | [animationSpeedSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 12 | [animationSpeedSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 13 | [animationSpeedSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"max"]; 14 | [animationSpeedSlider setProperty:@YES forKey:@"showValue"]; 15 | [animationSpeedSlider setProperty:[NSNumber numberWithFloat:0.5] forKey:@"default"]; 16 | [animationSpeedSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 17 | [animationSpeedSlider setProperty:@"animationSpeed" forKey:@"key"]; 18 | [animationSpeedSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 19 | 20 | PSSpecifier *colorGroup = [PSSpecifier emptyGroupSpecifier]; 21 | [colorGroup setProperty:@"Set color for flash, and mini image" forKey:@"footerText"]; 22 | PSSpecifier *colorPicker = [PSSpecifier preferenceSpecifierNamed:@"UI Color" target:self set:NULL get:NULL detail:nil cell:PSLinkCell edit:nil]; 23 | [colorPicker setProperty:%c(PFSimpleLiteColorCell) forKey:@"cellClass"]; 24 | [colorPicker setProperty:@"UI Color" forKey:@"label"]; 25 | [colorPicker setProperty:@{ 26 | @"defaults" : kColorIdentifier, 27 | @"key" : @"color", 28 | @"fallback" : @"#FFFFFF", 29 | @"PostNotification" : kColorChangedIdentifier, 30 | @"alpha" : @NO 31 | } forKey:@"libcolorpicker"]; 32 | colorPicker->action = @selector(cellAction); 33 | 34 | PSSpecifier *miniImageFinalScaleGroup = [PSSpecifier groupSpecifierWithName:@"Mini Image Scale"]; 35 | [miniImageFinalScaleGroup setProperty:@"label" forKey:@"Mini Image Scale"]; 36 | PSSpecifier *finalScaleSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Scale" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 37 | [finalScaleSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 38 | [finalScaleSlider setProperty:[NSNumber numberWithFloat:0.1] forKey:@"min"]; 39 | [finalScaleSlider setProperty:[NSNumber numberWithFloat:0.33] forKey:@"max"]; 40 | [finalScaleSlider setProperty:@YES forKey:@"showValue"]; 41 | [finalScaleSlider setProperty:[NSNumber numberWithFloat:0.2] forKey:@"default"]; 42 | [finalScaleSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 43 | [finalScaleSlider setProperty:@"miniImageScale" forKey:@"key"]; 44 | [finalScaleSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 45 | 46 | PSSpecifier *miniImageWhitePaddingGroup = [PSSpecifier groupSpecifierWithName:@"Mini Image Border"]; 47 | [miniImageWhitePaddingGroup setProperty:@"label" forKey:@"Mini Image Border"]; 48 | PSSpecifier *miniImageWhitePaddingSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Border" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 49 | [miniImageWhitePaddingSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 50 | [miniImageWhitePaddingSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"min"]; 51 | [miniImageWhitePaddingSlider setProperty:[NSNumber numberWithFloat:25.0] forKey:@"max"]; 52 | [miniImageWhitePaddingSlider setProperty:@YES forKey:@"showValue"]; 53 | [miniImageWhitePaddingSlider setProperty:[NSNumber numberWithFloat:6.0] forKey:@"default"]; 54 | [miniImageWhitePaddingSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 55 | [miniImageWhitePaddingSlider setProperty:@"miniImageWhitePadding" forKey:@"key"]; 56 | [miniImageWhitePaddingSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 57 | 58 | PSSpecifier *miniImageMarginGroup = [PSSpecifier groupSpecifierWithName:@"Mini Image Margin"]; 59 | [miniImageMarginGroup setProperty:@"label" forKey:@"Mini Image Margin"]; 60 | PSSpecifier *miniImageMarginSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Margin" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 61 | [miniImageMarginSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 62 | [miniImageMarginSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 63 | [miniImageMarginSlider setProperty:[NSNumber numberWithFloat:25.0] forKey:@"max"]; 64 | [miniImageMarginSlider setProperty:@YES forKey:@"showValue"]; 65 | [miniImageMarginSlider setProperty:[NSNumber numberWithFloat:10.0] forKey:@"default"]; 66 | [miniImageMarginSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 67 | [miniImageMarginSlider setProperty:@"miniImageMargin" forKey:@"key"]; 68 | [miniImageMarginSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 69 | 70 | PSSpecifier *miniImageRoundnessGroup = [PSSpecifier groupSpecifierWithName:@"Mini Image Roundness"]; 71 | [miniImageRoundnessGroup setProperty:@"label" forKey:@"Mini Image Roundness"]; 72 | PSSpecifier *miniImageRoundnessSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Roundness" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 73 | [miniImageRoundnessSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 74 | [miniImageRoundnessSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 75 | [miniImageRoundnessSlider setProperty:[NSNumber numberWithFloat:25.0] forKey:@"max"]; 76 | [miniImageRoundnessSlider setProperty:@YES forKey:@"showValue"]; 77 | [miniImageRoundnessSlider setProperty:[NSNumber numberWithFloat:4.0] forKey:@"default"]; 78 | [miniImageRoundnessSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 79 | [miniImageRoundnessSlider setProperty:@"miniImageRoundness" forKey:@"key"]; 80 | [miniImageRoundnessSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 81 | 82 | PSSpecifier *dismissAnimationSpeedGroup = [PSSpecifier groupSpecifierWithName:@"Dismiss Animation Speed"]; 83 | [dismissAnimationSpeedGroup setProperty:@"Dismiss Animation Speed" forKey:@"label"]; 84 | PSSpecifier *dismissAnimationSpeedSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Dismiss Animation Speed" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 85 | [dismissAnimationSpeedSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 86 | [dismissAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 87 | [dismissAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"max"]; 88 | [dismissAnimationSpeedSlider setProperty:@YES forKey:@"showValue"]; 89 | [dismissAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:0.5] forKey:@"default"]; 90 | [dismissAnimationSpeedSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 91 | [dismissAnimationSpeedSlider setProperty:@"dismissAnimationSpeed" forKey:@"key"]; 92 | [dismissAnimationSpeedSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 93 | 94 | PSSpecifier *previewAnimationSpeedGroup = [PSSpecifier groupSpecifierWithName:@"Preview Animation Speed"]; 95 | [previewAnimationSpeedGroup setProperty:@"Preview Animation Speed" forKey:@"label"]; 96 | [previewAnimationSpeedGroup setProperty:@"Mini Image preview (long press) animation speed" forKey:@"footerText"]; 97 | PSSpecifier *previewAnimationSpeedSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Preview Animation Speed" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 98 | [previewAnimationSpeedSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 99 | [previewAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 100 | [previewAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"max"]; 101 | [previewAnimationSpeedSlider setProperty:@YES forKey:@"showValue"]; 102 | [previewAnimationSpeedSlider setProperty:[NSNumber numberWithFloat:0.15] forKey:@"default"]; 103 | [previewAnimationSpeedSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 104 | [previewAnimationSpeedSlider setProperty:@"previewAnimationSpeed" forKey:@"key"]; 105 | [previewAnimationSpeedSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 106 | 107 | PSSpecifier *previewAlphaGroup = [PSSpecifier groupSpecifierWithName:@"Preview Alpha"]; 108 | [previewAlphaGroup setProperty:@"Preview Alpha" forKey:@"label"]; 109 | [previewAlphaGroup setProperty:@"Mini Image preview (long press) alpha" forKey:@"footerText"]; 110 | PSSpecifier *previewAlphaSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Preview Alpha" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 111 | [previewAlphaSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 112 | [previewAlphaSlider setProperty:[NSNumber numberWithFloat:0.0] forKey:@"min"]; 113 | [previewAlphaSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"max"]; 114 | [previewAlphaSlider setProperty:@YES forKey:@"showValue"]; 115 | [previewAlphaSlider setProperty:[NSNumber numberWithFloat:0.25] forKey:@"default"]; 116 | [previewAlphaSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 117 | [previewAlphaSlider setProperty:@"previewAlpha" forKey:@"key"]; 118 | [previewAlphaSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 119 | 120 | PSSpecifier *previewFinalScaleGroup = [PSSpecifier groupSpecifierWithName:@"Preview Scale"]; 121 | [previewFinalScaleGroup setProperty:@"Preview Scale" forKey:@"label"]; 122 | [previewFinalScaleGroup setProperty:@"Mini Image preview (long press) scale" forKey:@"footerText"]; 123 | PSSpecifier *previewScaleSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Preview Scale" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 124 | [previewScaleSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 125 | [previewScaleSlider setProperty:[NSNumber numberWithFloat:0.75] forKey:@"min"]; 126 | [previewScaleSlider setProperty:[NSNumber numberWithFloat:1.25] forKey:@"max"]; 127 | [previewScaleSlider setProperty:@YES forKey:@"showValue"]; 128 | [previewScaleSlider setProperty:[NSNumber numberWithFloat:1.05] forKey:@"default"]; 129 | [previewScaleSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 130 | [previewScaleSlider setProperty:@"previewScale" forKey:@"key"]; 131 | [previewScaleSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 132 | 133 | PSSpecifier *resetGroup = [PSSpecifier emptyGroupSpecifier]; 134 | PSSpecifier *resetAppearanceButton = [PSSpecifier preferenceSpecifierNamed:@"Reset Appearance" target:self set:NULL get:NULL detail:nil cell:PSButtonCell edit:nil]; 135 | resetAppearanceButton->action = @selector(resetAppearance); 136 | [resetAppearanceButton setProperty:@"Reset Appearance" forKey:@"label"]; 137 | [resetAppearanceButton setProperty:@1 forKey:@"alignment"]; 138 | 139 | _specifiers = [@[animationSpeedGroup, animationSpeedSlider, colorGroup, colorPicker, miniImageFinalScaleGroup, finalScaleSlider, miniImageWhitePaddingGroup, miniImageWhitePaddingSlider, miniImageMarginGroup, miniImageMarginSlider, miniImageRoundnessGroup, miniImageRoundnessSlider, dismissAnimationSpeedGroup, dismissAnimationSpeedSlider, previewAnimationSpeedGroup, previewAnimationSpeedSlider, previewAlphaGroup, previewAlphaSlider, previewFinalScaleGroup, previewScaleSlider, resetGroup, resetAppearanceButton] mutableCopy]; 140 | } 141 | 142 | return _specifiers; 143 | } 144 | 145 | - (void)resetAppearance { 146 | for (PSSpecifier *specifier in _specifiers) { 147 | if ([specifier propertyForKey:@"key"] != nil) { 148 | [self setPreferenceValue:[specifier propertyForKey:@"default"] specifier:specifier]; 149 | } else if ([specifier propertyForKey:@"libcolorpicker"] != nil) { // manually do it for color picker as its' key works differently 150 | NSDictionary *colorPickerDictionary = (NSDictionary *)[specifier propertyForKey:@"libcolorpicker"]; 151 | NSString *path = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", [colorPickerDictionary objectForKey:@"defaults"]]; 152 | NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithContentsOfFile:path] ?: [NSMutableDictionary dictionary]; 153 | [settings setObject:[colorPickerDictionary objectForKey:@"fallback"] forKey:[colorPickerDictionary objectForKey:@"key"]]; 154 | [settings writeToFile:path atomically:YES]; 155 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)[colorPickerDictionary objectForKey:@"PostNotification"], NULL, NULL, YES); 156 | } 157 | } 158 | [self reloadSpecifiers]; 159 | } 160 | 161 | - (void)viewWillAppear:(BOOL)animated { 162 | [self clearCache]; 163 | [self reload]; 164 | [super viewWillAppear:animated]; 165 | } 166 | 167 | @end -------------------------------------------------------------------------------- /screenshotxi/SXIConfigurationListController.xm: -------------------------------------------------------------------------------- 1 | #import "SXIConfigurationListController.h" 2 | #import "../headers.h" 3 | 4 | @implementation SXIConfigurationListController 5 | 6 | - (NSArray *)specifiers { 7 | if (_specifiers == nil) { 8 | PSSpecifier *swipeGroup = [PSSpecifier emptyGroupSpecifier]; 9 | PSSpecifier *enableRightSwipe = [PSSpecifier preferenceSpecifierNamed:@"Right Swipe" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 10 | [enableRightSwipe setProperty:@NO forKey:@"default"]; 11 | [enableRightSwipe setProperty:kTweakIdentifier forKey:@"defaults"]; 12 | [enableRightSwipe setProperty:@"isRightSwipeEnabled" forKey:@"key"]; 13 | [enableRightSwipe setProperty:@"Right Swipe" forKey:@"label"]; 14 | [enableRightSwipe setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 15 | 16 | PSSpecifier *notifyApplication = [PSSpecifier preferenceSpecifierNamed:@"Notify Applications" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 17 | [notifyApplication setProperty:@YES forKey:@"default"]; 18 | [notifyApplication setProperty:kTweakIdentifier forKey:@"defaults"]; 19 | [notifyApplication setProperty:@"isNotifyApplicationsEnabled" forKey:@"key"]; 20 | [notifyApplication setProperty:@"Notify Applications" forKey:@"label"]; 21 | [notifyApplication setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 22 | 23 | PSSpecifier *dismissTimeGroup = [PSSpecifier groupSpecifierWithName:@"Mini Image Dismiss Time"]; 24 | [dismissTimeGroup setProperty:@"Mini Image Dismiss Time" forKey:@"label"]; 25 | [dismissTimeGroup setProperty:@"With unlimited dimiss time, mini-image still gets dismissed when image is shared or edited" forKey:@"footerText"]; 26 | PSSpecifier *miniImageDismissSlider = [PSSpecifier preferenceSpecifierNamed:@"Mini-Image Dismiss Time" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSliderCell edit:nil]; 27 | [miniImageDismissSlider setProperty:%c(SXISliderCell) forKey:@"cellClass"]; 28 | [miniImageDismissSlider setProperty:[NSNumber numberWithFloat:1.0] forKey:@"min"]; 29 | [miniImageDismissSlider setProperty:[NSNumber numberWithFloat:25.0] forKey:@"max"]; 30 | [miniImageDismissSlider setProperty:@YES forKey:@"showValue"]; 31 | [miniImageDismissSlider setProperty:[NSNumber numberWithFloat:5.0] forKey:@"default"]; 32 | [miniImageDismissSlider setProperty:kTweakIdentifier forKey:@"defaults"]; 33 | [miniImageDismissSlider setProperty:@"dismissTime" forKey:@"key"]; 34 | [miniImageDismissSlider setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 35 | PSSpecifier *unlimitedDismiss = [PSSpecifier preferenceSpecifierNamed:@"Unlimited Dismiss Time" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 36 | [unlimitedDismiss setProperty:@NO forKey:@"default"]; 37 | [unlimitedDismiss setProperty:kTweakIdentifier forKey:@"defaults"]; 38 | [unlimitedDismiss setProperty:@"isUnlimitedDismissTimeEnabled" forKey:@"key"]; 39 | [unlimitedDismiss setProperty:@"Unlimited Dismiss Time" forKey:@"label"]; 40 | [unlimitedDismiss setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 41 | 42 | PSSpecifier *soundGroup = [PSSpecifier emptyGroupSpecifier]; 43 | PSSpecifier *disableShutterSound = [PSSpecifier preferenceSpecifierNamed:@"Disable Shutter Sound" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 44 | [disableShutterSound setProperty:@NO forKey:@"default"]; 45 | [disableShutterSound setProperty:kTweakIdentifier forKey:@"defaults"]; 46 | [disableShutterSound setProperty:@"isShutterSoundDisabled" forKey:@"key"]; 47 | [disableShutterSound setProperty:@"Disable Shutter Sound" forKey:@"label"]; 48 | [disableShutterSound setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 49 | PSSpecifier *copyToClipboard = [PSSpecifier preferenceSpecifierNamed:@"Copy to clipboard" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 50 | [copyToClipboard setProperty:@NO forKey:@"default"]; 51 | [copyToClipboard setProperty:kTweakIdentifier forKey:@"defaults"]; 52 | [copyToClipboard setProperty:@"isCopyToPasteBoardEnabled" forKey:@"key"]; 53 | [copyToClipboard setProperty:@"Copy to clipboard" forKey:@"label"]; 54 | [copyToClipboard setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 55 | 56 | PSSpecifier *saveGroup = [PSSpecifier groupSpecifierWithName:@"Screenshot"]; 57 | [saveGroup setProperty:@"Screenshot" forKey:@"label"]; 58 | [saveGroup setProperty:@"Spam screenshots is when new screenshot is taken while there is already a mini image on screen or the animation is in progress" forKey:@"footerText"]; 59 | PSSpecifier *dismissAction = [PSSpecifier preferenceSpecifierNamed:@"Save on Manual Dismiss" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 60 | [dismissAction setProperty:@YES forKey:@"default"]; 61 | [dismissAction setProperty:kTweakIdentifier forKey:@"defaults"]; 62 | [dismissAction setProperty:@"isSaveOnSwipeDismissEnabled" forKey:@"key"]; 63 | [dismissAction setProperty:@"Save on Manual Dismiss" forKey:@"label"]; 64 | [dismissAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 65 | PSSpecifier *rightDismissAction = [PSSpecifier preferenceSpecifierNamed:@"Save on Right Dismiss" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 66 | [rightDismissAction setProperty:@NO forKey:@"default"]; 67 | [rightDismissAction setProperty:kTweakIdentifier forKey:@"defaults"]; 68 | [rightDismissAction setProperty:@"isSaveOnRightSwipeDismissEnabled" forKey:@"key"]; 69 | [rightDismissAction setProperty:@"Save on Right Dismiss" forKey:@"label"]; 70 | [rightDismissAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 71 | PSSpecifier *autoDimissAction = [PSSpecifier preferenceSpecifierNamed:@"Save on Auto Dismiss" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 72 | [autoDimissAction setProperty:@YES forKey:@"default"]; 73 | [autoDimissAction setProperty:kTweakIdentifier forKey:@"defaults"]; 74 | [autoDimissAction setProperty:@"isSaveOnAutoDismissEnabled" forKey:@"key"]; 75 | [autoDimissAction setProperty:@"Save on Auto Dismiss" forKey:@"label"]; 76 | [autoDimissAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 77 | PSSpecifier *shareAction = [PSSpecifier preferenceSpecifierNamed:@"Save on Share" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 78 | [shareAction setProperty:@YES forKey:@"default"]; 79 | [shareAction setProperty:kTweakIdentifier forKey:@"defaults"]; 80 | [shareAction setProperty:@"isSaveOnShareEnabled" forKey:@"key"]; 81 | [shareAction setProperty:@"Save on Share" forKey:@"label"]; 82 | [shareAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 83 | PSSpecifier *editorAction = [PSSpecifier preferenceSpecifierNamed:@"Save Unedited (With Edited)" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 84 | [editorAction setProperty:@NO forKey:@"default"]; 85 | [editorAction setProperty:kTweakIdentifier forKey:@"defaults"]; 86 | [editorAction setProperty:@"isSaveUneditedEnabled" forKey:@"key"]; 87 | [editorAction setProperty:@"Save Unedited (With Edited)" forKey:@"label"]; 88 | [editorAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 89 | PSSpecifier *editorCancelAction = [PSSpecifier preferenceSpecifierNamed:@"Save Unedited On Cancel" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 90 | [editorCancelAction setProperty:@YES forKey:@"default"]; 91 | [editorCancelAction setProperty:kTweakIdentifier forKey:@"defaults"]; 92 | [editorCancelAction setProperty:@"isSaveUneditedOnCancelEnabled" forKey:@"key"]; 93 | [editorCancelAction setProperty:@"Save Unedited On Cancel" forKey:@"label"]; 94 | [editorCancelAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 95 | PSSpecifier *editorShareAction = [PSSpecifier preferenceSpecifierNamed:@"Save Unedited On Share" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 96 | [editorShareAction setProperty:@YES forKey:@"default"]; 97 | [editorShareAction setProperty:kTweakIdentifier forKey:@"defaults"]; 98 | [editorShareAction setProperty:@"isSaveUneditedOnShareEnabled" forKey:@"key"]; 99 | [editorShareAction setProperty:@"Save Unedited On Share" forKey:@"label"]; 100 | [editorShareAction setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 101 | PSSpecifier *spamSave = [PSSpecifier preferenceSpecifierNamed:@"Save spam screenshots" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 102 | [spamSave setProperty:@YES forKey:@"default"]; 103 | [spamSave setProperty:kTweakIdentifier forKey:@"defaults"]; 104 | [spamSave setProperty:@"isSpamSaveEnabled" forKey:@"key"]; 105 | [spamSave setProperty:@"Save spam screenshots" forKey:@"label"]; 106 | [spamSave setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 107 | 108 | PSSpecifier *behavior = [PSSpecifier groupSpecifierWithName:@"Force Dismiss"]; 109 | [behavior setProperty:@"Force Dismiss" forKey:@"label"]; 110 | [behavior setProperty:@"Force dismiss editor, share sheet and mini image automatically when device locked or call received" forKey:@"footerText"]; 111 | PSSpecifier *dismissOnLock = [PSSpecifier preferenceSpecifierNamed:@"Dismiss on Lock" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 112 | [dismissOnLock setProperty:@NO forKey:@"default"]; 113 | [dismissOnLock setProperty:kTweakIdentifier forKey:@"defaults"]; 114 | [dismissOnLock setProperty:@"isDismissOnLockEnabled" forKey:@"key"]; 115 | [dismissOnLock setProperty:@"Dismiss on Lock" forKey:@"label"]; 116 | [dismissOnLock setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 117 | PSSpecifier *dismissOnCall = [PSSpecifier preferenceSpecifierNamed:@"Dismiss on Call" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 118 | [dismissOnCall setProperty:@YES forKey:@"default"]; 119 | [dismissOnCall setProperty:kTweakIdentifier forKey:@"defaults"]; 120 | [dismissOnCall setProperty:@"isDismissOnCallEnabled" forKey:@"key"]; 121 | [dismissOnCall setProperty:@"Dismiss on Call" forKey:@"label"]; 122 | [dismissOnCall setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 123 | 124 | PSSpecifier *lockscreen = [PSSpecifier groupSpecifierWithName:@"Lockscreen"]; 125 | [lockscreen setProperty:@"Lockscreen" forKey:@"label"]; 126 | [lockscreen setProperty:@"Disable certain features on lockscreen" forKey:@"footerText"]; 127 | PSSpecifier *share = [PSSpecifier preferenceSpecifierNamed:@"Disable Sharing" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 128 | [share setProperty:@YES forKey:@"default"]; 129 | [share setProperty:kTweakIdentifier forKey:@"defaults"]; 130 | [share setProperty:@"isLockscreenShareDisabled" forKey:@"key"]; 131 | [share setProperty:@"Disable Sharing" forKey:@"label"]; 132 | [share setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 133 | PSSpecifier *editing = [PSSpecifier preferenceSpecifierNamed:@"Disable Editing" target:self set:@selector(setPreferenceValue:specifier:) get:@selector(readPreferenceValue:) detail:nil cell:PSSwitchCell edit:nil]; 134 | [editing setProperty:@NO forKey:@"default"]; 135 | [editing setProperty:kTweakIdentifier forKey:@"defaults"]; 136 | [editing setProperty:@"isLockscreenEditDisabled" forKey:@"key"]; 137 | [editing setProperty:@"Disable Editing" forKey:@"label"]; 138 | [editing setProperty:kSettingsChangedIdentifier forKey:@"PostNotification"]; 139 | 140 | PSSpecifier *resetGroup = [PSSpecifier emptyGroupSpecifier]; 141 | PSSpecifier *resetConfigurationButton = [PSSpecifier preferenceSpecifierNamed:@"Reset Configuration" target:self set:NULL get:NULL detail:nil cell:PSButtonCell edit:nil]; 142 | resetConfigurationButton->action = @selector(resetConfiguration); 143 | [resetConfigurationButton setProperty:@"Reset Configuration" forKey:@"label"]; 144 | [resetConfigurationButton setProperty:@1 forKey:@"alignment"]; 145 | 146 | _specifiers = [@[swipeGroup, enableRightSwipe, notifyApplication, dismissTimeGroup, miniImageDismissSlider, unlimitedDismiss, soundGroup, disableShutterSound, copyToClipboard, saveGroup, dismissAction, rightDismissAction, autoDimissAction, shareAction, editorAction, editorCancelAction, editorShareAction, spamSave, behavior, dismissOnLock, dismissOnCall, lockscreen, share, editing, resetGroup, resetConfigurationButton] mutableCopy]; 147 | } 148 | 149 | return _specifiers; 150 | } 151 | 152 | - (void)resetConfiguration { 153 | for (PSSpecifier *specifier in _specifiers) 154 | if ([specifier propertyForKey:@"key"] != nil) 155 | [self setPreferenceValue:[specifier propertyForKey:@"default"] specifier:specifier]; 156 | [self reloadSpecifiers]; 157 | } 158 | 159 | @end -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #import "headers.h" 2 | 3 | extern "C" UIImage *_UICreateScreenUIImageWithRotation(BOOL rotate); 4 | 5 | ESSWindow *window = nil; // need it to be global so it can be accessed in ESSContainerView.mm 6 | 7 | %hook SpringBoard 8 | -(void)applicationDidFinishLaunching:(id)arg1 { 9 | %orig(arg1); 10 | 11 | if (window != nil) 12 | [window release]; 13 | 14 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 15 | 16 | SBLockScreenManager *manager = [%c(SBLockScreenManager) sharedInstance]; 17 | if (manager != nil) { 18 | SBLockScreenViewControllerBase *lockScreenViewController = [manager lockScreenViewController]; 19 | if ([lockScreenViewController isKindOfClass:%c(SBLockScreenViewController)]) { 20 | UIView *lockScreenView = [(SBLockScreenViewController *)lockScreenViewController lockScreenView]; 21 | preferenceManager.aboveLockscreenWindowLevel = lockScreenView.window.windowLevel + 1; 22 | preferenceManager.aboveHomeAndAppsWindowLevel = lockScreenView.window.windowLevel - 2; 23 | } else if ([lockScreenViewController isKindOfClass:%c(SBDashBoardViewController)]) { 24 | UIView *dashBoardView = [(SBDashBoardViewController *)lockScreenViewController dashBoardView]; 25 | preferenceManager.aboveLockscreenWindowLevel = dashBoardView.window.windowLevel + 1; 26 | preferenceManager.aboveHomeAndAppsWindowLevel = dashBoardView.window.windowLevel - 2; 27 | } 28 | } 29 | 30 | [preferenceManager updatePriority]; 31 | 32 | window = [[ESSWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 33 | } 34 | 35 | -(void)noteInterfaceOrientationChanged:(UIInterfaceOrientation)arg1 duration:(CGFloat)arg2 logMessage:(id)arg3 { 36 | %orig(arg1, arg2, arg3); 37 | 38 | if (window != nil) { // manual rotation to fix split view controllers rotations 39 | ESSController *viewController = (ESSController *)(window.rootViewController); 40 | viewController.rotationEnabled = YES; 41 | [window _updateToInterfaceOrientation:arg1 animated:YES]; 42 | viewController.rotationEnabled = NO; 43 | } 44 | } 45 | 46 | -(void)noteInterfaceOrientationChanged:(UIInterfaceOrientation)arg1 duration:(CGFloat)arg2 { 47 | %orig(arg1, arg2); 48 | 49 | if (window != nil) { // manual rotation to fix split view controllers rotations 50 | ESSController *viewController = (ESSController *)(window.rootViewController); 51 | viewController.rotationEnabled = YES; 52 | [window _updateToInterfaceOrientation:arg1 animated:YES]; 53 | viewController.rotationEnabled = NO; 54 | } 55 | } 56 | 57 | -(void)frontDisplayDidChange:(id)arg1 { 58 | %orig(arg1); 59 | 60 | if (window != nil) { 61 | ESSController *viewController = (ESSController *)(window.rootViewController); 62 | viewController.rotationEnabled = YES; 63 | [window _updateToInterfaceOrientation:[self activeInterfaceOrientation] animated:YES]; 64 | viewController.rotationEnabled = NO; 65 | 66 | [viewController updateUndoAndRedoButtons]; 67 | 68 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 69 | 70 | if ([arg1 isKindOfClass:%c(SBLockScreenViewController)] || [arg1 isKindOfClass:%c(SBDashBoardViewController)]) { 71 | DisplayedControllerType currentControllerType = [viewController currentlyHostingViewControllerType]; 72 | if (preferenceManager.isDismissOnLockEnabled) { 73 | for (UIView *view in viewController.containerViews) { 74 | [NSObject cancelPreviousPerformRequestsWithTarget:viewController selector:@selector(autoHide:) object:view]; 75 | if ([view isKindOfClass:%c(ESSContainerView)] && currentControllerType == kNone && preferenceManager.isSaveOnSwipeDismissEnabled) 76 | [viewController saveScreenshot:((ESSContainerView *)view).image]; 77 | [viewController forceHideWithoutAnimations:view]; 78 | } 79 | 80 | if (currentControllerType == kEditor) { 81 | [viewController forceSaveMarkUpWithCompletion:^{ 82 | window.windowLevel = preferenceManager.currentTweakLevel; 83 | }]; 84 | } else if (currentControllerType == kShareSheet) { 85 | [viewController dismissShareSheetAnimated:NO completion:^{ 86 | window.windowLevel = preferenceManager.currentTweakLevel; 87 | }]; 88 | } else { 89 | window.windowLevel = preferenceManager.currentTweakLevel; 90 | } 91 | } else { 92 | if (currentControllerType == kEditor && preferenceManager.isLockscreenEditDisabled) { 93 | [viewController forceSaveMarkUpWithCompletion:^{ 94 | window.windowLevel = preferenceManager.currentTweakLevel; 95 | }]; 96 | } else if (currentControllerType == kShareSheet && preferenceManager.isLockscreenShareDisabled) { 97 | [viewController dismissShareSheetAnimated:NO completion:^{ 98 | window.windowLevel = preferenceManager.currentTweakLevel; 99 | }]; 100 | } else { 101 | window.windowLevel = preferenceManager.currentTweakLevel; 102 | } 103 | } 104 | } else { 105 | if (preferenceManager.currentTweakLevel == preferenceManager.aboveLockscreenWindowLevel) 106 | window.windowLevel = preferenceManager.aboveHomeAndAppsWindowLevel; 107 | } 108 | } 109 | } 110 | %end 111 | 112 | %hook SBScreenshotManager 113 | -(void)saveScreenshotsWithCompletion:(id)arg1 { 114 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 115 | if (window != nil && preferenceManager.isEnabled) { 116 | ESSController *viewController = (ESSController *)(window.rootViewController); 117 | if ([viewController currentlyHostingViewControllerType] != kNone) 118 | return; 119 | 120 | for (UIView *view in viewController.containerViews) { 121 | [NSObject cancelPreviousPerformRequestsWithTarget:viewController selector:@selector(autoHide:) object:view]; 122 | [view.layer removeAllAnimations]; 123 | view.hidden = TRUE; 124 | [view setNeedsDisplay]; 125 | if (preferenceManager.isSpamSaveEnabled && [view isKindOfClass:%c(ESSContainerView)]) 126 | [viewController saveScreenshot:((ESSContainerView *)view).image]; 127 | [viewController forceHideWithoutAnimations:view]; 128 | } 129 | 130 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 131 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 132 | 133 | dispatch_async(dispatch_get_main_queue(), ^{ 134 | if (!preferenceManager.isShutterSoundDisabled) 135 | AudioServicesPlaySystemSound(kPhotoShutterSystemSound); 136 | 137 | SBScreenFlash *flasher = [%c(SBScreenFlash) mainScreenFlasher]; 138 | UIImage *screenImage = _UICreateScreenUIImageWithRotation(TRUE); 139 | [flasher setScreenshotImage:screenImage]; 140 | [flasher screenshotwithCompletion:nil]; 141 | }); 142 | } else { 143 | %orig(arg1); 144 | } 145 | } 146 | %end 147 | 148 | %hook SBScreenShotter 149 | -(void)saveScreenshot:(BOOL)arg1 { 150 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 151 | if (window != nil && preferenceManager.isEnabled) { 152 | ESSController *viewController = (ESSController *)(window.rootViewController); 153 | if ([viewController currentlyHostingViewControllerType] != kNone) 154 | return; 155 | 156 | for (UIView *view in viewController.containerViews) { 157 | [NSObject cancelPreviousPerformRequestsWithTarget:viewController selector:@selector(autoHide:) object:view]; 158 | [view.layer removeAllAnimations]; 159 | view.hidden = TRUE; 160 | [view setNeedsDisplay]; 161 | if (preferenceManager.isSpamSaveEnabled && [view isKindOfClass:%c(ESSContainerView)]) 162 | [viewController saveScreenshot:((ESSContainerView *)view).image]; 163 | [viewController forceHideWithoutAnimations:view]; 164 | } 165 | 166 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 167 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 168 | 169 | dispatch_async(dispatch_get_main_queue(), ^{ 170 | if (!preferenceManager.isShutterSoundDisabled) 171 | AudioServicesPlaySystemSound(kPhotoShutterSystemSound); 172 | 173 | SBScreenFlash *flasher = [%c(SBScreenFlash) mainScreenFlasher]; 174 | UIImage *screenImage = _UICreateScreenUIImageWithRotation(TRUE); 175 | [flasher setScreenshotImage:screenImage]; 176 | [flasher screenshotwithCompletion:nil]; 177 | }); 178 | } else { 179 | %orig(arg1); 180 | } 181 | } 182 | %end 183 | 184 | %hook SBScreenFlash 185 | UIImage *_screenshotImage; 186 | 187 | %new 188 | -(void)screenshotwithCompletion:(id)arg1 { 189 | [self flashColor:[UIColor clearColor] withCompletion:arg1]; 190 | 191 | if (window != nil) { 192 | ESSController *viewController = (ESSController *)(window.rootViewController); 193 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 194 | 195 | CGFloat imageViewWidth = window.frame.size.width * preferenceManager.miniImageScale; 196 | CGFloat imageViewHeight = window.frame.size.height * preferenceManager.miniImageScale; 197 | 198 | UIWindow *_flashWindow = MSHookIvar(self, "_flashWindow"); 199 | if (_flashWindow != nil) { 200 | _flashWindow.hidden = YES; 201 | window.windowLevel = _flashWindow.windowLevel; // 2200 for flash window 202 | 203 | if (preferenceManager.screenFlashWindowLevel != window.windowLevel) { 204 | preferenceManager.screenFlashWindowLevel = window.windowLevel; 205 | [preferenceManager updatePriority]; 206 | } 207 | } 208 | 209 | if (preferenceManager.isNotifyApplicationsEnabled) { 210 | UIRemoteApplication *remoteApplication = [(SpringBoard *)[%c(SpringBoard) sharedApplication] _accessibilityFrontMostApplication].remoteApplication; 211 | [remoteApplication didTakeScreenshot]; 212 | } 213 | 214 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 215 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 216 | 217 | UIColor *borderColor = [LCPParseColorString([preferenceManager uiHexColor], @"#FFFFFF") retain]; 218 | ESSContainerView *containerView = [[ESSContainerView alloc] initWithFrame:CGRectMake(preferenceManager.miniImageMargin, window.frame.size.height - imageViewHeight - preferenceManager.miniImageMargin - 2 * preferenceManager.miniImageWhitePadding, imageViewWidth + 2 * preferenceManager.miniImageWhitePadding, imageViewHeight + 2 * preferenceManager.miniImageWhitePadding) withColor:borderColor]; 219 | [viewController.containerViews addObject:containerView]; 220 | [viewController.view addSubview:containerView]; 221 | 222 | [UIView animateWithDuration:preferenceManager.animationSpeed animations:^{ 223 | [containerView setTransform:CGAffineTransformMakeScale(1, 1)]; 224 | containerView.center = CGPointMake(preferenceManager.miniImageMargin + preferenceManager.miniImageWhitePadding + imageViewWidth / 2, window.frame.size.height - imageViewHeight / 2 - preferenceManager.miniImageMargin - preferenceManager.miniImageWhitePadding); 225 | [containerView.layer setCornerRadius:preferenceManager.miniImageRoundness]; 226 | } completion:^(BOOL finished) { 227 | if (preferenceManager.currentTweakLevel == preferenceManager.aboveLockscreenWindowLevel) 228 | window.windowLevel = ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) ? preferenceManager.aboveLockscreenWindowLevel : preferenceManager.aboveHomeAndAppsWindowLevel; 229 | else 230 | window.windowLevel = preferenceManager.currentTweakLevel; 231 | 232 | if (finished) { 233 | UIImage *image = _screenshotImage; 234 | _screenshotImage = nil; 235 | if (image == nil) { // just in case (should never actually go inside this if statement) 236 | PLPhotoLibrary *library = [PLPhotoLibrary sharedPhotoLibrary]; 237 | PLManagedAlbum *album = [library.albums firstObject]; 238 | PLManagedAsset *photo = [album.assets lastObject]; 239 | image = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[photo mainFileURL]]] autorelease]; 240 | } 241 | 242 | UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 243 | imageView.frame = CGRectMake(preferenceManager.miniImageWhitePadding, preferenceManager.miniImageWhitePadding, imageViewWidth, imageViewHeight); 244 | imageView.clipsToBounds = YES; 245 | imageView.contentMode = UIViewContentModeScaleAspectFit; 246 | 247 | UIBlurEffect *blur = nil; 248 | // lightness code stolen from https://stackoverflow.com/questions/2509443/check-if-uicolor-is-dark-or-bright 249 | const CGFloat *rgba = CGColorGetComponents(borderColor.CGColor); 250 | CGFloat brightness = (rgba[0] * 299 + rgba[1] * 587 * rgba[2] * 114) / 1000; 251 | if (brightness < 0.5) 252 | blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 253 | else 254 | blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; 255 | UIVisualEffectView *lightBlurView = [[UIVisualEffectView alloc] initWithEffect:blur]; 256 | [lightBlurView setFrame:imageView.bounds]; 257 | [imageView addSubview:lightBlurView]; 258 | [containerView insertSubview:imageView atIndex:0]; 259 | 260 | [UIView transitionWithView:imageView duration:preferenceManager.dismissAnimationSpeed options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ 261 | [lightBlurView setEffect:nil]; 262 | } completion:^(BOOL finished) { 263 | if (finished) { 264 | [lightBlurView removeFromSuperview]; 265 | [lightBlurView release]; 266 | 267 | if (preferenceManager.isCopyToPasteBoardEnabled) 268 | [UIPasteboard generalPasteboard].image = image; 269 | } 270 | }]; 271 | 272 | UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:viewController action:@selector(imageTapped:)]; 273 | [tapRecognizer setDelegate:viewController]; 274 | [containerView addGestureRecognizer:tapRecognizer]; 275 | 276 | UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:viewController action:@selector(imagePanned:)]; 277 | [panRecognizer setDelegate:viewController]; 278 | panRecognizer.minimumNumberOfTouches = 1; 279 | [containerView addGestureRecognizer:panRecognizer]; 280 | 281 | UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:viewController action:@selector(imageLongPressed:)]; 282 | [longPressRecognizer setDelegate:viewController]; 283 | longPressRecognizer.numberOfTapsRequired = 0; 284 | longPressRecognizer.minimumPressDuration = kLongPressStartDuration; 285 | longPressRecognizer.allowableMovement = kLongPressRange; 286 | [containerView addGestureRecognizer:longPressRecognizer]; 287 | 288 | [tapRecognizer requireGestureRecognizerToFail:longPressRecognizer]; 289 | [panRecognizer requireGestureRecognizerToFail:longPressRecognizer]; 290 | 291 | containerView.image = image; 292 | 293 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 294 | [viewController performSelector:@selector(autoHide:) withObject:containerView afterDelay:preferenceManager.dismissTime]; 295 | 296 | [imageView release]; 297 | [tapRecognizer release]; 298 | [panRecognizer release]; 299 | [longPressRecognizer release]; 300 | 301 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 302 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 303 | } 304 | }]; 305 | } 306 | } 307 | 308 | %new 309 | -(void)setScreenshotImage:(id)image { 310 | _screenshotImage = image; 311 | } 312 | 313 | %new 314 | -(UIImage *)screenshotImage { 315 | return _screenshotImage; 316 | } 317 | %end 318 | 319 | %hook MarkupViewController 320 | -(void)_updateUndoButtonWithController:(id)arg1 { 321 | %orig(arg1); 322 | 323 | if (window != nil) { 324 | ESSController *viewController = (ESSController *)(window.rootViewController); 325 | if ([viewController isEqualToMarkUpEditor:self]) // only call update on our view controller 326 | [viewController updateUndoAndRedoButtons]; 327 | } 328 | } 329 | %end 330 | 331 | %hook AKUndoController 332 | -(void)_annotationsWillBeRemoved:(id)arg1 onPageController:(id)arg2 { 333 | %orig(arg1, arg2); 334 | 335 | if (window != nil) { 336 | ESSController *viewController = (ESSController *)(window.rootViewController); 337 | if ([viewController isEqualToUndoController:self]) // only call update on our view controller 338 | [viewController updateUndoAndRedoButtons]; 339 | } 340 | } 341 | 342 | -(void)_annotationsWereAdded:(id)arg1 onPageController:(id)arg2 { 343 | %orig(arg1, arg2); 344 | 345 | if (window != nil) { 346 | ESSController *viewController = (ESSController *)(window.rootViewController); 347 | if ([viewController isEqualToUndoController:self]) // only call update on our view controller 348 | [viewController updateUndoAndRedoButtons]; 349 | } 350 | } 351 | %end 352 | 353 | %hook MUImageContentViewController 354 | -(CGFloat)_zoomToFitZoomFactorIncludingScrollViewEdgeInsets { 355 | CGFloat result = %orig(); 356 | if (window != nil) { 357 | ESSController *viewController = (ESSController *)(window.rootViewController); 358 | if ([viewController isEqualToImageContentViewController:self]) // only modify if it is our mark up editor's image controller 359 | return result * kImageMinimumScaleMultiplier; 360 | } 361 | return result; 362 | } 363 | %end 364 | 365 | %hook SBInCallAlertManager // to hide tweak when in phone call 366 | -(void)noteActivatedInCallAlert:(id)arg1 { 367 | %orig(arg1); 368 | 369 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 370 | 371 | if (window != nil && preferenceManager.isDismissOnCallEnabled) { 372 | ESSController *viewController = (ESSController *)(window.rootViewController); 373 | DisplayedControllerType currentControllerType = [viewController currentlyHostingViewControllerType]; 374 | for (UIView *view in viewController.containerViews) { 375 | [NSObject cancelPreviousPerformRequestsWithTarget:viewController selector:@selector(autoHide:) object:view]; 376 | if ([view isKindOfClass:%c(ESSContainerView)] && currentControllerType == kNone && preferenceManager.isSaveOnSwipeDismissEnabled) 377 | [viewController saveScreenshot:((ESSContainerView *)view).image]; 378 | [viewController forceHideWithoutAnimations:view]; 379 | } 380 | [viewController forceSaveMarkUpWithCompletion:nil]; 381 | [viewController dismissShareSheetAnimated:NO completion:nil]; 382 | } 383 | } 384 | %end 385 | 386 | %hook MUImageDownsamplingUtilities // winterboard fix (might even fix anemone) 387 | +(CGImageSourceRef)_newImageSourceWithSourceContent:(id)arg1 { 388 | if (window != nil) { 389 | ESSController *viewController = (ESSController *)(window.rootViewController); 390 | if ([viewController isEqualToSourceContent:arg1]) 391 | return %orig(nil); 392 | return %orig(arg1); 393 | } else { 394 | return %orig(arg1); 395 | } 396 | } 397 | %end 398 | 399 | static void preferencesChanged() { 400 | [[SXIPreferences sharedInstance] updatePreferences]; 401 | } 402 | 403 | %dtor { 404 | CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFStringRef)kSettingsChangedIdentifier, NULL); 405 | 406 | if (window != nil) { 407 | [window release]; 408 | window = nil; 409 | } 410 | } 411 | 412 | %ctor { 413 | preferencesChanged(); 414 | 415 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)preferencesChanged, (CFStringRef)kSettingsChangedIdentifier, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 416 | } -------------------------------------------------------------------------------- /ESSController.xm: -------------------------------------------------------------------------------- 1 | #import 2 | #import "headers.h" 3 | 4 | extern ESSWindow *window; 5 | 6 | @implementation ESSController 7 | +(UIImage *)imageFromView:(UIView *)view andView:(UIView *)secondView { 8 | UIGraphicsBeginImageContextWithOptions([view bounds].size, NO, 0.0); 9 | CGContextRef context = UIGraphicsGetCurrentContext(); 10 | if (CGAffineTransformIsIdentity(secondView.transform)) { 11 | [view.layer renderInContext:context]; 12 | [secondView.layer renderInContext:context]; 13 | } else { 14 | // calculate the translations and scales 15 | CGFloat scaleX = secondView.transform.a * view.frame.size.width / secondView.frame.size.width; 16 | CGFloat scaleY = secondView.transform.d * view.frame.size.height / secondView.frame.size.height; 17 | CGFloat translateX = scaleX < 0.0 ? [secondView bounds].size.width * -scaleX : 0.0; 18 | CGFloat translateY = scaleY < 0.0 ? [secondView bounds].size.height * -scaleY : 0.0; 19 | 20 | [view.layer renderInContext:context]; 21 | CGContextSaveGState(context); 22 | CGContextTranslateCTM(context, translateX, translateY); 23 | CGContextScaleCTM(context, scaleX, scaleY); 24 | [secondView.layer renderInContext:context]; 25 | CGContextRestoreGState(context); 26 | } 27 | UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); 28 | UIGraphicsEndImageContext(); 29 | return [result retain]; 30 | } 31 | 32 | -(id)init { 33 | self = [super init]; 34 | if (self != nil) { 35 | self.containerViews = [NSMutableArray array]; 36 | _activityViewController = nil; 37 | _markUpEditor = nil; 38 | self.rotationEnabled = NO; 39 | useLongPressAsPan = YES; 40 | timerDidTrigger = NO; 41 | didHideStatusBar = NO; 42 | resultEditedImage = nil; 43 | } 44 | return self; 45 | } 46 | 47 | -(void)dealloc { 48 | for (ESSContainerView *view in self.containerViews) { 49 | [view release]; 50 | view = nil; 51 | } 52 | if (_activityViewController != nil) 53 | [_activityViewController release]; 54 | _activityViewController = nil; 55 | if (_markUpEditor != nil) { 56 | if (_markUpEditor.navBar != nil) 57 | [_markUpEditor.navBar release]; 58 | _markUpEditor.navBar = nil; 59 | [_markUpEditor release]; 60 | } 61 | _markUpEditor = nil; 62 | if (redoButton != nil) 63 | [redoButton release]; 64 | redoButton = nil; 65 | if (undoButton != nil) 66 | [undoButton release]; 67 | undoButton = nil; 68 | if (saveButton != nil) 69 | [saveButton release]; 70 | saveButton = nil; 71 | if (shareButton != nil) 72 | [shareButton release]; 73 | shareButton = nil; 74 | if (resultEditedImage != nil) 75 | [resultEditedImage release]; 76 | resultEditedImage = nil; 77 | [super dealloc]; 78 | } 79 | 80 | -(void)saveScreenshot:(UIImage *)image { 81 | if (%c(SBScreenShotter)) 82 | UIImageWriteToSavedPhotosAlbum(image, [%c(SBScreenShotter) sharedInstance], @selector(finishedWritingScreenshot:didFinishSavingWithError:context:), nil); 83 | else if (%c(SBScreenshotManager)) 84 | [[((SpringBoard *)[%c(SpringBoard) sharedApplication]).screenshotManager _persistenceCoordinator] saveScreenshot:image withCompletion:nil]; 85 | } 86 | 87 | -(BOOL)shouldAutorotate { 88 | return self.rotationEnabled; 89 | } 90 | 91 | -(void)viewWillTransitionToSize:(CGSize)arg1 withTransitionCoordinator:(id)arg2 { 92 | [super viewWillTransitionToSize:arg1 withTransitionCoordinator:arg2]; 93 | 94 | if (_markUpEditor != nil && _markUpEditor.navBar != nil) 95 | [arg2 animateAlongsideTransition:^(id context) { 96 | _markUpEditor.navBar.frame = CGRectMake(0, 0, arg1.width, 44); 97 | } completion:nil]; 98 | } 99 | 100 | -(void)displayShareSheet:(ESSContainerView *)view { 101 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 102 | 103 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked] && preferenceManager.isLockscreenShareDisabled) { 104 | [view shake]; 105 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 106 | [self performSelector:@selector(autoHide:) withObject:view afterDelay:preferenceManager.dismissTime]; 107 | } else { 108 | if (_activityViewController == nil) { 109 | SpringBoard *springBoardApplication = (SpringBoard *)[%c(SpringBoard) sharedApplication]; 110 | if ([springBoardApplication _accessibilityFrontMostApplication] == nil) 111 | [springBoardApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; 112 | else 113 | [[%c(SBUIController) sharedInstance] _hideKeyboard]; 114 | 115 | _activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[view.image] applicationActivities:nil]; 116 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 117 | _activityViewController.popoverPresentationController.sourceView = view; 118 | [_activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activtyError) { 119 | [_activityViewController release]; 120 | _activityViewController = nil; 121 | if (completed) { 122 | [self forceHide:view]; 123 | 124 | if (activityType != UIActivityTypeSaveToCameraRoll && preferenceManager.isSaveOnShareEnabled) 125 | [self saveScreenshot:view.image]; 126 | } else { 127 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 128 | [self performSelector:@selector(autoHide:) withObject:view afterDelay:preferenceManager.dismissTime]; 129 | } 130 | }]; 131 | if (preferenceManager.isSaveOnSwipeDismissEnabled) 132 | _activityViewController.excludedActivityTypes = @[UIActivityTypeSaveToCameraRoll]; 133 | _activityViewController.showKeyboardAutomatically = YES; 134 | [window makeKeyWindow]; // blank keyboard fix 135 | 136 | [self presentViewController:_activityViewController animated:YES completion:nil]; 137 | } 138 | } 139 | } 140 | 141 | -(void)displayEditor:(ESSContainerView *)view { 142 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 143 | 144 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked] && preferenceManager.isLockscreenEditDisabled) { 145 | [view shake]; 146 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 147 | [self performSelector:@selector(autoHide:) withObject:view afterDelay:preferenceManager.dismissTime]; 148 | } else { 149 | if (%c(ANEMSettingsManager)) { 150 | ANEMSettingsManager *anemoneSettingsManager = [%c(ANEMSettingsManager) sharedManager]; 151 | if (anemoneSettingsManager != nil && [anemoneSettingsManager respondsToSelector:@selector(setCGImageHookEnabled:)]) 152 | [anemoneSettingsManager setCGImageHookEnabled:NO]; 153 | } 154 | SpringBoard *springBoardApplication = (SpringBoard *)[%c(SpringBoard) sharedApplication]; 155 | if ([springBoardApplication _accessibilityFrontMostApplication] == nil) { 156 | didHideStatusBar = YES; 157 | [springBoardApplication setStatusBarHidden:YES]; 158 | [self setNeedsStatusBarAppearanceUpdate]; 159 | [springBoardApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; 160 | } else { 161 | [[%c(SBUIController) sharedInstance] _hideKeyboard]; 162 | } 163 | 164 | if (resultEditedImage != nil) 165 | [resultEditedImage release]; 166 | resultEditedImage = nil; 167 | 168 | [self forceHide:view]; 169 | 170 | if (_markUpEditor == nil) { 171 | _markUpEditor = [[MarkupViewController alloc] initWithNibName:nil bundle:nil]; 172 | [_markUpEditor setImage:view.image]; 173 | if ([_markUpEditor respondsToSelector:@selector(setAnnotationEditingEnabled:)]) 174 | [_markUpEditor setAnnotationEditingEnabled:YES]; 175 | [_markUpEditor setShapeDetectionEnabled:YES]; 176 | [_markUpEditor setDelegate:self]; // really doesn't do anything as I don't implement any methods for delegate 177 | _markUpEditor.annotationController.overlayShouldPixelate = NO; 178 | [_markUpEditor.annotationController currentPageController].shouldPixelate = NO; 179 | 180 | NSBundle *bundle = [NSBundle bundleWithPath:kBundlePath]; 181 | 182 | UINavigationBar *navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)]; 183 | navigationBar.delegate = _markUpEditor; 184 | navigationBar.barStyle = UIBarStyleBlackTranslucent; 185 | _markUpEditor.navBar = navigationBar; 186 | 187 | UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@""]; 188 | 189 | UIBarButtonItem *cancelButton = nil; 190 | if (bundle != nil) { 191 | cancelButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"close" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(cancelMarkUp)]; 192 | saveButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"save" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(saveMarkUp)]; 193 | } else { 194 | cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop target:self action:@selector(cancelMarkUp)]; 195 | saveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(saveMarkUp)]; 196 | } 197 | [navigationItem setLeftBarButtonItems:@[cancelButton, saveButton]]; 198 | 199 | if (bundle != nil) { 200 | shareButton =[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"share" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(shareMarkUp:)]; 201 | redoButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"redo" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(redoMarkUp)]; 202 | undoButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"undo" inBundle:bundle compatibleWithTraitCollection:nil] style:UIBarButtonItemStylePlain target:self action:@selector(undoMarkUp)]; 203 | } else { 204 | shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(shareMarkUp:)]; 205 | redoButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRedo target:self action:@selector(redoMarkUp)]; 206 | undoButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemUndo target:self action:@selector(undoMarkUp)]; 207 | } 208 | [navigationItem setRightBarButtonItems:@[shareButton, redoButton, undoButton]]; 209 | 210 | navigationBar.items = @[navigationItem]; 211 | 212 | [_markUpEditor.view addSubview:navigationBar]; 213 | 214 | [window makeKeyWindow]; // blank keyboard fix 215 | 216 | [self presentViewController:_markUpEditor animated:YES completion:nil]; 217 | [self updateUndoAndRedoButtons]; 218 | 219 | [navigationItem release]; 220 | [cancelButton release]; 221 | } 222 | } 223 | } 224 | 225 | -(void)saveMarkUp { 226 | if (_markUpEditor != nil) { 227 | if ([SXIPreferences sharedInstance].isSaveUneditedEnabled) 228 | [self saveScreenshot:_markUpEditor.sourceContent]; 229 | 230 | if (resultEditedImage == nil) { 231 | [_markUpEditor.annotationController.modelController deselectAllAnnotations]; 232 | UIImage *sourceImage = (UIImage *)(_markUpEditor.sourceContent); 233 | UIImageView *imageView = [[UIImageView alloc] initWithImage:sourceImage]; 234 | imageView.frame = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height); 235 | UIView *overlayView = [_markUpEditor.annotationController currentPageController].overlayView; 236 | resultEditedImage = [ESSController imageFromView:imageView andView:overlayView]; 237 | 238 | [imageView release]; 239 | overlayView = nil; 240 | } 241 | [self saveScreenshot:resultEditedImage]; 242 | 243 | [self dismissMarkUpEditorAnimated:YES completion:nil]; 244 | } 245 | } 246 | 247 | -(void)forceSaveMarkUpWithCompletion:(void (^)())completion { 248 | if (_markUpEditor != nil) { 249 | if ([SXIPreferences sharedInstance].isSaveUneditedEnabled) 250 | [self saveScreenshot:_markUpEditor.sourceContent]; 251 | 252 | if (resultEditedImage == nil) { 253 | [_markUpEditor.annotationController.modelController deselectAllAnnotations]; 254 | UIImage *sourceImage = (UIImage *)(_markUpEditor.sourceContent); 255 | UIImageView *imageView = [[UIImageView alloc] initWithImage:sourceImage]; 256 | imageView.frame = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height); 257 | UIView *overlayView = [_markUpEditor.annotationController currentPageController].overlayView; 258 | resultEditedImage = [ESSController imageFromView:imageView andView:overlayView]; 259 | 260 | [imageView release]; 261 | overlayView = nil; 262 | } 263 | [self saveScreenshot:resultEditedImage]; 264 | 265 | [self dismissMarkUpEditorAnimated:NO completion:completion]; 266 | } 267 | } 268 | 269 | -(void)shareMarkUp:(UIBarButtonItem *)sender { 270 | if (_markUpEditor != nil) { 271 | if (resultEditedImage == nil) { 272 | [_markUpEditor.annotationController.modelController deselectAllAnnotations]; 273 | UIImage *sourceImage = (UIImage *)(_markUpEditor.sourceContent); 274 | UIImageView *imageView = [[UIImageView alloc] initWithImage:sourceImage]; 275 | imageView.frame = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height); 276 | UIView *overlayView = [_markUpEditor.annotationController currentPageController].overlayView; 277 | resultEditedImage = [ESSController imageFromView:imageView andView:overlayView]; 278 | 279 | [imageView release]; 280 | overlayView = nil; 281 | } 282 | 283 | UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[resultEditedImage] applicationActivities:nil]; 284 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 285 | activityViewController.popoverPresentationController.sourceView = [sender view]; 286 | [activityViewController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activtyError) { 287 | if (completed) { 288 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 289 | if (preferenceManager.isSaveUneditedOnShareEnabled) 290 | [self saveScreenshot:_markUpEditor.sourceContent]; 291 | if (activityType != UIActivityTypeSaveToCameraRoll && preferenceManager.isSaveOnShareEnabled) 292 | [self saveScreenshot:resultEditedImage]; 293 | [self dismissMarkUpEditorAnimated:YES completion:nil]; 294 | } 295 | }]; 296 | activityViewController.excludedActivityTypes = @[UIActivityTypeSaveToCameraRoll]; 297 | activityViewController.showKeyboardAutomatically = YES; 298 | [window makeKeyWindow]; // blank keyboard fix 299 | 300 | [_markUpEditor presentViewController:activityViewController animated:YES completion:nil]; 301 | 302 | [activityViewController release]; 303 | } 304 | } 305 | 306 | -(void)cancelMarkUp { 307 | if ([SXIPreferences sharedInstance].isSaveUneditedOnCancelEnabled) 308 | [self saveScreenshot:_markUpEditor.sourceContent]; 309 | [self dismissMarkUpEditorAnimated:YES completion:nil]; 310 | } 311 | 312 | -(void)dismissMarkUpEditorAnimated:(BOOL)animated completion:(void (^)())completion { 313 | if (_markUpEditor != nil) { 314 | void (^dismissMarkUp)() = ^{ 315 | [_markUpEditor dismissViewControllerAnimated:animated completion:^{ 316 | [_markUpEditor.navBar release]; 317 | _markUpEditor.navBar = nil; 318 | [_markUpEditor release]; 319 | _markUpEditor = nil; 320 | [redoButton release]; 321 | redoButton = nil; 322 | [undoButton release]; 323 | undoButton = nil; 324 | [saveButton release]; 325 | saveButton = nil; 326 | [shareButton release]; 327 | shareButton = nil; 328 | 329 | if (resultEditedImage != nil) 330 | [resultEditedImage release]; 331 | resultEditedImage = nil; 332 | 333 | if (%c(ANEMSettingsManager)) { 334 | ANEMSettingsManager *anemoneSettingsManager = [%c(ANEMSettingsManager) sharedManager]; 335 | if (anemoneSettingsManager != nil && [anemoneSettingsManager respondsToSelector:@selector(setCGImageHookEnabled:)]) 336 | [anemoneSettingsManager setCGImageHookEnabled:YES]; 337 | } 338 | 339 | if (didHideStatusBar) { 340 | didHideStatusBar = NO; 341 | [(SpringBoard *)[%c(SpringBoard) sharedApplication] setStatusBarHidden:NO]; 342 | [self setNeedsStatusBarAppearanceUpdate]; 343 | } 344 | 345 | if (completion != nil) 346 | completion(); 347 | }]; 348 | }; 349 | 350 | if ([_markUpEditor presentedViewController] != nil) 351 | [[_markUpEditor presentedViewController] dismissViewControllerAnimated:animated completion:dismissMarkUp]; 352 | else 353 | dismissMarkUp(); 354 | } 355 | } 356 | 357 | -(void)dismissShareSheetAnimated:(BOOL)animated completion:(void (^)(void))completion { 358 | if (_activityViewController != nil) 359 | [_activityViewController dismissViewControllerAnimated:animated completion:^{ 360 | [_activityViewController release]; 361 | _activityViewController = nil; 362 | 363 | if (completion != nil) 364 | completion(); 365 | }]; 366 | } 367 | 368 | -(void)undoMarkUp { 369 | if (_markUpEditor != nil) { 370 | NSUndoManager *undoManager = _markUpEditor.akUndoManager; 371 | if (undoButton != nil && undoManager.canUndo) 372 | [undoManager undo]; 373 | [self updateUndoAndRedoButtons]; 374 | } 375 | } 376 | 377 | -(void)redoMarkUp { 378 | if (_markUpEditor != nil) { 379 | NSUndoManager *undoManager = _markUpEditor.akUndoManager; 380 | if (undoButton != nil && undoManager.canRedo) 381 | [undoManager redo]; 382 | [self updateUndoAndRedoButtons]; 383 | } 384 | } 385 | 386 | -(void)updateUndoAndRedoButtons { 387 | if (_markUpEditor != nil) { 388 | NSUndoManager *undoManager = _markUpEditor.akUndoManager; 389 | [UIView animateWithDuration:[SXIPreferences sharedInstance].dismissAnimationSpeed animations:^{ 390 | if (redoButton != nil) 391 | redoButton.enabled = undoManager.canRedo; 392 | if (undoButton != nil) 393 | undoButton.enabled = undoManager.canUndo; 394 | if (saveButton != nil) 395 | saveButton.enabled = undoButton.enabled; 396 | } completion: ^(BOOL finished) { 397 | if (finished) 398 | if (resultEditedImage != nil) { 399 | [resultEditedImage release]; 400 | resultEditedImage = nil; 401 | } 402 | }]; 403 | 404 | if (shareButton != nil) { 405 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 406 | shareButton.enabled = ![SXIPreferences sharedInstance].isLockscreenShareDisabled; 407 | else 408 | shareButton.enabled = YES; 409 | } 410 | } 411 | } 412 | 413 | -(BOOL)isEqualToUndoController:(id)undoController { 414 | return _markUpEditor != nil && [_markUpEditor.annotationController.undoController isEqual:undoController]; 415 | } 416 | 417 | -(BOOL)isEqualToMarkUpEditor:(id)editor { 418 | return _markUpEditor != nil && [_markUpEditor isEqual:editor]; 419 | } 420 | 421 | -(BOOL)isEqualToImageContentViewController:(id)imageContentViewController { 422 | return _markUpEditor != nil && [_markUpEditor.contentViewController isEqual:imageContentViewController]; 423 | } 424 | 425 | -(BOOL)isEqualToSourceContent:(id)sourceContent { 426 | return _markUpEditor != nil && [_markUpEditor.sourceContent isEqual:sourceContent]; 427 | } 428 | 429 | -(BOOL)isPresentingEditor { 430 | return [self isEqualToMarkUpEditor:[self presentedViewController]]; 431 | } 432 | 433 | -(DisplayedControllerType)currentlyHostingViewControllerType { 434 | if (_activityViewController != nil) 435 | return kShareSheet; 436 | else if (_markUpEditor != nil) 437 | return kEditor; 438 | else 439 | return kNone; 440 | } 441 | 442 | -(void)autoHide:(UIView *)view { 443 | if (view != nil && [view isKindOfClass:%c(ESSContainerView)] && [SXIPreferences sharedInstance].isSaveOnAutoDismissEnabled) { 444 | ESSContainerView *containerView = (ESSContainerView *)view; 445 | [self saveScreenshot:containerView.image]; 446 | } 447 | [self forceHide:view]; 448 | } 449 | 450 | -(void)forceHide:(UIView *)view { 451 | if (view != nil && [self.containerViews containsObject:view]) { 452 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 453 | if (![view isKindOfClass:%c(ESSContainerView)]) 454 | [self forceHideWithoutAnimations:view]; 455 | else 456 | [UIView animateWithDuration:preferenceManager.dismissAnimationSpeed animations:^{ 457 | [view setTransform:CGAffineTransformMakeTranslation(-(2 * preferenceManager.miniImageMargin + view.frame.size.width), 0)]; 458 | view.alpha = 0; 459 | } completion:^(BOOL finished) { 460 | [self forceHideWithoutAnimations:view]; 461 | }]; 462 | } 463 | } 464 | 465 | -(void)forceHideRight:(UIView *)view { 466 | if (view != nil && [self.containerViews containsObject:view]) { 467 | if (![view isKindOfClass:%c(ESSContainerView)]) 468 | [self forceHideWithoutAnimations:view]; 469 | else 470 | [UIView animateWithDuration:[SXIPreferences sharedInstance].dismissAnimationSpeed animations:^{ 471 | [view setTransform:CGAffineTransformMakeTranslation(self.view.frame.size.width, 0)]; 472 | view.alpha = 0; 473 | } completion:^(BOOL finished) { 474 | [self forceHideWithoutAnimations:view]; 475 | }]; 476 | } 477 | } 478 | 479 | -(void)forceHideWithoutAnimations:(UIView *)view { 480 | if (view != nil && [self.containerViews containsObject:view]) { 481 | [self.containerViews removeObject:view]; 482 | [view removeFromSuperview]; 483 | [view release]; 484 | } 485 | 486 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 487 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 488 | } 489 | 490 | 491 | -(void)imagePanned:(UIPanGestureRecognizer *)recognizer { 492 | if (![recognizer.view isKindOfClass:%c(ESSContainerView)]) 493 | return; 494 | 495 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 496 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 497 | 498 | ESSContainerView *containerView = (ESSContainerView *)(recognizer.view); 499 | CGPoint translationPoint = [recognizer translationInView:self.view]; 500 | CGPoint velocityPoint = [recognizer velocityInView:self.view]; 501 | 502 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 503 | 504 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 505 | 506 | switch (recognizer.state) { 507 | case UIGestureRecognizerStateBegan: 508 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide:) object:containerView]; 509 | case UIGestureRecognizerStateChanged: 510 | if (translationPoint.x > 0 && !preferenceManager.isRightSwipeEnabled) 511 | translationPoint.x = 0; 512 | [containerView setTransform:CGAffineTransformMakeTranslation(translationPoint.x, 0)]; 513 | break; 514 | case UIGestureRecognizerStateEnded: 515 | if (containerView.frame.origin.x + translationPoint.x + velocityPoint.x < -containerView.frame.size.width) { 516 | [self forceHide:containerView]; 517 | 518 | if (preferenceManager.isSaveOnSwipeDismissEnabled) 519 | [self saveScreenshot:containerView.image]; 520 | } else if (containerView.frame.origin.x + translationPoint.x + velocityPoint.x > self.view.frame.size.width && preferenceManager.isRightSwipeEnabled) { 521 | [self forceHideRight:containerView]; 522 | 523 | if (preferenceManager.isSaveOnRightSwipeDismissEnabled) 524 | [self saveScreenshot:containerView.image]; 525 | } else { 526 | [UIView animateWithDuration:preferenceManager.dismissAnimationSpeed animations:^{ 527 | [containerView setTransform:CGAffineTransformMakeTranslation(0, 0)]; 528 | } completion:^(BOOL finished) { 529 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 530 | [self performSelector:@selector(autoHide:) withObject:containerView afterDelay:preferenceManager.dismissTime]; 531 | }]; 532 | } 533 | break; 534 | case UIGestureRecognizerStateCancelled: 535 | case UIGestureRecognizerStateFailed: 536 | break; 537 | default: 538 | break; 539 | } 540 | } 541 | 542 | -(void)imageLongPressed:(UILongPressGestureRecognizer *)recognizer { 543 | if (![recognizer.view isKindOfClass:%c(ESSContainerView)]) 544 | return; 545 | 546 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 547 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 548 | 549 | ESSContainerView *containerView = (ESSContainerView *)(recognizer.view); 550 | CGPoint location = [recognizer locationInView:self.view]; 551 | CGFloat differenceX = location.x - pressStartLocation.x; 552 | 553 | SXIPreferences *preferenceManager = [SXIPreferences sharedInstance]; 554 | 555 | switch (recognizer.state) { 556 | case UIGestureRecognizerStateBegan: 557 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide:) object:containerView]; 558 | [containerView highlightViewWithCompletion:nil]; 559 | pressStartTime = [NSDate timeIntervalSinceReferenceDate]; 560 | pressStartLocation = location; 561 | useLongPressAsPan = NO; 562 | timerDidTrigger = NO; 563 | [self performSelector:@selector(displayShareSheetTimerTriggered:) withObject:containerView afterDelay:kLongPressEndDuration]; 564 | break; 565 | case UIGestureRecognizerStateChanged: 566 | if (timerDidTrigger) { 567 | break; 568 | } else if (useLongPressAsPan) { 569 | if (differenceX > 0 && !preferenceManager.isRightSwipeEnabled) 570 | differenceX = 0; 571 | [containerView setTransform:CGAffineTransformMakeTranslation(differenceX, 0)]; 572 | } else if (fabs(differenceX) > kLongPressRange) { 573 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 574 | useLongPressAsPan = YES; 575 | [containerView unhighlightViewWithCompletion:nil]; 576 | } else if ([NSDate timeIntervalSinceReferenceDate] - pressStartTime >= kLongPressEndDuration) { 577 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 578 | 579 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 580 | [self displayShareSheet:containerView]; 581 | else 582 | [containerView unhighlightViewWithCompletion:^{ 583 | [self displayShareSheet:containerView]; 584 | }]; 585 | } 586 | break; 587 | case UIGestureRecognizerStateEnded: 588 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 589 | 590 | if (timerDidTrigger) { 591 | [containerView unhighlightViewWithCompletion:nil]; 592 | } else if (useLongPressAsPan) { 593 | if (containerView.frame.origin.x + differenceX < -containerView.frame.size.width) { 594 | [self forceHide:containerView]; 595 | 596 | if (preferenceManager.isSaveOnSwipeDismissEnabled) 597 | [self saveScreenshot:containerView.image]; 598 | } else if (containerView.frame.origin.x + differenceX > self.view.frame.size.width && preferenceManager.isRightSwipeEnabled) { 599 | [self forceHideRight:containerView]; 600 | 601 | if (preferenceManager.isSaveOnRightSwipeDismissEnabled) 602 | [self saveScreenshot:containerView.image]; 603 | } else { 604 | [UIView animateWithDuration:preferenceManager.dismissAnimationSpeed animations:^{ 605 | [containerView setTransform:CGAffineTransformMakeTranslation(0, 0)]; 606 | } completion:^(BOOL finished) { 607 | if (!preferenceManager.isUnlimitedDismissTimeEnabled) 608 | [self performSelector:@selector(autoHide:) withObject:containerView afterDelay:preferenceManager.dismissTime]; 609 | }]; 610 | } 611 | } else { 612 | [containerView unhighlightViewWithCompletion:^{ 613 | if ([NSDate timeIntervalSinceReferenceDate] - pressStartTime >= kLongPressEndDuration && fabs(differenceX) <= kLongPressRange) 614 | [self displayShareSheet:containerView]; 615 | else if (!preferenceManager.isUnlimitedDismissTimeEnabled) 616 | [self performSelector:@selector(autoHide:) withObject:containerView afterDelay:preferenceManager.dismissTime]; 617 | }]; 618 | } 619 | break; 620 | case UIGestureRecognizerStateCancelled: 621 | case UIGestureRecognizerStateFailed: 622 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 623 | 624 | [containerView unhighlightViewWithCompletion:nil]; 625 | break; 626 | default: 627 | break; 628 | } 629 | } 630 | 631 | -(void)imageTapped:(UITapGestureRecognizer *)recognizer { 632 | if (![recognizer.view isKindOfClass:%c(ESSContainerView)]) 633 | return; 634 | 635 | if ([(SpringBoard *)[%c(SpringBoard) sharedApplication] isLocked]) 636 | [[%c(SBBacklightController) sharedInstance] resetLockScreenIdleTimer]; 637 | 638 | ESSContainerView *containerView = (ESSContainerView *)(recognizer.view); 639 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide:) object:containerView]; 640 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(displayShareSheetTimerTriggered:) object:containerView]; 641 | 642 | [self displayEditor:containerView]; 643 | } 644 | 645 | -(void)displayShareSheetTimerTriggered:(UIView *)view { 646 | timerDidTrigger = YES; 647 | if (!useLongPressAsPan) { 648 | if (![view isKindOfClass:%c(ESSContainerView)]) 649 | return; 650 | 651 | ESSContainerView *containerView = (ESSContainerView *)view; 652 | if (containerView != nil) 653 | [self displayShareSheet:containerView]; 654 | } 655 | } 656 | @end --------------------------------------------------------------------------------