2 * Copyright (C) 2021 Cameron Katri
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 #import <Foundation/NSUserDefaults.h>
18 #import <CoreGraphics/CoreGraphics.h>
19 #import <UIKit/UIKit.h>
23 void openApplication(NSString *bundleID)
25 FBSOpenApplicationOptions* opts = [%c(FBSOpenApplicationOptions) optionsWithDictionary:@{
26 @"__LaunchOrigin" : @"BulletinDestinationCoverSheet",
27 @"__PromptUnlockDevice" : @YES,
28 @"__UnlockDevice" : @YES,
29 @"__LaunchImage" : @"",
32 FBSystemServiceOpenApplicationRequest* request = [%c(FBSystemServiceOpenApplicationRequest) request];
33 request.options = opts;
34 request.bundleIdentifier = bundleID;
35 request.trusted = YES;
36 request.clientProcess = [[%c(FBProcessManager) sharedInstance] systemApplicationProcess];
38 [[%c(SBMainWorkspace) sharedInstance] systemService:[%c(FBSystemService) sharedInstance] handleOpenApplicationRequest:request withCompletion:^{}];
41 %hook CSQuickActionsView
43 %property (nonatomic, retain) NSMutableArray * leftButtons;
44 %property (nonatomic, retain) NSMutableArray * rightButtons;
45 %property (nonatomic) BOOL leftOpen;
46 %property (nonatomic) BOOL rightOpen;
47 %property (nonatomic) BOOL collapseLeft;
48 %property (nonatomic) BOOL collapseRight;
50 -(id)initWithFrame:(CGRect)arg1 delegate:(id)arg2
54 NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.cameronkatri.quickactions"];
56 NSArray *leftButtons = (NSArray*)[defaults objectForKey:@"leftButtons"];
57 NSArray *rightButtons = (NSArray*)[defaults objectForKey:@"rightButtons"];
60 self.leftButtons = [[NSMutableArray alloc] init];
61 self.rightButtons = [[NSMutableArray alloc] init];
63 self.collapseLeft = [leftButtons count] > 1 ? true : false;
64 self.leftOpen = !self.collapseLeft;
66 if ([leftButtons count] == 1) {
67 [self.flashlightButton setBundleID:leftButtons[0]];
68 } else if ([leftButtons count] > 1) {
69 [self.flashlightButton setImage:nil];
70 for (int i = 0; i < [leftButtons count]; i++) {
71 CSQuickActionsButton *button = [[CSQuickActionsButton alloc] initWithType:(i + 2)];
72 [button setBundleID:leftButtons[i]];
74 [button setBackgroundEffectViewGroupName:[self _buttonGroupName]];
75 [button setLegibilitySettings:[self legibilitySettings]];
76 [button setPermitted:1];
78 [self insertSubview:button belowSubview:self.flashlightButton];
79 [self _addTargetsToButton:button];
80 [self.leftButtons addObject:button];
84 self.collapseRight = [rightButtons count] > 1 ? true : false;
85 self.rightOpen = !self.collapseRight;
87 if ([rightButtons count] == 1) {
88 [self.cameraButton setBundleID:rightButtons[0]];
89 } else if ([rightButtons count] > 1) {
90 [self.cameraButton setImage:nil];
91 for (int i = 0; i < [rightButtons count]; i++) {
92 CSQuickActionsButton *button = [[CSQuickActionsButton alloc] initWithType:(i + 2)];
93 [button setBundleID:rightButtons[i]];
95 [button setBackgroundEffectViewGroupName:[self _buttonGroupName]];
96 [button setLegibilitySettings:[self legibilitySettings]];
97 [button setPermitted:1];
99 [self insertSubview:button belowSubview:self.cameraButton];
100 [self _addTargetsToButton:button];
101 [self.rightButtons addObject:button];
109 -(CGRect)rightFrameForButton:(CSQuickActionsButton*)button
111 CGRect cameraFrame = [[self cameraButton] frame];
112 if (self.rightOpen) {
113 return CGRectMake(cameraFrame.origin.x,
114 cameraFrame.origin.y - ((cameraFrame.size.height * 3/4) * ((button.type + 1) / 2)),
115 cameraFrame.size.width, cameraFrame.size.height);
122 -(CGRect)leftFrameForButton:(CSQuickActionsButton*)button
124 CGRect flashlightFrame = [[self flashlightButton] frame];
126 return CGRectMake(flashlightFrame.origin.x,
127 flashlightFrame.origin.y - ((flashlightFrame.size.height * 3/4) * (button.type - 1)),
128 flashlightFrame.size.width, flashlightFrame.size.height);
130 return flashlightFrame;
134 -(void)setLegibilitySettings:(id)legibilitySettings
137 for (CSQuickActionsButton *button in [self leftButtons])
138 [button setLegibilitySettings:legibilitySettings];
139 for (CSQuickActionsButton *button in [self rightButtons])
140 [button setLegibilitySettings:legibilitySettings];
143 -(void)_layoutQuickActionButtons
147 UIEdgeInsets insets = [self _buttonOutsets];
148 if (SBFEffectiveHomeButtonType() != 2) {
149 CGRect bounds = [[UIScreen mainScreen] _referenceBounds];
151 CGFloat buttonWidth = 50 + insets.right + insets.left;
152 CGFloat buttonHeight = 50 + insets.top + insets.bottom;
154 [[self flashlightButton] setEdgeInsets:insets];
156 self.flashlightButton.frame = CGRectMake(insets.left,
157 bounds.size.height - buttonHeight - insets.bottom,
158 buttonWidth, buttonHeight);
160 [[self cameraButton] setEdgeInsets:insets];
162 self.cameraButton.frame = CGRectMake(bounds.size.width - insets.left - buttonWidth,
163 bounds.size.height - buttonHeight - insets.bottom,
164 buttonWidth, buttonHeight);
168 for (CSQuickActionsButton *button in [self leftButtons]) {
169 [button setEdgeInsets:insets];
170 button.frame = [self leftFrameForButton:button];
172 for (CSQuickActionsButton *button in [self rightButtons]) {
173 [button setEdgeInsets:insets];
174 button.frame = [self rightFrameForButton:button];
178 -(void)handleButtonPress:(CSQuickActionsButton *)button
180 [button setSelected:false];
182 if (button.type == 0 && self.collapseRight) {
183 [UIView animateWithDuration:0.25
185 options:UIViewAnimationOptionCurveEaseOut
187 for (CSQuickActionsButton *button in [self rightButtons]) {
188 button.frame = [self rightFrameForButton:button];
192 self.rightOpen = !self.rightOpen;
193 } else if (button.type == 1 && self.collapseLeft) {
194 [UIView animateWithDuration:0.25
196 options:UIViewAnimationOptionCurveEaseOut
198 for (CSQuickActionsButton *button in [self leftButtons]) {
199 button.frame = [self leftFrameForButton:button];
203 self.leftOpen = !self.leftOpen;
204 } else if (button.bundleID) {
205 openApplication(button.bundleID);
211 -(void)handleButtonTouchBegan:(CSQuickActionsButton *)button
213 if (button.bundleID != nil ||
214 (button.type == 0 && self.collapseRight) ||
215 (button.type == 1 && self.collapseLeft))
220 -(void)handleButtonTouchEnded:(CSQuickActionsButton *)button
222 if (button.bundleID != nil ||
223 (button.type == 0 && self.collapseRight) ||
224 (button.type == 1 && self.collapseLeft))
231 %hook CSQuickActionsButton
233 %property (nonatomic, retain) NSString *bundleID;
235 -(void)setImage:(UIImage *)img
238 [[self valueForKey:@"_contentView"] setImage:img];
241 -(void)setBundleID:(NSString*)bundleID
244 [self setImage:[UIImage _applicationIconImageForBundleIdentifier:bundleID format:0 scale:[UIScreen mainScreen].scale]];
249 %hook CSQuickActionsViewController
261 +(BOOL)deviceSupportsButtons
268 // vim: filetype=logos