From 15240ea1e0dc4fc86a3f36cffe5b9c14ff0b2c93 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Mon, 27 Dec 2021 01:08:28 -0500 Subject: I lost track of all the changes --- QuickActions/QuickActionsPrefs/Makefile | 16 -- .../QuickActionsPrefs/PSDetailController.h | 30 ++ .../QuickActionsPrefs/QASAppSelectorController.h | 18 ++ .../QuickActionsPrefs/QASAppSelectorController.m | 310 +++++++++++++++++++++ .../QuickActionsPrefs/Resources/Root.plist | 110 +++++--- 5 files changed, 422 insertions(+), 62 deletions(-) delete mode 100644 QuickActions/QuickActionsPrefs/Makefile create mode 100644 QuickActions/QuickActionsPrefs/PSDetailController.h create mode 100644 QuickActions/QuickActionsPrefs/QASAppSelectorController.h create mode 100644 QuickActions/QuickActionsPrefs/QASAppSelectorController.m (limited to 'QuickActions/QuickActionsPrefs') diff --git a/QuickActions/QuickActionsPrefs/Makefile b/QuickActions/QuickActionsPrefs/Makefile deleted file mode 100644 index df9918b..0000000 --- a/QuickActions/QuickActionsPrefs/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -TARGET := iphone:clang:14.4:13.0 - -include $(THEOS)/makefiles/common.mk - -ARCHS := arm64 arm64e - -BUNDLE_NAME = QuickActionsPrefs - -QuickActionsPrefs_FILES = QASRootListController.m -QuickActionsPrefs_FRAMEWORKS = UIKit -QuickActionsPrefs_PRIVATE_FRAMEWORKS = Preferences -QuickActionsPrefs_EXTRA_FRAMEWORKS = AltList -QuickActionsPrefs_INSTALL_PATH = /Library/PreferenceBundles -QuickActionsPrefs_CFLAGS = -fobjc-arc - -include $(THEOS_MAKE_PATH)/bundle.mk diff --git a/QuickActions/QuickActionsPrefs/PSDetailController.h b/QuickActions/QuickActionsPrefs/PSDetailController.h new file mode 100644 index 0000000..571b091 --- /dev/null +++ b/QuickActions/QuickActionsPrefs/PSDetailController.h @@ -0,0 +1,30 @@ +#import + +@class PSEditingPane; + +@interface PSDetailController : PSViewController { + + PSEditingPane* _pane; + +} + +@property (assign,nonatomic) PSEditingPane * pane; +-(void)willAnimateRotationToInterfaceOrientation:(long long)arg1 duration:(double)arg2 ; +-(void)willRotateToInterfaceOrientation:(long long)arg1 duration:(double)arg2 ; +-(PSEditingPane *)pane; +-(void)didRotateFromInterfaceOrientation:(long long)arg1 ; +-(void)viewWillDisappear:(BOOL)arg1 ; +-(void)viewDidLayoutSubviews; +-(void)setPane:(PSEditingPane *)arg1 ; +-(CGRect)paneFrame; +-(void)loadPane; +-(void)dealloc; +-(id)title; +-(void)viewDidAppear:(BOOL)arg1 ; +-(void)loadView; +-(void)suspend; +-(void)viewDidUnload; +-(void)viewWillAppear:(BOOL)arg1 ; +-(void)saveChanges; +-(void)statusBarWillAnimateByHeight:(double)arg1 ; +@end diff --git a/QuickActions/QuickActionsPrefs/QASAppSelectorController.h b/QuickActions/QuickActionsPrefs/QASAppSelectorController.h new file mode 100644 index 0000000..13ffe60 --- /dev/null +++ b/QuickActions/QuickActionsPrefs/QASAppSelectorController.h @@ -0,0 +1,18 @@ +#import +#import "PSDetailController.h" + +@interface UIImage (Private) ++(instancetype)_applicationIconImageForBundleIdentifier:(NSString*)bundleIdentifier format:(int)format scale:(CGFloat)scale; +-(UIImage *)_applicationIconImageForFormat:(int)format precomposed:(BOOL)precomposed scale:(CGFloat)scale; +@end + +@interface QASAppSelectorController : PSDetailController +@property (nonatomic) UITableView *tableView; +@property (nonatomic) NSMutableArray *enabled; +@property (nonatomic) NSMutableArray *disabled; +@property (nonatomic) NSArray *systemAvailable; +@property (nonatomic) NSMutableArray *systemDisabled; +@property (nonatomic) NSString *key; +@property (nonatomic) NSString *defaults; +@end \ No newline at end of file diff --git a/QuickActions/QuickActionsPrefs/QASAppSelectorController.m b/QuickActions/QuickActionsPrefs/QASAppSelectorController.m new file mode 100644 index 0000000..cfb6c7a --- /dev/null +++ b/QuickActions/QuickActionsPrefs/QASAppSelectorController.m @@ -0,0 +1,310 @@ +#import +#include +#import +#import +#import "QASAppSelectorController.h" + +@interface LSApplicationRecord +@property (readonly) NSArray * appTags; +@property (getter=isLaunchProhibited,readonly) BOOL launchProhibited; +@end + +@interface LSApplicationProxy : NSObject +@property (getter=isLaunchProhibited, nonatomic, readonly) BOOL launchProhibited; +@property (nonatomic, readonly) NSArray *appTags; +@property (nonatomic,readonly) LSApplicationRecord * correspondingApplicationRecord; ++ (id)applicationProxyForIdentifier:(id)arg1; +- (id)localizedNameForContext:(id)arg1; +- (NSString *)bundleIdentifier; +- (NSString *)applicationType; +- (NSURL *)bundleURL; +@end + +@interface LSApplicationProxy (StolenFromAltList) +- (BOOL)atl_isHidden; +@end + +@interface LSApplicationWorkspace : NSObject ++(id)defaultWorkspace; +-(NSArray *)allApplications; +@end + +@interface NSMutableArray (Custom) +-(void)sortApps; +@end + +// @interface ListItem : NSObject +// @property (nonatomic, retain) NSString *name; +// @property (nonatomic, retain) NSString *bundleID; +// @property (nonatomic, retain) NSString *type; +// @property (nonatomic, retain) UIImage *icon; +// -(ListItem *)initWithName:(NSString *)name bundleID:(NSString *)bundleID type:(NSString *)type icon:(UIImage *)icon; +// @end + +@implementation QASAppSelectorController +-(void)viewDidLoad +{ + [super viewDidLoad]; + + PSSpecifier *specifier = [self specifier]; + + self.defaults = [specifier propertyForKey:@"defaults"]; + self.key = [specifier propertyForKey:@"key"]; + + self.disabled = [NSMutableArray new]; + self.enabled = [NSMutableArray new]; + + NSArray *defaults = [[[NSUserDefaults alloc] initWithSuiteName:self.defaults] arrayForKey:self.key]; + + if (defaults == nil) { + if ([self.key isEqualToString:@"leftButtons"]) + [self.enabled addObject:@"com.apple.flashlight"]; + else if ([self.key isEqualToString:@"rightButtons"]) + [self.enabled addObject:@"com.apple.camera"]; + } else + [self.enabled addObjectsFromArray:defaults]; + + for (LSApplicationProxy *proxy in [[LSApplicationWorkspace defaultWorkspace] allApplications]) { + if (![proxy atl_isHidden] && [self.enabled indexOfObject:proxy.bundleIdentifier] == NSNotFound) + [self.disabled addObject:proxy.bundleIdentifier]; + } + + if ([self.enabled indexOfObject:@"com.apple.flashlight"] == NSNotFound) + [self.disabled addObject:@"com.apple.flashlight"]; + + if ([self.enabled indexOfObject:@"com.apple.donotdisturb"] == NSNotFound) + [self.disabled addObject:@"com.apple.donotdisturb"]; + + [self.disabled sortApps]; +} + +-(void)viewWillAppear:(BOOL)animated +{ + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + self.tableView.delegate = self; + self.tableView.dataSource = self; + self.tableView.editing = TRUE; + + [self.view addSubview:self.tableView]; +} + +-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + if (section == 0) + return @"Enabled"; + else if (section == 1) + return @"Disabled"; + else + return @""; +} + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 2; +} + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + if (section == 0) + return self.enabled.count; + else + return self.disabled.count; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSString *bundleid = indexPath.section == 0 ? self.enabled[indexPath.row] : self.disabled[indexPath.row]; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"com.cameronkatri.quickactions"]; + + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"com.cameronkatri.quickactions"]; + + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + if ([bundleid isEqualToString:@"com.apple.flashlight"]) { + cell.textLabel.text = @"Flashlight"; + cell.detailTextLabel.text = nil; + NSBundle *flashlightModule = [NSBundle bundleWithPath:@"/System/Library/ControlCenter/Bundles/FlashlightModule.bundle"]; + cell.imageView.image = [[UIImage imageNamed:@"SettingsIcon" + inBundle:flashlightModule + compatibleWithTraitCollection:nil] _applicationIconImageForFormat:0 precomposed:YES scale:[UIScreen mainScreen].scale]; + } else if ([bundleid isEqualToString:@"com.apple.donotdisturb"]) { + cell.textLabel.text = @"Do Not Disturb"; + cell.detailTextLabel.text = nil; + NSBundle *doNotDisturbBundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/DoNotDisturb.framework/PlugIns/DoNotDisturbIntents.appex"]; + cell.imageView.image = [[UIImage imageNamed:@"DoNotDisturb" + inBundle:doNotDisturbBundle + compatibleWithTraitCollection:nil] _applicationIconImageForFormat:0 precomposed:YES scale:[UIScreen mainScreen].scale]; + } else { + cell.textLabel.text = [[LSApplicationProxy applicationProxyForIdentifier:bundleid] localizedNameForContext:nil]; + if (cell.textLabel.text == nil) { + cell.textLabel.text = bundleid; + cell.detailTextLabel.text = nil; + } else { + cell.detailTextLabel.text = bundleid; + } + cell.detailTextLabel.textColor = [UIColor secondaryLabelColor]; + cell.imageView.image = [UIImage _applicationIconImageForBundleIdentifier:bundleid format:0 scale:[UIScreen mainScreen].scale]; + } + + cell.showsReorderControl = indexPath.section == 0 ? YES : FALSE; + + return cell; +} + +-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return indexPath.section == 0 ? UITableViewCellEditingStyleDelete : UITableViewCellEditingStyleInsert; +} + +-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath +{ + return indexPath.section == 0 ? YES : FALSE; +} + +-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(nonnull NSIndexPath *)sourceIndexPath toIndexPath:(nonnull NSIndexPath *)destinationIndexPath +{ + if (sourceIndexPath.section == 0) { + if (destinationIndexPath.section == 0) + [self.enabled exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row]; + else { + [self.disabled addObject:self.enabled[sourceIndexPath.row]]; + [self.enabled removeObjectAtIndex:sourceIndexPath.row]; + } + } else { + [self.enabled insertObject:self.disabled[sourceIndexPath.row] atIndex:destinationIndexPath.row]; + [self.disabled removeObjectAtIndex:sourceIndexPath.row]; + } + + [self.disabled sortApps]; + [tableView reloadData]; + + [[[NSUserDefaults alloc] initWithSuiteName:self.defaults] setObject:self.enabled forKey:self.key]; +} + +-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath +{ + if (sourceIndexPath.section == 0 && proposedDestinationIndexPath.section == 1) { + NSUInteger insPoint = [self.disabled + indexOfObject:self.enabled[sourceIndexPath.row] + inSortedRange:NSMakeRange(0, [self.disabled count]) + options:NSBinarySearchingInsertionIndex + usingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { + if ([obj1 isEqualToString:@"com.apple.flashlight"]) + return NSOrderedAscending; + else if ([obj2 isEqualToString:@"com.apple.flashlight"]) + return NSOrderedDescending; + NSString *obj1Name = [[LSApplicationProxy applicationProxyForIdentifier:obj1] localizedNameForContext:nil]; + NSString *obj2Name = [[LSApplicationProxy applicationProxyForIdentifier:obj2] localizedNameForContext:nil]; + return ([obj1Name localizedCaseInsensitiveCompare:obj2Name]); + }]; + return [NSIndexPath indexPathForRow:insPoint inSection:1]; + } + return proposedDestinationIndexPath; +} + +-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath +{ + NSString *item = indexPath.section == 0 ? self.enabled[indexPath.row] : self.disabled[indexPath.row]; + NSIndexPath *insertPath; + + if (editingStyle == UITableViewCellEditingStyleDelete) { + [self.enabled removeObject:item]; + [self.disabled addObject:item]; + [self.disabled sortApps]; + + insertPath = [NSIndexPath indexPathForRow:[self.disabled indexOfObject:item] inSection:1]; + } else if (editingStyle == UITableViewCellEditingStyleInsert) { + [self.disabled removeObject:item]; + [self.enabled addObject:item]; + + insertPath = [NSIndexPath indexPathForRow:([self.enabled count] - 1) inSection:0]; + } + + [tableView beginUpdates]; + [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:insertPath] withRowAnimation:UITableViewRowAnimationFade]; + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + [tableView endUpdates]; + + [[[NSUserDefaults alloc] initWithSuiteName:self.defaults] setObject:self.enabled forKey:self.key]; +} +@end + +@implementation NSMutableArray (Custom) +-(void)sortApps { + [self sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) { + if ([obj1 isEqualToString:@"com.apple.flashlight"]) + return NSOrderedAscending; + else if ([obj2 isEqualToString:@"com.apple.flashlight"]) + return NSOrderedDescending; + + NSString *obj1Name = [[LSApplicationProxy applicationProxyForIdentifier:obj1] localizedNameForContext:nil]; + NSString *obj2Name = [[LSApplicationProxy applicationProxyForIdentifier:obj2] localizedNameForContext:nil]; + + return ([obj1Name localizedCaseInsensitiveCompare:obj2Name]); + }]; +} +@end + +@implementation LSApplicationProxy (StolenFromAltList) + +BOOL tagArrayContainsTag(NSArray* tagArr, NSString* tag) +{ + if(!tagArr || !tag) return NO; + + __block BOOL found = NO; + + [tagArr enumerateObjectsUsingBlock:^(NSString* tagToCheck, NSUInteger idx, BOOL* stop) + { + if(![tagToCheck isKindOfClass:[NSString class]]) + { + return; + } + + if([tagToCheck rangeOfString:tag options:0].location != NSNotFound) + { + found = YES; + *stop = YES; + } + }]; + + return found; +} + +- (BOOL)atl_isHidden +{ + NSArray* appTags; + NSArray* recordAppTags; + NSArray* sbAppTags; + + BOOL launchProhibited = NO; + + if([self respondsToSelector:@selector(correspondingApplicationRecord)]) + { + // On iOS 14, self.appTags is always empty but the application record still has the correct ones + LSApplicationRecord* record = [self correspondingApplicationRecord]; + recordAppTags = record.appTags; + launchProhibited = record.launchProhibited; + } + if([self respondsToSelector:@selector(appTags)]) + { + appTags = self.appTags; + } + if(!launchProhibited && [self respondsToSelector:@selector(isLaunchProhibited)]) + { + launchProhibited = self.launchProhibited; + } + + NSURL* bundleURL = self.bundleURL; + if(bundleURL && [bundleURL checkResourceIsReachableAndReturnError:nil]) + { + NSBundle* bundle = [NSBundle bundleWithURL:bundleURL]; + sbAppTags = [bundle objectForInfoDictionaryKey:@"SBAppTags"]; + } + + BOOL isWebApplication = ([self.bundleIdentifier rangeOfString:@"com.apple.webapp" options:NSCaseInsensitiveSearch].location != NSNotFound); + return tagArrayContainsTag(appTags, @"hidden") || tagArrayContainsTag(recordAppTags, @"hidden") || tagArrayContainsTag(sbAppTags, @"hidden") || isWebApplication || launchProhibited; +} +@end diff --git a/QuickActions/QuickActionsPrefs/Resources/Root.plist b/QuickActions/QuickActionsPrefs/Resources/Root.plist index 728dc93..1eb8853 100644 --- a/QuickActions/QuickActionsPrefs/Resources/Root.plist +++ b/QuickActions/QuickActionsPrefs/Resources/Root.plist @@ -7,76 +7,94 @@ cell PSGroupCell + label + Left cell PSLinkListCell - defaults - com.cameronkatri.quickactions label - Left Apps + Left Buttons detail - ATLApplicationListMultiSelectionController + QASAppSelectorController + defaults + com.cameronkatri.quickactions key leftButtons - cellClass - ATLApplicationSelectionCell - sections - - - sectionType - System - - - sectionType - User - - - useSearchBar - - hideSearchBarWhileScrolling - - showIdentifiersAsSubtitle + + + cell + PSEditTextCell + label + Offset X + key + LeftOffsetX + defaults + com.cameronkatri.quickactions + isDecimalPad - includeIdentifiersInSearch + placeholder + 0 + + + cell + PSEditTextCell + label + Offset Y + key + LeftOffsetY + defaults + com.cameronkatri.quickactions + isDecimalPad + placeholder + 0 cell PSGroupCell + label + Right cell PSLinkListCell - defaults - com.cameronkatri.quickactions label - Right Apps + Right Buttons detail - ATLApplicationListMultiSelectionController + QASAppSelectorController + defaults + com.cameronkatri.quickactions key rightButtons - cellClass - ATLApplicationSelectionCell - sections - - - sectionType - System - - - sectionType - User - - - useSearchBar - - hideSearchBarWhileScrolling - - showIdentifiersAsSubtitle + + + cell + PSEditTextCell + label + Offset X + key + RightOffsetX + defaults + com.cameronkatri.quickactions + isDecimalPad - includeIdentifiersInSearch + placeholder + 0 + + + cell + PSEditTextCell + label + Offset Y + key + RightOffsetY + defaults + com.cameronkatri.quickactions + isDecimalPad + placeholder + 0 cell -- cgit v1.2.3-56-ge451