470 lines
17 KiB
Plaintext
470 lines
17 KiB
Plaintext
#import "AAConfigurationViewController.h"
|
|
#import "AAAppIconCell.h"
|
|
#import "CoreData/CoreData.h"
|
|
|
|
@interface AAConfigurationViewController () <UITableViewDelegate, UITableViewDataSource>
|
|
|
|
@property (nonatomic, retain) UITableView *tableView;
|
|
@property (nonatomic, retain) NSArray<NSString *> *actions;
|
|
@property (nonatomic, retain) NSIndexPath *selectedActionIndexPath;
|
|
@property (nonatomic, retain) NSIndexPath *selectedLimitationIndexPath;
|
|
@property (nonatomic, retain) UIView *fakeNavBar;
|
|
@property (nonatomic, retain) UILabel *titleLabel;
|
|
@property (nonatomic, retain) UIButton *doneButton;
|
|
@property (nonatomic, retain) UIButton *cancelButton;
|
|
@property (nonatomic, copy) NSString *titleString;
|
|
@property (nonatomic, copy) NSString *message;
|
|
@property (nonatomic, retain) NSArray<NSString *> *textFieldValues;
|
|
@property (nonatomic, retain) NSDictionary<NSString *, NSNumber *> *customAppActions;
|
|
@property (nonatomic, assign) BOOL isSpringBoard;
|
|
@property (nonatomic, assign) BOOL secure;
|
|
|
|
@end
|
|
|
|
@interface UIImage ()
|
|
|
|
+(id)_applicationIconImageForBundleIdentifier:(id)arg1 format:(int)arg2 scale:(double)arg3;
|
|
|
|
@end
|
|
|
|
@interface SpringBoard: UIApplication
|
|
|
|
-(id)_accessibilityFrontMostApplication;
|
|
|
|
@end
|
|
|
|
@implementation AAConfigurationViewController
|
|
|
|
extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);
|
|
|
|
-(id)initWithActions:(NSArray<NSString *> *)actions title:(NSString *)title message:(NSString *)message textFieldValues:(NSArray<NSString *> *)textFieldValues customAppActions:(NSDictionary<NSString *, NSNumber *> *)customAppActions secure:(BOOL)secure {
|
|
if (self = [super init]) {
|
|
self.actions = actions;
|
|
self.selectedActionIndexPath = [NSIndexPath indexPathForRow:0 inSection:1];
|
|
self.selectedLimitationIndexPath = [NSIndexPath indexPathForRow:0 inSection:2];
|
|
self.titleString = title;
|
|
self.message = message;
|
|
self.textFieldValues = textFieldValues;
|
|
self.customAppActions = customAppActions;
|
|
|
|
self.fakeNavBar = [[[UIView alloc] init] autorelease];
|
|
if (@available(iOS 13, *)) {
|
|
self.fakeNavBar.backgroundColor = [UIColor systemBackgroundColor];
|
|
} else {
|
|
self.fakeNavBar.backgroundColor = [UIColor whiteColor];
|
|
}
|
|
|
|
[self.view addSubview:self.fakeNavBar];
|
|
|
|
self.titleLabel = [[[UILabel alloc] init] autorelease];
|
|
self.titleLabel.text = @"Alert settings";
|
|
self.titleLabel.font = [UIFont systemFontOfSize:17.0 weight:UIFontWeightSemibold];
|
|
|
|
[self.fakeNavBar addSubview:self.titleLabel];
|
|
|
|
self.doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
self.doneButton.titleLabel.font = [UIFont systemFontOfSize:17.0 weight:UIFontWeightSemibold];
|
|
[self.doneButton addTarget:self action:@selector(doneTapped:) forControlEvents:UIControlEventTouchUpInside];
|
|
[self.doneButton setTitle:@"Done" forState:UIControlStateNormal];
|
|
|
|
[self.fakeNavBar addSubview:self.doneButton];
|
|
|
|
self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:17.0 weight:UIFontWeightRegular];
|
|
[self.cancelButton addTarget:self action:@selector(cancelTapped:) forControlEvents:UIControlEventTouchUpInside];
|
|
[self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
|
|
|
|
[self.fakeNavBar addSubview:self.cancelButton];
|
|
|
|
self.isSpringBoard = [[NSBundle mainBundle].bundleIdentifier isEqual:@"com.apple.springboard"];
|
|
self.secure = secure;
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
-(void)viewDidLoad {
|
|
[super viewDidLoad];
|
|
|
|
self.tableView = [[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped] autorelease];
|
|
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
|
|
if (@available(iOS 13, *)) {
|
|
self.tableView.backgroundColor = [UIColor systemBackgroundColor];
|
|
} else {
|
|
self.tableView.backgroundColor = [UIColor whiteColor];
|
|
}
|
|
self.tableView.preservesSuperviewLayoutMargins = YES;
|
|
|
|
[self.view addSubview:self.tableView];
|
|
|
|
[self.tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
|
|
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
|
|
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
|
|
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
|
|
|
|
self.tableView.dataSource = self;
|
|
self.tableView.delegate = self;
|
|
|
|
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ActionCell"];
|
|
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"LimitationCell"];
|
|
[self.tableView registerClass:[AAAppIconCell class] forCellReuseIdentifier:@"AppIconCell"];
|
|
}
|
|
|
|
-(void)viewDidLayoutSubviews {
|
|
[super viewDidLayoutSubviews];
|
|
|
|
CGFloat statusBarHeight;
|
|
|
|
if (self.isSpringBoard) {
|
|
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
|
|
} else {
|
|
if (@available(iOS 11.0, *)) {
|
|
statusBarHeight = self.view.safeAreaInsets.top;
|
|
} else {
|
|
statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
|
|
}
|
|
}
|
|
|
|
CGFloat fakeNavBarHeight;
|
|
|
|
if (@available(iOS 13, *)) {
|
|
fakeNavBarHeight = 56.0;
|
|
statusBarHeight = 0.0;
|
|
} else {
|
|
fakeNavBarHeight = statusBarHeight == 0.0 ? 32.0 : statusBarHeight + 44.0;
|
|
}
|
|
|
|
self.fakeNavBar.frame = CGRectMake(
|
|
0.0,
|
|
0.0,
|
|
self.view.bounds.size.width,
|
|
fakeNavBarHeight
|
|
);
|
|
|
|
self.tableView.contentInset = UIEdgeInsetsMake(
|
|
self.fakeNavBar.frame.size.height - (self.isSpringBoard ? 0.0 : statusBarHeight),
|
|
self.tableView.contentInset.left,
|
|
self.tableView.contentInset.bottom,
|
|
self.tableView.contentInset.right
|
|
);
|
|
|
|
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(
|
|
self.fakeNavBar.frame.size.height - (self.isSpringBoard ? 0.0 : statusBarHeight),
|
|
self.tableView.contentInset.left,
|
|
self.tableView.contentInset.bottom,
|
|
self.tableView.contentInset.right
|
|
);
|
|
|
|
CGSize titleLabelSize = self.titleLabel.intrinsicContentSize;
|
|
|
|
self.titleLabel.frame = CGRectMake(
|
|
self.fakeNavBar.bounds.size.width / 2.0 - titleLabelSize.width / 2.0,
|
|
statusBarHeight,
|
|
titleLabelSize.width,
|
|
fakeNavBarHeight - statusBarHeight
|
|
);
|
|
|
|
CGSize doneButtonSize = self.doneButton.intrinsicContentSize;
|
|
|
|
self.doneButton.frame = CGRectMake(
|
|
self.fakeNavBar.bounds.size.width - doneButtonSize.width - self.view.layoutMargins.left,
|
|
statusBarHeight + (fakeNavBarHeight - statusBarHeight) / 2.0 - doneButtonSize.height / 2.0,
|
|
doneButtonSize.width,
|
|
doneButtonSize.height
|
|
);
|
|
|
|
CGSize cancelButtonSize = self.cancelButton.intrinsicContentSize;
|
|
|
|
self.cancelButton.frame = CGRectMake(
|
|
self.view.layoutMargins.left,
|
|
statusBarHeight + (fakeNavBarHeight - statusBarHeight) / 2.0 - cancelButtonSize.height / 2.0,
|
|
cancelButtonSize.width,
|
|
cancelButtonSize.height
|
|
);
|
|
}
|
|
|
|
-(void)postSaveNotification {
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
[dict setObject:[NSString stringWithFormat:@"%@", self.titleString] forKey:@"title"];
|
|
[dict setObject:[NSString stringWithFormat:@"%@", self.message] forKey:@"message"];
|
|
[dict setObject:self.actions forKey:@"actions"];
|
|
[dict setObject:self.textFieldValues forKey:@"textfieldvalues"];
|
|
[dict setObject:[NSNumber numberWithInt:self.textFieldValues.count] forKey:@"textfieldcount"];
|
|
[dict setObject:[NSNumber numberWithInt:self.selectedActionIndexPath.row] forKey:@"selectedaction"];
|
|
|
|
NSMutableDictionary *appActions = [NSMutableDictionary dictionaryWithDictionary:self.customAppActions];
|
|
|
|
if (self.isSpringBoard) {
|
|
SpringBoard *sb = (SpringBoard *)[UIApplication sharedApplication];
|
|
|
|
id currentApp = [sb _accessibilityFrontMostApplication];
|
|
|
|
if (currentApp && self.selectedLimitationIndexPath.row == 0) {
|
|
NSString *currentAppBundleID = [currentApp valueForKey:@"bundleIdentifier"];
|
|
|
|
appActions[currentAppBundleID] = [NSNumber numberWithInt:self.selectedActionIndexPath.row];
|
|
} else {
|
|
[appActions removeAllObjects];
|
|
}
|
|
}
|
|
|
|
[dict setObject:appActions forKey:@"customappactions"];
|
|
|
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
|
|
NSString *jsonString = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
|
|
|
|
NSString *bundleID = [NSBundle mainBundle].bundleIdentifier;
|
|
|
|
CFNotificationCenterPostNotification(
|
|
CFNotificationCenterGetDistributedCenter(),
|
|
(CFStringRef)[NSString stringWithFormat:@"com.shiftcmdk.autoalerts.save.%@ %@", bundleID, jsonString],
|
|
NULL,
|
|
NULL,
|
|
YES
|
|
);
|
|
}
|
|
|
|
-(void)doneTapped:(UIBarButtonItem *)sender {
|
|
NSString *warningTitle = nil;
|
|
NSString *warningMessage = nil;
|
|
|
|
if (self.secure) {
|
|
warningTitle = @"Warning";
|
|
warningMessage = @"At least one text field is marked as secure. All input will be stored in plain text. Do you really want to save this alert?";
|
|
}
|
|
|
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:warningTitle message:warningMessage preferredStyle:UIAlertControllerStyleActionSheet];
|
|
|
|
UIAlertAction *saveAction = [UIAlertAction actionWithTitle:@"Save" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
|
[self postSaveNotification];
|
|
|
|
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
|
}];
|
|
|
|
UIAlertAction *saveAndRunAction = [UIAlertAction actionWithTitle:@"Save and Run" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
|
|
[self postSaveNotification];
|
|
|
|
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
|
|
if (self.delegate) {
|
|
[self.delegate saveAndRunAction:self.selectedActionIndexPath.row];
|
|
}
|
|
}];
|
|
}];
|
|
|
|
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {
|
|
|
|
}];
|
|
|
|
[alert addAction:saveAction];
|
|
[alert addAction:saveAndRunAction];
|
|
[alert addAction:cancelAction];
|
|
|
|
alert.popoverPresentationController.sourceView = self.doneButton;
|
|
alert.popoverPresentationController.sourceRect = self.doneButton.bounds;
|
|
|
|
[self presentViewController:alert animated:YES completion:nil];
|
|
}
|
|
|
|
-(void)cancelTapped:(UIBarButtonItem *)sender {
|
|
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
|
|
}
|
|
|
|
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
|
if (self.isSpringBoard) {
|
|
SpringBoard *sb = (SpringBoard *)[UIApplication sharedApplication];
|
|
|
|
if ([sb _accessibilityFrontMostApplication]) {
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
if (section == 0) {
|
|
return 1;
|
|
} else if (section == 1) {
|
|
return self.actions.count + 2;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
if (indexPath.section == 0) {
|
|
AAAppIconCell *cell = (AAAppIconCell *)[tableView dequeueReusableCellWithIdentifier:@"AppIconCell" forIndexPath:indexPath];
|
|
|
|
cell.appIconImageView.image = [UIImage _applicationIconImageForBundleIdentifier:[NSBundle mainBundle].bundleIdentifier format:2 scale:[UIScreen mainScreen].scale];
|
|
|
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
|
|
return cell;
|
|
} else if (indexPath.section == 1) {
|
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ActionCell" forIndexPath:indexPath];
|
|
|
|
if (indexPath.row == 0) {
|
|
cell.textLabel.text = @"No Action";
|
|
|
|
cell.textLabel.font = [UIFont systemFontOfSize:cell.textLabel.font.pointSize weight:UIFontWeightMedium];
|
|
} else if (indexPath.row == 1) {
|
|
cell.textLabel.text = @"Dismiss";
|
|
|
|
cell.textLabel.font = [UIFont systemFontOfSize:cell.textLabel.font.pointSize weight:UIFontWeightMedium];
|
|
} else {
|
|
cell.textLabel.text = [self.actions objectAtIndex:indexPath.row - 2];
|
|
|
|
cell.textLabel.font = [UIFont systemFontOfSize:cell.textLabel.font.pointSize];
|
|
}
|
|
|
|
if (@available(iOS 13, *)) {
|
|
cell.contentView.backgroundColor = [UIColor systemBackgroundColor];
|
|
cell.backgroundColor = [UIColor systemBackgroundColor];
|
|
} else {
|
|
cell.contentView.backgroundColor = [UIColor whiteColor];
|
|
cell.backgroundColor = [UIColor whiteColor];
|
|
}
|
|
|
|
cell.accessoryType = indexPath == self.selectedActionIndexPath ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
|
|
|
return cell;
|
|
} else {
|
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LimitationCell" forIndexPath:indexPath];
|
|
|
|
SpringBoard *sb = (SpringBoard *)[UIApplication sharedApplication];
|
|
|
|
id app = [sb _accessibilityFrontMostApplication];
|
|
|
|
if (indexPath.row == 0) {
|
|
cell.textLabel.text = [NSString stringWithFormat:@"Only in %@", [app valueForKey:@"displayName"]];
|
|
} else {
|
|
cell.textLabel.text = @"In Every App";
|
|
}
|
|
|
|
if (@available(iOS 13, *)) {
|
|
cell.contentView.backgroundColor = [UIColor systemBackgroundColor];
|
|
cell.backgroundColor = [UIColor systemBackgroundColor];
|
|
} else {
|
|
cell.contentView.backgroundColor = [UIColor whiteColor];
|
|
cell.backgroundColor = [UIColor whiteColor];
|
|
}
|
|
|
|
cell.accessoryType = indexPath == self.selectedLimitationIndexPath ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
|
|
|
return cell;
|
|
}
|
|
}
|
|
|
|
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
|
if (section == 1) {
|
|
return @"Automated action";
|
|
} else if (section == 2) {
|
|
return @"App specific settings";
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
|
|
if (section == 1) {
|
|
return @"Select the action that should be invoked automatically when this alert is shown.";
|
|
} else if (section == 2) {
|
|
return @"Alerts that are presented from SpringBoard can either be automated in a specific app or in every app.";
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
|
|
|
if (indexPath.section == 1) {
|
|
self.selectedActionIndexPath = indexPath;
|
|
|
|
for (int i = 0; i < [tableView numberOfRowsInSection:indexPath.section]; i++) {
|
|
NSIndexPath *theIndexPath = [NSIndexPath indexPathForRow:i inSection:indexPath.section];
|
|
|
|
UITableViewCell *cell = [tableView cellForRowAtIndexPath:theIndexPath];
|
|
|
|
if (cell) {
|
|
cell.accessoryType = theIndexPath == self.selectedActionIndexPath ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (indexPath.section == 2) {
|
|
self.selectedLimitationIndexPath = indexPath;
|
|
|
|
for (int i = 0; i < [tableView numberOfRowsInSection:indexPath.section]; i++) {
|
|
NSIndexPath *theIndexPath = [NSIndexPath indexPathForRow:i inSection:indexPath.section];
|
|
|
|
UITableViewCell *cell = [tableView cellForRowAtIndexPath:theIndexPath];
|
|
|
|
if (cell) {
|
|
cell.accessoryType = theIndexPath == self.selectedLimitationIndexPath ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
|
if (section == 0) {
|
|
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
|
if (section == 0) {
|
|
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
|
if (section == 0) {
|
|
return 16.0;
|
|
}
|
|
return UITableViewAutomaticDimension;
|
|
}
|
|
|
|
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
|
|
if (section == 0) {
|
|
return 8.0;
|
|
}
|
|
return UITableViewAutomaticDimension;
|
|
}
|
|
|
|
-(void)dealloc {
|
|
[self.tableView removeFromSuperview];
|
|
|
|
self.tableView = nil;
|
|
|
|
self.actions = nil;
|
|
|
|
self.selectedActionIndexPath = nil;
|
|
self.selectedLimitationIndexPath = nil;
|
|
|
|
[self.titleLabel removeFromSuperview];
|
|
|
|
self.titleLabel = nil;
|
|
|
|
[self.doneButton removeFromSuperview];
|
|
|
|
self.doneButton = nil;
|
|
|
|
[self.cancelButton removeFromSuperview];
|
|
|
|
self.cancelButton = nil;
|
|
|
|
[self.fakeNavBar removeFromSuperview];
|
|
|
|
self.fakeNavBar = nil;
|
|
|
|
self.titleString = nil;
|
|
self.message = nil;
|
|
self.textFieldValues = nil;
|
|
|
|
self.customAppActions = nil;
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
@end |