├── .gitignore ├── SwipyFolders.plist ├── screenshots ├── settings.PNG └── interface.PNG ├── swipyfoldersprefs ├── Resources │ ├── time.png │ ├── banner.png │ ├── cydia.png │ ├── email.png │ ├── paypal.png │ ├── swipe.png │ ├── time@2x.png │ ├── time@3x.png │ ├── twitter.png │ ├── Github@2x.png │ ├── Github@3x.png │ ├── cydia@2x.png │ ├── cydia@3x.png │ ├── email@2x.png │ ├── email@3x.png │ ├── paypal@2x.png │ ├── paypal@3x.png │ ├── respring.png │ ├── swipe@2x.png │ ├── swipe@3x.png │ ├── respring@2x.png │ ├── respring@3x.png │ ├── twitter@2x.png │ ├── twitter@3x.png │ ├── Info.plist │ ├── CustomFolderSettings.plist │ └── SwipyFoldersPrefs.plist ├── PreferenceHeaders │ ├── PSListItemsController.h │ ├── PSDiscreteSlider.h │ ├── PSSliderTableCell.h │ ├── PreferencesAppController.h │ ├── PSControlTableCell.h │ ├── PSRootController.h │ ├── PSEditableTableCell.h │ ├── PSHeaderFooterView.h │ ├── PSBundleController.h │ ├── PSSwitchTableCell.h │ ├── PSViewController.h │ ├── PSTableCell.h │ ├── PSListController.h │ └── PSSpecifier.h ├── SFSwitchTableCell.h ├── SFSliderTableCell.h ├── SFFolderListController.h ├── entry.plist ├── SFSliderTableCell.m ├── Makefile ├── SwipyFoldersPrefs.h ├── SFSwitchTableCell.m ├── SFCustomFolderSettingsController.m └── SwipyFoldersPrefs.xm ├── control ├── LICENSE ├── README.md ├── Makefile ├── SwipyFolders.h └── SwipyFolders.xm /.gitignore: -------------------------------------------------------------------------------- 1 | debs/ 2 | .theos/ 3 | packages/ 4 | -------------------------------------------------------------------------------- /SwipyFolders.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /screenshots/settings.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/screenshots/settings.PNG -------------------------------------------------------------------------------- /screenshots/interface.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/screenshots/interface.PNG -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/time.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/banner.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/cydia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/cydia.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/email.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/paypal.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/swipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/swipe.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/time@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/time@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/time@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/time@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/twitter.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/Github@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/Github@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/Github@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/Github@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/cydia@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/cydia@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/cydia@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/cydia@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/email@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/email@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/email@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/email@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/paypal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/paypal@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/paypal@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/paypal@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/respring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/respring.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/swipe@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/swipe@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/swipe@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/swipe@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/respring@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/respring@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/respring@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/respring@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/twitter@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/twitter@2x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/twitter@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JesseVelden/SwipyFolders/HEAD/swipyfoldersprefs/Resources/twitter@3x.png -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSListItemsController.h: -------------------------------------------------------------------------------- 1 | #import "PSListController.h" 2 | 3 | @interface PSListItemsController : PSListController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSDiscreteSlider.h: -------------------------------------------------------------------------------- 1 | @interface PSDiscreteSlider : UISlider 2 | 3 | @property (nonatomic, retain) UIColor *trackMarkersColor; 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSSliderTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PSControlTableCell.h" 2 | 3 | @interface PSSliderTableCell : PSControlTableCell 4 | - (UISlider *)newControl; 5 | @end 6 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFSwitchTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PreferenceHeaders/PSSwitchTableCell.h" 2 | 3 | @interface SFSwitchTableCell : PSSwitchTableCell 4 | @property(nonatomic, assign) BOOL hidesSeparators; 5 | @end 6 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PreferencesAppController.h: -------------------------------------------------------------------------------- 1 | @class PSUIPrefsRootController; 2 | 3 | @interface PreferencesAppController : UIApplication/*this is from Preferences.app, not framework*/ 4 | 5 | @property (nonatomic, retain) PSUIPrefsRootController *rootController; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSControlTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PSTableCell.h" 2 | 3 | @interface PSControlTableCell : PSTableCell 4 | 5 | - (void)controlChanged:(UIControl *)control; 6 | 7 | @property (nonatomic, retain) UIControl *control; 8 | @property (nonatomic, retain) id value; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSRootController.h: -------------------------------------------------------------------------------- 1 | @class PSListController; 2 | 3 | @interface PSRootController : UINavigationController 4 | 5 | - (instancetype)initWithTitle:(NSString *)title identifier:(NSString *)identifier; 6 | 7 | - (void)pushController:(PSListController *)controller; // < 3.2 8 | - (void)suspend; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSEditableTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PSTableCell.h" 2 | 3 | @interface PSEditableTableCell : PSTableCell { 4 | id _userInfo; 5 | SEL _targetSetter; 6 | id _realTarget; 7 | } 8 | 9 | - (void)controlChanged:(id)changed; 10 | - (void)setValueChangedOnReturn; 11 | - (void)setValueChangedTarget:(id)target action:(SEL)action userInfo:(id)info; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSHeaderFooterView.h: -------------------------------------------------------------------------------- 1 | @class PSSpecifier, UITableView; 2 | 3 | @protocol PSHeaderFooterView 4 | 5 | @required 6 | - (UIView *)initWithSpecifier:(PSSpecifier *)specifier; 7 | 8 | @optional 9 | - (CGFloat)preferredHeightForWidth:(CGFloat)width inTableView:(UITableView *)tableView; 10 | - (CGFloat)preferredHeightForWidth:(CGFloat)width; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFSliderTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PreferenceHeaders/PSSliderTableCell.h" 2 | #import "PreferenceHeaders/PSControlTableCell.h" 3 | #import "PreferenceHeaders/PSSpecifier.h" 4 | 5 | @interface SFSliderTableCell : PSSliderTableCell 6 | @end 7 | 8 | @interface UISpecifierSlider : UISlider { 9 | id userData; 10 | } 11 | 12 | @property (nonatomic, readwrite, retain) id userData; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSBundleController.h: -------------------------------------------------------------------------------- 1 | @class PSListController, PSSpecifier; 2 | 3 | @interface PSBundleController : NSObject 4 | 5 | - (instancetype)initWithParentListController:(PSListController *)listController; 6 | - (instancetype)initWithParentListController:(PSListController *)listController properties:(NSDictionary *)properties; 7 | 8 | - (NSArray *)specifiersWithSpecifier:(PSSpecifier *)specifier; 9 | 10 | - (void)load; 11 | - (void)unload; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: nl.jessevandervelden.swipyfolders 2 | Name: SwipyFolders 3 | Depends: mobilesubstrate, preferenceloader, firmware (>= 8.0), com.rpetrich.rocketbootstrap (>= 1.0.5) 4 | Version: 1.5.9 5 | Icon: file:///Library/PreferenceBundles/SwipyFoldersPrefs.bundle/swipe@2x.png 6 | Architecture: iphoneos-arm 7 | Description: Gestures for your folders 8 | Maintainer: Jesse van der Velden 9 | Author: Jesse van der Velden 10 | Section: Tweaks 11 | Depiction: http://megacookie.github.io/depictions/nl.jessevandervelden.swipyfolders 12 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFFolderListController.h: -------------------------------------------------------------------------------- 1 | #import "PreferenceHeaders/PSListController.h" 2 | 3 | @interface UIImage (Private) 4 | + (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier format:(int)format scale:(CGFloat)scale; 5 | + (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier roleIdentifier:(NSString *)roleIdentifier format:(int)format scale:(CGFloat)scale; 6 | @end 7 | 8 | 9 | @interface SFFolderListController : PSListController 10 | - (NSArray *)specifiers; 11 | - (UIImage *)createFolderIconImageWithIdentifiers:(NSArray*)bundleIdentifiers; 12 | @end 13 | -------------------------------------------------------------------------------- /swipyfoldersprefs/entry.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | SwipyFoldersPrefs 9 | cell 10 | PSLinkCell 11 | detail 12 | SwipyFoldersPrefs 13 | icon 14 | swipe.png 15 | isController 16 | 17 | label 18 | SwipyFolders 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFSliderTableCell.m: -------------------------------------------------------------------------------- 1 | #import "SFSliderTableCell.h" 2 | 3 | @implementation SFSliderTableCell 4 | 5 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)identifier specifier:(PSSpecifier*)specifier { 6 | self = [super initWithStyle:style reuseIdentifier:identifier specifier:specifier]; 7 | if (self) { 8 | UISlider *slider = (UISlider *)[self control]; 9 | [slider addTarget:specifier.target action:@selector(sliderMoved:) forControlEvents:UIControlEventAllTouchEvents]; 10 | 11 | } 12 | return self; 13 | } 14 | 15 | - (void)refreshCellContentsWithSpecifier:(PSSpecifier *)specifier { 16 | [super refreshCellContentsWithSpecifier:specifier]; 17 | 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSSwitchTableCell.h: -------------------------------------------------------------------------------- 1 | #import "PSControlTableCell.h" 2 | 3 | @class UIActivityIndicatorView; 4 | 5 | @interface PSSwitchTableCell : PSControlTableCell { 6 | UIActivityIndicatorView *_activityIndicator; 7 | } 8 | 9 | @property BOOL loading; 10 | 11 | - (BOOL)loading; 12 | - (void)setLoading:(BOOL)loading; 13 | - (id)controlValue; 14 | - (id)newControl; 15 | - (void)setCellEnabled:(BOOL)enabled; 16 | - (void)refreshCellContentsWithSpecifier:(id)specifier; 17 | - (id)initWithStyle:(int)style reuseIdentifier:(id)identifier specifier:(id)specifier; 18 | - (void)reloadWithSpecifier:(id)specifier animated:(BOOL)animated; 19 | - (BOOL)canReload; 20 | - (void)prepareForReuse; 21 | - (void)layoutSubviews; 22 | - (void)setValue:(id)value; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | SwipyFoldersPrefs 9 | CFBundleIdentifier 10 | nl.jessevandervelden.swipyfoldersprefs 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 | SwipyFoldersPrefs 23 | 24 | 25 | -------------------------------------------------------------------------------- /swipyfoldersprefs/Makefile: -------------------------------------------------------------------------------- 1 | BUNDLE_NAME = SwipyFoldersPrefs 2 | SwipyFoldersPrefs_FILES = SwipyFoldersPrefs.xm SFSliderTableCell.m SFSwitchTableCell.m SFCustomFolderSettingsController.m 3 | SwipyFoldersPrefs_INSTALL_PATH = /Library/PreferenceBundles 4 | 5 | SwipyFoldersPrefs_PRIVATE_FRAMEWORKS = Preferences AppSupport 6 | 7 | 8 | ifeq ($(SIMULATOR),1) 9 | # i386 slice is required for 32-bit iOS Simulator (iPhone 5, etc.) 10 | TARGET = simulator:clang 11 | ARCHS = x86_64 i386 12 | else 13 | SwipyFoldersPrefs_FRAMEWORKS = UIKit CoreGraphics Foundation 14 | endif 15 | 16 | 17 | GO_EASY_ON_ME = 1 18 | SwipyFoldersPrefs_LDFLAGS += -Wl,-segalign,4000 19 | SwipyFolders_CFLAGS = -fno-objc-arc -Wno-deprecated-declarations 20 | 21 | include $(THEOS)/makefiles/common.mk 22 | include $(THEOS_MAKE_PATH)/bundle.mk 23 | include $(THEOS_MAKE_PATH)/tweak.mk 24 | 25 | internal-stage:: 26 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 27 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/SwipyFoldersPrefs.plist$(ECHO_END) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2016 MegaCookie (Jesse van der Velden) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSViewController.h: -------------------------------------------------------------------------------- 1 | @class PSSpecifier; 2 | 3 | @interface PSViewController : UIViewController 4 | 5 | - (instancetype)initForContentSize:(CGSize)contentSize; 6 | 7 | - (void)pushController:(PSViewController *)controller; 8 | - (void)pushController:(PSViewController *)controller animate:(BOOL)animated; 9 | 10 | - (void)showController:(PSViewController *)controller; 11 | - (void)showController:(PSViewController *)controller animate:(BOOL)animated; 12 | 13 | - (id)readPreferenceValue:(PSSpecifier *)specifier; 14 | - (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier; 15 | 16 | @property (nonatomic, retain) PSSpecifier *specifier; 17 | @property (nonatomic, retain) PSViewController *parentController; 18 | @property (nonatomic, retain) PSViewController *rootController; 19 | 20 | - (void)suspend; 21 | 22 | - (void)willBecomeActive; 23 | - (void)willResignActive; 24 | - (void)willUnlock; 25 | 26 | - (void)didLock; 27 | - (void)didUnlock; 28 | - (void)didWake; 29 | 30 | - (void)formSheetViewDidDisappear; 31 | - (void)formSheetViewWillDisappear; 32 | 33 | - (void)popupViewDidDisappear; 34 | - (void)popupViewWillDisappear; 35 | 36 | - (void)handleURL:(NSURL *)url; 37 | - (void)statusBarWillAnimateByHeight:(float)arg1; 38 | 39 | - (BOOL)canBeShownFromSuspendedState; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwipyFolders 2 | *The way folders on iOS meant to be* 3 | [![Paypal](https://jessevandervelden.nl/donate.png)](https://www.paypal.me/JessevanderVelden) 4 | 5 | Beta repo: [megacookie.github.io](http://megacookie.github.io) 6 | 7 | Sick of the ugly folders staring at you? Ever wanted to swipe your folders open? Double tap actions? Short hold, or even 3D touch on a folder? 8 | **Now you can!** With **SwipyFolders** you can customize your folder experience. 9 | 10 | Basically two screenshots are worth two thousand words: 11 | 12 | Settings | Interface (first icon as folder preview) 13 | :--------------------------------------:|:-----------------------------: 14 | ![Settings](/screenshots/settings.PNG) | ![Interface](/screenshots/interface.PNG) 15 | 16 | 17 | Available gestures: 18 | * Single Tap 19 | * Swipe Up 20 | * Swipe Down 21 | * Double Tap 22 | * Short hold 23 | * 3D Touch (aka Force Touch) 24 | 25 | Every gesture can be customized to: 26 | * Open folder 27 | * Open first app 28 | * Open second app 29 | * Quick action on first icon 30 | * Open custom app with index 31 | * Open last app in the folder 32 | * Open the last opened app of the folder 33 | 34 | You can even set the first icon as the folder preview, and removing the background from the folder icon. Bye bye ugly looking folders! 35 | Since version 1.4.0 SwipyFolders ships with per folder customizable settings! 36 | 37 | Suggestions and improvements/ pull requests are welcome! 38 | 39 | License: MIT -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSTableCell.h: -------------------------------------------------------------------------------- 1 | @class PSSpecifier; 2 | 3 | typedef NS_ENUM(NSInteger, PSCellType) { 4 | PSGroupCell, 5 | PSLinkCell, 6 | PSLinkListCell, 7 | PSListItemCell, 8 | PSTitleValueCell, 9 | PSSliderCell, 10 | PSSwitchCell, 11 | PSStaticTextCell, 12 | PSEditTextCell, 13 | PSSegmentCell, 14 | PSGiantIconCell, 15 | PSGiantCell, 16 | PSSecureEditTextCell, 17 | PSButtonCell, 18 | PSEditTextViewCell 19 | }; 20 | 21 | @interface PSTableCell : UITableViewCell { 22 | id value; 23 | } 24 | 25 | + (PSCellType)cellTypeFromString:(NSString *)cellType; 26 | 27 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier; 28 | 29 | - (void)refreshCellContentsWithSpecifier:(PSSpecifier *)specifier; 30 | 31 | - (void)setSeparatorStyle:(UITableViewCellSeparatorStyle)style; 32 | 33 | @property (nonatomic, retain) PSSpecifier *specifier; 34 | @property (nonatomic) PSCellType type; 35 | @property (nonatomic, retain) id target; 36 | @property (nonatomic) SEL action; 37 | 38 | @property (nonatomic, retain) id cellTarget; 39 | @property (nonatomic) SEL cellAction; 40 | 41 | @property (nonatomic) BOOL cellEnabled; 42 | 43 | @property (nonatomic, retain) UIImage *icon; 44 | 45 | - (UIImage *)getLazyIcon; 46 | 47 | @property (nonatomic, retain, readonly) UIImage *blankIcon; 48 | @property (nonatomic, retain, readonly) NSString *lazyIconAppID; 49 | 50 | @property (nonatomic, retain, readonly) UILabel *titleLabel; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SwipyFoldersPrefs.h: -------------------------------------------------------------------------------- 1 | #import "PreferenceHeaders/PSListController.h" 2 | #import "PreferenceHeaders/PSSpecifier.h" 3 | #import "PreferenceHeaders/PSListItemsController.h" 4 | #import "PreferenceHeaders/PSTableCell.h" 5 | //This needs https://github.com/nst/iOS-Runtime-Headers/tree/master/PrivateFrameworks in the $THEOS/sdks/iPhoneOSXXX.sdk/System/Library/PrivateFrameworks 6 | 7 | 8 | @interface SwipyFoldersPrefs : PSListController 9 | @end 10 | 11 | @interface UITableViewLabel : UILabel 12 | @end 13 | 14 | @interface NSArray(Private) 15 | - (id)specifierForID:(id)id; 16 | @end 17 | 18 | @interface PSListItemsController (tableView) 19 | - (void)tableView:(id)arg1 didSelectRowAtIndexPath:(id)arg2; 20 | - (void)listItemSelected:(id)arg1; 21 | - (id)tableView:(id)arg1 cellForRowAtIndexPath:(id)arg2; 22 | - (id)itemsFromParent; 23 | @end 24 | 25 | @interface SFListItemsController : PSListItemsController 26 | @end 27 | 28 | @interface customAppText : NSObject 29 | +(NSString *) setTextForIndex: (int) number; 30 | +(NSString *) addSuffixToNumber:(int) number; 31 | @end 32 | 33 | @interface SBFolder : NSObject 34 | - (id)folderIcons; 35 | @end 36 | 37 | @interface CPDistributedMessagingCenter : NSObject 38 | +(CPDistributedMessagingCenter*)centerNamed:(NSString*)serverName; 39 | -(void)registerForMessageName:(NSString*)messageName target:(id)target selector:(SEL)selector; 40 | -(NSDictionary*)sendMessageAndReceiveReplyName:(NSString*)name userInfo:(NSDictionary*)info; 41 | -(void)runServerOnCurrentThread; 42 | @end 43 | 44 | @interface SpringBoard : NSObject 45 | - (void)_relaunchSpringBoardNow; 46 | @end 47 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = iphone:10.3:10.3 2 | ARCHS = armv7 armv7s arm64 3 | 4 | DEBUG = 0 5 | GO_EASY_ON_ME = 1 6 | PACKAGE_VERSION = $(THEOS_PACKAGE_BASE_VERSION) 7 | 8 | TWEAK_NAME = SwipyFolders 9 | SwipyFolders_FILES = SwipyFolders.xm 10 | SwipyFolders_CFLAGS = -fno-objc-arc -Wno-deprecated-declarations 11 | #SwipyFolders_PRIVATE_FRAMEWORKS = AppSupport 12 | SwipyFolders_LDFlags += -Wl,-segalign,4000 13 | SUBPROJECTS += swipyfoldersprefs 14 | 15 | #So in order to use the simulator: export SIMULATOR=1 && make simulator 16 | ifeq ($(SIMULATOR),1) 17 | # i386 slice is required for 32-bit iOS Simulator (iPhone 5, etc.) 18 | TARGET = simulator:clang 19 | ARCHS = x86_64 i386 20 | else 21 | SwipyFolders_FRAMEWORKS = UIKit Foundation QuartzCore CoreGraphics 22 | endif 23 | 24 | 25 | include $(THEOS)/makefiles/common.mk 26 | include $(THEOS_MAKE_PATH)/tweak.mk 27 | include $(THEOS_MAKE_PATH)/aggregate.mk 28 | 29 | simulator:: 30 | @make 31 | @echo Copying files to simject directory 32 | @cp $(THEOS_OBJ_DIR)/*.dylib /opt/simject 33 | @cp *.plist /opt/simject 34 | @find /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS\ *.simruntime/Contents/Resources/RuntimeRoot/Library/PreferenceLoader/Preferences -type d -print0 | sudo xargs -0 -n 1 cp -v $(PWD)/swipyfoldersprefs/entry.plist 35 | @find /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS\ *.simruntime/Contents/Resources/RuntimeRoot/Library/PreferenceBundles -type d -print0 | sudo xargs -0 -n 1 cp -vR $(THEOS_OBJ_DIR)/SwipyFoldersPrefs.bundle 36 | @echo Respringing simulator… 37 | @~/git/simject/bin/respring_simulator 38 | 39 | after-install:: 40 | install.exec "killall -9 SpringBoard" 41 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFSwitchTableCell.m: -------------------------------------------------------------------------------- 1 | #import "SFSwitchTableCell.h" 2 | 3 | static UIColor * UIColorFromRGB(int rgb) { 4 | return [UIColor colorWithRed:((rgb >> 16) & 0xFF) / 255.0F 5 | green:((rgb >> 8) & 0xFF) / 255.0F 6 | blue:(rgb & 0xFF) / 255.0F 7 | alpha:1]; 8 | } 9 | 10 | 11 | @implementation SFSwitchTableCell 12 | 13 | 14 | - (id)initWithStyle:(int)style reuseIdentifier:(id)identifier specifier:(id)specifier { 15 | self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier specifier:specifier]; 16 | if (self) { 17 | UIColor *tintColor = UIColorFromRGB(0xFF9000); 18 | [((UISwitch *)[self control]) setOnTintColor:tintColor]; 19 | 20 | _hidesSeparators = NO; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | - (void)refreshCellContentsWithSpecifier:(PSSpecifier *)specifier { 27 | [super refreshCellContentsWithSpecifier:specifier]; 28 | NSString *sublabel = [specifier propertyForKey:@"sublabel"]; 29 | if (sublabel) { 30 | self.detailTextLabel.text = [sublabel description]; 31 | self.detailTextLabel.textColor = [UIColor grayColor]; 32 | } 33 | } 34 | 35 | - (UITableViewCellSeparatorStyle)wantedSeparatorStyle { 36 | return (_hidesSeparators) ? UITableViewCellSeparatorStyleNone : 37 | UITableViewCellSeparatorStyleSingleLine; 38 | } 39 | 40 | - (void)setHidesSeparators:(BOOL)hides { 41 | if (hides != _hidesSeparators) { 42 | _hidesSeparators = hides; 43 | self.separatorStyle = [self wantedSeparatorStyle]; 44 | } 45 | } 46 | 47 | - (void)setSeparatorStyle:(UITableViewCellSeparatorStyle)style { 48 | [super setSeparatorStyle:[self wantedSeparatorStyle]]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSListController.h: -------------------------------------------------------------------------------- 1 | #import "PSViewController.h" 2 | 3 | @class PSRootController, PSSpecifier, PSTableCell; 4 | 5 | @interface PSListController : PSViewController { 6 | NSArray *_specifiers; 7 | UITableView* _table; 8 | } 9 | 10 | + (BOOL)displaysButtonBar; 11 | 12 | - (NSArray *)loadSpecifiersFromPlistName:(NSString *)name target:(PSListController *)target; 13 | - (NSArray *)loadSpecifiersFromPlistName:(NSString *)name target:(PSListController *)target bundle:(NSBundle *)bundle; 14 | 15 | - (Class)tableViewClass; 16 | - (UITableViewStyle)tableViewStyle; 17 | 18 | @property (nonatomic, retain) UITableView *view; 19 | @property (nonatomic, retain) UITableView *table; // 3.0 - 6.0 20 | @property (nonatomic, retain) UITableView *tableView; 21 | 22 | - (PSSpecifier *)specifierAtIndex:(NSInteger)index; 23 | - (PSSpecifier *)specifierAtIndexPath:(NSIndexPath *)indexPath; 24 | - (PSSpecifier *)specifierForID:(NSString *)identifier; 25 | - (NSArray *)specifiersForIDs:(NSArray *)identifiers; 26 | - (NSArray *)specifiersInGroup:(NSInteger)group; 27 | 28 | @property (nonatomic, retain) NSArray *specifiers; 29 | @property (nonatomic, retain) PSSpecifier *specifier; 30 | @property (nonatomic, retain) NSString *specifierID; 31 | @property (nonatomic, retain) NSString *specifierIDPendingPush; 32 | @property (nonatomic, retain) id specifierDataSource; 33 | 34 | - (NSInteger)numberOfGroups; 35 | - (NSInteger)rowsForGroup:(NSInteger)group; 36 | 37 | - (BOOL)getGroup:(NSInteger *)group row:(NSInteger *)row ofSpecifier:(PSSpecifier *)specifier; 38 | - (BOOL)getGroup:(NSInteger *)group row:(NSInteger *)row ofSpecifierAtIndex:(NSInteger)specifier; 39 | - (BOOL)getGroup:(NSInteger *)group row:(NSInteger *)row ofSpecifierID:(NSString *)specifierID; 40 | 41 | - (NSInteger)indexForIndexPath:(NSIndexPath *)indexPath; 42 | - (NSInteger)indexForRow:(NSInteger)row inGroup:(NSInteger)group; 43 | 44 | - (NSInteger)indexOfGroup:(NSInteger)group; 45 | - (NSInteger)indexOfSpecifier:(PSSpecifier *)specifier; 46 | - (NSInteger)indexOfSpecifierID:(NSString *)specifierID; 47 | 48 | - (NSIndexPath *)indexPathForIndex:(NSInteger)index; 49 | - (NSIndexPath *)indexPathForSpecifier:(PSSpecifier *)specifier; 50 | 51 | - (void)addSpecifier:(PSSpecifier *)specifier; 52 | - (void)addSpecifier:(PSSpecifier *)specifier animated:(BOOL)animated; 53 | - (void)addSpecifiersFromArray:(NSArray *)specifiers; 54 | - (void)addSpecifiersFromArray:(NSArray *)specifiers animated:(BOOL)animated; 55 | 56 | - (void)insertSpecifier:(PSSpecifier *)specifier afterSpecifier:(PSSpecifier *)afterSpecifier; 57 | - (void)insertSpecifier:(PSSpecifier *)specifier afterSpecifier:(PSSpecifier *)afterSpecifier animated:(BOOL)animated; 58 | - (void)insertSpecifier:(PSSpecifier *)specifier afterSpecifierID:(NSString *)specifierID; 59 | - (void)insertSpecifier:(PSSpecifier *)specifier afterSpecifierID:(NSString *)specifierID animated:(BOOL)animated; 60 | - (void)insertSpecifier:(PSSpecifier *)specifier atEndOfGroup:(NSInteger)groupIndex; 61 | - (void)insertSpecifier:(PSSpecifier *)specifier atEndOfGroup:(NSInteger)groupIndex animated:(BOOL)animated; 62 | - (void)insertSpecifier:(PSSpecifier *)specifier atIndex:(NSInteger)index; 63 | - (void)insertSpecifier:(PSSpecifier *)specifier atIndex:(NSInteger)index animated:(BOOL)animated; 64 | 65 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers afterSpecifier:(PSSpecifier *)specifier; 66 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers afterSpecifier:(PSSpecifier *)specifier animated:(BOOL)animated; 67 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers afterSpecifierID:(NSString *)specifierID; 68 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers afterSpecifierID:(NSString *)specifierID animated:(BOOL)animated; 69 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers atEndOfGroup:(NSInteger)groupIndex; 70 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers atEndOfGroup:(NSInteger)groupIndex animated:(BOOL)animated; 71 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers atIndex:(NSInteger)index; 72 | - (void)insertContiguousSpecifiers:(NSArray *)specifiers atIndex:(NSInteger)index animated:(BOOL)animated; 73 | 74 | - (void)reload; 75 | - (void)reloadSpecifier:(PSSpecifier *)specifier; 76 | - (void)reloadSpecifier:(PSSpecifier *)specifier animated:(BOOL)animated; 77 | - (void)reloadSpecifierAtIndex:(NSInteger)index; 78 | - (void)reloadSpecifierAtIndex:(NSInteger)index animated:(BOOL)animated; 79 | - (void)reloadSpecifierID:(NSString *)specifierID; 80 | - (void)reloadSpecifierID:(NSString *)specifierID animated:(BOOL)animated; 81 | - (void)reloadSpecifiers; 82 | 83 | - (void)removeContiguousSpecifiers:(NSArray *)specifiers; 84 | - (void)removeContiguousSpecifiers:(NSArray *)specifiers animated:(BOOL)animated; 85 | - (void)removeLastSpecifier; 86 | - (void)removeLastSpecifierAnimated:(BOOL)animated; 87 | - (void)removeSpecifier:(PSSpecifier *)specifier; 88 | - (void)removeSpecifier:(PSSpecifier *)specifier animated:(BOOL)animated; 89 | - (void)removeSpecifierAtIndex:(NSInteger)index; 90 | - (void)removeSpecifierAtIndex:(NSInteger)index animated:(BOOL)animated; 91 | - (void)removeSpecifierID:(NSString *)specifierID; 92 | - (void)removeSpecifierID:(NSString *)specifierID animated:(BOOL)animated; 93 | 94 | - (void)replaceContiguousSpecifiers:(NSArray *)specifiers withSpecifiers:(NSArray *)newSpecifiers; 95 | - (void)replaceContiguousSpecifiers:(NSArray *)specifiers withSpecifiers:(NSArray *)newSpecifiers animated:(BOOL)animated; 96 | 97 | - (void)updateSpecifiers:(NSArray *)specifiers withSpecifiers:(NSArray *)newSpecifiers; 98 | - (void)updateSpecifiersInRange:(NSRange)range withSpecifiers:(NSArray *)newSpecifiers; 99 | 100 | - (NSRange)rangeOfSpecifiersInGroupID:(NSString *)groupID; 101 | 102 | - (PSTableCell *)cachedCellForSpecifier:(PSSpecifier *)specifier; 103 | - (PSTableCell *)cachedCellForSpecifierID:(NSString *)specifierID; 104 | 105 | @property (nonatomic, retain) NSBundle *bundle; 106 | 107 | - (void)reloadIconForSpecifierForBundle:(NSBundle *)bundle; 108 | 109 | @property (nonatomic) BOOL forceSynchronousIconLoadForCreatedCells; 110 | 111 | @property (nonatomic, retain) UIColor *altTextColor; 112 | @property (nonatomic, retain) UIColor *backgroundColor; 113 | @property (nonatomic, retain) UIColor *buttonTextColor; 114 | @property (nonatomic, retain) UIColor *cellAccessoryColor; 115 | @property (nonatomic, retain) UIColor *cellAccessoryHighlightColor; 116 | @property (nonatomic, retain) UIColor *cellHighlightColor; 117 | @property (nonatomic, retain) UIColor *editableInsertionPointColor; 118 | @property (nonatomic, retain) UIColor *editablePlaceholderTextColor; 119 | @property (nonatomic, retain) UIColor *editableSelectionBarColor; 120 | @property (nonatomic, retain) UIColor *editableSelectionHighlightColor; 121 | @property (nonatomic, retain) UIColor *editableTextColor; 122 | @property (nonatomic, retain) UIColor *footerHyperlinkColor; 123 | @property (nonatomic, retain) UIColor *foregroundColor; 124 | @property (nonatomic, retain) UIColor *segmentedSliderTrackColor; 125 | @property (nonatomic, retain) UIColor *separatorColor; 126 | @property (nonatomic, retain) UIColor *textColor; 127 | 128 | @property (nonatomic) BOOL usesDarkTheme; 129 | @property (nonatomic) BOOL edgeToEdgeCells; 130 | @property (nonatomic) BOOL resusesCells; 131 | @property (nonatomic, readonly) NSInteger observerType; // TODO: what is this? 132 | 133 | @property (nonatomic, retain) NSDictionary *pendingURLResourceDictionary; 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /swipyfoldersprefs/PreferenceHeaders/PSSpecifier.h: -------------------------------------------------------------------------------- 1 | #import "PSTableCell.h" 2 | #include 3 | 4 | __BEGIN_DECLS 5 | 6 | extern NSString *const PSAccessoryKey; // @"accessory" 7 | extern NSString *const PSActionKey; // @"action" 8 | extern NSString *const PSAdjustFontSizeToFitWidthKey; // @"adjustFontSizeToFitWidth" 9 | extern NSString *const PSAlignmentKey; // @"alignment" 10 | extern NSString *const PSAppGroupBundleIDKey; // @"appGroupBundleID" 11 | extern NSString *const PSAutoCapsKey; // @"autoCaps" 12 | extern NSString *const PSAutoCorrectionKey; // @"autoCorrection" 13 | extern NSString *const PSBestGuesserKey; // @"bestGuess" 14 | extern NSString *const PSBundleCustomIconPathKey; // @"icon2" 15 | extern NSString *const PSBundleHasBundleIconKey; // @"hasBundleIcon" 16 | extern NSString *const PSBundleHasIconKey; // @"hasIcon" 17 | extern NSString *const PSBundleIconPathKey; // @"icon" 18 | extern NSString *const PSBundleIsControllerKey; // @"isController" 19 | extern NSString *const PSBundleOverridePrincipalClassKey; // @"overridePrincipalClass" 20 | extern NSString *const PSBundlePathKey; // @"bundle" 21 | extern NSString *const PSBundleTintedIconPathKey; // @"tintedIcon" 22 | extern NSString *const PSButtonActionKey; // @"buttonAction" 23 | extern NSString *const PSCancelKey; // @"cancel" 24 | extern NSString *const PSCellClassKey; // @"cellClass" 25 | extern NSString *const PSConfirmationActionKey; // @"confirmationAction" 26 | extern NSString *const PSConfirmationCancelActionKey; // @"cancel" 27 | extern NSString *const PSConfirmationCancelKey; // @"cancelTitle" 28 | extern NSString *const PSConfirmationDestructiveKey; // @"isDestructive" 29 | extern NSString *const PSConfirmationKey; // @"confirmation" 30 | extern NSString *const PSConfirmationOKKey; // @"okTitle" 31 | extern NSString *const PSConfirmationPromptKey; // @"prompt" 32 | extern NSString *const PSConfirmationTitleKey; // @"title" 33 | extern NSString *const PSContainerBundleIDKey; // @"containerBundleID" 34 | extern NSString *const PSControlIsLoadingKey; // @"control-loading" 35 | extern NSString *const PSControlKey; // @"control" 36 | extern NSString *const PSControllerLoadActionKey; // @"loadAction" 37 | extern NSString *const PSControlMaximumKey; // @"max" 38 | extern NSString *const PSControlMinimumKey; // @"min" 39 | extern NSString *const PSCopyableCellKey; // @"isCopyable" 40 | extern NSString *const PSDataSourceClassKey; // @"dataSourceClass" 41 | extern NSString *const PSDecimalKeyboardKey; // @"isDecimalPad" 42 | extern NSString *const PSDefaultsKey; // @"defaults" 43 | extern NSString *const PSDefaultValueKey; // @"default" 44 | extern NSString *const PSDeferItemSelectionKey; // @"deferItemSelection" 45 | extern NSString *const PSDeletionActionKey; // @"deletionAction" 46 | extern NSString *const PSDetailControllerClassKey; // @"detail" 47 | extern NSString *const PSEditableTableCellTextFieldShouldPopOnReturn; // @"textFieldShouldPopOnReturn" 48 | extern NSString *const PSEditPaneClassKey; // @"pane" 49 | extern NSString *const PSEmailAddressingKeyboardKey; // @"isEmailAddressing" 50 | extern NSString *const PSEmailAddressKeyboardKey; // @"isEmail" 51 | extern NSString *const PSEnabledKey; // @"enabled" 52 | extern NSString *const PSFooterAlignmentGroupKey; // @"footerAlignment" 53 | extern NSString *const PSFooterCellClassGroupKey; // @"footerCellClass" 54 | extern NSString *const PSFooterTextGroupKey; // @"footerText" 55 | extern NSString *const PSFooterViewKey; // @"footerView" 56 | extern NSString *const PSGetterKey; // @"get" 57 | extern NSString *const PSHeaderCellClassGroupKey; // @"headerCellClass" 58 | extern NSString *const PSHeaderDetailTextGroupKey; // @"headerDetailText" 59 | extern NSString *const PSHeaderViewKey; // @"headerView" 60 | extern NSString *const PSHidesDisclosureIndicatorKey; // @"hidesDisclosureIndicator" 61 | extern NSString *const PSIconImageKey; // @"iconImage" 62 | extern NSString *const PSIconImageShouldFlipForRightToLeftKey; // @"iconImageShouldFlipForRightToLeft" 63 | extern NSString *const PSIDKey; // @"id" 64 | extern NSString *const PSIPKeyboardKey; // @"isIP" 65 | extern NSString *const PSIsPerGizmoKey; // @"isPerGizmo" 66 | extern NSString *const PSIsRadioGroupKey; // @"isRadioGroup" 67 | extern NSString *const PSIsTopLevelKey; // @"isTopLevel" 68 | extern NSString *const PSKeyboardTypeKey; // @"keyboard" 69 | extern NSString *const PSKeyNameKey; // @"key" 70 | extern NSString *const PSLazilyLoadedBundleKey; // @"lazy-bundle" 71 | extern NSString *const PSLazyIconAppID; // @"appIDForLazyIcon" 72 | extern NSString *const PSLazyIconDontUnload; // @"dontUnloadLazyIcon" 73 | extern NSString *const PSLazyIconLoading; // @"useLazyIcons" 74 | extern NSString *const PSLazyIconLoadingCustomQueue; // @"customIconQueue" 75 | extern NSString *const PSMarginWidthKey; // @"marginWidth" 76 | extern NSString *const PSNegateValueKey; // @"negate" 77 | extern NSString *const PSNotifyNanoKey; // @"notifyNano" 78 | extern NSString *const PSNumberKeyboardKey; // @"isNumeric" 79 | extern NSString *const PSPlaceholderKey; // @"placeholder" 80 | extern NSString *const PSPrioritizeValueTextDisplayKey; // @"prioritizeValueTextDisplay" 81 | extern NSString *const PSRadioGroupCheckedSpecifierKey; // @"radioGroupCheckedSpecifier" 82 | extern NSString *const PSRequiredCapabilitiesKey; // @"requiredCapabilities" 83 | extern NSString *const PSRequiredCapabilitiesOrKey; // @"requiredCapabilitiesOr" 84 | extern NSString *const PSSearchNanoApplicationsBundlePath; // @"nanoAppsBundlePath" 85 | extern NSString *const PSSearchNanoInternalSettingsBundlePath; // @"nanoInternalBundlePath" 86 | extern NSString *const PSSearchNanoSettingsBundlePath; // @"nanoBundlePath" 87 | extern NSString *const PSSetterKey; // @"set" 88 | extern NSString *const PSSetupCustomClassKey; // @"customControllerClass" 89 | extern NSString *const PSShortTitlesDataSourceKey; // @"shortTitlesDataSource" 90 | extern NSString *const PSShortTitlesKey; // @"shortTitles" 91 | extern NSString *const PSSliderIsContinuous; // @"isContinuous" 92 | extern NSString *const PSSliderIsSegmented; // @"isSegmented" 93 | extern NSString *const PSSliderLeftImageKey; // @"leftImage" 94 | extern NSString *const PSSliderLeftImagePromiseKey; // @"leftImagePromise" 95 | extern NSString *const PSSliderRightImageKey; // @"rightImage" 96 | extern NSString *const PSSliderRightImagePromiseKey; // @"rightImagePromise" 97 | extern NSString *const PSSliderSegmentCount; // @"segmentCount" 98 | extern NSString *const PSSliderShowValueKey; // @"showValue" 99 | extern NSString *const PSSpecifierAuthenticationTokenKey; // @"authenticationToken" 100 | extern NSString *const PSSpecifierPasscodeKey; // @"passcode" 101 | extern NSString *const PSStaticTextMessageKey; // @"staticTextMessage" 102 | extern NSString *const PSTableCellClassKey; // @"cell" 103 | extern NSString *const PSTableCellHeightKey; // @"height" 104 | extern NSString *const PSTableCellKey; // @"cellObject" 105 | extern NSString *const PSTableCellUseEtchedAppearanceKey; // @"useEtched" 106 | extern NSString *const PSTextFieldNoAutoCorrectKey; // @"noAutoCorrect" 107 | extern NSString *const PSTextViewBottomMarginKey; // @"textViewBottomMargin" 108 | extern NSString *const PSTitleKey; // @"label" 109 | extern NSString *const PSTitlesDataSourceKey; // @"titlesDataSource" 110 | extern NSString *const PSURLKeyboardKey; // @"isURL" 111 | extern NSString *const PSValidTitlesKey; // @"validTitles" 112 | extern NSString *const PSValidValuesKey; // @"validValues" 113 | extern NSString *const PSValueChangedNotificationKey; // @"PostNotification" 114 | extern NSString *const PSValueKey; // @"value" 115 | extern NSString *const PSValuesDataSourceKey; // @"valuesDataSource" 116 | 117 | __END_DECLS 118 | 119 | @interface PSSpecifier : NSObject { 120 | @public 121 | SEL action; 122 | } 123 | 124 | + (instancetype)preferenceSpecifierNamed:(NSString *)identifier target:(id)target set:(SEL)set get:(SEL)get detail:(Class)detail cell:(PSCellType)cellType edit:(Class)edit; 125 | + (instancetype)emptyGroupSpecifier; 126 | + (instancetype)groupSpecifierWithName:(NSString *)name; 127 | 128 | @property (nonatomic, retain) id target; 129 | @property (nonatomic, retain) NSString *name; 130 | @property (nonatomic, retain) NSString *identifier; 131 | 132 | @property (nonatomic, retain) NSMutableDictionary *properties; 133 | 134 | - (id)propertyForKey:(NSString *)key; 135 | - (void)setProperty:(id)property forKey:(NSString *)key; 136 | - (void)removePropertyForKey:(NSString *)key; 137 | 138 | @property (nonatomic, retain) NSDictionary *shortTitleDictionary; 139 | @property (nonatomic, retain) NSDictionary *titleDictionary; 140 | 141 | @property (nonatomic) SEL controllerLoadAction; 142 | 143 | - (void)setUserInfo:(id)arg1; 144 | - (NSArray *)values; 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SFCustomFolderSettingsController.m: -------------------------------------------------------------------------------- 1 | #import "PreferenceHeaders/PSListController.h" 2 | #import "PreferenceHeaders/PSSpecifier.h" 3 | #import "PreferenceHeaders/PSListItemsController.h" 4 | #import "PreferenceHeaders/PSTableCell.h" 5 | #import "PreferenceHeaders/PSSwitchTableCell.h" 6 | 7 | 8 | @interface SFCustomFolderSettingsController : PSListController 9 | @end 10 | 11 | static NSUserDefaults *preferences; 12 | 13 | static NSDictionary *customFolderSettings; //root 14 | static NSDictionary *folderSettings; 15 | static NSString *folderName; 16 | static NSString *folderID; 17 | 18 | static int customAppMethod = 5; 19 | 20 | 21 | static NSString * addSuffixToNumber(int number) { 22 | NSString *suffix; 23 | int ones = number % 10; 24 | int tens = (number/10) % 10; 25 | 26 | if (tens == 1) { 27 | suffix = @"th"; 28 | } else { 29 | switch (ones) { 30 | case 1: 31 | suffix = @"st"; 32 | break; 33 | case 2: 34 | suffix = @"nd"; 35 | break; 36 | case 3: 37 | suffix = @"rd"; 38 | break; 39 | default: 40 | suffix = @"th"; 41 | break; 42 | } 43 | } 44 | return [NSString stringWithFormat:@"%d%@", number, suffix]; 45 | } 46 | 47 | static NSString * setCustomAppIndexTextForIndex(int number) { 48 | return [NSString stringWithFormat:@"Custom: open %@ app", addSuffixToNumber(number)]; 49 | } 50 | 51 | 52 | static void setSetting(id value, NSString * folderID, NSString * specifierID) { 53 | 54 | NSMutableDictionary *mutableCustomFolderSettings = [customFolderSettings mutableCopy]; 55 | NSMutableDictionary *mutableFolderSettings = [folderSettings mutableCopy]; 56 | if(!mutableFolderSettings) mutableFolderSettings = [NSMutableDictionary new]; 57 | if(!mutableCustomFolderSettings) mutableCustomFolderSettings = [NSMutableDictionary new]; 58 | 59 | 60 | [mutableFolderSettings setObject:value forKey:specifierID]; 61 | [mutableCustomFolderSettings setObject:mutableFolderSettings forKey:folderID]; 62 | 63 | preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 64 | [preferences setObject:mutableCustomFolderSettings forKey:@"customFolderSettings"]; 65 | [preferences synchronize]; 66 | 67 | 68 | CFStringRef toPost = (CFStringRef)@"nl.jessevandervelden.swipyfoldersprefs/prefsChanged"; //(CFStringRef)specifier.properties[@"PostNotification"]; 69 | if(toPost) CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), toPost, NULL, NULL, YES); 70 | 71 | customFolderSettings = [mutableCustomFolderSettings copy]; 72 | folderSettings = [mutableFolderSettings copy]; 73 | 74 | } 75 | 76 | @implementation SFCustomFolderSettingsController 77 | 78 | - (void)getCustomFolderSettings { 79 | preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 80 | customFolderSettings = [[preferences dictionaryForKey:@"customFolderSettings"] retain]; 81 | 82 | folderID = [self.specifier propertyForKey:@"folderID"]; 83 | folderSettings = customFolderSettings[folderID]; // >> Dit moet later een ID worden! 84 | folderName = [self.specifier name]; 85 | } 86 | 87 | 88 | - (NSArray *)specifiers { 89 | if (!_specifiers) { 90 | _specifiers = [[self loadSpecifiersFromPlistName:@"CustomFolderSettings" target:self] retain]; 91 | } 92 | 93 | /*for(int i=0; i<[_specifiers count]; i++) { 94 | PSSpecifier *specifier = _specifiers[i]; 95 | [specifier setProperty:[self.specifier name] forKey:@"folderName"]; 96 | }*/ 97 | 98 | return _specifiers; 99 | } 100 | 101 | - (void)viewWillAppear:(BOOL)animated { 102 | [super viewWillAppear:animated]; 103 | 104 | [self getCustomFolderSettings]; 105 | self.navigationItem.title = folderName; 106 | 107 | UITableView *tableView = self.table; 108 | [tableView reloadData]; 109 | } 110 | 111 | - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 112 | UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 113 | PSSpecifier *specifier = ((PSTableCell *) cell).specifier; 114 | 115 | if(![specifier.identifier isEqualToString:@"customFolderEnabled"]) { 116 | int method = [folderSettings[specifier.identifier] intValue]; 117 | if(method == customAppMethod) { 118 | //NSString *customAppIndexString = [NSString stringWithFormat:@"%@CustomAppIndex", specifier.identifier]; 119 | 120 | int customAppIndex = [folderSettings[[NSString stringWithFormat:@"%@CustomAppIndex", specifier.identifier]] intValue]; 121 | cell.detailTextLabel.text = setCustomAppIndexTextForIndex(customAppIndex); 122 | } 123 | } 124 | 125 | return cell; 126 | } 127 | 128 | -(id)readPreferenceValue:(PSSpecifier*)specifier { 129 | return folderSettings[specifier.identifier]; 130 | } 131 | 132 | -(void)setValuePreference:(id)value forSpecifier:(PSSpecifier*)specifier { 133 | setSetting(value, folderID, specifier.identifier); 134 | } 135 | 136 | @end 137 | 138 | 139 | @interface SFCustomFolderSettingsListItemsController : PSListItemsController 140 | @end 141 | 142 | @implementation SFCustomFolderSettingsListItemsController 143 | 144 | 145 | 146 | - (PSTableCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 147 | PSTableCell *cell = (PSTableCell*)[super tableView:tableView cellForRowAtIndexPath:indexPath]; 148 | PSSpecifier *specifier = cell.specifier; 149 | 150 | NSInteger method = [specifier.values[0] intValue]; 151 | 152 | if(method == customAppMethod) { 153 | int customAppIndex = [folderSettings[[NSString stringWithFormat:@"%@CustomAppIndex", [self.specifier identifier]]] intValue]; 154 | cell.textLabel.text = setCustomAppIndexTextForIndex(customAppIndex); 155 | } 156 | 157 | 158 | return cell; 159 | } 160 | 161 | 162 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 163 | [super tableView:tableView didSelectRowAtIndexPath:indexPath]; 164 | 165 | PSTableCell *cell = (PSTableCell*)[super tableView:tableView cellForRowAtIndexPath:indexPath]; 166 | PSSpecifier *specifier = cell.specifier; 167 | 168 | NSInteger method = [specifier.values[0] intValue]; 169 | 170 | if(method == customAppMethod) { 171 | 172 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"SwipyFolders" 173 | message:@"Enter an app's position in the folder. Example: the third app will be: 3" 174 | preferredStyle:UIAlertControllerStyleAlert]; 175 | 176 | UIAlertAction *cancelAction = [UIAlertAction 177 | actionWithTitle:@"Cancel" 178 | style:UIAlertActionStyleCancel 179 | handler:nil]; 180 | 181 | UIAlertAction *okAction = [UIAlertAction 182 | actionWithTitle:@"Enter" 183 | style:UIAlertActionStyleDefault 184 | handler:^(UIAlertAction *action) { 185 | 186 | UITextField *text_field = alertController.textFields.firstObject; 187 | NSString *appIndexText = text_field.text; 188 | NSNumber *appIndex = @([appIndexText intValue]); 189 | if (!appIndex || appIndex.integerValue < 1) { 190 | UIAlertController * alert= [UIAlertController alertControllerWithTitle:@"SwipyFolders" message:@"Please enter a valid number" preferredStyle:UIAlertControllerStyleAlert]; 191 | UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]; 192 | [alert addAction:dismissAction]; 193 | [self presentViewController:alert animated:YES completion:nil]; 194 | return; 195 | } 196 | 197 | NSIndexPath *ip = [NSIndexPath indexPathForRow:customAppMethod inSection:0]; 198 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:ip]; 199 | 200 | cell.textLabel.text = setCustomAppIndexTextForIndex([appIndex intValue]); 201 | 202 | NSString *specifierID = [NSString stringWithFormat:@"%@CustomAppIndex", [self.specifier identifier]]; 203 | 204 | setSetting(appIndexText, folderID, specifierID); 205 | setSetting(@"5", folderID, [self.specifier identifier]); 206 | 207 | 208 | }]; 209 | 210 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 211 | textField.placeholder = @"e.g. 3, 5, 99"; 212 | [textField resignFirstResponder]; 213 | [textField setKeyboardType:UIKeyboardTypeNumberPad]; 214 | UIView *spacerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; 215 | [textField setLeftViewMode:UITextFieldViewModeAlways]; 216 | [textField setLeftView:spacerView]; 217 | }]; 218 | 219 | [alertController addAction:cancelAction]; 220 | [alertController addAction:okAction]; 221 | [self presentViewController:alertController animated:YES completion:nil]; 222 | 223 | } 224 | 225 | } 226 | @end 227 | -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/CustomFolderSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | label 11 | APPEARANCE 12 | 13 | 14 | PostNotification 15 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 16 | cell 17 | PSSwitchCell 18 | cellClass 19 | SFSwitchTableCell 20 | default 21 | 22 | defaults 23 | nl.jessevandervelden.swipyfoldersprefs 24 | key 25 | customFolderAppearance 26 | id 27 | customFolderAppearance 28 | label 29 | Enable custom Appearance 30 | set 31 | setValuePreference:forSpecifier: 32 | 33 | 34 | PostNotification 35 | nl.jessevandervelden.swipyfoldersprefs/respring 36 | cell 37 | PSSwitchCell 38 | cellClass 39 | SFSwitchTableCell 40 | default 41 | 42 | defaults 43 | nl.jessevandervelden.swipyfoldersprefs 44 | key 45 | customFolderEnableFolderPreview 46 | id 47 | customFolderEnableFolderPreview 48 | label 49 | Set first icon as Folder Preview 50 | sublabel 51 | Needs a respring 52 | set 53 | setValuePreference:forSpecifier: 54 | 55 | 56 | 57 | PostNotification 58 | nl.jessevandervelden.swipyfoldersprefs/respring 59 | cell 60 | PSSwitchCell 61 | cellClass 62 | SFSwitchTableCell 63 | default 64 | 65 | defaults 66 | nl.jessevandervelden.swipyfoldersprefs 67 | key 68 | customFolderHideGreyFolderBackground 69 | id 70 | customFolderHideGreyFolderBackground 71 | label 72 | Hide grey Folder Background 73 | sublabel 74 | Needs a respring 75 | set 76 | setValuePreference:forSpecifier: 77 | 78 | 79 | cell 80 | PSGroupCell 81 | label 82 | FUNCTIONALITY 83 | 84 | 85 | PostNotification 86 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 87 | cell 88 | PSSwitchCell 89 | cellClass 90 | SFSwitchTableCell 91 | default 92 | 93 | defaults 94 | nl.jessevandervelden.swipyfoldersprefs 95 | key 96 | customFolderFunctionallity 97 | id 98 | customFolderFunctionallity 99 | label 100 | Enable custom Functionallity 101 | set 102 | setValuePreference:forSpecifier: 103 | 104 | 105 | PostNotification 106 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 107 | cell 108 | PSLinkListCell 109 | default 110 | 2 111 | defaults 112 | nl.jessevandervelden.swipyfoldersprefs 113 | detail 114 | SFCustomFolderSettingsListItemsController 115 | key 116 | customFolderSingleTapMethod 117 | id 118 | customFolderSingleTapMethod 119 | label 120 | Single Tap 121 | validTitles 122 | 123 | Open folder 124 | Open first app 125 | Open second app 126 | Quick action on folder 127 | Quick action on first app 128 | Custom: open x'th app 129 | Open last app 130 | Open last opened app 131 | Nothing 132 | 133 | validValues 134 | 135 | 1 136 | 2 137 | 3 138 | 8 139 | 4 140 | 5 141 | 6 142 | 7 143 | 0 144 | 145 | set 146 | setValuePreference:forSpecifier: 147 | 148 | 149 | PostNotification 150 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 151 | cell 152 | PSLinkListCell 153 | default 154 | 1 155 | defaults 156 | nl.jessevandervelden.swipyfoldersprefs 157 | detail 158 | SFCustomFolderSettingsListItemsController 159 | key 160 | customFolderSwipeUpMethod 161 | id 162 | customFolderSwipeUpMethod 163 | label 164 | Swipe Up 165 | validTitles 166 | 167 | Open folder 168 | Open first app 169 | Open second app 170 | Quick action on folder 171 | Quick action on first app 172 | Custom: open x'th app 173 | Open last app 174 | Open last opened app 175 | Nothing 176 | 177 | validValues 178 | 179 | 1 180 | 2 181 | 3 182 | 8 183 | 4 184 | 5 185 | 6 186 | 7 187 | 0 188 | 189 | set 190 | setValuePreference:forSpecifier: 191 | 192 | 193 | PostNotification 194 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 195 | cell 196 | PSLinkListCell 197 | default 198 | 0 199 | defaults 200 | nl.jessevandervelden.swipyfoldersprefs 201 | detail 202 | SFCustomFolderSettingsListItemsController 203 | key 204 | customFolderSwipeDownMethod 205 | id 206 | customFolderSwipeDownMethod 207 | label 208 | Swipe Down 209 | validTitles 210 | 211 | Open folder 212 | Open first app 213 | Open second app 214 | Quick action on folder 215 | Quick action on first app 216 | Custom: open x'th app 217 | Open last app 218 | Open last opened app 219 | Nothing 220 | 221 | validValues 222 | 223 | 1 224 | 2 225 | 3 226 | 8 227 | 4 228 | 5 229 | 6 230 | 7 231 | 0 232 | 233 | set 234 | setValuePreference:forSpecifier: 235 | 236 | 237 | PostNotification 238 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 239 | cell 240 | PSLinkListCell 241 | default 242 | 0 243 | defaults 244 | nl.jessevandervelden.swipyfoldersprefs 245 | detail 246 | SFCustomFolderSettingsListItemsController 247 | key 248 | customFolderDoubleTapMethod 249 | id 250 | customFolderDoubleTapMethod 251 | label 252 | Double Tap 253 | validTitles 254 | 255 | Open folder 256 | Open first app 257 | Open second app 258 | Quick action on folder 259 | Quick action on first app 260 | Custom: open x'th app 261 | Open last app 262 | Open last opened app 263 | Nothing 264 | 265 | validValues 266 | 267 | 1 268 | 2 269 | 3 270 | 8 271 | 4 272 | 5 273 | 6 274 | 7 275 | 0 276 | 277 | set 278 | setValuePreference:forSpecifier: 279 | 280 | 281 | PostNotification 282 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 283 | cell 284 | PSLinkListCell 285 | default 286 | 0 287 | defaults 288 | nl.jessevandervelden.swipyfoldersprefs 289 | detail 290 | SFCustomFolderSettingsListItemsController 291 | key 292 | customFolderShortHoldMethod 293 | id 294 | customFolderShortHoldMethod 295 | label 296 | Short press 297 | validTitles 298 | 299 | Open folder 300 | Open first app 301 | Open second app 302 | Quick action on folder 303 | Quick action on first app 304 | Custom: open x'th app 305 | Open last app 306 | Open last opened app 307 | Nothing 308 | 309 | validValues 310 | 311 | 1 312 | 2 313 | 3 314 | 8 315 | 4 316 | 5 317 | 6 318 | 7 319 | 0 320 | 321 | set 322 | setValuePreference:forSpecifier: 323 | staticTextMessage 324 | In order to be able to move icons on a long press, for a short press you just need to hold icons for a short time and release your finger in time. Otherwise, it will go into edit (jiggle) mode instead. | 'Quick action on folder' only works on iOS 10 and up 325 | 326 | 327 | PostNotification 328 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 329 | cell 330 | PSLinkListCell 331 | default 332 | 0 333 | defaults 334 | nl.jessevandervelden.swipyfoldersprefs 335 | detail 336 | SFCustomFolderSettingsListItemsController 337 | key 338 | customFolderLongHoldMethod 339 | id 340 | customFolderLongHoldMethod 341 | label 342 | Long press 343 | validTitles 344 | 345 | Open folder 346 | Open first app 347 | Open second app 348 | Quick action on folder 349 | Quick action on first app 350 | Custom: open x'th app 351 | Open last app 352 | Open last opened app 353 | Nothing 354 | 355 | validValues 356 | 357 | 1 358 | 2 359 | 3 360 | 8 361 | 4 362 | 5 363 | 6 364 | 7 365 | 0 366 | 367 | set 368 | setValuePreference:forSpecifier: 369 | staticTextMessage 370 | This will override the icon editing (jiggle) mode for folders. If you still want to use icon editing mode on folders too, use the 'Short press' method | 'Quick action on folder' only works on iOS 10 and up 371 | 372 | 373 | PostNotification 374 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 375 | cell 376 | PSLinkListCell 377 | default 378 | 4 379 | defaults 380 | nl.jessevandervelden.swipyfoldersprefs 381 | detail 382 | SFCustomFolderSettingsListItemsController 383 | key 384 | customFolderForceTouchMethod 385 | id 386 | customFolderForceTouchMethod 387 | label 388 | 3D Touch 389 | validTitles 390 | 391 | Open folder 392 | Open first app 393 | Open second app 394 | Quick action on folder 395 | Quick action on first app 396 | Custom: open x'th app 397 | Open last app 398 | Open last opened app 399 | Nothing 400 | 401 | validValues 402 | 403 | 1 404 | 2 405 | 3 406 | 8 407 | 4 408 | 5 409 | 6 410 | 7 411 | 0 412 | 413 | set 414 | setValuePreference:forSpecifier: 415 | staticTextMessage 416 | If you are facing issues with Appendix, try Manila instead 417 | 418 | 419 | 420 | cell 421 | PSGroupCell 422 | footerText 423 | Coming soon: MegaCookie/libFolders 424 | 425 | 426 | 427 | 428 | 429 | -------------------------------------------------------------------------------- /swipyfoldersprefs/SwipyFoldersPrefs.xm: -------------------------------------------------------------------------------- 1 | #include "SwipyFoldersPrefs.h" 2 | 3 | #import "SFSwitchTableCell.h" 4 | #import "SFSliderTableCell.h" 5 | #import "SFFolderListController.h" 6 | 7 | 8 | static NSUserDefaults *preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 9 | static int customAppMethod = 5; 10 | 11 | static NSString * addSuffixToNumber(int number) { 12 | NSString *suffix; 13 | int ones = number % 10; 14 | int tens = (number/10) % 10; 15 | 16 | if (tens == 1) { 17 | suffix = @"th"; 18 | } else { 19 | switch (ones) { 20 | case 1: 21 | suffix = @"st"; 22 | break; 23 | case 2: 24 | suffix = @"nd"; 25 | break; 26 | case 3: 27 | suffix = @"rd"; 28 | break; 29 | default: 30 | suffix = @"th"; 31 | break; 32 | } 33 | } 34 | return [NSString stringWithFormat:@"%d%@", number, suffix]; 35 | } 36 | 37 | static NSString * setCustomAppIndexTextForIndex(int number) { 38 | return [NSString stringWithFormat:@"Custom: open %@ app", addSuffixToNumber(number)]; 39 | } 40 | 41 | 42 | 43 | @implementation SwipyFoldersPrefs 44 | 45 | - (NSArray *)specifiers { 46 | if (!_specifiers) { 47 | _specifiers = [[self loadSpecifiersFromPlistName:@"SwipyFoldersPrefs" target:self] retain]; 48 | 49 | Class DisplayController = %c(PSUIDisplayController); // Appears to be iOS 9+. 50 | if (!DisplayController) { // iOS 8. 51 | DisplayController = %c(DisplayController); 52 | } 53 | } 54 | 55 | return _specifiers; 56 | } 57 | 58 | - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 59 | UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 60 | 61 | // Oh god the hacks. Remove the separator between the slider cell and the cell before it. 62 | // This hack is from http://stackoverflow.com/a/32818943. 63 | if ([cell isKindOfClass:%c(PSTableCell)]) { 64 | PSSpecifier *specifier = ((PSTableCell *) cell).specifier; 65 | NSString *identifier = specifier.identifier; 66 | 67 | if ([identifier isEqualToString:@"doubleTapTimeText"]) { 68 | NSLog(@"SwipyFolders: %lf", [preferences doubleForKey:@"doubleTapTime"]); 69 | double doubleTapTime = ([preferences doubleForKey:@"doubleTapTime"] == 0)? 0.2 : [preferences doubleForKey:@"doubleTapTime"]; 70 | CGFloat inset = cell.bounds.size.width * 10; 71 | cell.separatorInset = UIEdgeInsetsMake(0, inset, 0, 0); 72 | cell.indentationWidth = -inset; 73 | cell.indentationLevel = 1; 74 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%.2lf", doubleTapTime]; 75 | 76 | } else if ([identifier isEqualToString:@"longHoldTimeText"]) { 77 | double longHoldTime = ([preferences doubleForKey:@"longHoldTime"] == 0)? 0.2 : [preferences doubleForKey:@"longHoldTime"]; 78 | CGFloat inset = cell.bounds.size.width * 10; 79 | cell.separatorInset = UIEdgeInsetsMake(0, inset, 0, 0); 80 | cell.indentationWidth = -inset; 81 | cell.indentationLevel = 1; 82 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%.2lf", longHoldTime]; 83 | 84 | } else if ([identifier isEqualToString:@"singleTapMethod"] || [identifier isEqualToString:@"swipeUpMethod"] || [identifier isEqualToString:@"swipeDownMethod"] || [identifier isEqualToString:@"doubleTapMethod"] || [identifier isEqualToString:@"shortHoldMethod"] || [identifier isEqualToString:@"longHoldMethod"] || [identifier isEqualToString:@"forceTouchMethod"]) { 85 | 86 | int method = [preferences integerForKey:identifier]; 87 | if(method == 5) { 88 | int customAppIndex = [preferences integerForKey:[NSString stringWithFormat:@"%@CustomAppIndex", identifier]]; 89 | cell.detailTextLabel.text = setCustomAppIndexTextForIndex(customAppIndex); 90 | } 91 | } 92 | 93 | } 94 | return cell; 95 | } 96 | 97 | - (void)viewWillAppear:(BOOL)animated { 98 | [super viewWillAppear:animated]; 99 | UITableView *tableView = MSHookIvar(self, "_table"); 100 | [tableView reloadData]; 101 | } 102 | 103 | -(void)sliderMoved:(UISlider *)slider { 104 | UITableView *tableView = MSHookIvar(self, "_table"); 105 | 106 | CGPoint oiginInTableView = [slider convertPoint:CGPointZero toView:tableView]; 107 | NSIndexPath *indexPath = [tableView indexPathForRowAtPoint:oiginInTableView]; 108 | PSTableCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 109 | PSSpecifier *specifier = cell.specifier; 110 | 111 | NSString *specifierId = [NSString stringWithFormat:@"%@Text", specifier.identifier]; 112 | 113 | UITableViewCell *textCell = (UITableViewCell *)[self cachedCellForSpecifierID:specifierId]; 114 | textCell.detailTextLabel.text = [NSString stringWithFormat:@"%.2lf", slider.value]; 115 | 116 | } 117 | 118 | - (void)respring { 119 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), 120 | CFSTR("nl.jessevandervelden.swipyfoldersprefs/respring"), 121 | nil, 122 | nil, 123 | true); 124 | } 125 | 126 | - (void)github { 127 | NSURL *githubURL = [NSURL URLWithString:@"https://github.com/megacookie/SwipyFolders"]; 128 | [[UIApplication sharedApplication] openURL:githubURL]; 129 | } 130 | 131 | - (void)contact { 132 | NSURL *url = [NSURL URLWithString:@"mailto:mail@jessevandervelden.nl?subject=SwipyFolders"]; 133 | [[UIApplication sharedApplication] openURL:url]; 134 | } 135 | 136 | - (void)paypal { 137 | NSURL *url = [NSURL URLWithString:@"https://paypal.me/JessevanderVelden"]; 138 | [[UIApplication sharedApplication] openURL:url]; 139 | } 140 | 141 | - (void)twitter { 142 | NSURL *url = [NSURL URLWithString:@"https://twitter.com/JesseVelden"]; 143 | [[UIApplication sharedApplication] openURL:url]; 144 | } 145 | 146 | - (void)cydia { 147 | NSURL *url = [NSURL URLWithString:@"cydia://url/https://cydia.saurik.com/api/share#?source=http://megacookie.github.io/"]; 148 | [[UIApplication sharedApplication] openURL:url]; 149 | } 150 | 151 | 152 | @end 153 | 154 | @implementation SFListItemsController 155 | 156 | 157 | - (PSTableCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 158 | PSTableCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 159 | PSSpecifier *specifier = cell.specifier; 160 | 161 | NSInteger method = [specifier.values[0] intValue]; 162 | 163 | 164 | if(method == customAppMethod) { 165 | int customAppIndex = [preferences integerForKey:[NSString stringWithFormat:@"%@CustomAppIndex", self.specifier.identifier]]; 166 | cell.textLabel.text = setCustomAppIndexTextForIndex(customAppIndex); 167 | } 168 | 169 | return cell; 170 | } 171 | 172 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 173 | [super tableView:tableView didSelectRowAtIndexPath:indexPath]; //Instead of %orig(); 174 | PSTableCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 175 | PSSpecifier *specifier = cell.specifier; 176 | 177 | NSInteger method = [specifier.values[0] intValue]; 178 | 179 | //NSInteger selectedRow = indexPath.row; 180 | if(method == customAppMethod) { 181 | 182 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"SwipyFolders" 183 | message:@"Enter an app's position in the folder. Example: the third app will be: 3" 184 | preferredStyle:UIAlertControllerStyleAlert]; 185 | 186 | UIAlertAction *cancelAction = [UIAlertAction 187 | actionWithTitle:@"Cancel" 188 | style:UIAlertActionStyleCancel 189 | handler:nil]; 190 | 191 | UIAlertAction *okAction = [UIAlertAction 192 | actionWithTitle:@"Enter" 193 | style:UIAlertActionStyleDefault 194 | handler:^(UIAlertAction *action) { 195 | 196 | UITextField *text_field = alertController.textFields.firstObject; 197 | NSString *appIndexText = text_field.text; 198 | NSNumber *appIndex = @([appIndexText intValue]); 199 | if (!appIndex || appIndex.integerValue < 1) { 200 | UIAlertController * alert= [UIAlertController alertControllerWithTitle:@"SwipyFolders" message:@"Please enter a valid number" preferredStyle:UIAlertControllerStyleAlert]; 201 | UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]; 202 | [alert addAction:dismissAction]; 203 | [self presentViewController:alert animated:YES completion:nil]; 204 | return; 205 | } 206 | 207 | NSIndexPath *ip = [NSIndexPath indexPathForRow:customAppMethod inSection:0]; 208 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:ip]; 209 | 210 | cell.textLabel.text = setCustomAppIndexTextForIndex([appIndex intValue]); 211 | 212 | [preferences setInteger:appIndex.integerValue forKey:[NSString stringWithFormat:@"%@CustomAppIndex", self.specifier.identifier]]; 213 | [preferences synchronize]; 214 | 215 | 216 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 217 | // notify after file write to update 218 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)[self.specifier propertyForKey:@"PostNotification"], NULL, NULL, YES); 219 | }); 220 | 221 | 222 | 223 | }]; 224 | 225 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 226 | textField.placeholder = @"e.g. 3, 5, 99"; 227 | [textField resignFirstResponder]; 228 | [textField setKeyboardType:UIKeyboardTypeNumberPad]; 229 | UIView *spacerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; 230 | [textField setLeftViewMode:UITextFieldViewModeAlways]; 231 | [textField setLeftView:spacerView]; 232 | }]; 233 | 234 | [alertController addAction:cancelAction]; 235 | [alertController addAction:okAction]; 236 | [self presentViewController:alertController animated:YES completion:nil]; 237 | 238 | } 239 | 240 | } 241 | @end 242 | 243 | 244 | //Interface is imported 245 | @implementation SFFolderListController 246 | 247 | - (NSArray *)specifiers { 248 | 249 | if (!_specifiers) { 250 | 251 | CPDistributedMessagingCenter *messagingCenter = [CPDistributedMessagingCenter centerNamed:@"nl.jessevandervelden.swipyfolders.center"]; 252 | NSDictionary *foldersDictionary = [messagingCenter sendMessageAndReceiveReplyName:@"foldersRepresentation" userInfo:nil]; 253 | 254 | NSMutableArray *specs = [[[NSMutableArray alloc] init] retain]; 255 | 256 | PSSpecifier *header = [PSSpecifier emptyGroupSpecifier]; 257 | [header setProperty:@"Folders" forKey:@"label"]; 258 | header.name = @"Folders"; 259 | //[header setProperty:@"Coming soon: megacookie/libFolders for other developers" forKey:@"footerText"]; 260 | [specs insertObject:header atIndex:0]; 261 | 262 | NSArray * sortedFolderKeys = [[foldersDictionary allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]; 263 | 264 | //for(int i=0; i<[foldersDictionary count]; i++) { 265 | for (id key in sortedFolderKeys) { 266 | NSDictionary *currentFolder = [foldersDictionary objectForKey:key]; 267 | 268 | //NSDictionary *currentFolder = foldersDictionary[[NSString stringWithFormat:@"%d", i]]; 269 | PSSpecifier *spec = [PSSpecifier preferenceSpecifierNamed:currentFolder[@"displayName"] target:self set:NULL get:NULL detail:%c(SFCustomFolderSettingsController) cell:PSLinkCell edit:nil]; 270 | if ([UIImage respondsToSelector:@selector(_applicationIconImageForBundleIdentifier:format:scale:)]) { 271 | NSArray *applicationBundleIDs = currentFolder[@"applicationBundleIDs"]; 272 | [spec setProperty:[self createFolderIconImageWithIdentifiers:applicationBundleIDs] forKey:@"iconImage"]; 273 | } 274 | 275 | 276 | [spec setProperty:@"1" forKey:@"isController"]; 277 | [spec setProperty:currentFolder[@"folderID"] forKey:@"folderID"]; 278 | [specs addObject:spec]; 279 | 280 | } 281 | 282 | _specifiers = [[specs copy] retain]; 283 | 284 | Class DisplayController = %c(PSUIDisplayController); // Appears to be iOS 9+. 285 | if (!DisplayController) { // iOS 8. 286 | DisplayController = %c(DisplayController); 287 | } 288 | } 289 | 290 | return _specifiers; 291 | } 292 | 293 | - (UIImage *)createFolderIconImageWithIdentifiers:(NSArray*)bundleIdentifiers { 294 | double totalSize = 44.5; // Normal = 60 295 | double iconSize = 10.5; //Normal = 13 --> 13/(60/44.5) = 9.64, but I like bigger icons :P 296 | UIColor *backgroundColor = [UIColor colorWithRed:171.0/255.0 green:188.0/255.0 blue:216.0/255.0 alpha:1]; 297 | 298 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(totalSize, totalSize), false, 0.0); 299 | UIBezierPath *backgroundPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0, totalSize, totalSize) cornerRadius:10]; 300 | [backgroundColor setFill]; 301 | [backgroundPath fill]; 302 | 303 | double margin = (totalSize-iconSize*3)/4; //You got 4 margins! <--m--APP--m--APP--m--APP--m--> 304 | double width = margin; 305 | double height = margin; 306 | for(int i=0; i<[bundleIdentifiers count] && i<9; i++) { 307 | if(i%3 == 0 && i!=0) { //Unfortunately 0%3 == also 0, so double checking fot that! 308 | width = margin; 309 | height += iconSize+margin; 310 | } 311 | if(![bundleIdentifiers[i] isEqualToString:@"com.broganminer.anchor"] && ![bundleIdentifiers[i] isEqualToString:@""]) { 312 | UIImage *appImage = [UIImage _applicationIconImageForBundleIdentifier:bundleIdentifiers[i] format:0 scale:[UIScreen mainScreen].scale]; 313 | [appImage drawInRect:CGRectMake(width, height, iconSize, iconSize)]; 314 | } 315 | width += iconSize+margin; 316 | 317 | } 318 | 319 | UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); 320 | UIGraphicsEndImageContext(); 321 | 322 | return finalImage; 323 | } 324 | 325 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 326 | return 50; 327 | } 328 | 329 | - (void)viewWillAppear:(BOOL)animated { 330 | [super viewWillAppear:animated]; 331 | [self.table reloadData]; 332 | } 333 | 334 | - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 335 | UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath]; 336 | PSSpecifier *specifier = ((PSTableCell *) cell).specifier; 337 | 338 | NSUserDefaults *preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 339 | NSDictionary *customFolderSettings = [preferences dictionaryForKey:@"customFolderSettings"]; 340 | 341 | NSString *folderID = [specifier propertyForKey:@"folderID"]; 342 | NSDictionary *folderSettings = customFolderSettings[folderID]; // >> Dit moet later een ID worden! 343 | 344 | if([folderSettings[@"customFolderFunctionallity"] intValue] == 1 || [folderSettings[@"customFolderAppearance"] intValue] == 1) { 345 | cell.detailTextLabel.text = @"Enabled"; 346 | } else { 347 | cell.detailTextLabel.text = @"Not enabled"; 348 | } 349 | return cell; 350 | } 351 | 352 | @end 353 | -------------------------------------------------------------------------------- /swipyfoldersprefs/Resources/SwipyFoldersPrefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSStaticTextCell 10 | height 11 | 133 12 | icon 13 | banner.png 14 | 15 | 16 | PostNotification 17 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 18 | cell 19 | PSSwitchCell 20 | cellClass 21 | SFSwitchTableCell 22 | default 23 | 24 | defaults 25 | nl.jessevandervelden.swipyfoldersprefs 26 | key 27 | enabled 28 | label 29 | Enabled 30 | 31 | 32 | cell 33 | PSLinkCell 34 | detail 35 | SFFolderListController 36 | label 37 | Set per Folder settings 38 | isController 39 | 40 | id 41 | customFolderSettings 42 | 43 | 44 | action 45 | respring 46 | cell 47 | PSButtonCell 48 | icon 49 | respring.png 50 | label 51 | Respring 52 | 53 | 54 | 55 | 56 | 57 | cell 58 | PSGroupCell 59 | label 60 | APPEARANCE 61 | 62 | 63 | 64 | PostNotification 65 | nl.jessevandervelden.swipyfoldersprefs/respring 66 | cell 67 | PSSwitchCell 68 | cellClass 69 | SFSwitchTableCell 70 | default 71 | 72 | defaults 73 | nl.jessevandervelden.swipyfoldersprefs 74 | key 75 | enableFolderPreview 76 | label 77 | Set first icon as Folder Preview 78 | sublabel 79 | Needs a respring 80 | 81 | 82 | PostNotification 83 | nl.jessevandervelden.swipyfoldersprefs/respring 84 | cell 85 | PSSwitchCell 86 | cellClass 87 | SFSwitchTableCell 88 | default 89 | 90 | defaults 91 | nl.jessevandervelden.swipyfoldersprefs 92 | key 93 | hideGreyFolderBackground 94 | label 95 | Hide grey Folder Background 96 | sublabel 97 | Needs a respring 98 | 99 | 100 | PostNotification 101 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 102 | cell 103 | PSSwitchCell 104 | cellClass 105 | SFSwitchTableCell 106 | default 107 | 108 | defaults 109 | nl.jessevandervelden.swipyfoldersprefs 110 | key 111 | closeFolderOnOpen 112 | label 113 | Close folder automatically 114 | 115 | 116 | cell 117 | PSGroupCell 118 | label 119 | FUNCTIONALITY 120 | 121 | 122 | PostNotification 123 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 124 | cell 125 | PSLinkListCell 126 | default 127 | 2 128 | defaults 129 | nl.jessevandervelden.swipyfoldersprefs 130 | detail 131 | SFListItemsController 132 | key 133 | singleTapMethod 134 | id 135 | singleTapMethod 136 | label 137 | Single Tap 138 | validTitles 139 | 140 | Open folder 141 | Open first app 142 | Open second app 143 | Quick action on folder 144 | Quick action on first app 145 | Custom: open x'th app 146 | Open last app 147 | Open last opened app 148 | Nothing 149 | 150 | validValues 151 | 152 | 1 153 | 2 154 | 3 155 | 8 156 | 4 157 | 5 158 | 6 159 | 7 160 | 0 161 | 162 | staticTextMessage 163 | 'Quick action on folder' only works on iOS 10 and up 164 | 165 | 166 | PostNotification 167 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 168 | cell 169 | PSLinkListCell 170 | default 171 | 1 172 | defaults 173 | nl.jessevandervelden.swipyfoldersprefs 174 | detail 175 | SFListItemsController 176 | key 177 | swipeUpMethod 178 | id 179 | swipeUpMethod 180 | label 181 | Swipe Up 182 | validTitles 183 | 184 | Open folder 185 | Open first app 186 | Open second app 187 | Quick action on folder 188 | Quick action on first app 189 | Custom: open x'th app 190 | Open last app 191 | Open last opened app 192 | Nothing 193 | 194 | validValues 195 | 196 | 1 197 | 2 198 | 3 199 | 8 200 | 4 201 | 5 202 | 6 203 | 7 204 | 0 205 | 206 | staticTextMessage 207 | 'Quick action on folder' only works on iOS 10 and up 208 | 209 | 210 | PostNotification 211 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 212 | cell 213 | PSLinkListCell 214 | default 215 | 0 216 | defaults 217 | nl.jessevandervelden.swipyfoldersprefs 218 | detail 219 | SFListItemsController 220 | key 221 | swipeDownMethod 222 | id 223 | swipeDownMethod 224 | label 225 | Swipe Down 226 | validTitles 227 | 228 | Open folder 229 | Open first app 230 | Open second app 231 | Quick action on folder 232 | Quick action on first app 233 | Custom: open x'th app 234 | Open last app 235 | Open last opened app 236 | Nothing 237 | 238 | validValues 239 | 240 | 1 241 | 2 242 | 3 243 | 8 244 | 4 245 | 5 246 | 6 247 | 7 248 | 0 249 | 250 | staticTextMessage 251 | 'Quick action on folder' only works on iOS 10 and up 252 | 253 | 254 | PostNotification 255 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 256 | cell 257 | PSLinkListCell 258 | default 259 | 0 260 | defaults 261 | nl.jessevandervelden.swipyfoldersprefs 262 | detail 263 | SFListItemsController 264 | key 265 | doubleTapMethod 266 | id 267 | doubleTapMethod 268 | label 269 | Double Tap 270 | validTitles 271 | 272 | Open folder 273 | Open first app 274 | Open second app 275 | Quick action on folder 276 | Quick action on first app 277 | Custom: open x'th app 278 | Open last app 279 | Open last opened app 280 | Nothing 281 | 282 | validValues 283 | 284 | 1 285 | 2 286 | 3 287 | 8 288 | 4 289 | 5 290 | 6 291 | 7 292 | 0 293 | 294 | staticTextMessage 295 | When enabled, this will slow down the Single Tap action as it waits for the Double Tap Timeout. | 'Quick action on folder' only works on iOS 10 and up 296 | 297 | 298 | PostNotification 299 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 300 | cell 301 | PSLinkListCell 302 | default 303 | 0 304 | defaults 305 | nl.jessevandervelden.swipyfoldersprefs 306 | detail 307 | SFListItemsController 308 | key 309 | shortHoldMethod 310 | id 311 | shortHoldMethod 312 | label 313 | Short Press 314 | validTitles 315 | 316 | Open folder 317 | Open first app 318 | Open second app 319 | Quick action on folder 320 | Quick action on first app 321 | Custom: open x'th app 322 | Open last app 323 | Open last opened app 324 | Nothing 325 | 326 | validValues 327 | 328 | 1 329 | 2 330 | 3 331 | 8 332 | 4 333 | 5 334 | 6 335 | 7 336 | 0 337 | 338 | staticTextMessage 339 | In order to be able to move icons on a long press, for a short press you just need to hold icons for a short time and release your finger in time. Otherwise, it will go into edit (jiggle) mode instead. | 'Quick action on folder' only works on iOS 10 and up 340 | 341 | 342 | PostNotification 343 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 344 | cell 345 | PSLinkListCell 346 | default 347 | 0 348 | defaults 349 | nl.jessevandervelden.swipyfoldersprefs 350 | detail 351 | SFListItemsController 352 | key 353 | longHoldMethod 354 | id 355 | longHoldMethod 356 | label 357 | Long Press 358 | validTitles 359 | 360 | Open folder 361 | Open first app 362 | Open second app 363 | Quick action on folder 364 | Quick action on first app 365 | Custom: open x'th app 366 | Open last app 367 | Open last opened app 368 | Disabled 369 | 370 | validValues 371 | 372 | 1 373 | 2 374 | 3 375 | 8 376 | 4 377 | 5 378 | 6 379 | 7 380 | 0 381 | 382 | staticTextMessage 383 | This will override the icon editing (jiggle) mode for folders. If you still want to use icon editing mode on folders too, use the 'Short press' method 384 | This needs a respring in order to enable/disable. 385 | 386 | 387 | 388 | PostNotification 389 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 390 | cell 391 | PSLinkListCell 392 | default 393 | 4 394 | defaults 395 | nl.jessevandervelden.swipyfoldersprefs 396 | detail 397 | SFListItemsController 398 | key 399 | forceTouchMethod 400 | id 401 | forceTouchMethod 402 | label 403 | 3D Touch 404 | validTitles 405 | 406 | Open folder 407 | Open first app 408 | Open second app 409 | Quick action on folder 410 | Quick action on first app 411 | Custom: open x'th app 412 | Open last app 413 | Open last opened app 414 | Nothing 415 | 416 | validValues 417 | 418 | 1 419 | 2 420 | 3 421 | 8 422 | 4 423 | 5 424 | 6 425 | 7 426 | 0 427 | 428 | staticTextMessage 429 | If you are facing issues with the tweak Appendix, try Manila instead. | 'Quick action on folder' only works on iOS 10 and up 430 | 431 | 432 | 433 | cell 434 | PSGroupCell 435 | label 436 | SET TIMEOUTS 437 | footerText 438 | A respring is necesarry after changing 'Long Press Time' 439 | 440 | 441 | cell 442 | PSTitleValueCell 443 | label 444 | Double Tap Time 445 | id 446 | doubleTapTimeText 447 | 448 | 449 | PostNotification 450 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 451 | cell 452 | PSSliderCell 453 | cellClass 454 | SFSliderTableCell 455 | defaults 456 | nl.jessevandervelden.swipyfoldersprefs 457 | key 458 | doubleTapTime 459 | id 460 | doubleTapTime 461 | min 462 | 0.1 463 | max 464 | 0.75 465 | default 466 | 0.2 467 | isSegmented 468 | 469 | segmentCount 470 | 13 471 | showValue 472 | 473 | leftImage 474 | time.png 475 | 476 | 477 | cell 478 | PSTitleValueCell 479 | label 480 | Long Press Time 481 | id 482 | longHoldTimeText 483 | 484 | 485 | PostNotification 486 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 487 | cell 488 | PSSliderCell 489 | cellClass 490 | SFSliderTableCell 491 | defaults 492 | nl.jessevandervelden.swipyfoldersprefs 493 | key 494 | longHoldTime 495 | id 496 | longHoldTime 497 | min 498 | 0.1 499 | max 500 | 0.75 501 | default 502 | 0.2 503 | isSegmented 504 | 505 | segmentCount 506 | 13 507 | showValue 508 | 509 | leftImage 510 | time.png 511 | 512 | 513 | 514 | cell 515 | PSGroupCell 516 | label 517 | NESTED FOLDERS 518 | 519 | 520 | 521 | PostNotification 522 | nl.jessevandervelden.swipyfoldersprefs/prefsChanged 523 | cell 524 | PSLinkListCell 525 | default 526 | 0 527 | defaults 528 | nl.jessevandervelden.swipyfoldersprefs 529 | detail 530 | SFListItemsController 531 | key 532 | nestedFolderBehaviour 533 | id 534 | nestedFolderBehaviour 535 | label 536 | Nested folder Behaviour 537 | validTitles 538 | 539 | Off 540 | First app in first folder 541 | First app in a secondary folder 542 | 543 | validValues 544 | 545 | 0 546 | 1 547 | 2 548 | 549 | staticTextMessage 550 | When it is set to the first app in the first folder, the folder preview will show and open up the first app in the first folder. 551 | Otherwise when you got another folder at the first place in the folder, it will show and open the first app of the secondary folder instead. 552 | This has influence on: The folder preview, Opening the first app & 3D Touch. 553 | 554 | 555 | 556 | cell 557 | PSGroupCell 558 | label 559 | CREDITS 560 | 561 | 562 | action 563 | twitter 564 | cell 565 | PSButtonCell 566 | icon 567 | twitter.png 568 | label 569 | @JesseVelden 570 | 571 | 572 | action 573 | contact 574 | cell 575 | PSButtonCell 576 | icon 577 | email.png 578 | label 579 | Email me 580 | 581 | 582 | action 583 | github 584 | cell 585 | PSButtonCell 586 | icon 587 | Github.png 588 | label 589 | View Source on GitHub 590 | 591 | 592 | action 593 | paypal 594 | cell 595 | PSButtonCell 596 | icon 597 | paypal.png 598 | label 599 | Donate <3 600 | 601 | 602 | action 603 | cydia 604 | cell 605 | PSButtonCell 606 | icon 607 | cydia.png 608 | label 609 | Beta repo 610 | 611 | 612 | cell 613 | PSGroupCell 614 | footerText 615 | © 2016 - Jesse van der Velden - MegaCookie 616 | 617 | 618 | title 619 | SwipyFolders 620 | 621 | 622 | -------------------------------------------------------------------------------- /SwipyFolders.h: -------------------------------------------------------------------------------- 1 | @interface FBSystemService : NSObject 2 | - (id)sharedInstance; 3 | - (void)exitAndRelaunch:(bool)arg1; 4 | @end 5 | 6 | @interface _UITapticEngine : NSObject 7 | - (void)actuateFeedback:(NSInteger)count; 8 | @end 9 | 10 | @interface UIDevice (Private) 11 | - (_UITapticEngine *)_tapticEngine; 12 | @end 13 | 14 | @interface UIInteractionProgress : NSObject 15 | @property (assign, nonatomic, readonly) CGFloat percentComplete; 16 | @end 17 | @interface UIPreviewForceInteractionProgress : UIInteractionProgress 18 | - (id)initWithGestureRecognizer:(id)arg1; 19 | @end 20 | 21 | @interface SBApplication : NSObject 22 | @property(copy, nonatomic) NSArray *dynamicShortcutItems; 23 | @property(copy, nonatomic) NSArray *staticShortcutItems; 24 | @property (nonatomic,copy,readonly) NSArray * staticApplicationShortcutItems; 25 | @property (nonatomic,copy) NSArray * dynamicApplicationShortcutItems; 26 | - (void)loadStaticShortcutItemsFromInfoDictionary:(id)arg1 bundle:(id)arg2; 27 | - (NSString*)bundleIdentifier; 28 | - (NSString*)displayName; 29 | - (NSString*)displayIdentifier; 30 | - (NSString*)bundleContainerPath; 31 | - (NSString *)sandboxPath; 32 | - (NSString *)path; 33 | - (NSString *)dataContainerPath; 34 | - (_Bool)statusBarHiddenForCurrentOrientation; 35 | - (_Bool)isRunning; 36 | @end; 37 | 38 | 39 | @interface SBIcon : NSObject 40 | + (struct CGSize)defaultIconImageSize; 41 | + (struct CGSize)defaultIconSize; 42 | @property(readonly, copy, nonatomic) NSString *displayName; 43 | - (UIImage*)getIconImage:(int)arg1; 44 | - (_Bool)isFolderIcon; 45 | - (_Bool)isNewsstandIcon; 46 | - (void)launch; 47 | - (void)launchFromLocation:(NSInteger)location; 48 | - (void)launchFromLocation:(NSInteger)location context:(id)context; 49 | - (SBApplication*)application; 50 | - (id)folder; 51 | - (void)openAppFromFolder:(NSString*)folder; 52 | - (id)getIconView; 53 | - (void)setBadge:(id)arg1; 54 | @end 55 | 56 | @interface SBLeafIcon : SBIcon 57 | - (id)leafIdentifier; 58 | @end 59 | 60 | @interface SBApplicationIcon : SBLeafIcon 61 | - (SBApplication*)application; 62 | @end 63 | 64 | 65 | @interface SBFolder : NSObject 66 | @property(readonly, nonatomic) long listCount; 67 | @property(readonly, nonatomic) long maxIconCountInLists; 68 | @property(copy, nonatomic) NSString *displayName; 69 | @property(readonly, copy, nonatomic) NSArray *lists; 70 | @property (assign,nonatomic) SBIcon * icon; 71 | @property (assign,getter=isOpen,nonatomic) BOOL open; 72 | @property (retain, nonatomic) NSString * oldFolderID; 73 | - (SBApplicationIcon *)iconAtIndexPath:(NSIndexPath *)indexPath; 74 | - (id)folderIcons; 75 | - (id)defaultDisplayName; 76 | - (id)allIcons; 77 | - (id)orderedIcons; 78 | - (void)setDefaultDisplayName:(SBFolder*)folder; 79 | - (NSIndexPath*)indexPathForIcon:(id)arg1; 80 | - (void)didRemoveFolder:(id)arg1; 81 | 82 | 83 | - (NSString*)createFolderIDWithDisplayName:displayName andFirstIconIdentifier:(NSString*)firstIconIdentifier; 84 | - (NSString*)folderID; 85 | - (void)replaceOldFolderID:(NSString*)oldFolderID byNewFolderID:(NSString*)newFolderID; 86 | 87 | 88 | - (NSIndexPath*)getFolderIndexPathForIndex:(int)index; 89 | - (void)openLastApp; 90 | - (void)openAppAtIndex:(int)index; 91 | - (void)openFirstApp; 92 | - (void)openSecondApp; 93 | - (void)quickActionOnFirstApp; 94 | - (int)getFirstAppIconIndex; 95 | - (SBIcon*)getFirstIcon; 96 | - (void)createOldFolderID; 97 | 98 | @end 99 | 100 | @interface SBIconListModel : NSObject 101 | @property(readonly, nonatomic) __weak SBFolder *folder; 102 | - (void)removeListObserver:(id)arg1; 103 | - (void)removeNodeObserver:(id)arg1; 104 | @end 105 | 106 | @interface SBFolderView : UIView 107 | @property(retain, nonatomic) SBFolder *folder; 108 | @property(readonly, nonatomic, getter=isEditing) _Bool editing; 109 | @property (nonatomic,copy,readonly) NSArray * iconListViews; 110 | @property (nonatomic,readonly) long currentPageIndex; 111 | - (void)_setFolderName:(id)arg1; 112 | - (void)setEditing:(_Bool)arg1 animated:(_Bool)arg2; 113 | - (void)cleanupAfterClosing; 114 | - (void)updateIcon; 115 | @end 116 | 117 | @interface SBBookmarkIcon : SBLeafIcon //Eigenlijk SBLeafIcon 118 | @property(readonly, nonatomic) NSURL *launchURL; 119 | @end 120 | 121 | @interface SBIconIndexMutableList : NSObject 122 | @property(readonly, nonatomic) long count; 123 | @end 124 | 125 | @interface SBUIForceTouchGestureRecognizer : UIGestureRecognizer 126 | @end 127 | 128 | @interface SBIconImageView : UIView 129 | @property(readonly) Class superclass; 130 | @end 131 | 132 | 133 | @interface SBIconView : UIView 134 | @property (nonatomic, assign) UISwipeGestureRecognizer* swipeUp; 135 | @property (nonatomic, assign) UISwipeGestureRecognizer* swipeDown; 136 | @property (nonatomic, assign) UILongPressGestureRecognizer* longHold; 137 | 138 | @property(retain, nonatomic) SBIcon *icon; 139 | @property(assign, getter = isHighlighted) BOOL highlighted; 140 | @property(retain, nonatomic) UIPreviewForceInteractionProgress *shortcutMenuPresentProgress; 141 | @property(retain, nonatomic) UILongPressGestureRecognizer *shortcutMenuPeekGesture; 142 | @property (nonatomic,retain) SBUIForceTouchGestureRecognizer * appIconForceTouchGestureRecognizer; 143 | @property (assign,nonatomic) id delegate; 144 | 145 | + (id)sharedInstance; 146 | - (void)_handleSecondHalfLongPressTimer:(id)arg1; 147 | - (void)cancelLongPressTimer; 148 | + (struct CGSize)defaultIconImageSize; 149 | - (UIImageView *)_currentImageView; 150 | - (void)setWallpaperRelativeCenter:(struct CGPoint)arg1; 151 | - (void)setIsEditing:(_Bool)arg1; 152 | - (UIView*)labelView; 153 | - (void)setLabelHidden:(BOOL)arg1 ; 154 | -(void)_setPreparingForPotentialShortcutMenuPresentation:(BOOL)arg1 ; 155 | -(SBIconImageView*)_iconImageView; 156 | //New: 157 | - (NSDictionary*)getFolderSetting:(NSString*)setting withDefaultSetting:(NSInteger)globalSetting withDefaultCustomAppIndex:(NSInteger)globalAppIndex; 158 | - (void)sf_method:(NSDictionary*)methodInfo withForceTouch:(BOOL)forceTouch; 159 | - (void)sf_swipeUp:(UISwipeGestureRecognizer *)gesture; 160 | - (void)sf_swipeDown:(UISwipeGestureRecognizer *)gesture; 161 | - (void)sf_shortHold:(UILongPressGestureRecognizer *)gesture; 162 | 163 | - (BOOL)isFolderIconView; 164 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)swipeUp shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)ges; 165 | - (BOOL)gestureRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch; 166 | @end 167 | 168 | 169 | @interface SBSApplicationShortcutIcon : NSObject 170 | - (id)imagePNGData; 171 | - (id)templateImageName; 172 | @end 173 | @interface SBSApplicationShortcutCustomImageIcon : SBSApplicationShortcutIcon 174 | - (id)imageData; 175 | - (id)imagePNGData; 176 | - (id)initWithImageData:(id)arg1 dataType:(int)arg2; 177 | - (id)initWithImageData:(id)arg1 dataType:(int)arg2 isTemplate:(BOOL)arg3; 178 | - (id)initWithImagePNGData:(id)arg1; 179 | @end 180 | 181 | @class SBSApplicationShortcutIcon; 182 | @interface SBSApplicationShortcutItem : NSObject 183 | @property (nonatomic, copy) NSString *type; 184 | @property (nonatomic,copy) NSString * bundleIdentifierToLaunch; 185 | @property (nonatomic,copy) SBSApplicationShortcutIcon * icon; 186 | @property (nonatomic, copy) NSDictionary *userInfo; 187 | @property (nonatomic, retain) NSData *userInfoData; 188 | @property (nonatomic, copy) NSString *localizedTitle; 189 | 190 | - (id)icon; 191 | - (void)setIcon:(SBSApplicationShortcutIcon *)arg1; 192 | - (void)setLocalizedSubtitle:(NSString*)arg1; 193 | - (void)setLocalizedTitle:(NSString*)arg1; 194 | - (void)setType:(NSString *)arg1; 195 | -(void)setBundleIdentifierToLaunch:(NSString *)arg1 ; 196 | @end 197 | 198 | 199 | @interface SBUIIconForceTouchIconViewWrapperView : NSObject 200 | @property (nonatomic,readonly) SBIconView * iconView; 201 | @end 202 | 203 | @interface SBUIIconForceTouchViewController : UIViewController { 204 | SBUIIconForceTouchIconViewWrapperView* _iconViewWrapperViewBelow; 205 | SBUIIconForceTouchIconViewWrapperView* _iconViewWrapperViewAbove; 206 | } 207 | -(void)_presentAnimated:(BOOL)arg1 withCompletionHandler:(/*^block*/id)arg2 ; 208 | -(void)_dismissAnimated:(BOOL)arg1 withCompletionHandler:(/*^block*/id)arg2 ; 209 | @end 210 | 211 | 212 | @interface SBUIIconForceTouchController : NSObject 213 | @property (nonatomic,readonly) SBUIIconForceTouchViewController * iconForceTouchViewController; 214 | - (void)_dismissAnimated:(BOOL)arg1 withCompletionHandler:(/*^block*/id)arg2 ; 215 | - (void)dismissAnimated:(BOOL)arg1 withCompletionHandler:(/*^block*/id)arg2 ; 216 | - (void)_setupWithGestureRecognizer:(SBUIForceTouchGestureRecognizer *)recognizer; 217 | - (void)_presentAnimated:(BOOL)animated withCompletionHandler:(id)handler; 218 | @end 219 | 220 | @interface SBUIAppIconForceTouchShortcutViewController : SBUIIconForceTouchController 221 | @end 222 | 223 | @interface SBUIAppIconForceTouchControllerDataProvider : NSObject 224 | @property (nonatomic, readonly) SBUIForceTouchGestureRecognizer *gestureRecognizer; 225 | - (NSArray *)applicationShortcutItems; 226 | @end 227 | 228 | @interface SBUIAppIconForceTouchController : NSObject { 229 | SBUIIconForceTouchController *_iconForceTouchController; 230 | } 231 | - (void) dismissAnimated:(BOOL)arg1 withCompletionHandler:(id)arg2 ; 232 | - (void) _dismissAnimated:(BOOL)arg1 withCompletionHandler:(id)arg2 ; 233 | - (void)appIconForceTouchShortcutViewController:(SBUIAppIconForceTouchShortcutViewController *)controller activateApplicationShortcutItem:(SBSApplicationShortcutItem *)item; 234 | - (SBSApplicationShortcutItem *)_shareApplicationShortcutItemForDataProvider:(SBUIAppIconForceTouchControllerDataProvider *)provider; 235 | 236 | @end 237 | 238 | @interface WGWidgetViewController : NSObject 239 | @end 240 | 241 | 242 | 243 | @interface SBApplicationShortcutMenuItemView : UIView 244 | @property(readonly, nonatomic) long long menuPosition; 245 | @property(retain, nonatomic) SBSApplicationShortcutItem *shortcutItem; 246 | @property(nonatomic) _Bool highlighted; 247 | 248 | 249 | + (id)_imageForShortcutItem:(id)arg1 application:(id)arg2 assetManagerProvider:(id)arg3 monogrammerProvider:(id)arg4 maxHeight:(double *)arg5; 250 | @end 251 | @class SBApplicationShortcutMenuContentView; 252 | @protocol SBApplicationShortcutMenuContentViewDelegate 253 | - (void)menuContentView:(SBApplicationShortcutMenuContentView *)arg1 activateShortcutItem:(SBSApplicationShortcutItem *)arg2 index:(long long)arg3; 254 | - (_Bool)menuContentView:(SBApplicationShortcutMenuContentView *)arg1 canActivateShortcutItem:(SBSApplicationShortcutItem *)arg2; 255 | @end 256 | @interface SBApplicationShortcutMenuContentView : UIView 257 | @property(assign,nonatomic) id delegate; 258 | - (id)initWithInitialFrame:(struct CGRect)arg1 containerBounds:(struct CGRect)arg2 orientation:(long long)arg3 shortcutItems:(id)arg4 application:(id)arg5; 259 | - (void)_handlePress:(id)arg1; 260 | - (double)_rowHeight; 261 | - (void)_populateRowsWithShortcutItems:(id)arg1 application:(id)arg2; 262 | @end 263 | @class SBApplicationShortcutMenu; 264 | @protocol SBApplicationShortcutMenuDelegate 265 | - (void)applicationShortcutMenu:(SBApplicationShortcutMenu *)arg1 launchApplicationWithIconView:(SBIconView *)arg2; 266 | - (void)applicationShortcutMenu:(SBApplicationShortcutMenu *)arg1 startEditingForIconView:(SBIconView *)arg2; 267 | - (void)applicationShortcutMenu:(SBApplicationShortcutMenu *)arg1 activateShortcutItem:(SBSApplicationShortcutItem *)arg2 index:(long long)arg3; 268 | 269 | @optional 270 | - (void)applicationShortcutMenuDidPresent:(SBApplicationShortcutMenu *)arg1; 271 | - (void)applicationShortcutMenuDidDismiss:(SBApplicationShortcutMenu *)arg1; 272 | @end 273 | 274 | @interface SBApplicationShortcutMenu : UIView { 275 | SBApplicationShortcutMenuContentView* _contentView; 276 | } 277 | + (void)cancelPrepareForPotentialPresentationWithReason:(id)arg1; 278 | @property(retain, nonatomic) SBApplicationShortcutMenuContentView *contentView; 279 | @property(retain, nonatomic) SBApplication *application; 280 | @property(retain ,nonatomic) id applicationShortcutMenuDelegate; 281 | @property(readonly, nonatomic) _Bool isPresented; 282 | @property(retain, nonatomic) SBIconView *iconView; 283 | 284 | - (id)initWithFrame:(CGRect)arg1 application:(id)arg2 iconView:(id)arg3 interactionProgress:(id)arg4 orientation:(long long)arg5; 285 | - (void)presentAnimated:(_Bool)arg1; 286 | - (void)menuContentView:(id)arg1 activateShortcutItem:(id)arg2 index:(long long)arg3; 287 | - (void)updateFromPressGestureRecognizer:(id)arg1; 288 | - (void)dismissAnimated:(_Bool)arg1 completionHandler:(id)arg2; 289 | - (void)_dismissAnimated:(_Bool)arg1 finishPeeking:(_Bool)arg2 ignorePresentState:(_Bool)arg3 completionHandler:(id)arg4; 290 | - (void)applicationShortcutMenuDidDismiss:(id)arg1; 291 | - (void) onBioProtectSuccessWithMenuContentView:(id)arg1 activateShortcutItem:(id)arg2 index:(long long)arg3; 292 | - (void)interactionProgressDidUpdate:(UIPreviewForceInteractionProgress *)arg1; 293 | - (void)interactionProgress:(id)arg1 didEnd:(_Bool)arg2; 294 | - (_Bool)iconViewDisplaysBadges:(id)arg1; 295 | 296 | @end 297 | 298 | 299 | @interface SBIconListView : UIView 300 | -(void)setIconsNeedLayout; 301 | -(void)layoutIconsIfNeeded:(double)needed domino:(BOOL)domino; 302 | -(CGPoint)centerForIcon:(id)icon; 303 | -(CGPoint)originForIcon:(id)icon; 304 | -(CGPoint)originForIconAtIndex:(unsigned)index; 305 | -(CGSize)defaultIconSize; 306 | 307 | @end 308 | 309 | @interface SBRootIconListView : SBIconListView 310 | - (SBFolder*)folder; 311 | - (NSArray *)icons; 312 | - (unsigned long)indexOfIcon:(id)icon; 313 | @end 314 | 315 | @interface SBIconModel : NSObject 316 | - (SBIcon*)applicationIconForBundleIdentifier:(id)arg1; 317 | - (SBIcon*)applicationIconForDisplayIdentifier:(id)arg1; 318 | - (id)leafIconForIdentifier:(id)arg1; 319 | 320 | @end 321 | 322 | @interface SBIconViewMap 323 | - (SBIconView*)iconViewForIcon:(SBIcon*)icon; 324 | - (SBIconView*)mappedIconViewForIcon:(SBIcon*)icon; 325 | +(SBIconViewMap *)homescreenMap; 326 | @property(readonly, nonatomic) SBIconModel *iconModel; 327 | - (void)recycleAndPurgeAll; 328 | 329 | @end 330 | 331 | @interface SBRootFolder : SBFolder 332 | @end 333 | 334 | @interface SBRootFolderView : SBFolderView 335 | @property (nonatomic,retain) SBRootFolder * folder; 336 | @end 337 | 338 | 339 | @interface SBIconController : UIViewController 340 | @property(retain, nonatomic) SBApplicationShortcutMenu *presentedShortcutMenu; 341 | @property(readonly, nonatomic) SBIconViewMap *homescreenIconViewMap; 342 | @property (nonatomic,retain) SBIcon * lastTouchedIcon; 343 | @property (nonatomic,retain) id LETITCRASH; 344 | + (id)sharedInstance; 345 | - (void)_revealMenuForIconView:(id)arg1 presentImmediately:(BOOL)arg2; 346 | - (BOOL)_canRevealShortcutMenu; 347 | - (BOOL)isEditing; 348 | - (void)iconHandleLongPress:(id)arg1; 349 | - (void)iconTouchBegan:(id)arg1; 350 | - (void)setIsEditing:(BOOL)arg1; 351 | - (void)_handleShortcutMenuPeek:(UILongPressGestureRecognizer *)recognizer ; 352 | - (void)iconTapped:(SBIconView *)iconView; 353 | - (_Bool)hasOpenFolder; 354 | - (SBFolder*)openFolder; 355 | - (void)scrollToIconListContainingIcon:(SBIcon *)icon animate:(_Bool)arg2; 356 | -(void)openFolder:(id)folder animated:(BOOL)animated; 357 | - (void)closeFolderAnimated:(_Bool)arg1; 358 | - (void)closeFolderAnimated:(_Bool)arg1 withCompletion:(id)arg2; 359 | - (void)_closeFolderController:(id)arg1 animated:(_Bool)arg2 withCompletion:(id)arg3; 360 | -(void)alertView:(id)arg1 clickedButtonAtIndex:(int)arg2; 361 | -(int)currentFolderIconListIndex; 362 | -(int)currentIconListIndex; 363 | - (void)noteIconStateChangedExternally; 364 | - (void)unscatterAnimated:(_Bool)arg1 afterDelay:(double)arg2 withCompletion:(id)arg3; 365 | - (void)_awayControllerUnlocked:(id)unlocked; 366 | - (void)_lockScreenUIWillLock:(id)arg1; 367 | - (void)applicationShortcutMenuDidDismiss:(id)arg1; 368 | - (void)_dismissShortcutMenuAnimated:(_Bool)arg1 completionHandler:(id)arg2; 369 | - (void)dismissShortcutMenuWithCompletionHandler:(id)arg1; 370 | - (void)applicationShortcutMenuDidDismiss:(id)arg1; 371 | - (SBRootFolder *)rootFolder; 372 | - (void)_cleanupForDismissingShortcutMenu:(id)arg1; 373 | - (void)_dismissShortcutMenuAnimated:(_Bool)arg1 completionHandler:(id)arg2; 374 | - (void)dismissShortcutMenuWithCompletionHandler:(id)arg1; 375 | - (void)openFolderIcon:(id)arg1 animated:(_Bool)arg2 withCompletion:(id)arg3; 376 | - (SBRootIconListView*)currentFolderIconList; 377 | - (SBRootIconListView*)dockListView; 378 | - (SBRootIconListView*)currentRootIconList; 379 | - (void)_dismissAppIconForceTouchControllerIfNecessaryAnimated:(_Bool)arg1 withCompletionHandler:(id)arg2; 380 | -(BOOL)appIconForceTouchController:(id)arg1 shouldActivateApplicationShortcutItem:(id)arg2 atIndex:(unsigned long long)arg3 forGestureRecognizer:(id)arg4 ; 381 | -(BOOL)_isAppIconForceTouchControllerPeekingOrShowing; 382 | 383 | 384 | - (BOOL)isFolderIconView:(SBIconView *)view; 385 | - (void)launchFirstApp:(SBIconView *)iconView; 386 | - (void)revealMenuForIconView:(SBIconView *)iconView; 387 | 388 | 389 | -(id)_currentFolderController; 390 | 391 | @end 392 | 393 | @interface SBFolderController : NSObject 394 | -(void)prepareToClose; 395 | @property (nonatomic,retain) SBFolder * folder; 396 | @property (nonatomic,readonly) SBFolderView * contentView; 397 | @end 398 | 399 | 400 | 401 | @interface SBFolderIcon : SBIcon 402 | - (SBFolder *)folder; 403 | - (void)iconImageDidUpdate:(SBIcon *)icon; 404 | - (id)miniGridCellImageForIcon:(SBIcon*)icon; 405 | - (void)_updateBadgeValue; 406 | 407 | @end 408 | 409 | 410 | @interface SBIconBlurryBackgroundView : UIView 411 | - (void)dealloc; 412 | - (id)initWithFrame:(struct CGRect)arg1; 413 | - (void)didAddSubview:(id)arg1; 414 | @end 415 | 416 | @interface SBFolderIconBackgroundView : UIView 417 | - (UIImageView *)customImageView; 418 | - (void)setCustomImageView:(UIImageView *)imageView; 419 | - (id)initWithDefaultSize; 420 | - (id)_contentsImageForColor:(struct CGColor *)arg1; 421 | @end 422 | 423 | 424 | @interface SBFolderIconImageView : SBIconImageView 425 | - (SBFolderIcon *)_folderIcon; 426 | - (void)_showLeftMinigrid; 427 | - (SBFolderIconBackgroundView*)backgroundView; 428 | 429 | - (id)initWithFrame:(struct CGRect)arg1; 430 | - (void)_setPageElements:(id)arg1; 431 | - (void)_setupGridViewsInDefaultConfiguration; 432 | 433 | -(void)hideInnerFolderImageView:(BOOL)hide; 434 | 435 | - (void)setCustomIconImage:(UIImage *)image; 436 | - (void)setCustomImageView:(UIImageView *)imageView; 437 | - (UIImageView *)customImageView; 438 | 439 | @end 440 | 441 | 442 | @interface SBFolderIconView : SBIconView 443 | - (SBFolder *)folder; 444 | - (SBFolderIcon*)folderIcon; 445 | - (SBFolderIconImageView*)_folderIconImageView; 446 | 447 | - (void)scrollToGapOrTopIfFullOfPage:(unsigned long)arg1 animated:(_Bool)arg2; 448 | - (void)scrollToTopOfPage:(unsigned long)arg1 animated:(_Bool)arg2; 449 | - (void)scrollToFirstGapAnimated:(_Bool)arg1; 450 | - (void)scrollToTopOfFirstPageAnimated:(_Bool)arg1; 451 | 452 | 453 | 454 | - (void)folder:(id)arg1 didAddList:(id)arg2; 455 | 456 | - (void)setCustomIconImage:(UIImage *)image; 457 | - (void)setCustomImageView:(UIImageView *)imageView; 458 | -(UIImage*)generateIconImage:(int)image ; 459 | - (UIImage*)getGenericIconImage:(int)arg1; 460 | - (void)setCustomFolderIcon; 461 | 462 | - (UIView *)initWithFrame:(struct CGRect)frame; 463 | - (UIImageView *)customImageView; 464 | @end 465 | 466 | @interface SBApplicationShortcutStoreManager : NSObject 467 | + (id)sharedManager; 468 | - (void)saveSynchronously; 469 | - (void)setShortcutItems:(id)arg1 forBundleIdentifier:(id)arg2; 470 | - (id)shortcutItemsForBundleIdentifier:(id)arg1; 471 | - (id)init; 472 | @end 473 | 474 | 475 | @interface UIApplication (Private) 476 | -(BOOL)launchApplicationWithIdentifier:(NSString*)identifier suspended:(BOOL)suspended; 477 | @end 478 | 479 | @interface SBIconGridImage 480 | + (struct CGRect)rectAtIndex:(NSUInteger)index maxCount:(NSUInteger)count; 481 | + (struct CGSize)cellSpacing; 482 | + (struct CGSize)cellSize; 483 | @end 484 | 485 | @interface UIScrollViewPanGestureRecognizer : UIPanGestureRecognizer 486 | @end 487 | 488 | @interface SBSearchGesture : UIScrollViewPanGestureRecognizer 489 | @end 490 | 491 | @interface SBAppStatusBarManager : NSObject 492 | + (id)sharedInstance; 493 | - (void)showStatusBar; 494 | - (void)hideStatusBar; 495 | @end 496 | 497 | @interface SBUIController : NSObject 498 | - (void)restoreContentAndUnscatterIconsAnimated:(BOOL)animated withCompletion:(id)completion; 499 | @end 500 | 501 | @interface SBDeviceLockController : NSObject 502 | - (BOOL)attemptDeviceUnlockWithPassword:(NSString *)passcode appRequested:(BOOL)requested; 503 | @end 504 | 505 | @interface SBLockScreenManager : NSObject 506 | - (void)_bioAuthenticated:(id)arg1; 507 | - (void)_finishUIUnlockFromSource:(int)source withOptions:(id)options; 508 | - (_Bool)biometricEventMonitorShouldRelockAfterBioUnlock:(id)arg1; 509 | @end 510 | 511 | @interface SpringBoard : UIApplication 512 | - (SBApplication *)_accessibilityFrontMostApplication; 513 | - (BOOL)addIcon:(SBIcon *)icon asDirty:(BOOL)dirty; 514 | @end 515 | 516 | 517 | @interface SBFolderIconZoomAnimator : NSObject 518 | @property (nonatomic,retain,readonly) SBFolderIconView * targetIconView; 519 | @property (nonatomic,retain,readonly) SBFolderIcon * targetIcon; 520 | 521 | @end 522 | 523 | @interface SBWallpaperController : NSObject 524 | + (id)sharedInstance; 525 | - (int)variant; 526 | - (UIColor *)averageColorForVariant:(int)variant; 527 | @end 528 | 529 | 530 | @interface SBIconBadgeView : UIView 531 | + (id)checkoutAccessoryImagesForIcon:(id)arg1 location:(int)arg2; 532 | - (void)configureForIcon:(id)arg1 location:(int)arg2 highlighted:(_Bool)arg3; 533 | - (void)configureAnimatedForIcon:(id)arg1 location:(int)arg2 highlighted:(_Bool)arg3 withPreparation:(id)arg4 animation:(id)arg5 completion:(id)arg6; 534 | @end 535 | 536 | @interface UIGestureRecognizerTarget : NSObject { 537 | id _target; 538 | } 539 | @end 540 | 541 | @interface SBUIBiometricEventMonitor : NSObject 542 | 543 | @end 544 | 545 | @interface BioProtectController : NSObject 546 | - (void)biometricEventMonitor:(SBUIBiometricEventMonitor*)arg1 handleBiometricEvent:(int)arg2; 547 | - (void)showAlert; 548 | - (void)launchApplicationWithIdentifier:(id)arg1; 549 | - (BOOL)requiresAuthenticationForOpeningFolder:(SBFolder *)folder; 550 | - (void)authenticateForOpeningFolder:(SBFolder *)folder; 551 | - (BOOL)requiresAuthenticationForIdentifier:(id)identifier; 552 | - (void)authenticateForIdentifier:(id)arg1 object:(id)arg2 selector:(SEL)arg3 arrayOfArgumentsAsNSValuePointers:(id)arg4; 553 | @end 554 | 555 | 556 | 557 | @interface CPDistributedMessagingCenter : NSObject 558 | +(CPDistributedMessagingCenter*)centerNamed:(NSString*)serverName; 559 | -(void)registerForMessageName:(NSString*)messageName target:(id)target selector:(SEL)selector; 560 | -(NSDictionary*)sendMessageAndReceiveReplyName:(NSString*)name userInfo:(NSDictionary*)info; 561 | -(void)runServerOnCurrentThread; 562 | @end 563 | -------------------------------------------------------------------------------- /SwipyFolders.xm: -------------------------------------------------------------------------------- 1 | #import 2 | #import "SwipyFolders.h" 3 | 4 | 5 | /** 6 | * The preferences 7 | * 8 | */ 9 | 10 | static NSUserDefaults *preferences; 11 | static bool enabled; 12 | static bool showedFirstTimeMessage; 13 | static bool enableFolderPreview; 14 | static bool hideGreyFolderBackground; 15 | static bool closeFolderOnOpen; 16 | static bool longHoldInvokesEditMode; 17 | static NSInteger singleTapMethod; 18 | static NSInteger swipeUpMethod; 19 | static NSInteger swipeDownMethod; 20 | static NSInteger doubleTapMethod; 21 | static NSInteger shortHoldMethod; 22 | static NSInteger longHoldMethod; 23 | static CGFloat shortHoldTime; 24 | static CGFloat longHoldTime; 25 | static CGFloat doubleTapTime; 26 | static NSInteger forceTouchMethod; 27 | 28 | static NSInteger singleTapMethodCustomAppIndex; 29 | static NSInteger swipeUpMethodCustomAppIndex; 30 | static NSInteger swipeDownMethodCustomAppIndex; 31 | static NSInteger doubleTapMethodCustomAppIndex; 32 | static NSInteger shortHoldMethodCustomAppIndex; 33 | static NSInteger longHoldMethodCustomAppIndex; 34 | 35 | static NSInteger forceTouchMethodCustomAppIndex; 36 | 37 | static NSInteger nestedFolderBehaviour; 38 | 39 | static NSDictionary *customFolderSettings; 40 | 41 | static bool classicFoldersEnabled; 42 | 43 | static bool HAS_BIOPROTECT; 44 | 45 | static void loadPreferences() { 46 | preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 47 | 48 | classicFoldersEnabled = NO; 49 | if([NSFileManager.defaultManager fileExistsAtPath:@"/private/var/mobile/Library/Preferences/org.coolstar.classicfolders.plist"] && [NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/ClassicFolders.dylib"]) { 50 | NSUserDefaults *classicFolderPreferences = [[NSUserDefaults alloc] initWithSuiteName:@"org.coolstar.classicfolders"]; 51 | classicFoldersEnabled = ([classicFolderPreferences boolForKey:@"enabled"]) ? YES : NO; 52 | } 53 | 54 | if([NSFileManager.defaultManager fileExistsAtPath:@"/private/var/mobile/Library/Preferences/net.limneos.bioprotect.plist"] && [NSFileManager.defaultManager fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/BioProtect.dylib"]) { 55 | NSUserDefaults *bioProtectPreferences = [[NSUserDefaults alloc] initWithSuiteName:@"net.limneos.bioprotect"]; 56 | HAS_BIOPROTECT = ([bioProtectPreferences boolForKey:@"Enabled"]) ? YES : NO; 57 | } 58 | 59 | 60 | 61 | [preferences registerDefaults:@{ 62 | @"enabled": @YES, 63 | @"showedFirstTimeMessage": @NO, 64 | @"enableFolderPreview": @YES, 65 | @"hideGreyFolderBackground": @NO, 66 | @"closeFolderOnOpen": @YES, 67 | @"longHoldInvokesEditMode": @NO, 68 | @"singleTapMethod": [NSNumber numberWithInteger:2], 69 | @"swipeUpMethod": [NSNumber numberWithInteger:1], 70 | @"swipeDownMethod": [NSNumber numberWithInteger:0], 71 | @"doubleTapMethod": [NSNumber numberWithInteger:0], 72 | @"doubleTapTime": [NSNumber numberWithFloat:0.2], 73 | @"shortHoldMethod": [NSNumber numberWithInteger:0], 74 | @"shortHoldTime": [NSNumber numberWithFloat:0.2], 75 | @"longHoldMethod": [NSNumber numberWithInteger:0], 76 | @"longHoldTime": [NSNumber numberWithFloat:0.2], 77 | @"forceTouchMethod":[NSNumber numberWithInteger:4], 78 | 79 | @"singleTapMethodCustomAppIndex": [NSNumber numberWithInteger:3], 80 | @"swipeUpMethodCustomAppIndex": [NSNumber numberWithInteger:3], 81 | @"swipeDownMethodCustomAppIndex": [NSNumber numberWithInteger:3], 82 | @"doubleTapMethodCustomAppIndex": [NSNumber numberWithInteger:3], 83 | @"shortHoldMethodCustomAppIndex": [NSNumber numberWithInteger:3], 84 | @"longHoldMethodCustomAppIndex": [NSNumber numberWithInteger:3], 85 | @"forceTouchMethodCustomAppIndex": [NSNumber numberWithInteger:3], 86 | 87 | @"nestedFolderBehaviour": [NSNumber numberWithInteger:0], 88 | }]; 89 | 90 | enabled = [preferences boolForKey:@"enabled"]; 91 | showedFirstTimeMessage = [preferences boolForKey:@"showedFirstTimeMessage"]; 92 | enableFolderPreview = [preferences boolForKey:@"enableFolderPreview"]; 93 | hideGreyFolderBackground = [preferences boolForKey:@"hideGreyFolderBackground"]; 94 | closeFolderOnOpen = [preferences boolForKey:@"closeFolderOnOpen"]; 95 | longHoldInvokesEditMode = [preferences boolForKey:@"longHoldInvokesEditMode"]; 96 | singleTapMethod = [preferences integerForKey:@"singleTapMethod"]; 97 | swipeUpMethod = [preferences integerForKey:@"swipeUpMethod"]; 98 | swipeDownMethod = [preferences integerForKey:@"swipeDownMethod"]; 99 | doubleTapMethod = [preferences integerForKey:@"doubleTapMethod"]; 100 | doubleTapTime = [preferences floatForKey:@"doubleTapTime"]; 101 | shortHoldMethod = [preferences integerForKey:@"shortHoldMethod"]; 102 | shortHoldTime = [preferences floatForKey:@"shortHoldTime"]; 103 | longHoldMethod = [preferences integerForKey:@"longHoldMethod"]; 104 | longHoldTime = [preferences floatForKey:@"longHoldTime"]; 105 | forceTouchMethod = [preferences integerForKey:@"forceTouchMethod"]; 106 | 107 | singleTapMethodCustomAppIndex = [preferences integerForKey:@"singleTapMethodCustomAppIndex"]; 108 | swipeUpMethodCustomAppIndex = [preferences integerForKey:@"swipeUpMethodCustomAppIndex"]; 109 | swipeDownMethodCustomAppIndex = [preferences integerForKey:@"swipeDownMethodCustomAppIndex"]; 110 | doubleTapMethodCustomAppIndex = [preferences integerForKey:@"doubleTapMethodCustomAppIndex"]; 111 | shortHoldMethodCustomAppIndex = [preferences integerForKey:@"shortHoldMethodCustomAppIndex"]; 112 | longHoldMethodCustomAppIndex = [preferences integerForKey:@"longHoldMethodCustomAppIndex"]; 113 | forceTouchMethodCustomAppIndex = [preferences integerForKey:@"forceTouchMethodCustomAppIndex"]; 114 | 115 | nestedFolderBehaviour = [preferences integerForKey:@"nestedFolderBehaviour"]; 116 | 117 | customFolderSettings = [preferences dictionaryForKey:@"customFolderSettings"]; 118 | 119 | [preferences release]; 120 | } 121 | 122 | 123 | static UIColor *colorShiftedBy(UIColor *color, CGFloat shift) { 124 | CGFloat red, green, blue, alpha; 125 | [color getRed:&red green:&green blue:&blue alpha:&alpha]; 126 | return [UIColor colorWithRed:red + shift green:green + shift blue:blue + shift alpha:alpha]; 127 | } 128 | 129 | static void saveFolderSettings(NSDictionary *folderSettings) { 130 | NSUserDefaults *preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 131 | [preferences setObject:folderSettings forKey:@"customFolderSettings"]; 132 | [preferences synchronize]; 133 | customFolderSettings = [folderSettings copy]; 134 | } 135 | 136 | static void setFolderSetting(NSString *folderID, NSString *key, id setting) { 137 | NSMutableDictionary *mutableCustomFolderSettings = [customFolderSettings mutableCopy]; 138 | NSMutableDictionary *mutableFolderSettings = [customFolderSettings[folderID] mutableCopy]; 139 | if(!mutableFolderSettings) mutableFolderSettings = [NSMutableDictionary new]; 140 | if(!mutableCustomFolderSettings) mutableCustomFolderSettings = [NSMutableDictionary new]; 141 | 142 | [mutableFolderSettings setObject:setting forKey:key]; 143 | [mutableCustomFolderSettings setObject:mutableFolderSettings forKey:folderID]; 144 | 145 | saveFolderSettings(mutableCustomFolderSettings); 146 | } 147 | 148 | 149 | 150 | /** 151 | * Setting the folder preview (one icon in folder preview) 152 | * 153 | */ 154 | 155 | 156 | /*%hook SBIconImageView 157 | -(id)setFrame:(CGRect)frame{ 158 | frame = CGRectMake(frame.origin.x, frame.origin.y, 20, 20); 159 | return %orig(frame); 160 | } 161 | %end*/ 162 | 163 | %hook SBFolderIconImageView 164 | static UIImageView *customImageView; 165 | 166 | 167 | -(id)initWithFrame:(CGRect)arg1{ 168 | 169 | //UIView *view = %orig; 170 | self = %orig; 171 | 172 | if(enabled) { 173 | //CGSize size = [%c(SBIconView) defaultIconImageSize]; 174 | CGRect iconFrame = self.frame;//CGRectMake(0, 0, 60, 60); 175 | if(!hideGreyFolderBackground) { 176 | CGFloat iconSize = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 45 : 54; 177 | CGFloat offset = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 8.5 : 12; 178 | iconFrame = CGRectMake(offset, offset, iconSize, iconSize); //Full size is 60 179 | } else MSHookIvar(self, "_backgroundView").hidden = YES; 180 | 181 | 182 | self.customImageView = [[UIImageView alloc] initWithFrame:iconFrame]; 183 | self.customImageView.backgroundColor = [UIColor clearColor]; 184 | 185 | [self insertSubview:self.customImageView atIndex:0]; 186 | } 187 | 188 | return self; 189 | 190 | } 191 | 192 | 193 | %new(v@:@) - (void)setCustomImageView:(UIImageView *)imageView { 194 | objc_setAssociatedObject(self, &customImageView, imageView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 195 | } 196 | 197 | %new(@@:) - (UIImageView *)customImageView { 198 | return objc_getAssociatedObject(self, &customImageView); 199 | } 200 | 201 | -(void)dealloc { 202 | [self.customImageView release]; 203 | %orig; 204 | } 205 | 206 | - (void)_showLeftMinigrid{ 207 | %orig; 208 | SBFolder *folder = self._folderIcon.folder; 209 | NSString *folderID = folder.folderID; 210 | 211 | SBIconController *iconController = [%c(SBIconController) sharedInstance]; 212 | if(iconController.isEditing && ![folder.oldFolderID isEqualToString:@""]) { 213 | folderID = folder.oldFolderID; 214 | } 215 | 216 | NSDictionary *folderSettings = customFolderSettings[folderID]; 217 | 218 | 219 | if(enabled){ 220 | 221 | UIImageView *innerFolderImageView = MSHookIvar(self, "_leftWrapperView"); 222 | 223 | if((enableFolderPreview && !([folderSettings[@"customFolderAppearance"] intValue] == 1 && ([folderSettings[@"customFolderEnableFolderPreview"] intValue] == 0 || [folderSettings objectForKey:@"customFolderEnableFolderPreview"] == nil))) || ([folderSettings[@"customFolderAppearance"] intValue] == 1 && [folderSettings[@"customFolderEnableFolderPreview"] intValue] == 1)){ 224 | SBIcon *firstIcon = [folder getFirstIcon]; 225 | UIImage *firstImage = [firstIcon getIconImage:2]; 226 | 227 | self.customImageView.image = firstImage; 228 | [self hideInnerFolderImageView: YES]; 229 | 230 | CGSize size = [%c(SBIconView) defaultIconImageSize]; 231 | CGRect iconFrame = CGRectMake(0, 0, size.width, size.height); 232 | 233 | if((!hideGreyFolderBackground && !([folderSettings[@"customFolderAppearance"] intValue] == 1 && [folderSettings[@"customFolderHideGreyFolderBackground"] intValue] == 1)) || ([folderSettings[@"customFolderAppearance"] intValue] == 1 && [folderSettings[@"customFolderEnableFolderPreview"] intValue] == 1 && [folderSettings[@"customFolderHideGreyFolderBackground"] intValue] == 0)) { 234 | CGFloat iconSize = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 45 : 54; 235 | CGFloat offset = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 8.5 : 12; 236 | iconFrame = CGRectMake(offset, offset, iconSize, iconSize); 237 | } 238 | 239 | self.customImageView.frame = iconFrame; 240 | 241 | [self bringSubviewToFront:self.customImageView]; 242 | 243 | if([folderSettings[@"customFolderHideGreyFolderBackground"] intValue] == 1) { 244 | MSHookIvar(self, "_backgroundView").hidden = YES; 245 | } 246 | 247 | 248 | 249 | } else { 250 | self.customImageView.image = nil; 251 | [self hideInnerFolderImageView: NO]; 252 | [self sendSubviewToBack:self.customImageView]; //Misschien weg? 253 | [self bringSubviewToFront:innerFolderImageView]; 254 | 255 | } 256 | 257 | } 258 | 259 | } 260 | 261 | %new -(void)hideInnerFolderImageView:(BOOL)hide { 262 | UIImageView *innerFolderImageView = MSHookIvar(self, "_leftWrapperView"); 263 | innerFolderImageView.hidden = hide; 264 | } 265 | 266 | 267 | 268 | %end 269 | 270 | /** 271 | * Overwriting some folder opening animations 272 | * 273 | */ 274 | 275 | %hook SBFolderIconZoomAnimator 276 | 277 | -(void)_prepareAnimation{ 278 | 279 | %orig; 280 | 281 | SBFolderIconImageView *folderIconImageView = self.targetIconView._folderIconImageView; 282 | 283 | if(folderIconImageView.customImageView.image != nil && !self.targetIcon.folder.open) { //Yes the last argument returns NO already 284 | 285 | 286 | SBFolderView *innerFolderView = MSHookIvar(self, "_innerFolderView"); 287 | UIView *scrollView = MSHookIvar(innerFolderView, "_scrollView"); 288 | 289 | UIImageView *leftView = MSHookIvar(folderIconImageView, "_leftWrapperView"); 290 | leftView.hidden = YES; 291 | UIImageView *rightView = MSHookIvar(folderIconImageView, "_rightWrapperView"); 292 | rightView.hidden = YES; 293 | 294 | 295 | folderIconImageView.customImageView.hidden = NO; 296 | [folderIconImageView bringSubviewToFront:folderIconImageView.customImageView]; 297 | 298 | folderIconImageView.customImageView.alpha = 0; 299 | [UIView beginAnimations:nil context:NULL]; 300 | [UIView setAnimationDuration:0.5]; 301 | [folderIconImageView.customImageView setAlpha:1.0]; 302 | [scrollView setAlpha:0.0]; 303 | [UIView commitAnimations]; 304 | 305 | 306 | } else if(self.targetIcon.folder.open) { 307 | folderIconImageView.customImageView.hidden = YES; 308 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { 309 | folderIconImageView.customImageView.hidden = NO; 310 | }); 311 | } 312 | 313 | //If not calling %orig; the icons behind the screen are not removed, so cool iOS 10 gimmick? 314 | 315 | } 316 | %end 317 | 318 | 319 | 320 | %hook SBFolderIconView 321 | - (void)setIcon:(id)arg1 { 322 | %orig; 323 | if([[%c(SBIconController) sharedInstance] respondsToSelector:@selector(_handleShortcutMenuPeek:)]) { 324 | self.shortcutMenuPeekGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:[%c(SBIconController) sharedInstance] action:@selector(_handleShortcutMenuPeek:)]; 325 | self.shortcutMenuPresentProgress = [[UIPreviewForceInteractionProgress alloc] initWithGestureRecognizer:self.shortcutMenuPeekGesture]; 326 | [self cancelLongPressTimer]; 327 | } 328 | } 329 | 330 | %end 331 | 332 | 333 | 334 | 335 | static SBIcon *firstIcon; 336 | static SBIconView *tappedIcon; 337 | static NSDate *lastTouchedTime; 338 | static NSDate *lastTappedTime; 339 | static NSDate *forceTouchOpenedTime; 340 | static BOOL doubleTapRecognized; 341 | static BOOL forceTouchRecognized; 342 | static BOOL showFirstIconShortcuts; 343 | 344 | 345 | /* 346 | %hook SBUIAppIconForceTouchController 347 | - (id)_shortcutViewControllerForDataProvider:(id)arg1; //ios 10 348 | %end 349 | */ 350 | 351 | 352 | 353 | /** 354 | * FINALLLLYYYYYYYYYYYYYY The real iOS 10 methods to modify shortcuts 355 | */ 356 | 357 | %hook SBUIAppIconForceTouchControllerDataProvider 358 | 359 | - (id)applicationBundleIdentifier { 360 | //DEEESSSS 361 | 362 | SBIconController *iconController = [%c(SBIconController) sharedInstance]; 363 | 364 | if(iconController.lastTouchedIcon.isFolderIcon && enabled) { 365 | NSDictionary *methodDict = [iconController.lastTouchedIcon.getIconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 366 | NSInteger method = [methodDict[@"method"] intValue]; 367 | 368 | if(method == 4 || showFirstIconShortcuts) { 369 | SBFolderIcon *folderIcon = (SBFolderIcon*)iconController.lastTouchedIcon; 370 | SBFolder* folder = folderIcon.folder; 371 | SBIcon *firstIcon = [folder getFirstIcon]; 372 | return firstIcon.application.bundleIdentifier; 373 | } 374 | 375 | } 376 | return %orig; 377 | } 378 | - (id)applicationBundleURL { //Needed for the right icons 379 | 380 | SBIconController *iconController = [%c(SBIconController) sharedInstance]; 381 | if(iconController.lastTouchedIcon.isFolderIcon && enabled) { 382 | NSDictionary *methodDict = [iconController.lastTouchedIcon.getIconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 383 | NSInteger method = [methodDict[@"method"] intValue]; 384 | 385 | if(method == 4 || showFirstIconShortcuts) { 386 | SBFolderIcon *folderIcon = (SBFolderIcon*)iconController.lastTouchedIcon; 387 | SBFolder* folder = folderIcon.folder; 388 | SBIcon *firstIcon = [folder getFirstIcon]; 389 | NSString *pathString = [NSString stringWithFormat:@"file://%@",firstIcon.application.path]; 390 | 391 | return [NSURL URLWithString:pathString]; 392 | } 393 | } 394 | 395 | return %orig; 396 | } 397 | 398 | - (id)applicationShortcutItems { 399 | 400 | 401 | SBIconController *iconController = [%c(SBIconController) sharedInstance]; 402 | if(iconController.lastTouchedIcon.isFolderIcon && enabled) { 403 | NSDictionary *methodDict = [iconController.lastTouchedIcon.getIconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 404 | NSInteger method = [methodDict[@"method"] intValue]; 405 | 406 | if(method == 0) { 407 | return nil; 408 | } 409 | 410 | if(method == 4 || showFirstIconShortcuts) { 411 | SBFolderIcon *folderIcon = (SBFolderIcon*)iconController.lastTouchedIcon; 412 | SBFolder* folder = folderIcon.folder; 413 | SBIcon *firstIcon = [folder getFirstIcon]; 414 | //SBIconView *firstIconView = firstIcon.getIconView; 415 | //SBUIForceTouchGestureRecognizer *ftGestureRecognizer = firstIconView.appIconForceTouchGestureRecognizer; 416 | 417 | //NSArray *applicationShortcutItems = %orig; 418 | NSMutableArray *newItems = [NSMutableArray array]; //WithArray:applicationShortcutItems]; 419 | [newItems addObjectsFromArray:firstIcon.application.dynamicApplicationShortcutItems]; 420 | [newItems addObjectsFromArray:firstIcon.application.staticApplicationShortcutItems]; 421 | 422 | return newItems; 423 | } 424 | 425 | } 426 | 427 | return %orig; 428 | 429 | } 430 | %end 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | /** 439 | * Methods to iterate all folders, for folder specific options in the preference pane 440 | * 441 | */ 442 | 443 | CPDistributedMessagingCenter *messagingCenter; 444 | 445 | %hook SBIconController 446 | 447 | - (id)init { 448 | static dispatch_once_t once; 449 | dispatch_once(&once, ^{ 450 | messagingCenter = [%c(CPDistributedMessagingCenter) centerNamed:@"nl.jessevandervelden.swipyfolders.center"]; 451 | [messagingCenter runServerOnCurrentThread]; 452 | [messagingCenter registerForMessageName:@"foldersRepresentation" target:self selector:@selector(handleMessageNamed:withUserInfo:)]; 453 | }); 454 | return %orig; 455 | } 456 | 457 | %new - (NSDictionary*)handleMessageNamed:(NSString *)name withUserInfo:(NSDictionary *)userinfo { //Only going to use for sending over folders so no additional checks needed 458 | NSArray *folderArray = [[[self rootFolder] folderIcons] allObjects]; 459 | 460 | NSMutableDictionary *foldersRepresentation = [NSMutableDictionary dictionary]; 461 | 462 | for (int i=0; i<[folderArray count]; i++) { 463 | SBFolderIcon *folderIcon = [folderArray objectAtIndex:i]; 464 | SBFolder *folder = folderIcon.folder; 465 | 466 | //NSString *defaultDisplayName = MSHookIvar(folder, "defaultDisplayName"); 467 | NSArray *folderAppIcons = [folder.allIcons allObjects]; //orderedIcons iOS 9+ 468 | NSMutableArray *applicationBundleIDs = [[NSMutableArray alloc] init]; 469 | for(int k=0; k<[folderAppIcons count] && k<9; k++ ) { 470 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:k inSection:0]; 471 | SBIcon *appIcon = (SBApplicationIcon*)[folder iconAtIndexPath:indexPath]; 472 | if(appIcon.application.bundleIdentifier != nil){ 473 | [applicationBundleIDs addObject:appIcon.application.bundleIdentifier]; 474 | //SBApplicationIcon *appIcon = [folderAppIcons objectAtIndex:k]; 475 | }else { 476 | SBLeafIcon *leafIcon = (SBLeafIcon*)appIcon; 477 | if(leafIcon.leafIdentifier != nil) { 478 | [applicationBundleIDs addObject:leafIcon.leafIdentifier]; 479 | } else { 480 | [applicationBundleIDs addObject:@""]; 481 | } 482 | } 483 | 484 | } 485 | NSMutableDictionary *folderDictionary = [NSMutableDictionary dictionary]; 486 | [folderDictionary setObject:folder.displayName forKey:@"displayName"]; // String 487 | 488 | [folderDictionary setObject:applicationBundleIDs forKey:@"applicationBundleIDs"]; //NSArray with bundle id strings 489 | 490 | NSString *folderID = folder.folderID; 491 | 492 | [folderDictionary setObject:folderID forKey:@"folderID"]; 493 | 494 | [foldersRepresentation setObject:folderDictionary forKey:folderID]; //[NSString stringWithFormat:@"%d", i] 495 | 496 | } 497 | 498 | return foldersRepresentation; 499 | } 500 | 501 | 502 | 503 | /** 504 | * Some bugfixes on pre 9.3 devices: 505 | * 506 | */ 507 | 508 | //- (void)folderControllerShouldClose:(id)arg1; //9.3 not needed 509 | // Okay, this may look crazy, but without preventing closeFolderAnimated, a 3D touch will close the folder 510 | - (void)closeFolderAnimated:(_Bool)arg1 { 511 | if(enabled && forceTouchMethod == 1) { 512 | 513 | } else { 514 | %orig; 515 | } 516 | } 517 | 518 | 519 | //In order to still being able to close the folder with the home button: 520 | - (void)handleHomeButtonTap { 521 | %orig; 522 | 523 | if ([self hasOpenFolder] && enabled && forceTouchMethod == 1) { //9.0/9.1 524 | if([[%c(SBIconController) sharedInstance] respondsToSelector:@selector(closeFolderAnimated:withCompletion:)]) { 525 | [[%c(SBIconController) sharedInstance] closeFolderAnimated:YES withCompletion:nil]; 526 | } 527 | } 528 | } 529 | 530 | 531 | 532 | /** 533 | * Finally the real deal: 534 | * 535 | */ 536 | 537 | //A method for 3D Touch actions 538 | 539 | 540 | 541 | 542 | 543 | 544 | static BOOL interactionProgressDidComplete = NO; 545 | 546 | /* 547 | - (void)_handleAppIconForceTouchGestureRecognizer:(UILongPressGestureRecognizer *)recognizer; //iOS 10 548 | */ 549 | 550 | 551 | 552 | 553 | /* This works basically 554 | static id itemz2; 555 | -(id)appIconForceTouchController:(id)controller applicationShortcutItemsForGestureRecognizer:(UIGestureRecognizer *)recognizer { //iOS 10 556 | 557 | id selfie = %orig; 558 | if(!itemz2) itemz2 = [selfie retain]; 559 | 560 | return itemz2; 561 | 562 | SBIconView *iconView = (SBIconView*)recognizer.view; 563 | if(iconView.isFolderIconView) { 564 | NSDictionary *methodDict = [iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 565 | NSInteger method = [methodDict[@"method"] intValue]; 566 | 567 | if(method == 4) { 568 | SBFolderIcon *folderIcon = ((SBFolderIconView *)iconView).folderIcon; 569 | SBFolder* folder = folderIcon.folder; 570 | SBApplicationIcon *firstIcon = (SBApplicationIcon*)[folder getFirstIcon]; 571 | 572 | NSMutableArray *newItems = [NSMutableArray array]; 573 | [newItems addObjectsFromArray:firstIcon.application.dynamicApplicationShortcutItems]; 574 | [newItems addObjectsFromArray:firstIcon.application.staticApplicationShortcutItems]; 575 | for (SBSApplicationShortcutItem *item in newItems) { 576 | //[item setBundleIdentifierToLaunh: firstIcon.application.bundleIdentifier]; 577 | //UIApplicationShortcutIcon *fakeShortcutIcon = [[%c(UIApplicationShortcutIcon) alloc] initWithSBSApplicationShortcutIcon: [[%c(SBSApplicationShortcutSystemIcon) alloc] initWithType:UIApplicationShortcutIconTypeCompose]; 578 | //NSLog(@"swipyfolders: check deze %@", [SBSApplicationShortcutItem ]) 579 | 580 | 581 | //UIImage *appImage = [UIImage _applicationIconImageForBundleIdentifier:firstIcon.application.bundleIdentifier format:1 scale:[UIScreen mainScreen].scale]; 582 | //UIImage *iconImage = [UIImage imageWithData:item.icon.imagePNGData]; 583 | 584 | NSLog(@"swipyfodlers: %@", item.icon); 585 | if([item.icon isKindOfClass:%c(SBSApplicationShortcutTemplateIcon)]) { 586 | NSLog(@"swipyfodlers: %@", item.icon.templateImageName); 587 | } 588 | //SBSApplicationShortcutIcon *shortcutIcon = [[%c(SBSApplicationShortcutCustomImageIcon) alloc] initWithImagePNGData:UIImagePNGRepresentation(iconImage)]; 589 | //[item setIcon:shortcutIcon]; 590 | 591 | } 592 | return newItems; 593 | } 594 | 595 | 596 | } 597 | return %orig; 598 | 599 | 600 | }*/ 601 | 602 | 603 | //IOS 10, change the recognizer view to the firstIconView in the folder, just before launching the shortcut item. Otherwise it doesn't know what to do 604 | //[recognizer setView: firstIcon.getIconView]; can basically called anywhere AFTER showing all shortcutitems but BEFORE launching the actual shortcut. This needs to be set back too. 605 | - (BOOL)appIconForceTouchController:(SBUIAppIconForceTouchController *)forceTouchController shouldActivateApplicationShortcutItem:(SBSApplicationShortcutItem*)shortcutItem atIndex:(unsigned long long)index forGestureRecognizer:(SBUIForceTouchGestureRecognizer *)recognizer { 606 | 607 | SBIconView *iconView = (SBIconView*)recognizer.view; 608 | if(iconView.isFolderIconView && enabled) { 609 | NSDictionary *methodDict = [iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 610 | NSInteger method = [methodDict[@"method"] intValue]; 611 | 612 | if(method == 4) { 613 | SBFolderIcon *folderIcon = ((SBFolderIconView *)iconView).folderIcon; 614 | SBFolder* folder = folderIcon.folder; 615 | SBApplicationIcon *firstIcon = (SBApplicationIcon*)[folder getFirstIcon]; 616 | 617 | [recognizer setView: firstIcon.getIconView]; 618 | 619 | //Needs to be set back too, otherwise it will fuck up the next time 620 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { 621 | [recognizer setView: iconView]; 622 | }); 623 | 624 | return %orig(forceTouchController, shortcutItem, index, recognizer); 625 | } 626 | } 627 | 628 | return %orig; 629 | } 630 | 631 | 632 | /** 633 | * Handle force touch methods on iOS 9 ONLY 634 | * 635 | */ 636 | 637 | - (void)_handleShortcutMenuPeek:(UILongPressGestureRecognizer *)recognizer { //iOS 9 638 | SBIconView *iconView = (SBIconView*)recognizer.view; 639 | 640 | firstIcon = nil; 641 | if(!iconView.isFolderIconView) { 642 | %orig; 643 | return; 644 | } 645 | 646 | SBFolderIcon *folderIcon = ((SBFolderIconView *)iconView).folderIcon; 647 | SBFolder* folder = folderIcon.folder; 648 | firstIcon = [folder getFirstIcon]; 649 | NSDictionary *methodDict = [iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 650 | NSInteger method = [methodDict[@"method"] intValue]; 651 | 652 | if (!self.isEditing && iconView.isFolderIconView && method != 0 && firstIcon && enabled) { 653 | 654 | switch (recognizer.state) { 655 | case UIGestureRecognizerStateBegan: { 656 | [iconView cancelLongPressTimer]; 657 | 658 | forceTouchRecognized = YES; 659 | interactionProgressDidComplete = false; 660 | 661 | self.presentedShortcutMenu = [[%c(SBApplicationShortcutMenu) alloc] initWithFrame:[UIScreen mainScreen].bounds application:firstIcon.application iconView:iconView interactionProgress:iconView.shortcutMenuPresentProgress orientation:1]; 662 | self.presentedShortcutMenu.applicationShortcutMenuDelegate = self; 663 | UIViewController *rootView = [[UIApplication sharedApplication].keyWindow rootViewController]; 664 | [rootView.view addSubview:self.presentedShortcutMenu]; 665 | 666 | SBIconView *forceTouchIconView = MSHookIvar(self.presentedShortcutMenu, "_proxyIconView"); 667 | SBFolderIconImageView *folderIconImageView = MSHookIvar(forceTouchIconView, "_iconImageView"); 668 | 669 | UIView* folderBackgroundView = MSHookIvar(folderIconImageView, "_backgroundView"); 670 | SBWallpaperController *wallpaperCont = [%c(SBWallpaperController) sharedInstance]; 671 | UIColor *dominantColor = [wallpaperCont averageColorForVariant:1]; 672 | folderBackgroundView.backgroundColor = colorShiftedBy(dominantColor, 0.15); 673 | 674 | folderBackgroundView.alpha = 0; 675 | UIImageView *folderImageView = MSHookIvar(folderIconImageView, "_leftWrapperView"); 676 | 677 | if (method == 4) { 678 | [folderIconImageView bringSubviewToFront:folderIconImageView.customImageView]; 679 | folderIconImageView.customImageView.alpha = 0; 680 | } 681 | 682 | [UIView transitionWithView:folderImageView 683 | duration:0.5f 684 | options:UIViewAnimationOptionTransitionCrossDissolve 685 | animations:^{ 686 | if (method == 4) { 687 | folderIconImageView.customImageView.image = [firstIcon getIconImage:2]; 688 | folderIconImageView.customImageView.alpha = 1; 689 | folderImageView.hidden = YES; 690 | } 691 | folderBackgroundView.alpha = 1; 692 | } completion:nil]; 693 | 694 | 695 | 696 | }break; 697 | 698 | case UIGestureRecognizerStateChanged: { 699 | [iconView cancelLongPressTimer]; 700 | if (method == 4) [self.presentedShortcutMenu updateFromPressGestureRecognizer:recognizer]; 701 | }break; 702 | 703 | case UIGestureRecognizerStateEnded: { 704 | 705 | if (method == 4 && self.presentedShortcutMenu.isPresented) { 706 | SBApplicationShortcutMenuContentView *contentView = MSHookIvar(self.presentedShortcutMenu,"_contentView"); 707 | NSMutableArray *itemViews = MSHookIvar(contentView,"_itemViews"); 708 | for(SBApplicationShortcutMenuItemView *item in itemViews) { 709 | if (item.highlighted == YES) { 710 | [self.presentedShortcutMenu menuContentView:contentView activateShortcutItem:item.shortcutItem index:item.menuPosition]; 711 | break; 712 | } 713 | } 714 | } else if(method != 4) { 715 | [self.presentedShortcutMenu dismissAnimated:true completionHandler:nil]; 716 | } 717 | 718 | }break; 719 | default: 720 | break; 721 | 722 | } 723 | 724 | iconView.highlighted = NO; 725 | } else { 726 | %orig; 727 | } 728 | } 729 | 730 | - (void)setIsEditing:(_Bool)editing { 731 | %orig; 732 | if(editing && [self respondsToSelector:@selector(_cleanupForDismissingShortcutMenu:)]) { 733 | [self _cleanupForDismissingShortcutMenu:self.presentedShortcutMenu]; 734 | } 735 | } 736 | 737 | 738 | /** 739 | * Methods for setting other gestures on the folder icon 740 | * 741 | */ 742 | 743 | - (void) iconHandleLongPress:(SBIconView *)iconView { 744 | lastTouchedTime = nil; 745 | %orig; 746 | } 747 | 748 | - (void) iconTouchBegan:(SBIconView *)iconView { 749 | lastTouchedTime = [[NSDate date] retain]; 750 | %orig; 751 | } 752 | 753 | - (void)iconTapped:(SBIconView *)iconView { 754 | if (!self.isEditing && iconView.isFolderIconView && enabled) { 755 | 756 | NSDate *nowTime = [[NSDate date] retain]; 757 | if (shortHoldMethod != 0 && lastTouchedTime && [nowTime timeIntervalSinceDate:lastTouchedTime] >= shortHoldTime) { 758 | 759 | [iconView sf_method:[iconView getFolderSetting:@"ShortHoldMethod" withDefaultSetting:shortHoldMethod withDefaultCustomAppIndex:shortHoldMethodCustomAppIndex] withForceTouch:NO]; 760 | lastTouchedTime = nil; 761 | iconView.highlighted = NO; 762 | return; 763 | } else if (doubleTapMethod != 0) { 764 | if (iconView == tappedIcon) { 765 | if (doubleTapMethod != 0 && [nowTime timeIntervalSinceDate:lastTappedTime] < doubleTapTime) { 766 | doubleTapRecognized = YES; 767 | 768 | [iconView sf_method:[iconView getFolderSetting:@"DoubleTapMethod" withDefaultSetting:doubleTapMethod withDefaultCustomAppIndex:doubleTapMethodCustomAppIndex] withForceTouch:NO]; 769 | lastTappedTime = nil; 770 | iconView.highlighted = NO; 771 | return; 772 | } 773 | } 774 | tappedIcon = iconView; 775 | lastTappedTime = nowTime; 776 | doubleTapRecognized = NO; 777 | iconView.highlighted = NO; 778 | 779 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(doubleTapTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { 780 | if (!doubleTapRecognized && iconView == tappedIcon) { 781 | [iconView sf_method:[iconView getFolderSetting:@"SingleTapMethod" withDefaultSetting:singleTapMethod withDefaultCustomAppIndex:singleTapMethodCustomAppIndex] withForceTouch:NO]; 782 | } 783 | }); 784 | } else { 785 | NSDictionary *method = [iconView getFolderSetting:@"SingleTapMethod" withDefaultSetting:singleTapMethod withDefaultCustomAppIndex:singleTapMethodCustomAppIndex]; 786 | [iconView sf_method:method withForceTouch:NO]; 787 | iconView.highlighted = NO; 788 | return; 789 | } 790 | } else { 791 | if(self.hasOpenFolder && !iconView.isFolderIconView && enabled) { 792 | [iconView.icon openAppFromFolder:self.openFolder.folderID]; 793 | if(closeFolderOnOpen) [self closeFolderAnimated:NO withCompletion:nil]; 794 | } 795 | 796 | %orig; 797 | } 798 | forceTouchRecognized = NO; 799 | } 800 | 801 | %end 802 | 803 | 804 | /** 805 | * Additional force touch methods for doing an action on force touch iOS 10 806 | * 807 | */ 808 | %hook SBUIIconForceTouchController 809 | -(void)_presentAnimated:(BOOL)arg1 withCompletionHandler:(id)arg2{ 810 | if(enabled && arg2) { //So basically when we call it ourselfs (in sf_methods we send arg2=nil) to let NOT run this. Fucking ugly, but hey it works :P 811 | SBUIIconForceTouchIconViewWrapperView *wrapperView = MSHookIvar(self.iconForceTouchViewController, "_iconViewWrapperViewAbove"); 812 | if([wrapperView respondsToSelector:@selector(iconView)]) { 813 | SBFolderIconView *iconView = (SBFolderIconView*)wrapperView.iconView; 814 | if([iconView isKindOfClass:%c(SBFolderIconView)]) { 815 | if([iconView isFolderIconView]) { 816 | NSDictionary *methodDict = [iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 817 | NSInteger method = [methodDict[@"method"] intValue]; 818 | if(method != 4 && method != 8){ 819 | BOOL animated = (method == 0); 820 | %orig(animated, nil); 821 | [self _dismissAnimated:NO withCompletionHandler:nil]; 822 | if(method != 0) [iconView sf_method:methodDict withForceTouch:YES]; //DEES ***** 823 | return; 824 | } 825 | } 826 | } 827 | } 828 | 829 | } 830 | %orig; 831 | 832 | } 833 | 834 | %end 835 | 836 | /* 837 | * Protecting folders for those with BioProtect 838 | * even fixing security breach introduced by BioProtect (to open apps by force touch) 839 | */ 840 | static BOOL isProtected = NO; 841 | %hook SBApplicationShortcutMenu //iOS 9 842 | - (void)menuContentView:(id)arg1 activateShortcutItem:(id)arg2 index:(long long)arg3 { 843 | if(HAS_BIOPROTECT){ 844 | if([self.iconView isFolderIconView]) { 845 | SBFolder* folder = ((SBFolderIconView *)self.iconView).folderIcon.folder; 846 | SBIcon *firstIcon = [folder getFirstIcon]; 847 | NSString *bundleIdentifier = firstIcon.application.bundleIdentifier; 848 | if ([[%c(BioProtectController) sharedInstance ] requiresAuthenticationForIdentifier: bundleIdentifier ] && !isProtected){ 849 | NSArray *arguments=[NSArray arrayWithObjects:[NSValue valueWithPointer:&arg1],[NSValue valueWithPointer:&arg2],[NSValue valueWithPointer:&arg3],NULL]; 850 | [[%c(BioProtectController) sharedInstance] authenticateForIdentifier:bundleIdentifier object:self selector:@selector(onBioProtectSuccessWithMenuContentView:activateShortcutItem:index:) arrayOfArgumentsAsNSValuePointers:arguments]; 851 | return; 852 | } 853 | } 854 | } 855 | isProtected = NO; 856 | %orig; 857 | } 858 | 859 | %new - (void) onBioProtectSuccessWithMenuContentView:(id)arg1 activateShortcutItem:(id)arg2 index:(long long)arg3 { 860 | isProtected = YES; 861 | [self menuContentView:arg1 activateShortcutItem:arg2 index:arg3]; 862 | 863 | } 864 | 865 | /** 866 | * Some methods to let 3D Touch work on folder icons, and some animations 867 | * 868 | */ 869 | 870 | - (void)interactionProgress:(id)arg1 didEnd:(_Bool)arg2 { 871 | 872 | if (enabled && arg2 && self.iconView.isFolderIconView) { 873 | NSDictionary *methodDict = [self.iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 874 | NSInteger method = [methodDict[@"method"] intValue]; 875 | if(method != 4 && method != 0){ 876 | [self dismissAnimated:false completionHandler:nil]; 877 | [self.iconView sf_method:methodDict withForceTouch:YES]; 878 | return; 879 | } 880 | } 881 | 882 | %orig; 883 | } 884 | 885 | 886 | - (void)dismissAnimated:(_Bool)arg1 completionHandler:(id)arg2{ 887 | if(enabled && arg1 && self.iconView.isFolderIconView) { 888 | SBIconView *forceTouchIconView = MSHookIvar(self, "_proxyIconView"); 889 | SBFolderIconImageView *folderIconImageView = MSHookIvar(forceTouchIconView, "_iconImageView"); 890 | UIImageView *folderImageView = MSHookIvar(folderIconImageView, "_leftWrapperView"); 891 | UIView* folderBackgroundView = MSHookIvar(folderIconImageView, "_backgroundView"); 892 | [UIView beginAnimations:nil context:NULL]; 893 | [UIView setAnimationDuration:0.3]; 894 | if (folderIconImageView.customImageView.image != nil) [folderIconImageView.customImageView setAlpha:0.0]; 895 | else [folderImageView setAlpha:0.0]; 896 | [folderBackgroundView setAlpha:0.0]; 897 | [UIView commitAnimations]; 898 | } 899 | %orig; 900 | } 901 | 902 | - (void)_finishPeekingWithCompletionHandler:(id)arg1 { 903 | if(enabled && self.iconView.isFolderIconView) { 904 | SBIconView *forceTouchIconView = MSHookIvar(self, "_proxyIconView"); 905 | SBFolderIconImageView *folderIconImageView = MSHookIvar(forceTouchIconView, "_iconImageView"); 906 | UIImageView *folderImageView = MSHookIvar(folderIconImageView, "_leftWrapperView"); 907 | UIView* folderBackgroundView = MSHookIvar(folderIconImageView, "_backgroundView"); 908 | [UIView beginAnimations:nil context:NULL]; 909 | [UIView setAnimationDuration:0.5]; 910 | if (folderIconImageView.customImageView.image != nil) [folderIconImageView.customImageView setAlpha:0.0]; 911 | else [folderImageView setAlpha:0.0]; 912 | [folderBackgroundView setAlpha:0.0]; 913 | [UIView commitAnimations]; 914 | } 915 | %orig; 916 | } 917 | 918 | 919 | - (id)_shortcutItemsToDisplay { 920 | //Sometimes the labelview of the forceTouchIconView isn't hidden, (even normal aplications) so in order to prevent that: 921 | SBIconView *forceTouchIconView = MSHookIvar(self, "_proxyIconView"); 922 | forceTouchIconView.labelView.hidden = YES; 923 | 924 | NSMutableArray *items = %orig; 925 | if (enabled) { 926 | NSDictionary *methodDict = [self.iconView getFolderSetting:@"ForceTouchMethod" withDefaultSetting:forceTouchMethod withDefaultCustomAppIndex:forceTouchMethodCustomAppIndex]; 927 | NSInteger method = [methodDict[@"method"] intValue]; 928 | 929 | //In order to set blurring on forceTouch folderIcons, where the first app doesn't support Force Touch, add a fake action 930 | if ([items count] == 0 && self.iconView.isFolderIconView && method != 4 && method != 0) { 931 | SBSApplicationShortcutItem *action = [[%c(SBSApplicationShortcutItem) alloc] init]; 932 | [action setLocalizedTitle:@"Fake Action"]; 933 | 934 | [items addObject:action]; 935 | } 936 | } 937 | return items; 938 | } 939 | 940 | %end 941 | 942 | 943 | 944 | %hook SBIconView 945 | /** 946 | * Get folder specific settings 947 | * 948 | */ 949 | 950 | %property (nonatomic, assign) id swipeUp; 951 | %property (nonatomic, assign) id swipeDown; 952 | %property (nonatomic, assign) id longHold; 953 | 954 | 955 | %new - (BOOL)isFolderIconView { 956 | return self.icon.isFolderIcon && !([self.icon respondsToSelector:@selector(isNewsstandIcon)] && self.icon.isNewsstandIcon); 957 | } 958 | 959 | %new - (NSDictionary*)getFolderSetting:(NSString*)setting withDefaultSetting:(NSInteger)globalSetting withDefaultCustomAppIndex:(NSInteger)globalAppIndex { 960 | SBFolder *folder = ((SBIconView *)self).icon.folder; 961 | NSDictionary *folderSettings = customFolderSettings[folder.folderID]; 962 | 963 | NSNumber *sendMethod = [NSNumber numberWithInt:globalSetting]; 964 | NSNumber *sendAppIndex = [NSNumber numberWithInt:globalAppIndex]; 965 | 966 | NSString *method = [NSString stringWithFormat:@"customFolder%@",setting]; 967 | 968 | if([folderSettings[@"customFolderFunctionallity"] intValue] == 1){ 969 | if([folderSettings objectForKey:method]) sendMethod = [NSNumber numberWithInt:[[folderSettings objectForKey:method] intValue]]; 970 | if([[folderSettings objectForKey:method] intValue] == 5){ 971 | NSString *appIndexSetting = [NSString stringWithFormat:@"customFolder%@CustomAppIndex",setting]; 972 | sendAppIndex = [NSNumber numberWithInt:[[folderSettings objectForKey:appIndexSetting] intValue]]; 973 | } 974 | } 975 | 976 | 977 | NSMutableDictionary *sendInfo = [NSMutableDictionary new]; 978 | [sendInfo setObject:sendMethod forKey:@"method"]; 979 | [sendInfo setObject:sendAppIndex forKey:@"customAppIndex"]; 980 | if(folderSettings[@"lastOpenedApp"]) [sendInfo setObject:folderSettings[@"lastOpenedApp"] forKey:@"lastOpenedApp"]; 981 | 982 | 983 | return sendInfo; 984 | } 985 | 986 | /** 987 | * Add the last gestures to the folder icon 988 | * 989 | */ 990 | 991 | - (void)setIcon:(SBIcon*)icon { 992 | 993 | %orig; 994 | 995 | //SBIconController* iconController = [%c(SBIconController) sharedInstance]; 996 | 997 | if (self.isFolderIconView) { 998 | 999 | if(!self.swipeUp) { 1000 | self.swipeUp = [[%c(UISwipeGestureRecognizer) alloc] initWithTarget:self action:@selector(sf_swipeUp:)]; 1001 | self.swipeUp.direction = UISwipeGestureRecognizerDirectionUp; 1002 | self.swipeUp.delegate = (id )self; 1003 | [self addGestureRecognizer:self.swipeUp]; 1004 | } 1005 | 1006 | if(!self.swipeDown) { 1007 | self.swipeDown = [[%c(UISwipeGestureRecognizer) alloc] initWithTarget:self action:@selector(sf_swipeDown:)]; 1008 | self.swipeDown.direction = UISwipeGestureRecognizerDirectionDown; 1009 | self.swipeDown.delegate = (id )self; 1010 | [self addGestureRecognizer:self.swipeDown]; 1011 | } 1012 | 1013 | NSDictionary *methodDict = [self getFolderSetting:@"LongHoldMethod" withDefaultSetting:longHoldMethod withDefaultCustomAppIndex:longHoldMethodCustomAppIndex]; 1014 | NSInteger longHoldMethod = [methodDict[@"method"] intValue]; 1015 | 1016 | if(!self.longHold && longHoldMethod != 0) { 1017 | self.longHold = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(sf_longHold:)]; 1018 | self.longHold.minimumPressDuration = longHoldTime; 1019 | [self addGestureRecognizer:self.longHold]; 1020 | 1021 | } 1022 | 1023 | } 1024 | } 1025 | 1026 | - (void)setIsEditing:(_Bool)editing animated:(_Bool)arg2 { 1027 | %orig; 1028 | 1029 | //Maybe a check that we're only disabeling our own gesture recognizers? 1030 | if(editing && self.isFolderIconView) { 1031 | for (UIGestureRecognizer *recognizer in self.gestureRecognizers) { 1032 | recognizer.enabled = NO; 1033 | } 1034 | 1035 | } else if (!editing && self.isFolderIconView) { 1036 | for (UIGestureRecognizer *recognizer in self.gestureRecognizers) { 1037 | recognizer.enabled = YES; 1038 | } 1039 | } 1040 | 1041 | } 1042 | 1043 | %new - (void)sf_longHold:(UILongPressGestureRecognizer *)gesture { 1044 | if (gesture.state == UIGestureRecognizerStateBegan) { 1045 | [self sf_method:[self getFolderSetting:@"LongHoldMethod" withDefaultSetting:longHoldMethod withDefaultCustomAppIndex:longHoldMethodCustomAppIndex] withForceTouch:NO]; 1046 | } 1047 | } 1048 | 1049 | %new - (void)sf_swipeUp:(UISwipeGestureRecognizer *)gesture { 1050 | SBIconController* iconController = [%c(SBIconController) sharedInstance]; 1051 | if([iconController respondsToSelector:@selector(_isAppIconForceTouchControllerPeekingOrShowing)]) { 1052 | SBUIAppIconForceTouchController *forceTouchController = MSHookIvar(iconController, "_appIconForceTouchController"); 1053 | if(![iconController _isAppIconForceTouchControllerPeekingOrShowing]) { 1054 | [forceTouchController dismissAnimated:NO withCompletionHandler:nil]; 1055 | [self sf_method:[self getFolderSetting:@"SwipeUpMethod" withDefaultSetting:swipeUpMethod withDefaultCustomAppIndex:swipeUpMethodCustomAppIndex] withForceTouch:NO]; 1056 | } 1057 | } else { 1058 | [self sf_method:[self getFolderSetting:@"SwipeUpMethod" withDefaultSetting:swipeUpMethod withDefaultCustomAppIndex:swipeUpMethodCustomAppIndex] withForceTouch:NO]; 1059 | } 1060 | } 1061 | 1062 | %new - (void)sf_swipeDown:(UISwipeGestureRecognizer *)gesture { 1063 | 1064 | SBIconController* iconController = [%c(SBIconController) sharedInstance]; 1065 | if([iconController respondsToSelector:@selector(_isAppIconForceTouchControllerPeekingOrShowing)]) { 1066 | SBUIAppIconForceTouchController *forceTouchController = MSHookIvar(iconController, "_appIconForceTouchController"); 1067 | if(![iconController _isAppIconForceTouchControllerPeekingOrShowing]) { 1068 | [forceTouchController dismissAnimated:NO withCompletionHandler:nil]; 1069 | [self sf_method:[self getFolderSetting:@"SwipeDownMethod" withDefaultSetting:swipeDownMethod withDefaultCustomAppIndex:swipeDownMethodCustomAppIndex] withForceTouch:NO]; 1070 | } 1071 | } else { 1072 | [self sf_method:[self getFolderSetting:@"SwipeDownMethod" withDefaultSetting:swipeDownMethod withDefaultCustomAppIndex:swipeDownMethodCustomAppIndex] withForceTouch:NO]; 1073 | } 1074 | } 1075 | 1076 | 1077 | /** 1078 | * The method to do specific actions on a gesture 1079 | * 1080 | */ 1081 | 1082 | %new - (void)sf_method:(NSDictionary*)methodDict withForceTouch:(BOOL)forceTouch{ 1083 | NSInteger method = [methodDict[@"method"] intValue]; 1084 | NSInteger customAppIndex = [methodDict[@"customAppIndex"] intValue]; 1085 | NSString *lastOpenedApp; 1086 | if([methodDict objectForKey:@"lastOpenedApp"] != nil) { 1087 | lastOpenedApp = methodDict[@"lastOpenedApp"]; 1088 | } else if(method == 7) { 1089 | method = 2; 1090 | } 1091 | 1092 | SBFolder * folder = ((SBIconView *)self).icon.folder; 1093 | 1094 | 1095 | SBIconController* iconController = [%c(SBIconController) sharedInstance]; 1096 | 1097 | if(enabled && !iconController.isEditing) { 1098 | 1099 | switch (method) { 1100 | case 1: { 1101 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1102 | 1103 | if(HAS_BIOPROTECT) { 1104 | if ([[%c(BioProtectController) sharedInstance ] requiresAuthenticationForOpeningFolder: folder ]){ 1105 | [[%c(BioProtectController) sharedInstance ] authenticateForOpeningFolder: folder ]; 1106 | return; 1107 | } 1108 | } 1109 | 1110 | 1111 | SBFolderIconView *folderIconView = (SBFolderIconView*)self; 1112 | UIImageView *innerFolderImageView = MSHookIvar([folderIconView _folderIconImageView], "_leftWrapperView"); 1113 | 1114 | 1115 | SBFolderIcon *folderIcon = ((SBFolderIconView *)self).folderIcon; 1116 | if(!classicFoldersEnabled) [folderIcon setBadge:[NSNumber numberWithInt:0]]; 1117 | 1118 | if([iconController respondsToSelector:@selector(openFolder:animated:)]) { 1119 | [iconController openFolder:folder animated:YES]; //Open Folder 1120 | } 1121 | 1122 | if([iconController respondsToSelector:@selector(openFolderIcon:animated:withCompletion:)]) { //iOS 10 1123 | [iconController openFolderIcon:self.icon animated:YES withCompletion:nil]; 1124 | } 1125 | 1126 | if(!classicFoldersEnabled) { 1127 | innerFolderImageView.hidden = YES; 1128 | folderIconView._folderIconImageView.customImageView.hidden = YES; 1129 | 1130 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { 1131 | if(folderIconView._folderIconImageView.customImageView.image == nil) innerFolderImageView.hidden = NO; 1132 | folderIconView._folderIconImageView.customImageView.hidden = NO; 1133 | [folderIcon _updateBadgeValue]; 1134 | }); 1135 | } 1136 | 1137 | if(forceTouch) self.highlighted = NO; 1138 | 1139 | }break; 1140 | 1141 | case 2: { 1142 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1143 | firstIcon = [folder getFirstIcon]; 1144 | [firstIcon openAppFromFolder:folder.folderID]; 1145 | 1146 | }break; 1147 | 1148 | case 3: { 1149 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1150 | [folder openAppAtIndex:1]; 1151 | }break; 1152 | 1153 | case 8: 1154 | case 4: { 1155 | //Currently this won't be used as it will be handled natively 1156 | if([iconController respondsToSelector:@selector(presentedShortcutMenu)]) { //iOS 9 1157 | [iconController.presentedShortcutMenu interactionProgress:self.shortcutMenuPresentProgress didEnd:YES]; 1158 | //[iconController.presentedShortcutMenu presentAnimated:YES]; 1159 | 1160 | [iconController.presentedShortcutMenu dismissAnimated:NO completionHandler:nil]; 1161 | SBApplicationShortcutMenu *shortcutMenu = MSHookIvar(iconController, "_presentedShortcutMenu"); 1162 | NSDate *nowTime = [[NSDate date] retain]; 1163 | 1164 | if(!shortcutMenu.isPresented && (forceTouchOpenedTime == nil || [nowTime timeIntervalSinceDate:forceTouchOpenedTime] > 1)) { 1165 | 1166 | firstIcon = [folder iconAtIndexPath:[NSIndexPath indexPathForRow:folder.getFirstAppIconIndex inSection:0]]; 1167 | iconController.presentedShortcutMenu = [[%c(SBApplicationShortcutMenu) alloc] initWithFrame:[UIScreen mainScreen].bounds application:firstIcon.application iconView:self interactionProgress:nil orientation:1]; 1168 | iconController.presentedShortcutMenu.applicationShortcutMenuDelegate = iconController; 1169 | UIViewController *rootView = [[UIApplication sharedApplication].keyWindow rootViewController]; 1170 | [rootView.view addSubview:iconController.presentedShortcutMenu]; 1171 | 1172 | [iconController.presentedShortcutMenu presentAnimated:YES]; 1173 | SBIconView *editedIconView = MSHookIvar(iconController.presentedShortcutMenu, "_proxyIconView"); 1174 | editedIconView.labelView.hidden = YES; 1175 | SBFolderIconImageView *folderIconImageView = MSHookIvar(editedIconView, "_iconImageView"); 1176 | UIImageView *folderImageView = MSHookIvar(folderIconImageView, "_leftWrapperView"); 1177 | folderImageView.image = [firstIcon getIconImage:2]; 1178 | //[iconController _dismissShortcutMenuAnimated:YES completionHandler:nil]; //HIERMEE LAAT JE DE STATUSBAR WEER ZIEN! 1179 | forceTouchOpenedTime = nowTime; 1180 | } 1181 | } 1182 | if([self respondsToSelector:@selector(appIconForceTouchGestureRecognizer)]) { //iOS 10 1183 | 1184 | 1185 | SBUIForceTouchGestureRecognizer *forceGesture = [self appIconForceTouchGestureRecognizer]; 1186 | SBUIAppIconForceTouchController *forceTouchAppController = MSHookIvar(iconController, "_appIconForceTouchController"); 1187 | SBUIIconForceTouchController *forceController = MSHookIvar(forceTouchAppController, "_iconForceTouchController"); 1188 | 1189 | if(method == 4) showFirstIconShortcuts = YES; 1190 | [forceController _setupWithGestureRecognizer:forceGesture]; 1191 | [forceController _presentAnimated:YES withCompletionHandler:nil]; //When completionhandler is set to nil, the method will understand to just use the orignal method. 1192 | if(method == 4) showFirstIconShortcuts = NO; 1193 | } 1194 | 1195 | }break; 1196 | 1197 | case 5: { 1198 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1199 | [folder openAppAtIndex: customAppIndex-1]; 1200 | }break; 1201 | 1202 | case 6: { 1203 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1204 | [folder openLastApp]; 1205 | }break; 1206 | 1207 | case 7: { 1208 | if(forceTouch) [[UIDevice currentDevice]._tapticEngine actuateFeedback:1]; 1209 | //Open the last opened app from the folder 1210 | 1211 | //Using SBLeafIcon in order to also loads SBBookmarkIcons!! 1212 | 1213 | SBLeafIcon *icon = nil; 1214 | if([[%c(SBIconController) sharedInstance] respondsToSelector:@selector(homescreenIconViewMap)]) { 1215 | icon = [[[[%c(SBIconController) sharedInstance] homescreenIconViewMap] iconModel] leafIconForIdentifier:lastOpenedApp]; //IOS 9.3 1216 | } else { 1217 | if ([[[%c(SBIconViewMap) homescreenMap] iconModel] respondsToSelector:@selector(leafIconForIdentifier:)]) { 1218 | icon = [[[%c(SBIconViewMap) homescreenMap] iconModel] leafIconForIdentifier:lastOpenedApp]; //IOS 4+ 1219 | } 1220 | } 1221 | 1222 | [icon openAppFromFolder:folder.folderID]; 1223 | 1224 | } 1225 | 1226 | default: 1227 | break; 1228 | } 1229 | } 1230 | } 1231 | 1232 | 1233 | /** 1234 | * To disable Spotlight view from showing up, if user swipes down on the icon 1235 | * and better swiping up support to prevent moving SpringBoard: 1236 | * gestureRecognizer will be the gesture with the sf_method, otherGestureRecognizer will be disabled. 1237 | */ 1238 | 1239 | %new - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 1240 | 1241 | if(!enabled) return YES; 1242 | 1243 | BOOL conflictGesture = NO; 1244 | 1245 | NSArray *targets = MSHookIvar(otherGestureRecognizer, "_targets"); 1246 | for(UIGestureRecognizerTarget *_target in targets) { 1247 | id target = MSHookIvar(_target, "_target"); 1248 | if([target isKindOfClass:%c(SBSearchScrollView)]) { 1249 | otherGestureRecognizer.enabled = NO; 1250 | } 1251 | /*if([target isKindOfClass:%c(SBIconScrollView)]) { 1252 | gestureRecognizer.enabled = YES; 1253 | otherGestureRecognizer.enabled = YES; 1254 | }*/ 1255 | } 1256 | 1257 | return !conflictGesture; 1258 | 1259 | } 1260 | 1261 | %end 1262 | 1263 | 1264 | 1265 | %hook SBIcon 1266 | 1267 | /** 1268 | * Helper function to get an icon view 1269 | * 1270 | */ 1271 | 1272 | 1273 | %new - (SBIconView*)getIconView { 1274 | SBIconView *iconView; 1275 | if([[%c(SBIconController) sharedInstance] respondsToSelector:@selector(homescreenIconViewMap)]) { 1276 | iconView = [[[%c(SBIconController) sharedInstance] homescreenIconViewMap] mappedIconViewForIcon:self]; 1277 | } else { 1278 | iconView = [[%c(SBIconViewMap) homescreenMap] mappedIconViewForIcon:self]; 1279 | } 1280 | 1281 | return iconView; 1282 | } 1283 | 1284 | /** 1285 | * Opening a specific app, and log that to the folder settings as the last opened app in folder settings 1286 | * and check if BioProtect is enabled for a specific app 1287 | * 1288 | */ 1289 | 1290 | 1291 | %new - (void)openAppFromFolder:(NSString*)folderID { 1292 | if(HAS_BIOPROTECT) { 1293 | if ([[%c(BioProtectController) sharedInstance ] requiresAuthenticationForIdentifier: self.application.bundleIdentifier ]){ 1294 | [[%c(BioProtectController) sharedInstance ] launchApplicationWithIdentifier: self.application.bundleIdentifier ]; 1295 | return; 1296 | } 1297 | } 1298 | 1299 | 1300 | NSString *lastOpenedIdentifier; 1301 | if(![self isKindOfClass:%c(SBLeafIcon)]){ 1302 | lastOpenedIdentifier = self.application.bundleIdentifier; 1303 | } else { 1304 | SBLeafIcon *leafIcon = (SBLeafIcon*)self; 1305 | lastOpenedIdentifier = leafIcon.leafIdentifier; 1306 | } 1307 | 1308 | setFolderSetting(folderID, @"lastOpenedApp", lastOpenedIdentifier); 1309 | 1310 | if([self respondsToSelector:@selector(launchFromLocation:context:)]) { 1311 | [self launchFromLocation:0 context:nil]; 1312 | } else if ([self respondsToSelector:@selector(launchFromLocation:)]) { 1313 | [self launchFromLocation:0]; 1314 | } else if ([self respondsToSelector:@selector(launch)]) { 1315 | [self launch]; 1316 | } 1317 | 1318 | } 1319 | 1320 | %end 1321 | 1322 | 1323 | /** 1324 | * Methods to save a new folder ID after editing 1325 | * 1326 | */ 1327 | 1328 | %hook SBFolderView 1329 | 1330 | %new - (void)updateIcon { 1331 | if(enabled) { 1332 | SBIcon *icon = self.folder.icon; 1333 | SBFolderIconView *folderIconView = (SBFolderIconView*)icon.getIconView; 1334 | SBFolderIconImageView *folderIconImageView = folderIconView._folderIconImageView; 1335 | 1336 | if(folderIconImageView.customImageView.image != nil) { 1337 | [folderIconImageView hideInnerFolderImageView: YES]; 1338 | [folderIconImageView bringSubviewToFront:folderIconImageView.customImageView]; 1339 | SBIcon *firstIcon = [self.folder getFirstIcon]; 1340 | UIImage *firstImage = [firstIcon getIconImage:2]; 1341 | 1342 | 1343 | [UIView transitionWithView:folderIconImageView.customImageView 1344 | duration:0.5f 1345 | options:UIViewAnimationOptionTransitionCrossDissolve 1346 | animations:^{ 1347 | folderIconImageView.customImageView.image = firstImage; 1348 | } completion:nil]; 1349 | 1350 | } else { 1351 | //[folderIconImageView sendSubviewToBack:folderIconImageView.backgroundView]; // The most important part 1352 | } 1353 | } 1354 | } 1355 | 1356 | %end 1357 | 1358 | 1359 | %hook SBFolder 1360 | 1361 | static NSString *oldFolderID; 1362 | %new - (void)createOldFolderID { 1363 | self.oldFolderID = [self folderID]; 1364 | } 1365 | 1366 | %new(v@:@) - (void)setOldFolderID:(NSString *)folderID { 1367 | objc_setAssociatedObject(self, &oldFolderID, folderID, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 1368 | } 1369 | 1370 | %new(@@:) - (NSString *)oldFolderID { 1371 | return objc_getAssociatedObject(self, &oldFolderID); 1372 | } 1373 | 1374 | 1375 | /** 1376 | * Getting the folder ID, based on the folder name and the first app in the folder 1377 | * 1378 | */ 1379 | 1380 | %new - (NSString*)folderID { 1381 | //Misschien iets meer optimalisatie. Gewoon geen md5 1382 | SBIcon *firstIcon = [self iconAtIndexPath: [self getFolderIndexPathForIndex:[self getFirstAppIconIndex]]]; //To ignore nested folder settings 1383 | 1384 | NSString *firstIconIdentifier; 1385 | if(![firstIcon isKindOfClass:%c(SBLeafIcon)]){ 1386 | firstIconIdentifier = firstIcon.application.bundleIdentifier; 1387 | } else { 1388 | SBLeafIcon *leafIcon = (SBLeafIcon*)firstIcon; 1389 | firstIconIdentifier = leafIcon.leafIdentifier; 1390 | } 1391 | 1392 | return [self createFolderIDWithDisplayName:self.displayName andFirstIconIdentifier:firstIconIdentifier]; 1393 | } 1394 | 1395 | %new - (NSString*)createFolderIDWithDisplayName:displayName andFirstIconIdentifier:(NSString*)firstIconIdentifier { 1396 | 1397 | NSString *folderID = [NSString stringWithFormat:@"%@-%@", displayName, firstIconIdentifier]; 1398 | 1399 | return folderID; 1400 | } 1401 | 1402 | 1403 | /** 1404 | * Some methods to get the first index of an app in a folder 1405 | * as some stupids are using other tweaks 1406 | * 1407 | */ 1408 | 1409 | 1410 | %new - (NSIndexPath*)getFolderIndexPathForIndex:(int)index { //The beauty of long method names :P 1411 | long maxIconCountInList = MSHookIvar(self, "_maxIconCountInLists"); 1412 | int indexInList = index % maxIconCountInList; 1413 | int section = floor(index/maxIconCountInList); 1414 | return [NSIndexPath indexPathForRow:indexInList inSection:section]; 1415 | } 1416 | 1417 | //For the stupids who want nested folder support. I should get paid for it ;( 1418 | %new - (int)getFirstAppIconIndex { 1419 | long maxIconCountInLists = MSHookIvar(self, "_maxIconCountInLists"); 1420 | int i = 0; 1421 | while(i <= (self.listCount * maxIconCountInLists)) { 1422 | NSIndexPath *indexPath = [self getFolderIndexPathForIndex:i]; 1423 | //SBApplicationIcon *icon = [self iconAtIndexPath:indexPath]; 1424 | SBIcon *icon = (SBApplicationIcon*)[self iconAtIndexPath:indexPath]; 1425 | if([icon respondsToSelector:@selector(application)]) { 1426 | if(icon.application.displayName != nil){ //&& ![icon isKindOfClass:%c(SBFolderIcon) 1427 | return i; 1428 | break; 1429 | } else if([icon isKindOfClass:%c(SBLeafIcon)]){ 1430 | SBLeafIcon *leafIcon = (SBLeafIcon*)icon; 1431 | if(leafIcon.leafIdentifier != nil) { 1432 | return i; 1433 | break; 1434 | } 1435 | } 1436 | } 1437 | i++; 1438 | } 1439 | return i; 1440 | 1441 | } 1442 | 1443 | %new - (SBIcon*)getFirstIcon { 1444 | switch (nestedFolderBehaviour) { 1445 | case 2: { 1446 | SBIcon *icon = [self iconAtIndexPath: [self getFolderIndexPathForIndex:0]]; 1447 | if([icon isKindOfClass:%c(SBFolderIcon)]) { 1448 | return [icon.folder iconAtIndexPath: [icon.folder getFolderIndexPathForIndex:[icon.folder getFirstAppIconIndex]]]; 1449 | } else { 1450 | return [self iconAtIndexPath: [self getFolderIndexPathForIndex:[self getFirstAppIconIndex]]]; 1451 | } 1452 | }break; 1453 | default: { 1454 | return [self iconAtIndexPath: [self getFolderIndexPathForIndex:[self getFirstAppIconIndex]]]; 1455 | }break; 1456 | } 1457 | } 1458 | 1459 | 1460 | /** 1461 | * Some methods to open up apps at a specific index 1462 | * 1463 | */ 1464 | 1465 | %new - (void)openLastApp { 1466 | SBIconIndexMutableList *iconList = MSHookIvar(self, "_lists"); 1467 | long maxIconCountInList = MSHookIvar(self, "_maxIconCountInLists"); //9 1468 | 1469 | int i = (iconList.count * maxIconCountInList) - maxIconCountInList; //Begin at the last page index 1470 | NSIndexPath *indexPath = [self getFolderIndexPathForIndex:0]; 1471 | 1472 | while(i <= (maxIconCountInList * iconList.count)) { 1473 | //SBApplicationIcon *icon = [self iconAtIndexPath: [self getFolderIndexPathForIndex:i]]; 1474 | SBIcon *icon = (SBApplicationIcon*)[self iconAtIndexPath:[self getFolderIndexPathForIndex:i]]; 1475 | if([icon respondsToSelector:@selector(application)]) { 1476 | if(icon.application.displayName != nil){ //&& ![icon isKindOfClass:%c(SBFolderIcon)] 1477 | indexPath = [self getFolderIndexPathForIndex:i]; 1478 | } else if([icon isKindOfClass:%c(SBLeafIcon)]){ 1479 | SBLeafIcon *leafIcon = (SBLeafIcon*)icon; 1480 | if(leafIcon.leafIdentifier != nil) { 1481 | indexPath = [self getFolderIndexPathForIndex:i]; 1482 | } 1483 | } 1484 | } 1485 | i++; 1486 | } 1487 | 1488 | [[self iconAtIndexPath:indexPath] openAppFromFolder:self.folderID]; 1489 | 1490 | } 1491 | 1492 | %new - (void)openAppAtIndex:(int)index { 1493 | SBIconController* iconController = [%c(SBIconController) sharedInstance]; 1494 | 1495 | if (!iconController.isEditing) { 1496 | 1497 | SBIconIndexMutableList *iconList = MSHookIvar(self, "_lists"); 1498 | long maxIconCountInList = MSHookIvar(self, "_maxIconCountInLists"); //9 1499 | int i = [self getFirstAppIconIndex]+index; 1500 | 1501 | while (i <= (maxIconCountInList * iconList.count)) { 1502 | NSIndexPath *indexPath = [self getFolderIndexPathForIndex:i]; 1503 | //SBApplicationIcon *icon = [self iconAtIndexPath:indexPath]; 1504 | SBIcon *icon = (SBApplicationIcon*)[self iconAtIndexPath:indexPath]; 1505 | if([icon respondsToSelector:@selector(application)]) { 1506 | if(icon.application.displayName != nil ){ // && ![icon isKindOfClass:%c(SBFolderIcon)] 1507 | [icon openAppFromFolder:self.folderID]; 1508 | break; 1509 | } else if([icon isKindOfClass:%c(SBLeafIcon)]){ 1510 | SBLeafIcon *leafIcon = (SBLeafIcon*)icon; 1511 | if(leafIcon.leafIdentifier != nil) { 1512 | [icon openAppFromFolder:self.folderID]; 1513 | } 1514 | } 1515 | } 1516 | i++; 1517 | } 1518 | 1519 | } 1520 | } 1521 | 1522 | %end 1523 | 1524 | 1525 | 1526 | 1527 | %hook SBRootFolderView 1528 | static NSMutableArray *oldFolderIDsAtBeginEditing; 1529 | 1530 | -(void)setEditing:(BOOL)editing animated:(BOOL)arg2 { 1531 | NSArray *folderArray = [self.folder.folderIcons allObjects]; //ALL FOLDERS ^^ 1532 | NSMutableArray *oldFolderIDsAtEndEditing; 1533 | 1534 | NSMutableDictionary *mutableCustomFolderSettings; 1535 | 1536 | if(editing) oldFolderIDsAtBeginEditing = [[NSMutableArray alloc] init]; 1537 | else { 1538 | oldFolderIDsAtEndEditing = [[NSMutableArray alloc] init]; 1539 | mutableCustomFolderSettings = [customFolderSettings mutableCopy]; 1540 | } 1541 | 1542 | 1543 | 1544 | for (int i=0; i<[folderArray count]; i++) { 1545 | SBFolderIcon *folderIcon = [folderArray objectAtIndex:i]; 1546 | SBFolder *folder = folderIcon.folder; 1547 | 1548 | if(editing) { 1549 | [folder createOldFolderID]; 1550 | [oldFolderIDsAtBeginEditing addObject:[folder folderID]]; 1551 | } else { 1552 | if(folder.oldFolderID) [oldFolderIDsAtEndEditing addObject:folder.oldFolderID]; 1553 | //[folder replaceOldFolderID:folder.oldFolderID byNewFolderID:[folder folderID]]; 1554 | //Hieronder is efficienter: 1555 | if(![folder.oldFolderID isEqualToString:[folder folderID]] && [mutableCustomFolderSettings objectForKey:folder.oldFolderID]) { 1556 | [mutableCustomFolderSettings removeObjectForKey:folder.oldFolderID]; 1557 | [mutableCustomFolderSettings setObject:customFolderSettings[folder.oldFolderID] forKey:[folder folderID]]; 1558 | } 1559 | } 1560 | } 1561 | 1562 | //Remove the folders from customFolderSettings when the folder itself is removed 1563 | if(!editing && mutableCustomFolderSettings) { 1564 | for (int i=0; i<[oldFolderIDsAtBeginEditing count]; i++) { 1565 | NSString *oldFolderID = [oldFolderIDsAtBeginEditing objectAtIndex:i]; 1566 | if(![oldFolderIDsAtEndEditing containsObject:oldFolderID] && [oldFolderIDsAtEndEditing count] > 0 && [customFolderSettings objectForKey:oldFolderID]) { 1567 | 1568 | [mutableCustomFolderSettings removeObjectForKey:oldFolderID]; 1569 | } 1570 | } 1571 | saveFolderSettings(mutableCustomFolderSettings); 1572 | } 1573 | 1574 | %orig; 1575 | 1576 | } 1577 | 1578 | 1579 | %end 1580 | 1581 | %hook SBLockScreenViewControllerBase 1582 | -(void)deactivate { 1583 | %orig; 1584 | 1585 | if(!showedFirstTimeMessage) { 1586 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"SwipyFolders" 1587 | message:@"Thanks for installing SwipyFolders! Default settings:\n First icon as folder preview\nSingle tap: opens the first app\nSwipe up: opens the folder\nThis all can be changed in the settings." 1588 | delegate:nil 1589 | cancelButtonTitle:@"Cool!" 1590 | otherButtonTitles:nil]; 1591 | [alert show]; 1592 | [alert release]; 1593 | 1594 | NSUserDefaults *preferences = [[NSUserDefaults alloc] initWithSuiteName:@"nl.jessevandervelden.swipyfoldersprefs"]; 1595 | [preferences setBool:YES forKey:@"showedFirstTimeMessage"]; 1596 | [preferences synchronize]; 1597 | showedFirstTimeMessage = YES; 1598 | } 1599 | } 1600 | %end 1601 | 1602 | /** 1603 | * Finally register a listener to reload preferences on changes 1604 | * 1605 | */ 1606 | 1607 | 1608 | static void respring() { 1609 | [[%c(FBSystemService) sharedInstance] exitAndRelaunch:YES]; 1610 | } 1611 | 1612 | %ctor{ 1613 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), 1614 | NULL, 1615 | (CFNotificationCallback)loadPreferences, 1616 | CFSTR("nl.jessevandervelden.swipyfoldersprefs/prefsChanged"), 1617 | NULL, 1618 | CFNotificationSuspensionBehaviorDeliverImmediately); 1619 | 1620 | 1621 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), 1622 | NULL, 1623 | (CFNotificationCallback)respring, 1624 | CFSTR("nl.jessevandervelden.swipyfoldersprefs/respring"), 1625 | NULL, 1626 | CFNotificationSuspensionBehaviorDeliverImmediately); 1627 | 1628 | 1629 | 1630 | loadPreferences(); 1631 | } 1632 | --------------------------------------------------------------------------------