Initial commit
This commit is contained in:
12
autoalertspreferences/AAAlertOverviewController.h
Normal file
12
autoalertspreferences/AAAlertOverviewController.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#import <Preferences/PSViewController.h>
|
||||
#import "../Model/AAAlertInfo.h"
|
||||
#import "AADeleteDelegate.h"
|
||||
|
||||
@interface AAAlertOverviewController : PSViewController
|
||||
|
||||
@property (nonatomic, retain) UITableView *tableView;
|
||||
@property (nonatomic, retain) AAAlertInfo *alertInfo;
|
||||
@property (nonatomic, retain) NSMutableDictionary<NSString *, NSString *> *appsDict;
|
||||
@property (nonatomic, assign) id<AADeleteDelegate> deleteDelegate;
|
||||
|
||||
@end
|
||||
324
autoalertspreferences/AAAlertOverviewController.xm
Normal file
324
autoalertspreferences/AAAlertOverviewController.xm
Normal file
@@ -0,0 +1,324 @@
|
||||
#import "AAAlertOverviewController.h"
|
||||
|
||||
@interface AAAlertOverviewController () <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@property (nonatomic, retain) NSArray<NSString *> *visibleSections;
|
||||
@property (nonatomic, retain) NSMutableArray<NSString *> *sortedBundleIDs;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIImage ()
|
||||
|
||||
+(id)_applicationIconImageForBundleIdentifier:(id)arg1 format:(int)arg2 scale:(double)arg3;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AAAlertOverviewController
|
||||
|
||||
extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.navigationItem.title = @"Alert Details";
|
||||
|
||||
UIBarButtonItem *trashItem = [[[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
|
||||
target:self
|
||||
action:@selector(deleteAlert:)
|
||||
] autorelease];
|
||||
|
||||
self.navigationItem.rightBarButtonItem = trashItem;
|
||||
|
||||
self.tableView = [[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped] autorelease];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
|
||||
[self.view addSubview:self.tableView];
|
||||
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"TitleCell"];
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"MessageCell"];
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ActionCell"];
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"SelectedActionCell"];
|
||||
|
||||
NSMutableArray *sections = [NSMutableArray array];
|
||||
|
||||
if (self.alertInfo.actions.count > 0) {
|
||||
[sections addObject:@"Actions"];
|
||||
}
|
||||
|
||||
if (self.alertInfo.customAppActions.count == 0) {
|
||||
[sections addObject:@"SelectedAction"];
|
||||
}
|
||||
|
||||
if (self.alertInfo.textFieldValues.count > 0) {
|
||||
[sections addObject:@"TextFields"];
|
||||
}
|
||||
|
||||
if (self.alertInfo.customAppActions.count > 0) {
|
||||
[sections addObject:@"CustomAppActions"];
|
||||
|
||||
self.sortedBundleIDs = [NSMutableArray arrayWithArray:[[self.alertInfo.customAppActions allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
|
||||
NSString *firstName;
|
||||
|
||||
if (self.appsDict[obj1]) {
|
||||
firstName = self.appsDict[obj1];
|
||||
} else {
|
||||
firstName = obj1;
|
||||
}
|
||||
|
||||
NSString *secondName;
|
||||
|
||||
if (self.appsDict[obj2]) {
|
||||
secondName = self.appsDict[obj2];
|
||||
} else {
|
||||
secondName = obj2;
|
||||
}
|
||||
|
||||
return [firstName compare:secondName options:NSCaseInsensitiveSearch];
|
||||
}]];
|
||||
}
|
||||
|
||||
self.visibleSections = sections;
|
||||
}
|
||||
|
||||
-(void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
self.tableView.frame = self.view.bounds;
|
||||
}
|
||||
|
||||
-(void)postDeleteNotificationAndPopViewController {
|
||||
CFNotificationCenterPostNotification(
|
||||
CFNotificationCenterGetDistributedCenter(),
|
||||
(CFStringRef)[NSString stringWithFormat:@"com.shiftcmdk.autoalerts.delete.%@", self.alertInfo.identifier],
|
||||
NULL,
|
||||
NULL,
|
||||
YES
|
||||
);
|
||||
|
||||
if (self.deleteDelegate) {
|
||||
[self.deleteDelegate didDelete];
|
||||
}
|
||||
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
-(void)deleteAlert:(UIBarButtonItem *)sender {
|
||||
UIAlertController *deleteAlert = [UIAlertController alertControllerWithTitle:@"Delete alert" message:@"Do you really want to delete this automated alert?" preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
[self postDeleteNotificationAndPopViewController];
|
||||
}];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
|
||||
|
||||
[deleteAlert addAction:deleteAction];
|
||||
[deleteAlert addAction:cancelAction];
|
||||
|
||||
[self presentViewController:deleteAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return 2 + self.visibleSections.count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (section > 1) {
|
||||
NSString *identifier = self.visibleSections[section - 2];
|
||||
|
||||
if ([identifier isEqual:@"Actions"]) {
|
||||
return self.alertInfo.actions.count;
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"SelectedAction"]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"TextFields"]) {
|
||||
return self.alertInfo.textFieldValues.count;
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"CustomAppActions"]) {
|
||||
return self.alertInfo.customAppActions.count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell;
|
||||
|
||||
if (indexPath.section == 0) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"TitleCell" forIndexPath:indexPath];
|
||||
|
||||
cell.textLabel.text = self.alertInfo.title;
|
||||
cell.textLabel.numberOfLines = 0;
|
||||
} else if (indexPath.section == 1) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"MessageCell" forIndexPath:indexPath];
|
||||
|
||||
cell.textLabel.text = self.alertInfo.message;
|
||||
cell.textLabel.numberOfLines = 0;
|
||||
} else {
|
||||
NSString *identifier = self.visibleSections[indexPath.section - 2];
|
||||
|
||||
if ([identifier isEqual:@"Actions"]) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"ActionCell" forIndexPath:indexPath];
|
||||
|
||||
cell.textLabel.text = self.alertInfo.actions[indexPath.row];
|
||||
} else if ([identifier isEqual:@"SelectedAction"]) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"SelectedActionCell" forIndexPath:indexPath];
|
||||
|
||||
int selectedAction = self.alertInfo.selectedAction;
|
||||
|
||||
NSString *actionString;
|
||||
|
||||
if (selectedAction == 0) {
|
||||
actionString = @"No Action";
|
||||
} else if (selectedAction == 1) {
|
||||
actionString = @"Dismiss";
|
||||
} else {
|
||||
actionString = self.alertInfo.actions[selectedAction - 2];
|
||||
}
|
||||
|
||||
cell.textLabel.text = actionString;
|
||||
} else if ([identifier isEqual:@"TextFields"]) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"TextFieldCell"];
|
||||
|
||||
if (!cell) {
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"TextFieldCell"] autorelease];
|
||||
}
|
||||
|
||||
cell.textLabel.text = [NSString stringWithFormat:@"Text Field %i", (int)indexPath.row + 1];
|
||||
cell.detailTextLabel.text = self.alertInfo.textFieldValues[indexPath.row];
|
||||
} else if ([identifier isEqual:@"CustomAppActions"]) {
|
||||
cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell"];
|
||||
|
||||
if (!cell) {
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"AppCell"] autorelease];
|
||||
}
|
||||
|
||||
NSString *bundleID = self.sortedBundleIDs[indexPath.row];
|
||||
|
||||
UIImage *icon = [UIImage _applicationIconImageForBundleIdentifier:bundleID format:0 scale:[UIScreen mainScreen].scale];
|
||||
|
||||
cell.imageView.image = icon;
|
||||
cell.textLabel.text = self.appsDict[bundleID] ? self.appsDict[bundleID] : bundleID;
|
||||
|
||||
int selectedAction = [self.alertInfo.customAppActions[bundleID] intValue];
|
||||
|
||||
NSString *actionString;
|
||||
|
||||
if (selectedAction == 0) {
|
||||
actionString = @"No Action";
|
||||
} else if (selectedAction == 1) {
|
||||
actionString = @"Dismiss";
|
||||
} else {
|
||||
actionString = self.alertInfo.actions[selectedAction - 2];
|
||||
}
|
||||
|
||||
cell.detailTextLabel.text = actionString;
|
||||
} else {
|
||||
cell = [[[UITableViewCell alloc] init] autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return @"Title";
|
||||
case 1:
|
||||
return @"Message";
|
||||
default: {
|
||||
NSString *identifier = self.visibleSections[section - 2];
|
||||
|
||||
if ([identifier isEqual:@"Actions"]) {
|
||||
return @"Actions";
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"SelectedAction"]) {
|
||||
return @"Selected action";
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"TextFields"]) {
|
||||
return @"Text fields";
|
||||
}
|
||||
|
||||
if ([identifier isEqual:@"CustomAppActions"]) {
|
||||
return @"App specific settings";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return indexPath.section > 1 && [self.visibleSections[indexPath.section - 2] isEqual:@"CustomAppActions"];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
NSString *bundleID = self.sortedBundleIDs[indexPath.row];
|
||||
|
||||
[self.sortedBundleIDs removeObjectAtIndex:indexPath.row];
|
||||
|
||||
[self.alertInfo.customAppActions removeObjectForKey:bundleID];
|
||||
|
||||
if (self.alertInfo.customAppActions.count > 0) {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
[dict setObject:[NSString stringWithFormat:@"%@", self.alertInfo.title] forKey:@"title"];
|
||||
[dict setObject:[NSString stringWithFormat:@"%@", self.alertInfo.message] forKey:@"message"];
|
||||
[dict setObject:self.alertInfo.actions forKey:@"actions"];
|
||||
[dict setObject:self.alertInfo.textFieldValues forKey:@"textfieldvalues"];
|
||||
[dict setObject:[NSNumber numberWithInt:self.alertInfo.textFieldValues.count] forKey:@"textfieldcount"];
|
||||
[dict setObject:[NSNumber numberWithInt:self.alertInfo.selectedAction] forKey:@"selectedaction"];
|
||||
[dict setObject:self.alertInfo.customAppActions forKey:@"customappactions"];
|
||||
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil];
|
||||
NSString *jsonString = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
|
||||
|
||||
CFNotificationCenterPostNotification(
|
||||
CFNotificationCenterGetDistributedCenter(),
|
||||
(CFStringRef)[NSString stringWithFormat:@"com.shiftcmdk.autoalerts.save.%@ %@", self.alertInfo.bundleID, jsonString],
|
||||
NULL,
|
||||
NULL,
|
||||
YES
|
||||
);
|
||||
} else {
|
||||
[self postDeleteNotificationAndPopViewController];
|
||||
}
|
||||
|
||||
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
[self.tableView removeFromSuperview];
|
||||
|
||||
self.tableView = nil;
|
||||
|
||||
self.alertInfo = nil;
|
||||
|
||||
self.visibleSections = nil;
|
||||
|
||||
self.appsDict = nil;
|
||||
|
||||
self.sortedBundleIDs = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
11
autoalertspreferences/AAApp.h
Normal file
11
autoalertspreferences/AAApp.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#import "../Model/AAAlertInfo.h"
|
||||
|
||||
@interface AAApp: NSObject
|
||||
|
||||
-(id)initWithBundleID:(NSString *)bundleID name:(NSString *)name infos:(NSMutableArray<AAAlertInfo *> *)infos;
|
||||
|
||||
@property (nonatomic, copy) NSString *bundleID;
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
@property (nonatomic, retain) NSMutableArray<AAAlertInfo *> *infos;
|
||||
|
||||
@end
|
||||
24
autoalertspreferences/AAApp.m
Normal file
24
autoalertspreferences/AAApp.m
Normal file
@@ -0,0 +1,24 @@
|
||||
#import "AAApp.h"
|
||||
|
||||
@implementation AAApp
|
||||
|
||||
-(id)initWithBundleID:(NSString *)bundleID name:(NSString *)name infos:(NSMutableArray<AAAlertInfo *> *)infos {
|
||||
if (self = [super init]) {
|
||||
self.bundleID = bundleID;
|
||||
self.name = name;
|
||||
self.infos = infos;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
self.bundleID = nil;
|
||||
self.name = nil;
|
||||
|
||||
self.infos = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
12
autoalertspreferences/AAAppOverviewController.h
Normal file
12
autoalertspreferences/AAAppOverviewController.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#import <Preferences/PSViewController.h>
|
||||
#import "AAApp.h"
|
||||
#import "AADeleteDelegate.h"
|
||||
|
||||
@interface AAAppOverviewController : PSViewController
|
||||
|
||||
@property (nonatomic, retain) UITableView *tableView;
|
||||
@property (nonatomic, retain) AAApp *app;
|
||||
@property (nonatomic, retain) NSMutableDictionary<NSString *, NSString *> *appsDict;
|
||||
@property (nonatomic, assign) id<AADeleteDelegate> deleteDelegate;
|
||||
|
||||
@end
|
||||
160
autoalertspreferences/AAAppOverviewController.xm
Normal file
160
autoalertspreferences/AAAppOverviewController.xm
Normal file
@@ -0,0 +1,160 @@
|
||||
#import "AAAppOverviewController.h"
|
||||
#import "AAAlertOverviewController.h"
|
||||
#import "AADeleteDelegate.h"
|
||||
|
||||
@interface AAAppOverviewController () <UITableViewDelegate, UITableViewDataSource, AADeleteDelegate>
|
||||
|
||||
@property (nonatomic, assign) BOOL shouldDelete;
|
||||
@property (nonatomic, retain) NSIndexPath *selectedIndexPath;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AAAppOverviewController
|
||||
|
||||
extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.navigationItem.title = self.app.name;
|
||||
|
||||
self.tableView = [[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped] autorelease];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
|
||||
[self.view addSubview:self.tableView];
|
||||
|
||||
self.shouldDelete = NO;
|
||||
}
|
||||
|
||||
-(void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (self.shouldDelete && self.selectedIndexPath) {
|
||||
if (self.app.infos.count == 1) {
|
||||
[self.app.infos removeObjectAtIndex:self.selectedIndexPath.row];
|
||||
|
||||
if (self.deleteDelegate) {
|
||||
[self.deleteDelegate didDelete];
|
||||
}
|
||||
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
} else {
|
||||
[self.app.infos removeObjectAtIndex:self.selectedIndexPath.row];
|
||||
|
||||
[self.tableView deleteRowsAtIndexPaths:@[self.selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
|
||||
self.shouldDelete = NO;
|
||||
self.selectedIndexPath = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
self.tableView.frame = self.view.bounds;
|
||||
}
|
||||
|
||||
-(void)didDelete {
|
||||
self.shouldDelete = YES;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.app.infos.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AlertOverviewCell"];
|
||||
|
||||
AAAlertInfo *info = [self.app.infos objectAtIndex:indexPath.row];
|
||||
|
||||
if (!cell) {
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"AlertOverviewCell"] autorelease];
|
||||
}
|
||||
|
||||
cell.textLabel.text = info.title;
|
||||
cell.detailTextLabel.text = info.message;
|
||||
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
return @"Automated alerts";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
self.selectedIndexPath = indexPath;
|
||||
|
||||
AAAlertOverviewController *ctrl = [[[AAAlertOverviewController alloc] init] autorelease];
|
||||
ctrl.alertInfo = [self.app.infos objectAtIndex:indexPath.row];
|
||||
ctrl.appsDict = self.appsDict;
|
||||
ctrl.deleteDelegate = self;
|
||||
|
||||
[self.navigationController pushViewController:ctrl animated:YES];
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
UIAlertController *deleteAlert = [UIAlertController alertControllerWithTitle:@"Delete alert" message:@"Do you really want to delete this automated alert?" preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
CFNotificationCenterPostNotification(
|
||||
CFNotificationCenterGetDistributedCenter(),
|
||||
(CFStringRef)[NSString stringWithFormat:@"com.shiftcmdk.autoalerts.delete.%@", self.app.infos[indexPath.row].identifier],
|
||||
NULL,
|
||||
NULL,
|
||||
YES
|
||||
);
|
||||
|
||||
[self.app.infos removeObjectAtIndex:indexPath.row];
|
||||
|
||||
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
|
||||
if (self.deleteDelegate && self.app.infos.count == 0) {
|
||||
[self.deleteDelegate didDelete];
|
||||
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
|
||||
|
||||
[deleteAlert addAction:deleteAction];
|
||||
[deleteAlert addAction:cancelAction];
|
||||
|
||||
[self presentViewController:deleteAlert animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
[self.tableView removeFromSuperview];
|
||||
|
||||
self.tableView = nil;
|
||||
|
||||
self.app = nil;
|
||||
|
||||
self.appsDict = nil;
|
||||
|
||||
self.selectedIndexPath = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
5
autoalertspreferences/AADeleteDelegate.h
Normal file
5
autoalertspreferences/AADeleteDelegate.h
Normal file
@@ -0,0 +1,5 @@
|
||||
@protocol AADeleteDelegate <NSObject>
|
||||
|
||||
-(void)didDelete;
|
||||
|
||||
@end
|
||||
7
autoalertspreferences/AARootListController.h
Normal file
7
autoalertspreferences/AARootListController.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#import <Preferences/PSViewController.h>
|
||||
|
||||
@interface AARootListController : PSViewController
|
||||
|
||||
@property (nonatomic, retain) UITableView *tableView;
|
||||
|
||||
@end
|
||||
295
autoalertspreferences/AARootListController.xm
Normal file
295
autoalertspreferences/AARootListController.xm
Normal file
@@ -0,0 +1,295 @@
|
||||
#include "AARootListController.h"
|
||||
#import "../AAAlertManager.h"
|
||||
#import "AAApp.h"
|
||||
#import "AAAppOverviewController.h"
|
||||
|
||||
@interface LSApplicationProxy: NSObject
|
||||
|
||||
@property (nonatomic,readonly) NSString * bundleIdentifier;
|
||||
-(id)localizedName;
|
||||
@property (nonatomic,readonly) NSString * primaryIconName;
|
||||
@property (setter=_setInfoDictionary:,nonatomic,copy) id _infoDictionary;
|
||||
|
||||
@end
|
||||
|
||||
@interface LSApplicationWorkspace : NSObject
|
||||
|
||||
+(id)defaultWorkspace;
|
||||
-(id)allInstalledApplications;
|
||||
-(id)allApplications;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIImage ()
|
||||
|
||||
+(id)_applicationIconImageForBundleIdentifier:(id)arg1 format:(int)arg2 scale:(double)arg3;
|
||||
|
||||
@end
|
||||
|
||||
@interface AARootListController () <UITableViewDelegate, UITableViewDataSource, AADeleteDelegate>
|
||||
|
||||
@property (nonatomic, retain) NSMutableArray<AAApp *> *apps;
|
||||
@property (nonatomic, retain) NSMutableDictionary<NSString *, NSString *> *appsDict;
|
||||
@property (nonatomic, assign) BOOL shouldDelete;
|
||||
@property (nonatomic, retain) NSIndexPath *selectedIndexPath;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AARootListController
|
||||
|
||||
extern "C" CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void);
|
||||
|
||||
-(id)init {
|
||||
if (self = [super init]) {
|
||||
self.navigationItem.title = @"AutoAlerts";
|
||||
|
||||
[[AAAlertManager sharedManager] initialize];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
self.tableView = [[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped] autorelease];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
|
||||
[self.view addSubview:self.tableView];
|
||||
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"AppCell"];
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"EnabledCell"];
|
||||
|
||||
self.navigationItem.title = @"AutoAlerts";
|
||||
|
||||
self.apps = [NSMutableArray array];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
NSArray<LSApplicationProxy *> *apps = [[%c(LSApplicationWorkspace) defaultWorkspace] allApplications];
|
||||
|
||||
NSMutableDictionary<NSString *, NSString *> *theAppsDict = [NSMutableDictionary dictionary];
|
||||
|
||||
for (LSApplicationProxy *app in apps) {
|
||||
theAppsDict[app.bundleIdentifier] = [app localizedName];
|
||||
}
|
||||
|
||||
NSArray<AAAlertInfo *> *allAlerts = [[AAAlertManager sharedManager] allAlerts];
|
||||
|
||||
NSMutableDictionary<NSString *, NSMutableArray *> *alertsDict = [NSMutableDictionary dictionary];
|
||||
|
||||
for (AAAlertInfo *info in allAlerts) {
|
||||
NSMutableArray *arr = alertsDict[info.bundleID];
|
||||
|
||||
if (arr) {
|
||||
[arr addObject:info];
|
||||
} else {
|
||||
alertsDict[info.bundleID] = [NSMutableArray arrayWithObject:info];
|
||||
}
|
||||
}
|
||||
|
||||
NSMutableArray<AAApp *> *appEntries = [NSMutableArray array];
|
||||
|
||||
for (NSString *key in alertsDict) {
|
||||
NSString *name;
|
||||
|
||||
if (theAppsDict[key] && theAppsDict[key].length > 0) {
|
||||
name = theAppsDict[key];
|
||||
} else if ([key isEqual:@"com.apple.springboard"]) {
|
||||
name = @"SpringBoard";
|
||||
} else {
|
||||
name = key;
|
||||
}
|
||||
|
||||
NSSortDescriptor *titleSort = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES];
|
||||
NSSortDescriptor *messageSort = [NSSortDescriptor sortDescriptorWithKey:@"message" ascending:YES];
|
||||
NSMutableArray *sortedInfos = [NSMutableArray arrayWithArray:[alertsDict[key] sortedArrayUsingDescriptors:@[titleSort, messageSort]]];
|
||||
|
||||
AAApp *app = [[[AAApp alloc] initWithBundleID:key name:name infos:sortedInfos] autorelease];
|
||||
|
||||
[appEntries addObject:app];
|
||||
}
|
||||
|
||||
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
|
||||
NSMutableArray *tempApps = [NSMutableArray arrayWithArray:[appEntries sortedArrayUsingDescriptors:@[sort]]];
|
||||
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
|
||||
for (int i = 0; i < tempApps.count; i++) {
|
||||
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:1]];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.apps = tempApps;
|
||||
|
||||
self.appsDict = theAppsDict;
|
||||
|
||||
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
});
|
||||
});
|
||||
|
||||
self.shouldDelete = NO;
|
||||
}
|
||||
|
||||
-(void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (self.shouldDelete && self.selectedIndexPath) {
|
||||
[self.apps removeObjectAtIndex:self.selectedIndexPath.row];
|
||||
|
||||
[self.tableView deleteRowsAtIndexPaths:@[self.selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
|
||||
self.shouldDelete = NO;
|
||||
self.selectedIndexPath = nil;
|
||||
}
|
||||
}
|
||||
|
||||
-(void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
|
||||
self.tableView.frame = self.view.bounds;
|
||||
}
|
||||
|
||||
-(void)didDelete {
|
||||
self.shouldDelete = YES;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
return 1;
|
||||
}
|
||||
return self.apps.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.section == 0) {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"EnabledCell" forIndexPath:indexPath];
|
||||
|
||||
cell.textLabel.text = @"Enabled";
|
||||
|
||||
UISwitch *switchView = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
|
||||
[switchView addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
|
||||
NSUserDefaults *defaults = [[[NSUserDefaults alloc] initWithSuiteName:@"com.shiftcmdk.autoalertspreferences"] autorelease];
|
||||
|
||||
switchView.on = [defaults objectForKey:@"enabled"] == nil || [defaults boolForKey:@"enabled"];
|
||||
|
||||
cell.accessoryView = switchView;
|
||||
|
||||
return cell;
|
||||
} else {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppCell" forIndexPath:indexPath];
|
||||
|
||||
AAApp *app = [self.apps objectAtIndex:indexPath.row];
|
||||
|
||||
UIImage *icon = [UIImage _applicationIconImageForBundleIdentifier:app.bundleID format:0 scale:[UIScreen mainScreen].scale];
|
||||
|
||||
cell.imageView.image = icon;
|
||||
cell.textLabel.text = app.name;
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
self.selectedIndexPath = indexPath;
|
||||
|
||||
AAAppOverviewController *ctrl = [[[AAAppOverviewController alloc] init] autorelease];
|
||||
ctrl.app = [self.apps objectAtIndex:indexPath.row];
|
||||
ctrl.appsDict = self.appsDict;
|
||||
ctrl.deleteDelegate = self;
|
||||
|
||||
[self pushController:ctrl animate:YES];
|
||||
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
return @"General";
|
||||
}
|
||||
|
||||
if (section == 1) {
|
||||
return @"Apps";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
return @"Apps may need to be restarted after enabling or disabling this option.";
|
||||
}
|
||||
|
||||
if (section == 1) {
|
||||
return @"Apps with automated alerts will appear here.";
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return indexPath.section == 1;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
UIAlertController *deleteAlert = [UIAlertController alertControllerWithTitle:@"Delete alerts" message:[NSString stringWithFormat:@"Do you really want to delete all automated alerts for %@?", self.apps[indexPath.row].name] preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
CFNotificationCenterPostNotification(
|
||||
CFNotificationCenterGetDistributedCenter(),
|
||||
(CFStringRef)[NSString stringWithFormat:@"com.shiftcmdk.autoalerts.deletewithbundleid.%@", self.apps[indexPath.row].bundleID],
|
||||
NULL,
|
||||
NULL,
|
||||
YES
|
||||
);
|
||||
|
||||
[self.apps removeObjectAtIndex:indexPath.row];
|
||||
|
||||
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
|
||||
|
||||
[deleteAlert addAction:deleteAction];
|
||||
[deleteAlert addAction:cancelAction];
|
||||
|
||||
[self presentViewController:deleteAlert animated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)switchChanged:(UISwitch *)sender {
|
||||
NSUserDefaults *defaults = [[[NSUserDefaults alloc] initWithSuiteName:@"com.shiftcmdk.autoalertspreferences"] autorelease];
|
||||
|
||||
[defaults setBool:sender.isOn forKey:@"enabled"];
|
||||
|
||||
CFNotificationCenterPostNotification(
|
||||
CFNotificationCenterGetDistributedCenter(),
|
||||
(CFStringRef)@"com.shiftcmdk.autoalerts.toggle",
|
||||
NULL,
|
||||
NULL,
|
||||
YES
|
||||
);
|
||||
}
|
||||
|
||||
-(void)dealloc {
|
||||
[self.tableView removeFromSuperview];
|
||||
|
||||
self.tableView = nil;
|
||||
|
||||
self.apps = nil;
|
||||
|
||||
self.appsDict = nil;
|
||||
|
||||
self.selectedIndexPath = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
13
autoalertspreferences/Makefile
Normal file
13
autoalertspreferences/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
BUNDLE_NAME = AutoAlertsPreferences
|
||||
AutoAlertsPreferences_FILES = AARootListController.xm ../Model/AAAlertInfo.m ../AAAlertManager.m ../AACoreDataStack.m AAApp.m AAAppOverviewController.xm AAAlertOverviewController.xm
|
||||
AutoAlertsPreferences_INSTALL_PATH = /Library/PreferenceBundles
|
||||
AutoAlertsPreferences_FRAMEWORKS = UIKit
|
||||
AutoAlertsPreferences_PRIVATE_FRAMEWORKS = Preferences
|
||||
|
||||
include $(THEOS_MAKE_PATH)/bundle.mk
|
||||
|
||||
internal-stage::
|
||||
$(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END)
|
||||
$(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/AutoAlertsPreferences.plist$(ECHO_END)
|
||||
BIN
autoalertspreferences/Resources/AutoAlerts.momd/AutoAlerts.mom
Normal file
BIN
autoalertspreferences/Resources/AutoAlerts.momd/AutoAlerts.mom
Normal file
Binary file not shown.
Binary file not shown.
24
autoalertspreferences/Resources/Info.plist
Normal file
24
autoalertspreferences/Resources/Info.plist
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>AutoAlertsPreferences</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.shiftcmdk.autoalertspreferences</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>AARootListController</string>
|
||||
</dict>
|
||||
</plist>
|
||||
17
autoalertspreferences/Resources/Root.plist
Normal file
17
autoalertspreferences/Resources/Root.plist
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>items</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSGroupCell</string>
|
||||
<key>label</key>
|
||||
<string>AutoAlerts</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>title</key>
|
||||
<string>AutoAlerts</string>
|
||||
</dict>
|
||||
</plist>
|
||||
21
autoalertspreferences/entry.plist
Normal file
21
autoalertspreferences/entry.plist
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>entry</key>
|
||||
<dict>
|
||||
<key>bundle</key>
|
||||
<string>AutoAlertsPreferences</string>
|
||||
<key>cell</key>
|
||||
<string>PSLinkCell</string>
|
||||
<key>detail</key>
|
||||
<string>AARootListController</string>
|
||||
<key>icon</key>
|
||||
<string>icon.png</string>
|
||||
<key>isController</key>
|
||||
<true/>
|
||||
<key>label</key>
|
||||
<string>AutoAlerts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Reference in New Issue
Block a user