summaryrefslogtreecommitdiffstats
path: root/QuickActions/QuickActionsPrefs
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-12-27 01:08:28 -0500
committerCameron Katri <me@cameronkatri.com>2021-12-27 01:08:28 -0500
commit15240ea1e0dc4fc86a3f36cffe5b9c14ff0b2c93 (patch)
treeb88d424cbcdce6487a2e85dfd380bc4eb7fd682e /QuickActions/QuickActionsPrefs
parent6c781fd0b08f0fe3ccd2d3e0d79c9739c2f288c8 (diff)
downloadtweaks-15240ea1e0dc4fc86a3f36cffe5b9c14ff0b2c93.tar.gz
tweaks-15240ea1e0dc4fc86a3f36cffe5b9c14ff0b2c93.tar.zst
tweaks-15240ea1e0dc4fc86a3f36cffe5b9c14ff0b2c93.zip
I lost track of all the changes
Diffstat (limited to 'QuickActions/QuickActionsPrefs')
-rw-r--r--QuickActions/QuickActionsPrefs/Makefile16
-rw-r--r--QuickActions/QuickActionsPrefs/PSDetailController.h30
-rw-r--r--QuickActions/QuickActionsPrefs/QASAppSelectorController.h18
-rw-r--r--QuickActions/QuickActionsPrefs/QASAppSelectorController.m310
-rw-r--r--QuickActions/QuickActionsPrefs/Resources/Root.plist110
5 files changed, 422 insertions, 62 deletions
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 <Preferences/PSViewController.h>
+
+@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 <UIKit/UIKit.h>
+#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<UITableViewDataSource,
+UITableViewDelegate>
+@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 <Foundation/Foundation.h>
+#include <objc/NSObject.h>
+#import <UIKit/UIKit.h>
+#import <Preferences/PSSpecifier.h>
+#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<LSApplicationProxy *> *)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 @@
<dict>
<key>cell</key>
<string>PSGroupCell</string>
+ <key>label</key>
+ <string>Left</string>
</dict>
<dict>
<key>cell</key>
<string>PSLinkListCell</string>
- <key>defaults</key>
- <string>com.cameronkatri.quickactions</string>
<key>label</key>
- <string>Left Apps</string>
+ <string>Left Buttons</string>
<key>detail</key>
- <string>ATLApplicationListMultiSelectionController</string>
+ <string>QASAppSelectorController</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
<key>key</key>
<string>leftButtons</string>
- <key>cellClass</key>
- <string>ATLApplicationSelectionCell</string>
- <key>sections</key>
- <array>
- <dict>
- <key>sectionType</key>
- <string>System</string>
- </dict>
- <dict>
- <key>sectionType</key>
- <string>User</string>
- </dict>
- </array>
- <key>useSearchBar</key>
- <true/>
- <key>hideSearchBarWhileScrolling</key>
- <false/>
- <key>showIdentifiersAsSubtitle</key>
+ </dict>
+ <dict>
+ <key>cell</key>
+ <string>PSEditTextCell</string>
+ <key>label</key>
+ <string>Offset X</string>
+ <key>key</key>
+ <string>LeftOffsetX</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
+ <key>isDecimalPad</key>
<true/>
- <key>includeIdentifiersInSearch</key>
+ <key>placeholder</key>
+ <string>0</string>
+ </dict>
+ <dict>
+ <key>cell</key>
+ <string>PSEditTextCell</string>
+ <key>label</key>
+ <string>Offset Y</string>
+ <key>key</key>
+ <string>LeftOffsetY</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
+ <key>isDecimalPad</key>
<true/>
+ <key>placeholder</key>
+ <string>0</string>
</dict>
<dict>
<key>cell</key>
<string>PSGroupCell</string>
+ <key>label</key>
+ <string>Right</string>
</dict>
<dict>
<key>cell</key>
<string>PSLinkListCell</string>
- <key>defaults</key>
- <string>com.cameronkatri.quickactions</string>
<key>label</key>
- <string>Right Apps</string>
+ <string>Right Buttons</string>
<key>detail</key>
- <string>ATLApplicationListMultiSelectionController</string>
+ <string>QASAppSelectorController</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
<key>key</key>
<string>rightButtons</string>
- <key>cellClass</key>
- <string>ATLApplicationSelectionCell</string>
- <key>sections</key>
- <array>
- <dict>
- <key>sectionType</key>
- <string>System</string>
- </dict>
- <dict>
- <key>sectionType</key>
- <string>User</string>
- </dict>
- </array>
- <key>useSearchBar</key>
- <true/>
- <key>hideSearchBarWhileScrolling</key>
- <false/>
- <key>showIdentifiersAsSubtitle</key>
+ </dict>
+ <dict>
+ <key>cell</key>
+ <string>PSEditTextCell</string>
+ <key>label</key>
+ <string>Offset X</string>
+ <key>key</key>
+ <string>RightOffsetX</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
+ <key>isDecimalPad</key>
<true/>
- <key>includeIdentifiersInSearch</key>
+ <key>placeholder</key>
+ <string>0</string>
+ </dict>
+ <dict>
+ <key>cell</key>
+ <string>PSEditTextCell</string>
+ <key>label</key>
+ <string>Offset Y</string>
+ <key>key</key>
+ <string>RightOffsetY</string>
+ <key>defaults</key>
+ <string>com.cameronkatri.quickactions</string>
+ <key>isDecimalPad</key>
<true/>
+ <key>placeholder</key>
+ <string>0</string>
</dict>
<dict>
<key>cell</key>