├── .gitignore ├── LICENSE ├── Makefile ├── Prefs ├── AXNAppearanceSettings.m ├── AXNController.h ├── AXNDebugController.m ├── AXNListItemsController.h ├── AXNListItemsController.m ├── AXNLocationController.m ├── Makefile ├── NSTask.h ├── Preferences.h ├── Preferences.m ├── Resources │ ├── Prefs.plist │ ├── axon.png │ ├── en.lproj │ │ └── Prefs.strings │ ├── icon.png │ ├── icon@2x.png │ └── ko.lproj │ │ └── Prefs.strings └── entry.plist ├── README.md ├── Tweak ├── AXNAppCell.h ├── AXNAppCell.m ├── AXNManager.h ├── AXNManager.m ├── AXNRequestWrapper.h ├── AXNRequestWrapper.m ├── AXNView.h ├── AXNView.m ├── Axon.plist ├── Makefile ├── Protocol.h ├── RandomHeaders.h ├── Tweak.h └── Tweak.xm └── control /.gitignore: -------------------------------------------------------------------------------- 1 | .theos 2 | obj 3 | .DS_Store 4 | /*.xcodeproj 5 | /packages 6 | /TODO -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Eva (Nepeta) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | include $(THEOS)/makefiles/common.mk 3 | 4 | SUBPROJECTS += Tweak Prefs 5 | 6 | include $(THEOS_MAKE_PATH)/aggregate.mk -------------------------------------------------------------------------------- /Prefs/AXNAppearanceSettings.m: -------------------------------------------------------------------------------- 1 | #import "Preferences.h" 2 | 3 | @implementation AXNAppearanceSettings 4 | 5 | -(UIColor *)tintColor { 6 | return [UIColor colorWithRed:0.169 green:0.184 blue:0.275 alpha:1.0]; 7 | } 8 | 9 | -(UIColor *)statusBarTintColor { 10 | return [UIColor whiteColor]; 11 | } 12 | 13 | -(UIColor *)navigationBarTitleColor { 14 | return [UIColor whiteColor]; 15 | } 16 | 17 | -(UIColor *)navigationBarTintColor { 18 | return [UIColor whiteColor]; 19 | } 20 | 21 | -(UIColor *)tableViewCellSeparatorColor { 22 | return [UIColor colorWithWhite:0 alpha:0]; 23 | } 24 | 25 | -(UIColor *)navigationBarBackgroundColor { 26 | return [UIColor colorWithRed:0.169 green:0.184 blue:0.275 alpha:1.0]; 27 | } 28 | 29 | -(BOOL)translucentNavigationBar { 30 | return NO; 31 | } 32 | 33 | @end -------------------------------------------------------------------------------- /Prefs/AXNController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import 4 | #import 5 | // #import 6 | #import 7 | #import 8 | 9 | #define PREFERENCE_IDENTIFIER @"/var/mobile/Library/Preferences/me.nepeta.axon.plist" 10 | 11 | 12 | @interface PSListController (Private) 13 | - (void)insertSpecifier:(id)arg1 atIndex:(long long)arg2 animated:(bool)arg3; 14 | @end 15 | 16 | @interface PSSpecifier (Private) 17 | - (void)loadValuesAndTitlesFromDataSource; 18 | - (void)setValues:(id)arg1 titles:(id)arg2; 19 | @end 20 | 21 | @interface PSEditableListController : PSListController 22 | -(void)editDoneTapped; 23 | -(id)_editButtonBarItem; 24 | -(void)_setEditable:(BOOL)arg1 animated:(BOOL)arg2 ; 25 | -(BOOL)performDeletionActionForSpecifier:(id)arg1 ; 26 | -(void)setEditingButtonHidden:(BOOL)arg1 animated:(BOOL)arg2 ; 27 | -(void)setEditButtonEnabled:(BOOL)arg1 ; 28 | -(void)didLock; 29 | -(void)showController:(id)arg1 animate:(BOOL)arg2 ; 30 | -(void)_updateNavigationBar; 31 | -(id)init; 32 | -(void)viewWillAppear:(BOOL)arg1 ; 33 | -(id)tableView:(id)arg1 willSelectRowAtIndexPath:(id)arg2 ; 34 | -(long long)tableView:(id)arg1 editingStyleForRowAtIndexPath:(id)arg2 ; 35 | -(void)tableView:(id)arg1 commitEditingStyle:(long long)arg2 forRowAtIndexPath:(id)arg3 ; 36 | -(void)setEditable:(BOOL)arg1 ; 37 | -(void)suspend; 38 | -(BOOL)editable; 39 | @end 40 | -------------------------------------------------------------------------------- /Prefs/AXNDebugController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AXNController.h" 3 | 4 | @interface AXNDebugController : PSListController 5 | @end 6 | 7 | @implementation AXNDebugController 8 | -(id)specifiers { 9 | if(_specifiers == nil) 10 | { 11 | NSMutableArray *specifiers = [[NSMutableArray alloc] init]; 12 | 13 | [specifiers addObject:({ 14 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Debug Options" target:self set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 15 | [specifier.properties setValue:@"The debug options can help you solve issue!.." forKey:@"footerText"]; 16 | specifier; 17 | })]; 18 | 19 | [specifiers addObject:({ 20 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Clear all notification" target:self set:nil get:nil detail:nil cell:PSButtonCell edit:nil]; 21 | specifier->action = @selector(clearAll); 22 | specifier; 23 | })]; 24 | [specifiers addObject:({ 25 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Save notification list" target:self set:nil get:nil detail:nil cell:PSButtonCell edit:nil]; 26 | specifier->action = @selector(saveNotification); 27 | specifier; 28 | })]; 29 | [specifiers addObject:({ 30 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Report Issue" target:self set:nil get:nil detail:nil cell:PSButtonCell edit:nil]; 31 | specifier->action = @selector(report); 32 | specifier; 33 | })]; 34 | 35 | _specifiers = [specifiers copy]; 36 | } 37 | 38 | return _specifiers; 39 | } 40 | 41 | -(void)clearAll { 42 | [[objc_getClass("NSDistributedNotificationCenter") defaultCenter] postNotificationName:@"me.nepeta.axon.clearAllNotification" object:nil]; 43 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" message:@"All notifications registered with Axon have been removed." preferredStyle:UIAlertControllerStyleAlert]; 44 | [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { 45 | }]]; 46 | return [self presentViewController:alert animated:YES completion:nil]; 47 | } 48 | -(void)saveNotification { 49 | [[objc_getClass("NSDistributedNotificationCenter") defaultCenter] postNotificationName:@"me.nepeta.axon.saveNotification" object:nil]; 50 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" message:@"All notifications registered with Axon have been saved to /var/mobile/Documents/AxonDebug.txt" preferredStyle:UIAlertControllerStyleAlert]; 51 | [alert addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { 52 | }]]; 53 | return [self presentViewController:alert animated:YES completion:nil]; 54 | } 55 | -(void)report { 56 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString: @"https://github.com/Baw-Appie/Axon/issues/new"] options:@{} completionHandler:nil]; 57 | } 58 | @end 59 | -------------------------------------------------------------------------------- /Prefs/AXNListItemsController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AXNListItemsController : PSListItemsController 4 | 5 | @property (nonatomic, retain) UILabel *titleLabel; 6 | 7 | @end -------------------------------------------------------------------------------- /Prefs/AXNListItemsController.m: -------------------------------------------------------------------------------- 1 | #import "AXNListItemsController.h" 2 | 3 | @implementation AXNListItemsController 4 | 5 | - (instancetype)init { 6 | self = [super init]; 7 | 8 | if (self) { 9 | self.navigationItem.titleView = [UIView new]; 10 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,10,10)]; 11 | self.titleLabel.font = [UIFont boldSystemFontOfSize:17]; 12 | self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; 13 | self.titleLabel.text = self.navigationItem.title; 14 | self.titleLabel.textColor = [UIColor whiteColor]; 15 | self.titleLabel.textAlignment = NSTextAlignmentCenter; 16 | [self.navigationItem.titleView addSubview:self.titleLabel]; 17 | 18 | [NSLayoutConstraint activateConstraints:@[ 19 | [self.titleLabel.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor], 20 | [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor], 21 | [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor], 22 | [self.titleLabel.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor], 23 | ]]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | - (void)viewWillAppear:(BOOL)animated { 30 | [super viewWillAppear:animated]; 31 | [self.titleLabel setText:self.navigationItem.title]; 32 | } 33 | 34 | @end -------------------------------------------------------------------------------- /Prefs/AXNLocationController.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AXNController.h" 3 | NSMutableDictionary *prefs; 4 | 5 | @interface AXNLocationController : PSListController { 6 | PSSpecifier *_autoLayoutLocationSpecifier; 7 | PSSpecifier *_yAxisSpecifier; 8 | } 9 | @property (nonatomic, strong) PSSpecifier *autoLayoutLocationSpecifier; 10 | @property (nonatomic, strong) PSSpecifier *yAxisSpecifier; 11 | @end 12 | 13 | 14 | 15 | @implementation AXNLocationController 16 | -(id)specifiers { 17 | if(_specifiers == nil) 18 | { 19 | NSMutableArray *specifiers = [[NSMutableArray alloc] init]; 20 | 21 | if(![[NSFileManager defaultManager] fileExistsAtPath:PREFERENCE_IDENTIFIER]) prefs = [[NSMutableDictionary alloc] init]; 22 | else prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:PREFERENCE_IDENTIFIER]; 23 | 24 | [specifiers addObject:({ 25 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Location" target:self set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 26 | specifier; 27 | })]; 28 | 29 | [specifiers addObject:({ 30 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Auto Layout" target:self set:@selector(setSwitch:forSpecifier:) get:@selector(getSwitch:) detail:nil cell:PSSwitchCell edit:nil]; 31 | [specifier.properties setValue:@"autoLayout" forKey:@"displayIdentifier"]; 32 | specifier; 33 | })]; 34 | 35 | 36 | [specifiers addObject:({ 37 | PSSpecifier *specifier = [PSSpecifier preferenceSpecifierNamed:@"Y-Axis" target:self set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 38 | specifier; 39 | })]; 40 | 41 | self.autoLayoutLocationSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Location" target:self set:@selector(setNumber:forSpecifier:) get:@selector(getSwitch:) detail:nil cell:PSSegmentCell edit:nil]; 42 | [self.autoLayoutLocationSpecifier setValues:@[@0, @1] titles:@[@"Top", @"Bottom (Beta)"]]; 43 | [self.autoLayoutLocationSpecifier.properties setValue:@"location" forKey:@"displayIdentifier"]; 44 | 45 | self.yAxisSpecifier = [PSSpecifier preferenceSpecifierNamed:@"size" target:self set:@selector(setNumber:forSpecifier:) get:@selector(getSwitch:) detail:Nil cell:PSSliderCell edit:Nil]; 46 | [self.yAxisSpecifier setProperty:@"yAxis" forKey:@"displayIdentifier"]; 47 | [self.yAxisSpecifier setProperty:@500 forKey:@"default"]; 48 | [self.yAxisSpecifier setProperty:@0 forKey:@"min"]; 49 | [self.yAxisSpecifier setProperty:[NSNumber numberWithFloat:[UIScreen mainScreen].bounds.size.height] forKey:@"max"]; 50 | [self.yAxisSpecifier setProperty:@YES forKey:@"showValue"]; 51 | 52 | if([[self getValue:@"autoLayout"] isEqual:@1]) { 53 | [specifiers addObject:self.autoLayoutLocationSpecifier]; 54 | } else { 55 | [specifiers addObject:self.yAxisSpecifier]; 56 | } 57 | 58 | _specifiers = [specifiers copy]; 59 | } 60 | 61 | return _specifiers; 62 | } 63 | 64 | -(void)setSwitch:(NSNumber *)value forSpecifier:(PSSpecifier *)specifier { 65 | prefs[[specifier propertyForKey:@"displayIdentifier"]] = [NSNumber numberWithBool:[value boolValue]]; 66 | [[prefs copy] writeToFile:PREFERENCE_IDENTIFIER atomically:FALSE]; 67 | 68 | if([[specifier propertyForKey:@"displayIdentifier"] isEqualToString:@"autoLayout"]) { 69 | if([[self getValue:@"autoLayout"] isEqual:@1]) { 70 | [self removeSpecifier:self.yAxisSpecifier animated:true]; 71 | [self addSpecifier:self.autoLayoutLocationSpecifier animated:true]; 72 | } else { 73 | [self removeSpecifier:self.autoLayoutLocationSpecifier animated:true]; 74 | [self addSpecifier:self.yAxisSpecifier animated:true]; 75 | } 76 | } 77 | } 78 | -(void)setNumber:(NSNumber *)value forSpecifier:(PSSpecifier *)specifier { 79 | prefs[[specifier propertyForKey:@"displayIdentifier"]] = value; 80 | [[prefs copy] writeToFile:PREFERENCE_IDENTIFIER atomically:FALSE]; 81 | } 82 | -(NSNumber *)getSwitch:(PSSpecifier *)specifier { 83 | return [self getValue:[specifier propertyForKey:@"displayIdentifier"]]; 84 | } 85 | -(NSNumber *)getValue:(NSString *)name { 86 | return prefs[name] ? [NSNumber numberWithInteger:[prefs[name] intValue]] : @(1); 87 | } 88 | @end 89 | -------------------------------------------------------------------------------- /Prefs/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS = arm64 arm64e 2 | TARGET = iphone:12.2:12.2 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | 6 | BUNDLE_NAME = AxonPrefs 7 | $(BUNDLE_NAME)_FILES = Preferences.m AXNAppearanceSettings.m AXNListItemsController.m AXNDebugController.m AXNLocationController.m 8 | $(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles 9 | $(BUNDLE_NAME)_FRAMEWORKS = UIKit 10 | $(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences 11 | # $(BUNDLE_NAME)_EXTRA_FRAMEWORKS = Cephei CepheiPrefs 12 | 13 | include $(THEOS_MAKE_PATH)/bundle.mk 14 | 15 | internal-stage:: 16 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 17 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/$(BUNDLE_NAME).plist$(ECHO_END) -------------------------------------------------------------------------------- /Prefs/NSTask.h: -------------------------------------------------------------------------------- 1 | @interface NSTask : NSObject 2 | 3 | @property (copy) NSArray *arguments; 4 | @property (copy) NSString *currentDirectoryPath; 5 | @property (copy) NSDictionary *environment; 6 | @property (copy) NSString *launchPath; 7 | @property (readonly) int processIdentifier; 8 | @property long long qualityOfService; 9 | @property (getter=isRunning, readonly) bool running; 10 | @property (retain) id standardError; 11 | @property (retain) id standardInput; 12 | @property (retain) id standardOutput; 13 | @property (copy) id /* block */ terminationHandler; 14 | @property (readonly) long long terminationReason; 15 | @property (readonly) int terminationStatus; 16 | 17 | + (id)currentTaskDictionary; 18 | + (id)launchedTaskWithDictionary:(id)arg1; 19 | + (id)launchedTaskWithLaunchPath:(id)arg1 arguments:(id)arg2; 20 | 21 | - (id)init; 22 | - (void)interrupt; 23 | - (bool)isRunning; 24 | - (void)launch; 25 | - (int)processIdentifier; 26 | - (long long)qualityOfService; 27 | - (bool)resume; 28 | - (bool)suspend; 29 | - (long long)suspendCount; 30 | - (void)terminate; 31 | - (id /* block */)terminationHandler; 32 | - (long long)terminationReason; 33 | - (int)terminationStatus; 34 | 35 | @end -------------------------------------------------------------------------------- /Prefs/Preferences.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | // #import 4 | // #import 5 | // #import 6 | #import "NSTask.h" 7 | 8 | @interface AXNAppearanceSettings : PSListController 9 | // @interface AXNAppearanceSettings : HBAppearanceSettings 10 | 11 | @end 12 | 13 | // @interface AXNPrefsListController : HBRootListController { 14 | @interface AXNPrefsListController : PSListController { 15 | UITableView * _table; 16 | } 17 | 18 | @property (nonatomic, retain) UIBarButtonItem *respringButton; 19 | @property (nonatomic, retain) UIView *headerView; 20 | @property (nonatomic, retain) UIImageView *headerImageView; 21 | @property (nonatomic, retain) UILabel *titleLabel; 22 | @property (nonatomic, retain) UIImageView *iconView; 23 | - (void)respring:(id)sender; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Prefs/Preferences.m: -------------------------------------------------------------------------------- 1 | #import "Preferences.h" 2 | 3 | @implementation AXNPrefsListController 4 | @synthesize respringButton; 5 | 6 | - (instancetype)init { 7 | self = [super init]; 8 | 9 | // if (self) { 10 | // AXNAppearanceSettings *appearanceSettings = [[AXNAppearanceSettings alloc] init]; 11 | // self.hb_appearanceSettings = appearanceSettings; 12 | // self.respringButton = [[UIBarButtonItem alloc] initWithTitle:@"Respring" 13 | // style:UIBarButtonItemStylePlain 14 | // target:self 15 | // action:@selector(respring:)]; 16 | // self.respringButton.tintColor = [UIColor whiteColor]; 17 | // self.navigationItem.rightBarButtonItem = self.respringButton; 18 | // 19 | // self.navigationItem.titleView = [UIView new]; 20 | // self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,10,10)]; 21 | // self.titleLabel.font = [UIFont boldSystemFontOfSize:17]; 22 | // self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; 23 | // self.titleLabel.text = @"Axon"; 24 | // self.titleLabel.textColor = [UIColor whiteColor]; 25 | // self.titleLabel.textAlignment = NSTextAlignmentCenter; 26 | // [self.navigationItem.titleView addSubview:self.titleLabel]; 27 | // 28 | // self.iconView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,10,10)]; 29 | // self.iconView.contentMode = UIViewContentModeScaleAspectFit; 30 | // self.iconView.image = [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/AxonPrefs.bundle/icon@2x.png"]; 31 | // self.iconView.translatesAutoresizingMaskIntoConstraints = NO; 32 | // self.iconView.alpha = 0.0; 33 | // [self.navigationItem.titleView addSubview:self.iconView]; 34 | // 35 | // [NSLayoutConstraint activateConstraints:@[ 36 | // [self.titleLabel.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor], 37 | // [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor], 38 | // [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor], 39 | // [self.titleLabel.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor], 40 | // [self.iconView.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor], 41 | // [self.iconView.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor], 42 | // [self.iconView.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor], 43 | // [self.iconView.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor], 44 | // ]]; 45 | // } 46 | 47 | return self; 48 | } 49 | 50 | - (id)specifiers { 51 | if(_specifiers == nil) { 52 | _specifiers = [[self loadSpecifiersFromPlistName:@"Prefs" target:self] retain]; 53 | // BOOL iOS13 = [[[UIDevice currentDevice] systemVersion] floatValue] >= 13; 54 | // for (PSSpecifier *specifier in _specifiers) { 55 | // if([[specifier propertyForKey:@"id"] isEqualToString:@"BADGES"] && iOS13) [specifier setProperty:@"Note: Some features are not available for iOS 13 and later." forKey:@"footerText"]; 56 | // if([[specifier propertyForKey:@"id"] isEqualToString:@"SHOW_BACKGROUND"] && iOS13) [specifier setProperty:@NO forKey:@"enabled"]; 57 | // } 58 | } 59 | return _specifiers; 60 | } 61 | 62 | // - (void)viewDidLoad { 63 | // [super viewDidLoad]; 64 | // 65 | // self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)]; 66 | // self.headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,200,200)]; 67 | // self.headerImageView.contentMode = UIViewContentModeScaleAspectFill; 68 | // self.headerImageView.image = [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/AxonPrefs.bundle/axon.png"]; 69 | // self.headerImageView.translatesAutoresizingMaskIntoConstraints = NO; 70 | // 71 | // [self.headerView addSubview:self.headerImageView]; 72 | // [NSLayoutConstraint activateConstraints:@[ 73 | // [self.headerImageView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor], 74 | // [self.headerImageView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor], 75 | // [self.headerImageView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor], 76 | // [self.headerImageView.bottomAnchor constraintEqualToAnchor:self.headerView.bottomAnchor], 77 | // ]]; 78 | // 79 | // _table.tableHeaderView = self.headerView; 80 | // } 81 | // 82 | // - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 83 | // tableView.tableHeaderView = self.headerView; 84 | // return [super tableView:tableView cellForRowAtIndexPath:indexPath]; 85 | // } 86 | // 87 | // - (void)viewWillAppear:(BOOL)animated { 88 | // [super viewWillAppear:animated]; 89 | // 90 | // CGRect frame = self.table.bounds; 91 | // frame.origin.y = -frame.size.height; 92 | // 93 | // self.navigationController.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:0.169 green:0.184 blue:0.275 alpha:1.0]; 94 | // [self.navigationController.navigationController.navigationBar setShadowImage: [UIImage new]]; 95 | // self.navigationController.navigationController.navigationBar.tintColor = [UIColor whiteColor]; 96 | // self.navigationController.navigationController.navigationBar.translucent = NO; 97 | // } 98 | // 99 | // - (void)viewDidAppear:(BOOL)animated { 100 | // [super viewDidAppear:animated]; 101 | // 102 | // [self.navigationController.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}]; 103 | // } 104 | // 105 | // - (void)viewWillDisappear:(BOOL)animated { 106 | // [super viewWillDisappear:animated]; 107 | // 108 | // [self.navigationController.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]}]; 109 | // } 110 | // 111 | // - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 112 | // CGFloat offsetY = scrollView.contentOffset.y; 113 | // 114 | // if (offsetY > 200) { 115 | // [UIView animateWithDuration:0.2 animations:^{ 116 | // self.iconView.alpha = 1.0; 117 | // self.titleLabel.alpha = 0.0; 118 | // }]; 119 | // } else { 120 | // [UIView animateWithDuration:0.2 animations:^{ 121 | // self.iconView.alpha = 0.0; 122 | // self.titleLabel.alpha = 1.0; 123 | // }]; 124 | // } 125 | // 126 | // if (offsetY > 0) offsetY = 0; 127 | // self.headerImageView.frame = CGRectMake(0, offsetY, self.headerView.frame.size.width, 200 - offsetY); 128 | // } 129 | 130 | - (void)respring:(id)sender { 131 | NSTask *t = [[[NSTask alloc] init] autorelease]; 132 | [t setLaunchPath:@"/usr/bin/killall"]; 133 | [t setArguments:[NSArray arrayWithObjects:@"backboardd", nil]]; 134 | [t launch]; 135 | } 136 | @end 137 | -------------------------------------------------------------------------------- /Prefs/Resources/Prefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 23 | 24 | cell 25 | PSSwitchCell 26 | default 27 | 28 | defaults 29 | me.nepeta.axon 30 | label 31 | ENABLED_RESPRING 32 | key 33 | Enabled 34 | alternateColors 35 | 36 | PostNotification 37 | me.nepeta.axon/ReloadPrefs 38 | 39 | 40 | cell 41 | PSSwitchCell 42 | default 43 | 44 | defaults 45 | me.nepeta.axon 46 | label 47 | HAPTIC_FEEDBACK 48 | key 49 | HapticFeedback 50 | alternateColors 51 | 52 | PostNotification 53 | me.nepeta.axon/ReloadPrefs 54 | 55 | 56 | cell 57 | PSLinkListCell 58 | detail 59 | AXNListItemsController 60 | default 61 | 0 62 | defaults 63 | me.nepeta.axon 64 | label 65 | DARK_MODE 66 | key 67 | DarkMode 68 | validValues 69 | 70 | 0 71 | 1 72 | 2 73 | 74 | validTitles 75 | 76 | SYSTEM 77 | LIGHT 78 | DARK 79 | 80 | PostNotification 81 | me.nepeta.axon/ReloadPrefs 82 | 83 | 84 | cell 85 | PSLinkListCell 86 | detail 87 | AXNListItemsController 88 | default 89 | 0 90 | defaults 91 | me.nepeta.axon 92 | label 93 | STYLE 94 | key 95 | Style 96 | validValues 97 | 98 | 0 99 | 1 100 | 2 101 | 3 102 | 4 103 | 5 104 | 105 | validTitles 106 | 107 | DEFAULT 108 | PACKED 109 | COMPACT 110 | TINY 111 | GROUP 112 | ROUNEDED_GROUP 113 | 114 | PostNotification 115 | me.nepeta.axon/ReloadPrefs 116 | 117 | 118 | detail 119 | AXNLocationController 120 | cell 121 | PSLinkListCell 122 | label 123 | LOCATION 124 | 125 | 126 | 127 | cell 128 | PSGroupCell 129 | label 130 | VERTICAL 131 | footerText 132 | VERTICAL_INFO 133 | isStaticText 134 | 135 | 136 | 137 | cell 138 | PSSwitchCell 139 | default 140 | 141 | defaults 142 | me.nepeta.axon 143 | label 144 | VERTICAL_RESPRING 145 | key 146 | Vertical 147 | alternateColors 148 | 149 | PostNotification 150 | me.nepeta.axon/ReloadPrefs 151 | 152 | 153 | cell 154 | PSSegmentCell 155 | default 156 | 0 157 | defaults 158 | me.nepeta.axon 159 | key 160 | VerticalPosition 161 | validValues 162 | 163 | 0 164 | 1 165 | 166 | validTitles 167 | 168 | LEFT 169 | RIGHT 170 | 171 | alignment 172 | 2 173 | PostNotification 174 | me.nepeta.axon/ReloadPrefs 175 | 176 | 177 | 178 | cell 179 | PSGroupCell 180 | label 181 | SORTING 182 | isStaticText 183 | 184 | 185 | 186 | cell 187 | PSSegmentCell 188 | default 189 | 0 190 | defaults 191 | me.nepeta.axon 192 | key 193 | SortingMode 194 | validValues 195 | 196 | 0 197 | 1 198 | 2 199 | 200 | validTitles 201 | 202 | BY_DATE 203 | BY_COUNT 204 | BY_NAME 205 | 206 | alignment 207 | 3 208 | PostNotification 209 | me.nepeta.axon/ReloadPrefs 210 | 211 | 212 | 213 | 214 | 215 | cell 216 | PSGroupCell 217 | label 218 | ICON_STYLE 219 | isStaticText 220 | 221 | 222 | 223 | cell 224 | PSSegmentCell 225 | default 226 | 0 227 | defaults 228 | me.nepeta.axon 229 | key 230 | iconStyle 231 | validValues 232 | 233 | 0 234 | 1 235 | 2 236 | 237 | validTitles 238 | 239 | DEFAULT 240 | ROUNDED 241 | SQUARE 242 | 243 | alignment 244 | 3 245 | PostNotification 246 | me.nepeta.axon/ReloadPrefs 247 | 248 | 249 | 250 | 251 | cell 252 | PSGroupCell 253 | label 254 | SHOW 255 | isStaticText 256 | 257 | 258 | 259 | cell 260 | PSSegmentCell 261 | default 262 | 0 263 | defaults 264 | me.nepeta.axon 265 | key 266 | ShowByDefault 267 | validValues 268 | 269 | 0 270 | 1 271 | 2 272 | 3 273 | 274 | validTitles 275 | 276 | NOTHING 277 | LATEST_NOTIFICATION 278 | FIRST_SECTION 279 | SELECTED_SECTION 280 | 281 | alignment 282 | 3 283 | PostNotification 284 | me.nepeta.axon/ReloadPrefs 285 | 286 | 287 | 288 | cell 289 | PSGroupCell 290 | label 291 | SELECTION_STYLE 292 | isStaticText 293 | 294 | 295 | 296 | cell 297 | PSSegmentCell 298 | default 299 | 0 300 | defaults 301 | me.nepeta.axon 302 | key 303 | SelectionStyle 304 | validValues 305 | 306 | 0 307 | 1 308 | 2 309 | 310 | validTitles 311 | 312 | BACKGROUND 313 | DIM 314 | NONE 315 | 316 | alignment 317 | 2 318 | PostNotification 319 | me.nepeta.axon/ReloadPrefs 320 | 321 | 322 | 323 | cell 324 | PSGroupCell 325 | label 326 | BLUR 327 | isStaticText 328 | 329 | 330 | 331 | cell 332 | PSSwitchCell 333 | default 334 | 335 | defaults 336 | me.nepeta.axon 337 | label 338 | ADD_BLUR 339 | key 340 | addBlur 341 | alternateColors 342 | 343 | PostNotification 344 | me.nepeta.axon/ReloadPrefs 345 | 346 | 347 | 348 | cell 349 | PSGroupCell 350 | label 351 | BADGES 352 | isStaticText 353 | 354 | 355 | 356 | cell 357 | PSSwitchCell 358 | default 359 | 360 | defaults 361 | me.nepeta.axon 362 | label 363 | ENABLED 364 | key 365 | BadgesEnabled 366 | alternateColors 367 | 368 | PostNotification 369 | me.nepeta.axon/ReloadPrefs 370 | 371 | 372 | cell 373 | PSSwitchCell 374 | default 375 | 376 | defaults 377 | me.nepeta.axon 378 | label 379 | SHOW_BACKGROUND 380 | key 381 | BadgesShowBackground 382 | alternateColors 383 | 384 | PostNotification 385 | me.nepeta.axon/ReloadPrefs 386 | 387 | 388 | 389 | cell 390 | PSGroupCell 391 | label 392 | SPACING 393 | isStaticText 394 | 395 | 396 | 397 | cell 398 | PSSliderCell 399 | default 400 | 10 401 | defaults 402 | me.nepeta.axon 403 | key 404 | Spacing 405 | min 406 | 0 407 | max 408 | 20 409 | showValue 410 | 411 | isSegmented 412 | 413 | PostNotification 414 | me.nepeta.axon/ReloadPrefs 415 | 416 | 417 | 418 | cell 419 | PSGroupCell 420 | label 421 | ALIGNMENT 422 | isStaticText 423 | 424 | 425 | 426 | cell 427 | PSSegmentCell 428 | default 429 | 1 430 | defaults 431 | me.nepeta.axon 432 | key 433 | Alignment 434 | validValues 435 | 436 | 0 437 | 1 438 | 2 439 | 440 | validTitles 441 | 442 | LEFT 443 | CENTER 444 | RIGHT 445 | 446 | alignment 447 | 3 448 | PostNotification 449 | me.nepeta.axon/ReloadPrefs 450 | 451 | 452 | 453 | 454 | cell 455 | PSGroupCell 456 | footerText 457 | Axon by Nepeta and BawAppie, KritantaDev 458 | isStaticText 459 | 460 | 461 | 471 | 472 | detail 473 | AXNDebugController 474 | cell 475 | PSLinkListCell 476 | label 477 | DEBUG 478 | 479 | 480 | action 481 | respring: 482 | cell 483 | PSButtonCell 484 | label 485 | RESPRING 486 | 487 | 497 | 498 | title 499 | Axon 500 | 501 | 502 | -------------------------------------------------------------------------------- /Prefs/Resources/axon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baw-Appie/Axon/23716151aa5b4c8cd9f466eb1d6d5c539e2a9291/Prefs/Resources/axon.png -------------------------------------------------------------------------------- /Prefs/Resources/en.lproj/Prefs.strings: -------------------------------------------------------------------------------- 1 | { 2 | "ENABLED_RESPRING" = "Enabled (Respring required)"; 3 | "VERTICAL" = "Vertical mode"; 4 | "VERTICAL_INFO" = "Rotates Axon by 90 deg, puts it to one of the sides and makes your notification smaller. Respring required. Experimental."; 5 | "VERTICAL_RESPRING" = "Vertical (Respring required)"; 6 | "ENABLED" = "Enabled"; 7 | "HAPTIC_FEEDBACK" = "Haptic feedback"; 8 | "DARK_MODE" = "Dark mode"; 9 | 10 | "SYSTEM" = "System"; 11 | "LIGHT" = "Light"; 12 | "DARK" = "Dark"; 13 | 14 | "STYLE" = "Style"; 15 | "DEFAULT" = "Default"; 16 | "PACKED" = "Packed"; 17 | "COMPACT" = "Compact"; 18 | "TINY" = "Tiny"; 19 | "GROUP" = "Group (Beta, Respring required)"; 20 | "ROUNEDED_GROUP" = "Rounded Group (Beta, Respring required)"; 21 | 22 | "SHOW" = "Show by default"; 23 | "NOTHING" = "Nothing"; 24 | "LATEST_NOTIFICATION" = "Latest notification"; 25 | "FIRST_SECTION" = "First section"; 26 | "SELECTED_SECTION" = "Selected section"; 27 | 28 | "SORTING" = "Sorting"; 29 | "BY_DATE" = "Latest"; 30 | "BY_NAME" = "By app name"; 31 | "BY_COUNT" = "By count"; 32 | 33 | "ICON_STYLE" = "Icon style"; 34 | "ROUNDED" = "Rounded"; 35 | "SQUARE" = "Square"; 36 | 37 | "SELECTION_STYLE" = "Selection style"; 38 | "BACKGROUND" = "Add background"; 39 | "DIM" = "Dim others"; 40 | "NONE" = "None"; 41 | 42 | "ADD_BLUR" = "Add Blur"; 43 | 44 | "LOCATION" = "Location"; 45 | "TOP" = "Top"; 46 | "BOTTOM" = "Bottom (Beta)"; 47 | 48 | "BADGES" = "Badges"; 49 | "SHOW_BACKGROUND" = "Show background"; 50 | 51 | "SPACING" = "Spacing"; 52 | 53 | "ALIGNMENT" = "Alignment"; 54 | "LEFT" = "Left"; 55 | "CENTER" = "Center"; 56 | "RIGHT" = "Right"; 57 | 58 | "CREDITS_1" = "Ahmed Bousrih"; 59 | "CREDITS_1_INFO" = "Designed the icon and banners."; 60 | 61 | "RESPRING" = "Respring"; 62 | "DEBUG" = "Debug options"; 63 | "SOURCE_CODE" = "Source code"; 64 | "DONATE_TO_NEPETA" = "Donate to Nepeta"; 65 | "SUPPORT_ME" = "Support me!"; 66 | } 67 | -------------------------------------------------------------------------------- /Prefs/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baw-Appie/Axon/23716151aa5b4c8cd9f466eb1d6d5c539e2a9291/Prefs/Resources/icon.png -------------------------------------------------------------------------------- /Prefs/Resources/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baw-Appie/Axon/23716151aa5b4c8cd9f466eb1d6d5c539e2a9291/Prefs/Resources/icon@2x.png -------------------------------------------------------------------------------- /Prefs/Resources/ko.lproj/Prefs.strings: -------------------------------------------------------------------------------- 1 | { 2 | "ENABLED_RESPRING" = "활성화 (리스프링 필요)"; 3 | "VERTICAL" = "수직 모드"; 4 | "VERTICAL_INFO" = "Axon을 90도 회전시킵니다. 알림의 한쪽이 작게 보이게 됩니다. 리스프링 필요. 실험적 기능."; 5 | "VERTICAL_RESPRING" = "수직 모드 (리스프링 필요)"; 6 | "ENABLED" = "활성화"; 7 | "HAPTIC_FEEDBACK" = "햅틱 피드백"; 8 | "DARK_MODE" = "다크 모드"; 9 | 10 | "SYSTEM" = "시스템"; 11 | "LIGHT" = "라이트"; 12 | "DARK" = "다크"; 13 | 14 | "STYLE" = "스타일"; 15 | "DEFAULT" = "기본"; 16 | "PACKED" = "압축된"; 17 | "COMPACT" = "컴팩트"; 18 | "TINY" = "작은"; 19 | "GROUP" = "그룹 (베타, 리스프링 필요)"; 20 | "ROUNEDED_GROUP" = "동그란 그룹 (베타, 리스프링 필요)"; 21 | 22 | "SHOW" = "기본으로 표시"; 23 | "NOTHING" = "안함"; 24 | "LATEST_NOTIFICATION" = "마지막 알림"; 25 | "FIRST_SECTION" = "첫 섹션"; 26 | "SELECTED_SECTION" = "선택된 섹션"; 27 | 28 | "SORTING" = "정렬"; 29 | "BY_DATE" = "최신순"; 30 | "BY_NAME" = "앱 이름순"; 31 | "BY_COUNT" = "갯수순"; 32 | 33 | "ICON_STYLE" = "아이콘 스타일"; 34 | "ROUNDED" = "둥글게"; 35 | "SQUARE" = "각지게"; 36 | 37 | "SELECTION_STYLE" = "선택 스타일"; 38 | "BACKGROUND" = "배경 추가"; 39 | "DIM" = "다른것 어둡게"; 40 | "NONE" = "없음"; 41 | 42 | "ADD_BLUR" = "흐림 효과 추가"; 43 | 44 | "LOCATION" = "위치"; 45 | "TOP" = "위"; 46 | "BOTTOM" = "아래 (베타)"; 47 | 48 | "BADGES" = "뱃지"; 49 | "SHOW_BACKGROUND" = "배경 보이기"; 50 | 51 | "SPACING" = "간격"; 52 | 53 | "ALIGNMENT" = "정렬"; 54 | "LEFT" = "왼쪽"; 55 | "CENTER" = "중앙"; 56 | "RIGHT" = "오른쪽"; 57 | 58 | "CREDITS_1" = "Ahmed Bousrih"; 59 | "CREDITS_1_INFO" = "아이콘과 배너 디자인"; 60 | 61 | "RESPRING" = "리스프링"; 62 | "DEBUG" = "디버그 옵션"; 63 | "SOURCE_CODE" = "소스 코드"; 64 | "DONATE_TO_NEPETA" = "Nepeta에게 후원"; 65 | "SUPPORT_ME" = "저를 지원해주세요!"; 66 | } 67 | -------------------------------------------------------------------------------- /Prefs/entry.plist: -------------------------------------------------------------------------------- 1 | { 2 | entry = { 3 | bundle = AxonPrefs; 4 | cell = PSLinkCell; 5 | detail = AXNPrefsListController; 6 | isController = 1; 7 | label = Axon; 8 | icon = icon.png; 9 | }; 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Axon 2 | 3 | A tweak that does something weird to notifications. -------------------------------------------------------------------------------- /Tweak/AXNAppCell.h: -------------------------------------------------------------------------------- 1 | @interface MPArtworkColorAnalyzer : NSObject 2 | - (void)analyzeWithCompletionHandler:(id /* block */)arg1; 3 | - (id)initWithImage:(id)arg1 algorithm:(long long)arg2; 4 | @end 5 | 6 | typedef NS_ENUM(NSInteger, MTMaterialRecipe) { 7 | MTMaterialRecipeNone, 8 | MTMaterialRecipeNotifications, 9 | MTMaterialRecipeWidgetHosts, 10 | MTMaterialRecipeWidgets, 11 | MTMaterialRecipeControlCenterModules, 12 | MTMaterialRecipeSwitcherContinuityItem, 13 | MTMaterialRecipePreviewBackground, 14 | MTMaterialRecipeNotificationsDark, 15 | MTMaterialRecipeControlCenterModulesSheer 16 | }; 17 | 18 | typedef NS_OPTIONS(NSUInteger, MTMaterialOptions) { 19 | MTMaterialOptionsNone = 0, 20 | MTMaterialOptionsGamma = 1 << 0, 21 | MTMaterialOptionsBlur = 1 << 1, 22 | MTMaterialOptionsZoom = 1 << 2, 23 | MTMaterialOptionsLuminanceMap = 1 << 3, 24 | MTMaterialOptionsBaseOverlay = 1 << 4, 25 | MTMaterialOptionsPrimaryOverlay = 1 << 5, 26 | MTMaterialOptionsSecondaryOverlay = 1 << 6, 27 | MTMaterialOptionsAuxiliaryOverlay = 1 << 7, 28 | MTMaterialOptionsCaptureOnly = 1 << 8 29 | }; 30 | 31 | @interface MTMaterialView : UIView 32 | +(id)materialViewWithRecipe:(long long)arg1 options:(unsigned long long)arg2 ; 33 | +(id)materialViewWithRecipe:(long long)arg1 configuration:(unsigned long long)arg2 ; 34 | @end 35 | 36 | @interface MPArtworkColorAnalysis : NSObject 37 | @property (nonatomic, readonly) UIColor *backgroundColor; 38 | @property (nonatomic, readonly) UIColor *primaryTextColor; 39 | @property (nonatomic, readonly) UIColor *secondaryTextColor; 40 | @end 41 | 42 | @interface AXNAppCell : UICollectionViewCell { 43 | NSArray *_styleConstraints; 44 | } 45 | 46 | @property (nonatomic, retain) UIImageView *iconView; 47 | @property (nonatomic, retain) UIView *blurView; 48 | @property (nonatomic, retain) UILabel *badgeLabel; 49 | @property (nonatomic, retain) NSString *bundleIdentifier; 50 | @property (nonatomic, assign) NSInteger notificationCount; 51 | @property (nonatomic, assign) NSInteger selectionStyle; 52 | @property (nonatomic, assign) BOOL addBlur; 53 | @property (nonatomic, assign) NSInteger style; 54 | @property (nonatomic, assign) NSInteger iconStyle; 55 | @property (nonatomic, assign) BOOL badgesEnabled; 56 | @property (nonatomic, assign) BOOL badgesShowBackground; 57 | @property (nonatomic, assign) NSInteger darkMode; 58 | @property (nonatomic, assign) BOOL isSetupComplete; 59 | 60 | @end 61 | @interface SBApplicationController 62 | +(id)sharedInstance; 63 | -(id)applicationWithBundleIdentifier:(id)arg1; 64 | @end 65 | @interface SBApplication 66 | @property (nonatomic,readonly) NSString * displayName; 67 | @end 68 | -------------------------------------------------------------------------------- /Tweak/AXNAppCell.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AXNAppCell.h" 3 | #import "AXNManager.h" 4 | 5 | @implementation AXNAppCell 6 | 7 | NSMutableDictionary* prefs; 8 | 9 | UIView *getBlurView(CGRect frame) { 10 | NSInteger darkModeTmp = [prefs[@"DarkMode"] intValue] ?: 0; 11 | UIView *blurView; 12 | if(darkModeTmp == 0) { 13 | id materialView = objc_getClass("MTMaterialView"); 14 | if([materialView respondsToSelector:@selector(materialViewWithRecipe:options:)]) blurView = [materialView materialViewWithRecipe:MTMaterialRecipeNotifications options:MTMaterialOptionsBlur]; 15 | else blurView = [materialView materialViewWithRecipe:MTMaterialRecipeNotifications configuration:1]; 16 | blurView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.45]; 17 | } else if(darkModeTmp == 1) { 18 | blurView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; 19 | } else if(darkModeTmp == 2) { 20 | blurView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; 21 | } 22 | blurView.frame = frame; 23 | return blurView; 24 | } 25 | 26 | -(id)initWithFrame:(CGRect)frame { 27 | self = [super initWithFrame:frame]; 28 | _style = -1; 29 | 30 | // for some unknown reason AXNView isn't able to set badgesEnabled, so i'm loading it from the preferences 31 | prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/me.nepeta.axon.plist"]; 32 | self.badgesEnabled = prefs[@"BadgesEnabled"] != nil ? [prefs[@"BadgesEnabled"] boolValue] : true; 33 | 34 | UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showMenu:)]; 35 | [self addGestureRecognizer:recognizer]; 36 | 37 | self.layer.cornerRadius = 13; 38 | self.layer.continuousCorners = YES; 39 | self.layer.masksToBounds = YES; 40 | 41 | self.iconView = [[UIImageView alloc] initWithFrame:frame]; 42 | self.iconView.translatesAutoresizingMaskIntoConstraints = NO; 43 | self.iconView.contentMode = UIViewContentModeScaleAspectFit; 44 | 45 | if (self.badgesEnabled) { 46 | self.badgeLabel = [[UILabel alloc] initWithFrame:frame]; 47 | self.badgeLabel.font = [UIFont boldSystemFontOfSize:14]; 48 | self.badgeLabel.translatesAutoresizingMaskIntoConstraints = NO; 49 | self.badgeLabel.text = @"0"; 50 | self.badgeLabel.textColor = [UIColor whiteColor]; 51 | self.badgeLabel.backgroundColor = [UIColor blackColor]; 52 | self.badgeLabel.layer.cornerRadius = 10; 53 | self.badgeLabel.layer.masksToBounds = YES; 54 | self.badgeLabel.textAlignment = NSTextAlignmentCenter; 55 | } 56 | 57 | self.blurView = getBlurView(CGRectMake(0, 0, frame.size.width, frame.size.height)); 58 | // self.blurView.bounds = self.bounds; 59 | 60 | if (self.badgesEnabled) { 61 | _styleConstraints = @[ 62 | @[ // default 63 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 64 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10], 65 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 66 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-30], 67 | [self.badgeLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], 68 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10], 69 | [self.badgeLabel.heightAnchor constraintEqualToConstant:20], 70 | [self.badgeLabel.widthAnchor constraintEqualToConstant:30], 71 | ], 72 | @[ // packed 73 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10], 74 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10], 75 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 76 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10], 77 | [self.badgeLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 78 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 79 | [self.badgeLabel.heightAnchor constraintEqualToConstant:20], 80 | [self.badgeLabel.widthAnchor constraintEqualToConstant:30], 81 | ], 82 | @[ // compact 83 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 84 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 85 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 86 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 87 | [self.badgeLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], 88 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 89 | [self.badgeLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10], 90 | [self.badgeLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 91 | ], 92 | @[ // tiny 93 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 94 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 95 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 96 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-25], 97 | [self.badgeLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], 98 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 99 | [self.badgeLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 100 | [self.badgeLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 101 | ], 102 | @[ // group 103 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 104 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], 105 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-28], 106 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 107 | 108 | [self.badgeLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], 109 | [self.badgeLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 110 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 111 | [self.badgeLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], 112 | [self.badgeLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 113 | ], 114 | @[ // group rounded 115 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:8], 116 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:3], 117 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-26], 118 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-8], 119 | 120 | [self.badgeLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor], 121 | [self.badgeLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:8], 122 | [self.badgeLabel.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-8], 123 | [self.badgeLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:33], 124 | [self.badgeLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-7], 125 | ] 126 | ]; 127 | } else if (!self.badgesEnabled) { 128 | _styleConstraints = @[ 129 | @[ // default 130 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10], 131 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10], 132 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 133 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10], 134 | ], 135 | @[ // packed 136 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10], 137 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10], 138 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10], 139 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10], 140 | ], 141 | @[ // compact 142 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 143 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 144 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 145 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 146 | ], 147 | @[ // tiny 148 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 149 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 150 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 151 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 152 | ], 153 | @[ // group 154 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5], 155 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5], 156 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5], 157 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5], 158 | ], 159 | @[ // group rounded 160 | [self.iconView.topAnchor constraintEqualToAnchor:self.topAnchor constant:8], 161 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:8], 162 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-8], 163 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-8], 164 | ] 165 | ]; 166 | } 167 | 168 | return self; 169 | } 170 | 171 | -(UISemanticContentAttribute)semanticContentAttribute { 172 | return UISemanticContentAttributeForceLeftToRight; 173 | } 174 | 175 | -(void)axnClearAll { 176 | [[AXNManager sharedInstance] clearAll:self.bundleIdentifier]; 177 | } 178 | -(void)axnRealClearAll { 179 | [[AXNManager sharedInstance] clearAll]; 180 | } 181 | 182 | -(BOOL)canBecomeFirstResponder { 183 | return YES; 184 | } 185 | 186 | -(BOOL)canPerformAction:(SEL)action withSender:(id)sender { 187 | return (action == @selector(axnClearAll)); 188 | } 189 | 190 | -(NSString *)getAppName { 191 | return [AXNManager sharedInstance].names[self.bundleIdentifier]; 192 | 193 | SBApplication *app = [[NSClassFromString(@"SBApplicationController") sharedInstance] applicationWithBundleIdentifier:self.bundleIdentifier]; 194 | return app.displayName; 195 | } 196 | 197 | -(void)showMenu:(UILongPressGestureRecognizer *)sender { 198 | if (sender.state == UIGestureRecognizerStateBegan) { 199 | AudioServicesPlaySystemSound(1519); 200 | 201 | float version = [[[UIDevice currentDevice] systemVersion] floatValue]; 202 | 203 | if(version >= 13) { 204 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Notification Option" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 205 | [alert addAction:[UIAlertAction actionWithTitle:[NSString stringWithFormat:@"Clear All %@ notifications", [self getAppName]] style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { 206 | [self axnClearAll]; 207 | }]]; 208 | [alert addAction:[UIAlertAction actionWithTitle:@"Clear All notifications" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { 209 | [self axnRealClearAll]; 210 | }]]; 211 | [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { 212 | }]]; 213 | UIResponder *responder = self; 214 | while ([responder isKindOfClass:[UIView class]]) responder = [responder nextResponder]; 215 | [(UIViewController *)responder presentViewController:alert animated:YES completion:nil]; 216 | } else { 217 | [self becomeFirstResponder]; 218 | UIMenuController *menu = [UIMenuController sharedMenuController]; 219 | menu.menuItems = @[ 220 | [[UIMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Clear All %@ notifications", [self getAppName]] action:@selector(axnClearAll)], 221 | [[UIMenuItem alloc] initWithTitle:@"Clear All notifications" action:@selector(axnRealClearAll)] 222 | ]; 223 | [menu setTargetRect:self.bounds inView:self]; 224 | [menu setMenuVisible:YES animated:YES]; 225 | } 226 | } 227 | } 228 | 229 | -(void)setBundleIdentifier:(NSString *)value { 230 | _bundleIdentifier = value; 231 | 232 | if(self.iconStyle == 0) self.iconView.image = [[AXNManager sharedInstance] getIcon:value rounded:_style == 5]; 233 | else if(self.iconStyle == 1) self.iconView.image = [[AXNManager sharedInstance] getIcon:value rounded:true]; 234 | else if(self.iconStyle == 2) self.iconView.image = [[AXNManager sharedInstance] getIcon:value rounded:false]; 235 | 236 | self.badgeLabel.backgroundColor = [UIColor clearColor]; 237 | if(_style != 4) self.badgeLabel.textColor = [[AXNManager sharedInstance] fallbackColor]; 238 | if(_style == 5) self.badgeLabel.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.2]; 239 | 240 | BOOL iOS13 = [[[UIDevice currentDevice] systemVersion] floatValue] >= 13; 241 | 242 | if (self.badgesShowBackground && self.iconView.image && _style != 4) { 243 | if ([AXNManager sharedInstance].backgroundColorCache[value] && [AXNManager sharedInstance].textColorCache[value]) { 244 | self.badgeLabel.backgroundColor = [[AXNManager sharedInstance].backgroundColorCache[value] copy]; 245 | self.badgeLabel.textColor = [[AXNManager sharedInstance].textColorCache[value] copy]; 246 | } else { 247 | if(iOS13) { 248 | CGSize size = {1, 1}; 249 | UIGraphicsBeginImageContext(size); 250 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 251 | CGContextSetInterpolationQuality(ctx, kCGInterpolationMedium); 252 | [[self.iconView.image copy] drawInRect:(CGRect){.size = size} blendMode:kCGBlendModeCopy alpha:1]; 253 | uint8_t *data = CGBitmapContextGetData(ctx); 254 | UIColor *backgroundColor = [UIColor colorWithRed:data[2] / 255.0f green:data[1] / 255.0f blue:data[0] / 255.0f alpha:1]; 255 | UIGraphicsEndImageContext(); 256 | CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; 257 | [backgroundColor getRed:&red green:&green blue:&blue alpha:&alpha]; 258 | int threshold = 105; 259 | int bgDelta = ((red * 0.299) + (green * 0.587) + (blue * 0.114)); 260 | UIColor *textColor = (255 - bgDelta < threshold) ? [UIColor blackColor] : [UIColor whiteColor]; 261 | self.badgeLabel.backgroundColor = [backgroundColor copy]; 262 | self.badgeLabel.textColor = [textColor copy]; 263 | } else { 264 | __weak AXNAppCell *weakSelf = self; 265 | MPArtworkColorAnalyzer *colorAnalyzer = [[MPArtworkColorAnalyzer alloc] initWithImage:self.iconView.image algorithm:0]; 266 | [colorAnalyzer analyzeWithCompletionHandler:^(MPArtworkColorAnalyzer *analyzer, MPArtworkColorAnalysis *analysis) { 267 | [AXNManager sharedInstance].backgroundColorCache[value] = [analysis.backgroundColor copy]; 268 | [AXNManager sharedInstance].textColorCache[value] = [analysis.primaryTextColor copy]; 269 | [weakSelf badgeLabel].backgroundColor = [analysis.backgroundColor copy]; 270 | [weakSelf badgeLabel].textColor = [analysis.primaryTextColor copy]; 271 | }]; 272 | } 273 | } 274 | } 275 | } 276 | 277 | -(void)setNotificationCount:(NSInteger)value { 278 | _notificationCount = value; 279 | 280 | if (value <= 99) { 281 | self.badgeLabel.text = [NSString stringWithFormat:@"%ld", value]; 282 | } else { 283 | self.badgeLabel.text = @"99+"; 284 | } 285 | } 286 | 287 | -(void)setSelectionStyle:(NSInteger)style { 288 | _selectionStyle = style; 289 | 290 | self.iconView.alpha = 1.0; 291 | self.badgeLabel.alpha = 1.0; 292 | self.backgroundColor = [UIColor clearColor]; 293 | } 294 | 295 | -(void)setStyle:(NSInteger)style { 296 | if (_style == style) return; 297 | NSInteger oldStyle = _style; 298 | 299 | if (style >= [_styleConstraints count] || style < 0) _style = 0; 300 | else _style = style; 301 | 302 | if (style == 2) self.badgeLabel.layer.cornerRadius = 8; 303 | if(style == 3 || style == 4 || style == 5) { 304 | if (style == 3) { 305 | self.layer.cornerRadius = 10; 306 | self.badgeLabel.layer.cornerRadius = 8; 307 | } else if(style == 4) { 308 | self.layer.cornerRadius = 10; 309 | self.badgeLabel.textAlignment = NSTextAlignmentRight; 310 | self.badgeLabel.backgroundColor = [UIColor clearColor]; 311 | self.badgeLabel.textColor = [UIColor whiteColor]; 312 | } else { 313 | self.layer.cornerRadius = 18; 314 | self.alpha = 0.5; 315 | self.badgeLabel.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.2]; 316 | } 317 | if (self.addBlur || style == 4 || style == 5) [self addSubview:self.blurView]; 318 | if (self.badgesEnabled) [self addSubview:self.badgeLabel]; 319 | [self addSubview:self.iconView]; 320 | } else { 321 | if (self.addBlur || style == 4 || style == 5) [self addSubview:self.blurView]; 322 | [self addSubview:self.iconView]; 323 | if (self.badgesEnabled) [self addSubview:self.badgeLabel]; 324 | } 325 | 326 | if (oldStyle != -1) [NSLayoutConstraint deactivateConstraints:_styleConstraints[oldStyle]]; 327 | [NSLayoutConstraint activateConstraints:_styleConstraints[_style]]; 328 | [self setNeedsLayout]; 329 | } 330 | 331 | -(void)setDarkMode:(NSInteger)darkMode { 332 | if (_darkMode == darkMode) return; 333 | 334 | self.blurView = getBlurView(self.blurView.frame); 335 | self.badgeLabel.textColor = darkMode ? [UIColor whiteColor] : [UIColor blackColor]; 336 | self.badgeLabel.alpha = 0.4f; 337 | 338 | [self setNeedsDisplay]; 339 | } 340 | 341 | -(void)setSelected:(BOOL)selected { 342 | [super setSelected:selected]; 343 | if(self.selectionStyle == 2) return; 344 | 345 | if (selected) { 346 | [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ 347 | switch (self.selectionStyle) { 348 | case 1: 349 | self.iconView.alpha = 1.0; 350 | self.badgeLabel.alpha = 1.0; 351 | break; 352 | default: 353 | if (!self.darkMode) self.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; 354 | else if (self.darkMode) self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; 355 | } 356 | } completion:NULL]; 357 | } else { 358 | [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ 359 | switch (self.selectionStyle) { 360 | case 1: 361 | self.iconView.alpha = 0.5; 362 | self.badgeLabel.alpha = 0.5; 363 | break; 364 | default: 365 | self.backgroundColor = [UIColor clearColor]; 366 | } 367 | } completion:NULL]; 368 | } 369 | } 370 | 371 | @end 372 | -------------------------------------------------------------------------------- /Tweak/AXNManager.h: -------------------------------------------------------------------------------- 1 | #import "AXNView.h" 2 | #import "RandomHeaders.h" 3 | #import "Protocol.h" 4 | 5 | @interface AXNManager : NSObject 6 | 7 | @property (nonatomic, retain) NSMutableDictionary *notificationRequests; 8 | @property (nonatomic, retain) NSMutableDictionary *names; 9 | @property (nonatomic, retain) NSMutableDictionary *timestamps; 10 | @property (nonatomic, retain) NSMutableDictionary *iconStore; 11 | @property (nonatomic, retain) NSMutableDictionary *backgroundColorCache; 12 | @property (nonatomic, retain) NSMutableDictionary *textColorCache; 13 | @property (nonatomic, retain) NSMutableDictionary *countCache; 14 | @property (nonatomic, retain) UIColor *fallbackColor; 15 | @property (nonatomic, weak) NCNotificationRequest *latestRequest; 16 | @property (nonatomic, weak) AXNView *view; 17 | @property (nonatomic, weak) id clvc; 18 | @property (nonatomic, weak) id sbclvc; 19 | @property (nonatomic, weak) NCNotificationDispatcher *dispatcher; 20 | 21 | +(instancetype)sharedInstance; 22 | -(id)init; 23 | -(void)getRidOfWaste; 24 | -(void)insertNotificationRequest:(id)req; 25 | -(void)removeNotificationRequest:(id)req; 26 | -(void)modifyNotificationRequest:(id)req; 27 | -(UIImage *)getIcon:(NSString *)bundleIdentifier; 28 | -(UIImage *)getIcon:(NSString *)bundleIdentifier rounded:(BOOL)rounded; 29 | -(void)clearAll:(NSString *)bundleIdentifier; 30 | -(void)clearAll; 31 | 32 | -(void)showNotificationRequest:(id)req; 33 | -(void)hideNotificationRequest:(id)req; 34 | 35 | -(void)showNotificationRequests:(id)reqs; 36 | -(void)hideNotificationRequests:(id)reqs; 37 | 38 | -(id)requestsForBundleIdentifier:(NSString *)bundleIdentifier; 39 | -(NSArray *)allRequestsForBundleIdentifier:(NSString *)bundleIdentifier; 40 | -(void)showNotificationRequestsForBundleIdentifier:(NSString *)bundleIdentifier; 41 | -(void)hideAllNotificationRequests; 42 | -(void)hideAllNotificationRequestsExcept:(id)notification; 43 | -(void)revealNotificationHistory:(BOOL)revealed; 44 | 45 | -(void)invalidateCountCache; 46 | -(NSInteger)countForBundleIdentifier:(NSString *)bundleIdentifier; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Tweak/AXNManager.m: -------------------------------------------------------------------------------- 1 | #import "AXNManager.h" 2 | #import "AXNRequestWrapper.h" 3 | #import "Tweak.h" 4 | 5 | @implementation AXNManager 6 | 7 | +(instancetype)sharedInstance { 8 | static AXNManager *sharedInstance = nil; 9 | static dispatch_once_t onceToken; 10 | dispatch_once(&onceToken, ^{ 11 | sharedInstance = [[AXNManager alloc] init]; 12 | sharedInstance.names = [NSMutableDictionary new]; 13 | sharedInstance.timestamps = [NSMutableDictionary new]; 14 | sharedInstance.notificationRequests = [NSMutableDictionary new]; 15 | sharedInstance.iconStore = [NSMutableDictionary new]; 16 | sharedInstance.backgroundColorCache = [NSMutableDictionary new]; 17 | sharedInstance.textColorCache = [NSMutableDictionary new]; 18 | sharedInstance.countCache = [NSMutableDictionary new]; 19 | sharedInstance.fallbackColor = [UIColor whiteColor]; 20 | }); 21 | return sharedInstance; 22 | } 23 | 24 | -(id)init { 25 | [[objc_getClass("NSDistributedNotificationCenter") defaultCenter] addObserver:self selector:@selector(clearAll) name:@"me.nepeta.axon.clearAllNotification" object:nil]; 26 | [[objc_getClass("NSDistributedNotificationCenter") defaultCenter] addObserver:self selector:@selector(saveNotificationForDebug) name:@"me.nepeta.axon.saveNotification" object:nil]; 27 | return self; 28 | } 29 | 30 | -(void)saveNotificationForDebug { 31 | NSMutableArray *array = [NSMutableArray new]; 32 | for(NSArray *value in [self.notificationRequests allValues]) { 33 | for(AXNRequestWrapper *req in value) [array addObject:req.request]; 34 | } 35 | [[array description] writeToFile:@"/var/mobile/Documents/AxonDebug.txt" atomically:false encoding:NSUTF8StringEncoding error:nil]; 36 | } 37 | 38 | -(void)getRidOfWaste { 39 | for (NSString *bundleIdentifier in [self.notificationRequests allKeys]) { 40 | __weak NSMutableArray *requests = self.notificationRequests[bundleIdentifier]; 41 | for (int i = [requests count] - 1; i >= 0; i--) { 42 | __weak AXNRequestWrapper *wrapped = requests[i]; 43 | if (!wrapped || ![wrapped request]) [requests removeObjectAtIndex:i]; 44 | } 45 | } 46 | } 47 | 48 | -(void)invalidateCountCache { 49 | [self.countCache removeAllObjects]; 50 | } 51 | 52 | -(void)updateCountForBundleIdentifier:(NSString *)bundleIdentifier { 53 | NSArray *requests = [self requestsForBundleIdentifier:bundleIdentifier]; 54 | NSInteger count = [requests count]; 55 | if (count == 0) { 56 | self.countCache[bundleIdentifier] = @(0); 57 | return; 58 | } 59 | 60 | if ([self.dispatcher respondsToSelector:@selector(notificationStore)] && [self.dispatcher.notificationStore respondsToSelector:@selector(coalescedNotificationForRequest:)]) { 61 | count = 0; 62 | NSMutableArray *coalescedNotifications = [NSMutableArray new]; 63 | for (NCNotificationRequest *req in requests) { 64 | NCCoalescedNotification *coalesced = [self coalescedNotificationForRequest:req]; 65 | if (!coalesced) { 66 | count++; 67 | continue; 68 | } 69 | 70 | if (![coalescedNotifications containsObject:coalesced]) { 71 | count += [coalesced.notificationRequests count]; 72 | [coalescedNotifications addObject:coalesced]; 73 | } 74 | } 75 | } 76 | 77 | self.countCache[bundleIdentifier] = @(count); 78 | } 79 | 80 | -(NSInteger)countForBundleIdentifier:(NSString *)bundleIdentifier { 81 | if (self.countCache[bundleIdentifier]) return [self.countCache[bundleIdentifier] intValue]; 82 | 83 | [self updateCountForBundleIdentifier:bundleIdentifier]; 84 | 85 | if (self.countCache[bundleIdentifier]) return [self.countCache[bundleIdentifier] intValue]; 86 | else return 0; 87 | } 88 | 89 | -(UIImage *)getIcon:(NSString *)bundleIdentifier { 90 | if (self.iconStore[bundleIdentifier]) return self.iconStore[bundleIdentifier]; 91 | UIImage *image; 92 | SBIconModel *model; 93 | 94 | SBIconController *iconController = [NSClassFromString(@"SBIconController") sharedInstance]; 95 | 96 | if([iconController respondsToSelector:@selector(homescreenIconViewMap)]) model = [[iconController homescreenIconViewMap] iconModel]; 97 | else if([iconController respondsToSelector:@selector(model)]) model = [iconController model]; 98 | SBIcon *icon = [model applicationIconForBundleIdentifier:bundleIdentifier]; 99 | if([icon respondsToSelector:@selector(getIconImage:)]) image = [icon getIconImage:2]; 100 | else if([icon respondsToSelector:@selector(iconImageWithInfo:)]) image = [icon iconImageWithInfo:(struct SBIconImageInfo){60,60,2,0}]; 101 | 102 | if (!image) { 103 | NSLog(@"[Axon] Image Not Founded!"); 104 | NSArray *requests = [self requestsForBundleIdentifier:bundleIdentifier]; 105 | for (int i = 0; i < [requests count]; i++) { 106 | NCNotificationRequest *request = requests[i]; 107 | if ([request.sectionIdentifier isEqualToString:bundleIdentifier] && request.content && request.content.icon) { 108 | image = request.content.icon; 109 | break; 110 | } 111 | } 112 | } 113 | 114 | if (!image && model) { 115 | icon = [model applicationIconForBundleIdentifier:@"com.apple.Preferences"]; 116 | if([icon respondsToSelector:@selector(getIconImage:)]) image = [icon getIconImage:2]; 117 | else if([icon respondsToSelector:@selector(iconImageWithInfo:)]) image = [icon iconImageWithInfo:(struct SBIconImageInfo){60,60,2,0}]; 118 | } 119 | 120 | if (!image) { 121 | image = [UIImage _applicationIconImageForBundleIdentifier:bundleIdentifier format:0 scale:[UIScreen mainScreen].scale]; 122 | } 123 | 124 | if (image) { 125 | self.iconStore[bundleIdentifier] = [image copy]; 126 | } 127 | 128 | return image ?: [UIImage new]; 129 | } 130 | 131 | -(UIImage *)getIcon:(NSString *)bundleIdentifier rounded:(BOOL)rounded { 132 | UIImage *image = [self getIcon:bundleIdentifier]; 133 | if(rounded) { 134 | UIGraphicsBeginImageContextWithOptions(CGRectMake(0,0,60,60).size, NO, 1.0); 135 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0,60,60) cornerRadius:30] addClip]; 136 | [image drawInRect:CGRectMake(0,0,60,60)]; 137 | UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); 138 | UIGraphicsEndImageContext(); 139 | 140 | return finalImage; 141 | } else { 142 | return image; 143 | } 144 | } 145 | 146 | -(void)clearAll:(NSString *)bundleIdentifier { 147 | if (self.notificationRequests[bundleIdentifier]) { 148 | [self.dispatcher destination:nil requestsClearingNotificationRequests:[self allRequestsForBundleIdentifier:bundleIdentifier]]; 149 | } 150 | self.notificationRequests[bundleIdentifier] = nil; 151 | } 152 | 153 | -(void)clearAll { 154 | for(NSString *item in [self.notificationRequests allKeys]) { 155 | [self.dispatcher destination:nil requestsClearingNotificationRequests:[self allRequestsForBundleIdentifier:item]]; 156 | } 157 | self.notificationRequests = [@{} mutableCopy]; 158 | } 159 | 160 | -(void)insertNotificationRequest:(NCNotificationRequest *)req { 161 | if (!req || ![req notificationIdentifier] || !req.bulletin || !req.bulletin.sectionID) return; 162 | NSString *bundleIdentifier = req.bulletin.sectionID; 163 | 164 | if (req.content && req.content.header) { 165 | self.names[bundleIdentifier] = [req.content.header copy]; 166 | } 167 | 168 | if (req.timestamp) { 169 | if (!self.timestamps[bundleIdentifier] || [req.timestamp compare:self.timestamps[bundleIdentifier]] == NSOrderedDescending) { 170 | self.timestamps[bundleIdentifier] = [req.timestamp copy]; 171 | } 172 | 173 | if (!self.latestRequest || [req.timestamp compare:self.latestRequest.timestamp] == NSOrderedDescending) { 174 | self.latestRequest = req; 175 | } 176 | } 177 | 178 | [self getRidOfWaste]; 179 | if (self.notificationRequests[bundleIdentifier]) { 180 | BOOL found = NO; 181 | for (int i = 0; i < [self.notificationRequests[bundleIdentifier] count]; i++) { 182 | __weak AXNRequestWrapper *wrapped = self.notificationRequests[bundleIdentifier][i]; 183 | if (wrapped && [[req notificationIdentifier] isEqualToString:[wrapped notificationIdentifier]]) { 184 | found = YES; 185 | break; 186 | } 187 | } 188 | 189 | if (!found) [self.notificationRequests[bundleIdentifier] addObject:[AXNRequestWrapper wrapRequest:req]]; 190 | } else { 191 | self.notificationRequests[bundleIdentifier] = [NSMutableArray new]; 192 | [self.notificationRequests[bundleIdentifier] addObject:[AXNRequestWrapper wrapRequest:req]]; 193 | } 194 | 195 | [self updateCountForBundleIdentifier:bundleIdentifier]; 196 | } 197 | 198 | -(void)removeNotificationRequest:(NCNotificationRequest *)req { 199 | if (!req || ![req notificationIdentifier] || !req.bulletin || !req.bulletin.sectionID) return; 200 | NSString *bundleIdentifier = req.bulletin.sectionID; 201 | 202 | if (self.latestRequest && [[self.latestRequest notificationIdentifier] isEqualToString:[req notificationIdentifier]]) { 203 | self.latestRequest = nil; 204 | } 205 | 206 | [self getRidOfWaste]; 207 | 208 | BOOL latestRequestVerified = true; 209 | if(self.view.showByDefault == 1) latestRequestVerified = false; 210 | if (self.notificationRequests[bundleIdentifier]) { 211 | __weak NSMutableArray *requests = self.notificationRequests[bundleIdentifier]; 212 | for (int i = [requests count] - 1; i >= 0; i--) { 213 | __weak AXNRequestWrapper *wrapped = requests[i]; 214 | if (wrapped && [[req notificationIdentifier] isEqualToString:[wrapped notificationIdentifier]]) { 215 | [requests removeObjectAtIndex:i]; 216 | if(!latestRequestVerified && [[wrapped notificationIdentifier] isEqualToString:[self.latestRequest notificationIdentifier]]) latestRequestVerified = true; 217 | } 218 | } 219 | } 220 | if(!latestRequestVerified) self.latestRequest = nil; 221 | 222 | [self updateCountForBundleIdentifier:bundleIdentifier]; 223 | } 224 | 225 | -(void)modifyNotificationRequest:(NCNotificationRequest *)req { 226 | if (!req || ![req notificationIdentifier] || !req.bulletin || !req.bulletin.sectionID) return; 227 | NSString *bundleIdentifier = req.bulletin.sectionID; 228 | 229 | if (self.latestRequest && [[self.latestRequest notificationIdentifier] isEqualToString:[req notificationIdentifier]]) { 230 | self.latestRequest = req; 231 | } 232 | 233 | [self getRidOfWaste]; 234 | if (self.notificationRequests[bundleIdentifier]) { 235 | __weak NSMutableArray *requests = self.notificationRequests[bundleIdentifier]; 236 | for (int i = [requests count] - 1; i >= 0; i--) { 237 | __weak AXNRequestWrapper *wrapped = requests[i]; 238 | if (wrapped && [wrapped notificationIdentifier] && [[req notificationIdentifier] isEqualToString:[wrapped notificationIdentifier]]) { 239 | [requests removeObjectAtIndex:i]; 240 | [requests insertObject:[AXNRequestWrapper wrapRequest:req] atIndex:i]; 241 | return; 242 | } 243 | } 244 | } 245 | } 246 | 247 | -(void)setLatestRequest:(NCNotificationRequest *)request { 248 | _latestRequest = request; 249 | 250 | if (self.view.showingLatestRequest) { 251 | [self.view reset]; 252 | } 253 | } 254 | 255 | -(NSArray *)requestsForBundleIdentifier:(NSString *)bundleIdentifier { 256 | NSMutableArray *array = [NSMutableArray new]; 257 | if (!self.notificationRequests[bundleIdentifier]) return array; 258 | 259 | [self getRidOfWaste]; 260 | 261 | for (int i = 0; i < [self.notificationRequests[bundleIdentifier] count]; i++) { 262 | __weak AXNRequestWrapper *wrapped = self.notificationRequests[bundleIdentifier][i]; 263 | if (wrapped && [wrapped request]) [array addObject:[wrapped request]]; 264 | } 265 | 266 | return array; 267 | } 268 | 269 | -(NSArray *)allRequestsForBundleIdentifier:(NSString *)bundleIdentifier { 270 | NSArray *requests = [self requestsForBundleIdentifier:bundleIdentifier]; 271 | 272 | if ([self.dispatcher respondsToSelector:@selector(notificationStore)] && [self.dispatcher.notificationStore respondsToSelector:@selector(coalescedNotificationForRequest:)]) { 273 | NSMutableArray *allRequests = [NSMutableArray new]; 274 | NSMutableArray *coalescedNotifications = [NSMutableArray new]; 275 | 276 | for (NCNotificationRequest *req in requests) { 277 | NCCoalescedNotification *coalesced = [self coalescedNotificationForRequest:req]; 278 | if (!coalesced) { 279 | BOOL found = NO; 280 | for (int i = 0; i < [allRequests count]; i++) { 281 | if ([[req notificationIdentifier] isEqualToString:[allRequests[i] notificationIdentifier]]) { 282 | found = YES; 283 | break; 284 | } 285 | } 286 | 287 | if (!found) { 288 | [allRequests addObject:req]; 289 | } 290 | continue; 291 | } 292 | 293 | if (![coalescedNotifications containsObject:coalesced]) { 294 | for (NCNotificationRequest *request in coalesced.notificationRequests) { 295 | BOOL found = NO; 296 | for (int i = 0; i < [allRequests count]; i++) { 297 | if ([[request notificationIdentifier] isEqualToString:[allRequests[i] notificationIdentifier]]) { 298 | found = YES; 299 | break; 300 | } 301 | } 302 | 303 | if (!found) { 304 | [allRequests addObject:request]; 305 | } 306 | } 307 | [coalescedNotifications addObject:coalesced]; 308 | } 309 | } 310 | 311 | return allRequests; 312 | } else { 313 | return requests; 314 | } 315 | } 316 | 317 | -(id)coalescedNotificationForRequest:(id)req { 318 | NCCoalescedNotification *coalesced = nil; 319 | if ([self.dispatcher respondsToSelector:@selector(notificationStore)] && [self.dispatcher.notificationStore respondsToSelector:@selector(coalescedNotificationForRequest:)]) { 320 | coalesced = [self.dispatcher.notificationStore coalescedNotificationForRequest:req]; 321 | } 322 | return coalesced; 323 | } 324 | 325 | -(void)showNotificationRequest:(NCNotificationRequest *)req { 326 | if (!req) return; 327 | self.clvc.axnAllowChanges = YES; 328 | if ([self.clvc respondsToSelector:@selector(insertNotificationRequest:forCoalescedNotification:)]) [self.clvc insertNotificationRequest:req forCoalescedNotification:[self coalescedNotificationForRequest:req]]; 329 | else [self.clvc insertNotificationRequest:req]; 330 | self.clvc.axnAllowChanges = NO; 331 | } 332 | 333 | -(void)hideNotificationRequest:(NCNotificationRequest *)req { 334 | if (!req) return; 335 | self.clvc.axnAllowChanges = YES; 336 | [self insertNotificationRequest:req]; 337 | if ([self.clvc respondsToSelector:@selector(removeNotificationRequest:forCoalescedNotification:)]) [self.clvc removeNotificationRequest:req forCoalescedNotification:[self coalescedNotificationForRequest:req]]; 338 | else [self.clvc removeNotificationRequest:req]; 339 | self.clvc.axnAllowChanges = NO; 340 | 341 | } 342 | 343 | -(void)showNotificationRequests:(id)reqs { 344 | if (!reqs) return; 345 | for (id req in reqs) { 346 | [self showNotificationRequest:req]; 347 | } 348 | } 349 | 350 | -(void)hideNotificationRequests:(id)reqs { 351 | if (!reqs) return; 352 | for (id req in reqs) { 353 | [self hideNotificationRequest:req]; 354 | } 355 | } 356 | 357 | -(void)showNotificationRequestsForBundleIdentifier:(NSString *)bundleIdentifier { 358 | [self showNotificationRequests:[self requestsForBundleIdentifier:bundleIdentifier]]; 359 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 360 | [self.clvc updateNotifications]; 361 | }); 362 | } 363 | 364 | -(void)hideAllNotificationRequests { 365 | [self hideNotificationRequests:[self.clvc allNotificationRequests]]; 366 | } 367 | 368 | -(void)hideAllNotificationRequestsExcept:(id)notification { 369 | NSMutableSet *set = [[self.clvc allNotificationRequests] mutableCopy]; 370 | [set removeObject:notification]; 371 | [self hideNotificationRequests:set]; 372 | } 373 | 374 | -(void)revealNotificationHistory:(BOOL)revealed { 375 | [self.clvc revealNotificationHistory:revealed]; 376 | } 377 | 378 | @end 379 | -------------------------------------------------------------------------------- /Tweak/AXNRequestWrapper.h: -------------------------------------------------------------------------------- 1 | #import "RandomHeaders.h" 2 | 3 | @interface AXNRequestWrapper : NSObject 4 | 5 | @property (nonatomic, strong) NSString *notificationIdentifier; 6 | @property (nonatomic, strong) NCNotificationRequest *request; 7 | 8 | +(AXNRequestWrapper *)wrapRequest:(NCNotificationRequest *)request; 9 | 10 | @end -------------------------------------------------------------------------------- /Tweak/AXNRequestWrapper.m: -------------------------------------------------------------------------------- 1 | #import "AXNRequestWrapper.h" 2 | 3 | @implementation AXNRequestWrapper 4 | 5 | +(AXNRequestWrapper *)wrapRequest:(NCNotificationRequest *)request { 6 | if (!request || ![request notificationIdentifier]) return nil; 7 | AXNRequestWrapper *wrapped = [AXNRequestWrapper alloc]; 8 | wrapped.request = [request copy]; 9 | wrapped.notificationIdentifier = [[wrapped.request notificationIdentifier] copy]; 10 | return wrapped; 11 | } 12 | 13 | @end -------------------------------------------------------------------------------- /Tweak/AXNView.h: -------------------------------------------------------------------------------- 1 | #import "RandomHeaders.h" 2 | 3 | @interface AXNView : UIView 4 | 5 | @property (nonatomic, retain) NSMutableArray *list; 6 | @property (nonatomic, retain) UICollectionView *collectionView; 7 | @property (nonatomic, retain) UICollectionViewFlowLayout *collectionViewLayout; 8 | @property (nonatomic, retain) NSString *selectedBundleIdentifier; 9 | 10 | @property (nonatomic, assign) BOOL hapticFeedback; 11 | @property (nonatomic, assign) BOOL badgesEnabled; 12 | @property (nonatomic, assign) BOOL badgesShowBackground; 13 | @property (nonatomic, assign) NSInteger darkMode; 14 | @property (nonatomic, assign) BOOL showingLatestRequest; 15 | @property (nonatomic, assign) NSInteger selectionStyle; 16 | @property (nonatomic, assign) BOOL addBlur; 17 | @property (nonatomic, assign) NSInteger style; 18 | @property (nonatomic, assign) NSInteger sortingMode; 19 | @property (nonatomic, assign) NSInteger showByDefault; 20 | @property (nonatomic, assign) NSInteger alignment; 21 | @property (nonatomic, assign) NSInteger iconStyle; 22 | @property (nonatomic, assign) CGFloat spacing; 23 | 24 | -(void)refresh; 25 | -(void)reset; 26 | 27 | /* Compatibility stuff. */ 28 | -(void)setContentHost:(id)arg1 ; 29 | -(void)setSizeToMimic:(CGSize)arg1 ; 30 | -(void)_layoutContentHost; 31 | -(CGSize)sizeToMimic; 32 | -(id)contentHost; 33 | -(void)_updateSizeToMimic; 34 | -(unsigned long long)_optionsForMainOverlay; 35 | 36 | @end -------------------------------------------------------------------------------- /Tweak/AXNView.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AXNView.h" 3 | #import "AXNAppCell.h" 4 | #import "AXNManager.h" 5 | 6 | @implementation AXNView 7 | 8 | -(id)initWithFrame:(CGRect)frame { 9 | self = [super initWithFrame:frame]; 10 | 11 | self.badgesEnabled = YES; 12 | self.badgesShowBackground = YES; 13 | self.showingLatestRequest = NO; 14 | self.list = [NSMutableArray new]; 15 | 16 | self.collectionViewLayout = [[UICollectionViewFlowLayout alloc] init]; 17 | self.collectionViewLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 18 | 19 | self.collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:self.collectionViewLayout]; 20 | self.collectionView.showsHorizontalScrollIndicator = NO; 21 | self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; 22 | self.collectionView.dataSource = self; 23 | self.collectionView.delegate = self; 24 | self.collectionView.backgroundColor = [UIColor clearColor]; 25 | [self.collectionView registerClass:[AXNAppCell class] forCellWithReuseIdentifier:@"AppCell"]; 26 | 27 | [self addSubview:self.collectionView]; 28 | 29 | [NSLayoutConstraint activateConstraints:@[ 30 | [self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor], 31 | [self.collectionView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], 32 | [self.collectionView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], 33 | [self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], 34 | ]]; 35 | 36 | return self; 37 | } 38 | 39 | - (void)viewDidLayoutSubviews { 40 | [self.collectionView.collectionViewLayout invalidateLayout]; 41 | } 42 | 43 | - (void)setSpacing:(CGFloat)spacing { 44 | _spacing = spacing; 45 | self.collectionViewLayout.minimumLineSpacing = spacing; 46 | self.collectionViewLayout.minimumInteritemSpacing = spacing; 47 | } 48 | 49 | - (void)setAlignment:(NSInteger)alignment { 50 | if (alignment == _alignment) return; 51 | 52 | _alignment = alignment; 53 | if (_alignment > 2 || _alignment < 0) _alignment = 1; 54 | 55 | self.collectionView.semanticContentAttribute = UISemanticContentAttributeUnspecified; 56 | if (alignment == 0) self.collectionView.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight; 57 | else if (alignment == 2) self.collectionView.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft; 58 | 59 | [self.collectionView setNeedsLayout]; 60 | [self.collectionView layoutIfNeeded]; 61 | } 62 | 63 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 64 | if (section == 0) return [self.list count]; 65 | else return 0; 66 | } 67 | 68 | - (void)reset { 69 | if (self.showByDefault == 3) return; 70 | if (self.showByDefault == 2 && [self.list count] > 0 && [self.list[0][@"bundleIdentifier"] isEqualToString:self.selectedBundleIdentifier]) return; 71 | 72 | self.showingLatestRequest = NO; 73 | self.selectedBundleIdentifier = nil; 74 | if(self.showByDefault != 1) [[AXNManager sharedInstance] hideAllNotificationRequests]; 75 | 76 | switch (self.showByDefault) { 77 | case 1: 78 | if ([AXNManager sharedInstance].latestRequest) { 79 | [[AXNManager sharedInstance] showNotificationRequest:[AXNManager sharedInstance].latestRequest]; 80 | [[AXNManager sharedInstance] hideAllNotificationRequestsExcept:[AXNManager sharedInstance].latestRequest]; 81 | self.showingLatestRequest = YES; 82 | } else [[AXNManager sharedInstance] hideAllNotificationRequests]; 83 | break; 84 | case 2: 85 | if ([self.list count] > 0) { 86 | [self collectionView:self.collectionView didSelectItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; 87 | } 88 | return; 89 | } 90 | 91 | [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; 92 | [[AXNManager sharedInstance] revealNotificationHistory:false]; 93 | } 94 | 95 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 96 | AXNAppCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath] ?: [[AXNAppCell alloc] initWithFrame:CGRectMake(0,0,64,64)]; 97 | NSDictionary *dict = self.list[indexPath.row]; 98 | cell.iconStyle = self.iconStyle; 99 | cell.darkMode = self.darkMode; 100 | cell.badgesShowBackground = self.badgesShowBackground; 101 | cell.bundleIdentifier = dict[@"bundleIdentifier"]; 102 | cell.notificationCount = [dict[@"notificationCount"] intValue]; 103 | cell.backgroundColor = [UIColor clearColor]; 104 | cell.selectionStyle = self.selectionStyle; 105 | cell.addBlur = self.addBlur; 106 | cell.selected = [self.selectedBundleIdentifier isEqualToString:cell.bundleIdentifier]; 107 | // cell.badgesEnabled = self.badgesEnabled; 108 | cell.style = self.style; 109 | 110 | if (cell.selected) { 111 | [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; 112 | } 113 | 114 | // if (self.style == 5) cell.alpha = 0.5; 115 | 116 | return cell; 117 | } 118 | 119 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { 120 | if (self.hapticFeedback) AudioServicesPlaySystemSound(1519); 121 | AXNAppCell *cell = (AXNAppCell *)[collectionView cellForItemAtIndexPath:indexPath]; 122 | if (cell.selected) { 123 | self.selectedBundleIdentifier = nil; 124 | [collectionView deselectItemAtIndexPath:indexPath animated:NO]; 125 | [self collectionView:collectionView didDeselectItemAtIndexPath:indexPath]; 126 | return NO; 127 | } else { 128 | return YES; 129 | } 130 | } 131 | 132 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 133 | AXNAppCell *cell = (AXNAppCell *)[collectionView cellForItemAtIndexPath:indexPath]; 134 | 135 | if (![self.selectedBundleIdentifier isEqualToString:cell.bundleIdentifier]) { 136 | [[AXNManager sharedInstance] hideAllNotificationRequests]; 137 | } 138 | self.selectedBundleIdentifier = cell.bundleIdentifier; 139 | 140 | [[AXNManager sharedInstance] showNotificationRequestsForBundleIdentifier:cell.bundleIdentifier]; 141 | self.showingLatestRequest = NO; 142 | 143 | [[NSClassFromString(@"SBIdleTimerGlobalCoordinator") sharedInstance] resetIdleTimer]; 144 | [[AXNManager sharedInstance] revealNotificationHistory:YES]; 145 | 146 | if (self.collectionViewLayout.scrollDirection == UICollectionViewScrollDirectionVertical) { 147 | if([[AXNManager sharedInstance].clvc respondsToSelector:@selector(collectionView)]) [[[AXNManager sharedInstance].clvc collectionView] _scrollToTopIfPossible:YES]; 148 | } 149 | } 150 | 151 | - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath { 152 | [[AXNManager sharedInstance] hideAllNotificationRequests]; 153 | self.showingLatestRequest = NO; 154 | 155 | [[AXNManager sharedInstance] revealNotificationHistory:NO]; 156 | } 157 | 158 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 159 | if (self.badgesEnabled) { 160 | switch (self.style) { 161 | case 1: return CGSizeMake(64, 64); 162 | case 2: return CGSizeMake(48, 48); 163 | case 3: return CGSizeMake(40, 64); 164 | case 4: return CGSizeMake(60, 30); 165 | case 5: return CGSizeMake(60, 36); 166 | default: return CGSizeMake(64, 90); 167 | } 168 | } else if (!self.badgesEnabled) { 169 | switch (self.style) { 170 | case 1: return CGSizeMake(64, 64); 171 | case 2: return CGSizeMake(48, 48); 172 | case 3: return CGSizeMake(41, 41); 173 | case 4: return CGSizeMake(60, 30); 174 | case 5: return CGSizeMake(60, 36); 175 | default: return CGSizeMake(64, 6); 176 | } 177 | } 178 | return CGSizeMake(0, 0); 179 | } 180 | 181 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { 182 | if (self.alignment != 1) return UIEdgeInsetsMake(0, 0, 0, 0); 183 | 184 | CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing]; 185 | CGFloat width = 64; 186 | CGFloat viewWidth = self.bounds.size.width; 187 | 188 | if (self.style == 2) width = 48; 189 | else if (self.style == 3) width = 40; 190 | 191 | if (self.collectionViewLayout.scrollDirection == UICollectionViewScrollDirectionVertical) { 192 | width = 90; 193 | if (self.style == 1 || self.style == 3) width = 64; 194 | else if (self.style == 2) width = 48; 195 | 196 | viewWidth = self.bounds.size.height; 197 | } 198 | 199 | NSInteger count = [self collectionView:collectionView numberOfItemsInSection:section]; 200 | CGFloat totalCellWidth = width * count; 201 | CGFloat totalSpacingWidth = spacing * (count - 1); 202 | if (totalSpacingWidth < 0) totalSpacingWidth = 0; 203 | 204 | CGFloat leftInset = (viewWidth - (totalCellWidth + totalSpacingWidth)) / 2; 205 | if (leftInset < 0) { 206 | return [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset]; 207 | } 208 | CGFloat rightInset = leftInset; 209 | 210 | if (self.collectionViewLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) { 211 | return UIEdgeInsetsMake(0, leftInset, 0, rightInset); 212 | } else { 213 | return UIEdgeInsetsMake(leftInset, 0, rightInset, 0); 214 | } 215 | } 216 | 217 | - (void)refresh { 218 | [self.list removeAllObjects]; 219 | NSArray *sortedKeys = @[]; 220 | 221 | switch (self.sortingMode) { 222 | case 1: 223 | sortedKeys = [[[AXNManager sharedInstance].notificationRequests allKeys] sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 224 | NSInteger first = [[AXNManager sharedInstance] countForBundleIdentifier:a]; 225 | NSInteger second = [[AXNManager sharedInstance] countForBundleIdentifier:b]; 226 | if (first < second) return (NSComparisonResult)NSOrderedDescending; 227 | if (first > second) return (NSComparisonResult)NSOrderedAscending; 228 | return (NSComparisonResult)NSOrderedSame; 229 | }]; 230 | break; 231 | case 2: 232 | sortedKeys = [[[AXNManager sharedInstance].notificationRequests allKeys] sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 233 | NSString *first = [[AXNManager sharedInstance].names objectForKey:a]; 234 | NSString *second = [[AXNManager sharedInstance].names objectForKey:b]; 235 | return [first compare:second]; 236 | }]; 237 | break; 238 | default: 239 | sortedKeys = [[[AXNManager sharedInstance].notificationRequests allKeys] sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 240 | NSDate *first = [[AXNManager sharedInstance].timestamps objectForKey:a]; 241 | NSDate *second = [[AXNManager sharedInstance].timestamps objectForKey:b]; 242 | return [second compare:first] == NSOrderedDescending; 243 | }]; 244 | } 245 | 246 | for (NSString *key in sortedKeys) { 247 | NSInteger count = [[AXNManager sharedInstance] countForBundleIdentifier:key]; 248 | if (count == 0) continue; 249 | [self.list addObject:@{ 250 | @"bundleIdentifier": key, 251 | @"notificationCount": @(count) 252 | }]; 253 | } 254 | 255 | [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; 256 | [[AXNManager sharedInstance].sbclvc _setListHasContent:([self.list count] > 0)]; 257 | } 258 | 259 | /* Compatibility stuff to keep it from safe moding. */ 260 | 261 | -(void)setContentHost:(id)arg1 {} 262 | -(void)setSizeToMimic:(CGSize)arg1 {} 263 | -(void)_layoutContentHost {} 264 | -(CGSize)sizeToMimic { return self.frame.size; } 265 | -(id)contentHost { return nil; } 266 | -(void)_updateSizeToMimic {} 267 | -(unsigned long long)_optionsForMainOverlay { return 0; } 268 | 269 | @end 270 | -------------------------------------------------------------------------------- /Tweak/Axon.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /Tweak/Makefile: -------------------------------------------------------------------------------- 1 | ARCHS = arm64 arm64e 2 | TARGET = iphone:12.2:12.2 3 | 4 | INSTALL_TARGET_PROCESSES = SpringBoard 5 | 6 | include $(THEOS)/makefiles/common.mk 7 | 8 | TWEAK_NAME = Axon 9 | $(TWEAK_NAME)_FILES = Tweak.xm $(wildcard AXN*.m) 10 | $(TWEAK_NAME)_FRAMEWORKS += QuartzCore WebKit MediaPlayer 11 | ADDITIONAL_OBJCFLAGS = -fobjc-arc 12 | 13 | include $(THEOS_MAKE_PATH)/tweak.mk -------------------------------------------------------------------------------- /Tweak/Protocol.h: -------------------------------------------------------------------------------- 1 | @protocol clvc 2 | @property (nonatomic,assign) BOOL axnAllowChanges; 3 | 4 | @optional 5 | -(void)insertNotificationRequest:(id)arg1 ; 6 | -(void)modifyNotificationRequest:(id)arg1 ; 7 | -(void)removeNotificationRequest:(id)arg1 ; 8 | -(void)insertNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 9 | -(void)modifyNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 10 | -(void)removeNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 11 | -(NSSet *)allNotificationRequests; 12 | -(id)collectionView; 13 | -(void)revealNotificationHistory:(BOOL)revealed; 14 | -(void)updateNotifications; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Tweak/RandomHeaders.h: -------------------------------------------------------------------------------- 1 | #import "Protocol.h" 2 | #import 3 | #import 4 | 5 | @interface BBBulletin : NSObject 6 | 7 | @property (nonatomic,readonly) NSString * sectionDisplayName; 8 | @property (nonatomic,copy) NSString * section; 9 | @property (nonatomic,copy) NSString * sectionID; 10 | @property (nonatomic,copy) NSSet * subsectionIDs; 11 | @property (nonatomic,copy) NSString * recordID; 12 | @property (nonatomic,copy) NSString * publisherBulletinID; 13 | @property (nonatomic,copy) NSString * dismissalID; 14 | @property (nonatomic,copy) NSString * categoryID; 15 | @property (nonatomic,copy) NSString * threadID; 16 | @property (nonatomic,copy) NSArray * peopleIDs; 17 | @property (nonatomic,copy) NSString * bulletinID; 18 | 19 | @end 20 | 21 | @interface NCNotificationContent : NSObject 22 | 23 | @property (nonatomic,readonly) UIImage * icon; 24 | @property (nonatomic,copy,readonly) NSString * header; 25 | 26 | @end 27 | 28 | @interface NCNotificationRequest : NSObject 29 | 30 | @property (nonatomic,readonly) NCNotificationContent * content; 31 | @property (nonatomic,copy,readonly) NSString * sectionIdentifier; 32 | @property (nonatomic,copy,readonly) NSString * notificationIdentifier; 33 | @property (nonatomic,copy,readonly) NSString * threadIdentifier; 34 | @property (nonatomic,copy,readonly) NSString * categoryIdentifier; 35 | @property (nonatomic,readonly) BBBulletin * bulletin; 36 | @property (nonatomic,readonly) NSDate * timestamp; 37 | 38 | @end 39 | 40 | @interface NCCoalescedNotification : NSObject 41 | 42 | @property (nonatomic,copy,readonly) NSArray * notificationRequests; 43 | 44 | @end 45 | 46 | @interface NCNotificationCombinedListViewController : UIViewController 47 | 48 | @property (nonatomic, assign) BOOL axnAllowChanges; 49 | -(id)allNotificationRequests; 50 | -(id)axnNotificationRequests; 51 | -(bool)insertNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 52 | -(void)removeNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 53 | -(bool)modifyNotificationRequest:(id)arg1 forCoalescedNotification:(id)arg2 ; 54 | -(void)insertNotificationRequestIntoRecentsSection:(id)arg1 forCoalescedNotification:(id)arg2 ; 55 | -(void)_performNotificationHistorySectionOperation:(/*^block*/ id)arg1 animated:(bool)arg2 delayAnimation:(bool)arg3 ; 56 | -(void)removeNotificationRequestFromRecentsSection:(id)arg1 forCoalescedNotification:(id)arg2 ; 57 | -(void)forceNotificationHistoryRevealed:(bool)arg1 animated:(bool)arg2 ; 58 | -(void)_revealNotificationsHistory; 59 | -(void)setShouldAllowNotificationsHistoryReveal:(bool)arg1 ; 60 | -(void)_setShowingNotificationsHistory:(bool)arg1 animated:(bool)arg2 ; 61 | -(void)_setShowingNotificationsHistory:(bool)arg1 ; 62 | -(bool)shouldAllowNotificationsHistoryReveal; 63 | -(void)setDidPlayRevealHaptic:(bool)arg1 ; 64 | -(void)setNotificationHistorySectionNeedsReload:(bool)arg1 ; 65 | -(void)_reloadNotificationHistorySectionIfNecessary; 66 | -(id)_coalescingIdentifierForNotificationRequest:(id)arg1 ; 67 | -(bool)hasContent; 68 | -(void)clearAllCoalescingControlsCells; 69 | -(void)clearAll; 70 | -(UICollectionView*)collectionView; 71 | -(void)_resetNotificationsHistory; 72 | 73 | @end 74 | 75 | @interface SBDashBoardCombinedListViewController : UIViewController 76 | -(void)_setListHasContent:(BOOL)arg1; 77 | -(bool)hasContent; 78 | @end 79 | 80 | @interface NCNotificationStore : NSObject 81 | 82 | -(NCCoalescedNotification *)coalescedNotificationForRequest:(id)arg1 ; 83 | 84 | @end 85 | 86 | @interface NCNotificationDispatcher : NSObject 87 | 88 | @property (nonatomic,retain) NCNotificationStore * notificationStore; 89 | -(void)destination:(id)arg1 requestsClearingNotificationRequests:(id)arg2 ; 90 | -(void)destination:(id)arg1 requestsClearingNotificationRequests:(id)arg2 fromDestinations:(id)arg3 ; 91 | 92 | @end 93 | 94 | @interface SBNCNotificationDispatcher : NSObject 95 | 96 | @property (nonatomic,retain) NCNotificationDispatcher * dispatcher; 97 | 98 | @end 99 | 100 | @interface SBIcon : NSObject 101 | 102 | struct SBIconImageInfo { 103 | CGFloat width; 104 | CGFloat height; 105 | CGFloat field1; 106 | CGFloat field2; 107 | }; 108 | 109 | -(UIImage *)getIconImage:(int)arg1 ; 110 | -(UIImage *)iconImageWithInfo:(struct SBIconImageInfo)info; 111 | 112 | @end 113 | 114 | @interface SBIconModel : NSObject 115 | 116 | -(SBIcon *)applicationIconForBundleIdentifier:(id)arg1 ; 117 | 118 | @end 119 | 120 | @interface SBIconViewMap : NSObject 121 | 122 | @property (nonatomic,readonly) SBIconModel * iconModel; 123 | 124 | @end 125 | 126 | @interface SBIconController : UIViewController 127 | 128 | @property (nonatomic, retain) WKWebView *axnIntegrityView; 129 | +(id)sharedInstance; 130 | -(SBIconViewMap *)homescreenIconViewMap; 131 | -(SBIconModel *)model; 132 | 133 | @end 134 | 135 | @interface UIImage (Private) 136 | 137 | + (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)bundleIdentifier format:(int)format scale:(CGFloat)scale; 138 | 139 | @end 140 | 141 | @interface CALayer (Private) 142 | 143 | @property (nonatomic, assign) BOOL continuousCorners; 144 | 145 | @end 146 | 147 | @interface _UILegibilitySettings : NSObject 148 | 149 | @property (nonatomic,retain) UIColor * primaryColor; 150 | 151 | @end 152 | 153 | @interface SBFLockScreenDateView : UIView 154 | 155 | @property (nonatomic,retain) _UILegibilitySettings * legibilitySettings; 156 | -(id)initWithFrame:(CGRect)arg1 ; 157 | -(void)setLegibilitySettings:(_UILegibilitySettings *)arg1 ; 158 | 159 | @end 160 | 161 | @interface SBIdleTimerGlobalCoordinator : NSObject 162 | 163 | +(id)sharedInstance; 164 | -(void)resetIdleTimer; 165 | 166 | @end 167 | 168 | @interface UIScrollView(Private) 169 | 170 | -(BOOL)_scrollToTopIfPossible:(BOOL)arg1; 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /Tweak/Tweak.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import "RandomHeaders.h" 5 | #import "AXNView.h" 6 | 7 | @interface SBDashBoardNotificationAdjunctListViewController : UIViewController { 8 | UIStackView* _stackView; 9 | } 10 | 11 | @property (nonatomic, retain) AXNView *axnView; 12 | 13 | -(void)adjunctListModel:(id)arg1 didAddItem:(id)arg2 ; 14 | -(void)adjunctListModel:(id)arg1 didRemoveItem:(id)arg2 ; 15 | -(void)_didUpdateDisplay; 16 | -(CGSize)sizeToMimic; 17 | -(void)_insertItem:(id)arg1 animated:(BOOL)arg2 ; 18 | -(void)_removeItem:(id)arg1 animated:(BOOL)arg2 ; 19 | -(BOOL)isPresentingContent; 20 | 21 | @end 22 | // iOS13 Support 23 | @interface CSNotificationAdjunctListViewController : UIViewController { 24 | UIStackView* _stackView; 25 | } 26 | 27 | @property (nonatomic, retain) AXNView *axnView; 28 | 29 | -(void)adjunctListModel:(id)arg1 didAddItem:(id)arg2 ; 30 | -(void)adjunctListModel:(id)arg1 didRemoveItem:(id)arg2 ; 31 | -(void)_didUpdateDisplay; 32 | -(CGSize)sizeToMimic; 33 | -(void)_insertItem:(id)arg1 animated:(BOOL)arg2 ; 34 | -(void)_removeItem:(id)arg1 animated:(BOOL)arg2 ; 35 | -(BOOL)isPresentingContent; 36 | 37 | @end 38 | 39 | 40 | @interface SBDashBoardCombinedListViewController (Axon) 41 | 42 | @property (nonatomic, retain) AXNView *axnView; 43 | 44 | @end 45 | // iOS13 Support 46 | @interface CSCombinedListViewController : UIViewController 47 | 48 | @property (nonatomic, retain) AXNView *axnView; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Tweak/Tweak.xm: -------------------------------------------------------------------------------- 1 | #import "Tweak.h" 2 | #import "AXNManager.h" 3 | 4 | NSDictionary *prefs; 5 | BOOL initialized = NO; 6 | BOOL enabled; 7 | BOOL vertical; 8 | BOOL badgesEnabled; 9 | BOOL badgesShowBackground; 10 | BOOL hapticFeedback; 11 | NSInteger darkMode; 12 | NSInteger sortingMode; 13 | NSInteger selectionStyle; 14 | BOOL addBlur; 15 | NSInteger style; 16 | NSInteger showByDefault; 17 | NSInteger alignment; 18 | NSInteger iconStyle; 19 | NSInteger verticalPosition; 20 | NSInteger autoLayout; 21 | NSInteger yAxis; 22 | NSInteger location; 23 | CGFloat spacing; 24 | 25 | void updateViewConfiguration() { 26 | if (initialized && [AXNManager sharedInstance].view) { 27 | [AXNManager sharedInstance].view.hapticFeedback = hapticFeedback; 28 | [AXNManager sharedInstance].view.badgesEnabled = badgesEnabled; 29 | [AXNManager sharedInstance].view.badgesShowBackground = badgesShowBackground; 30 | [AXNManager sharedInstance].view.selectionStyle = selectionStyle; 31 | [AXNManager sharedInstance].view.addBlur = addBlur; 32 | [AXNManager sharedInstance].view.sortingMode = sortingMode; 33 | [AXNManager sharedInstance].view.style = style; 34 | [AXNManager sharedInstance].view.darkMode = darkMode; 35 | [AXNManager sharedInstance].view.showByDefault = showByDefault; 36 | [AXNManager sharedInstance].view.spacing = spacing; 37 | [AXNManager sharedInstance].view.alignment = alignment; 38 | [AXNManager sharedInstance].view.iconStyle = iconStyle; 39 | } 40 | } 41 | 42 | %group Axon 43 | 44 | @interface NCNotificationListSectionHeaderView : UIView 45 | @end 46 | 47 | %hook NCNotificationListSectionHeaderView 48 | - (void)layoutSubviews { 49 | self.hidden = 1; 50 | } 51 | -(CGRect)frame { 52 | return CGRectMake(0,0,0,0); 53 | } 54 | -(BOOL)hidden { 55 | return true; 56 | } 57 | %end 58 | 59 | #pragma mark Legibility color 60 | 61 | %hook SBFLockScreenDateView 62 | 63 | -(id)initWithFrame:(CGRect)arg1 { 64 | %orig; 65 | if (self.legibilitySettings && self.legibilitySettings.primaryColor) { 66 | [AXNManager sharedInstance].fallbackColor = [self.legibilitySettings.primaryColor copy]; 67 | } 68 | return self; 69 | } 70 | 71 | -(void)setLegibilitySettings:(_UILegibilitySettings *)arg1 { 72 | %orig; 73 | if (self.legibilitySettings && self.legibilitySettings.primaryColor) { 74 | [AXNManager sharedInstance].fallbackColor = [self.legibilitySettings.primaryColor copy]; 75 | } 76 | } 77 | 78 | %end 79 | 80 | #pragma mark Store dispatcher for future use 81 | 82 | %hook SBNCNotificationDispatcher 83 | 84 | -(id)init { 85 | %orig; 86 | [AXNManager sharedInstance].dispatcher = self.dispatcher; 87 | return self; 88 | } 89 | 90 | -(void)setDispatcher:(NCNotificationDispatcher *)arg1 { 91 | %orig; 92 | [AXNManager sharedInstance].dispatcher = arg1; 93 | } 94 | 95 | %end 96 | 97 | #pragma mark Inject the Axon view into NC 98 | 99 | %hook SBDashBoardNotificationAdjunctListViewController 100 | 101 | %property (nonatomic, retain) AXNView *axnView; 102 | 103 | 104 | -(BOOL)hasContent { 105 | return YES; 106 | } 107 | 108 | %end 109 | 110 | // iOS13 Support 111 | %hook CSNotificationAdjunctListViewController 112 | %property (nonatomic, retain) AXNView *axnView; 113 | %end 114 | 115 | #pragma mark Notification management 116 | 117 | %hook NCNotificationCombinedListViewController 118 | 119 | %property (nonatomic,assign) BOOL axnAllowChanges; 120 | 121 | /* Store this object for future use. */ 122 | 123 | -(id)init { 124 | %orig; 125 | [AXNManager sharedInstance].clvc = self; 126 | self.axnAllowChanges = NO; 127 | return self; 128 | } 129 | 130 | /* Replace notification management functions with our logic. */ 131 | 132 | -(bool)insertNotificationRequest:(NCNotificationRequest *)req forCoalescedNotification:(id)arg2 { 133 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 134 | [[AXNManager sharedInstance] insertNotificationRequest:req]; 135 | [[AXNManager sharedInstance].view refresh]; 136 | 137 | if (req.bulletin.sectionID) { 138 | NSString *bundleIdentifier = req.bulletin.sectionID; 139 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 140 | } 141 | 142 | if (![AXNManager sharedInstance].view.selectedBundleIdentifier && showByDefault == 1) { 143 | [[AXNManager sharedInstance].view reset]; 144 | } 145 | 146 | return YES; 147 | } 148 | 149 | -(bool)removeNotificationRequest:(NCNotificationRequest *)req forCoalescedNotification:(id)arg2 { 150 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 151 | 152 | NSString *identifier = [[req notificationIdentifier] copy]; 153 | 154 | [[AXNManager sharedInstance] removeNotificationRequest:req]; 155 | [[AXNManager sharedInstance].view refresh]; 156 | 157 | if (req.bulletin.sectionID) { 158 | NSString *bundleIdentifier = req.bulletin.sectionID; 159 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 160 | } 161 | 162 | if ([AXNManager sharedInstance].view.showingLatestRequest && identifier && 163 | [[[AXNManager sharedInstance].latestRequest notificationIdentifier] isEqualToString:identifier]) { 164 | %orig; 165 | } 166 | 167 | return YES; 168 | } 169 | 170 | -(bool)modifyNotificationRequest:(NCNotificationRequest *)req forCoalescedNotification:(id)arg2 { 171 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 172 | 173 | NSString *identifier = [[req notificationIdentifier] copy]; 174 | 175 | [[AXNManager sharedInstance] modifyNotificationRequest:req]; 176 | [[AXNManager sharedInstance].view refresh]; 177 | 178 | if (req.bulletin.sectionID) { 179 | NSString *bundleIdentifier = req.bulletin.sectionID; 180 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 181 | } 182 | 183 | if ([AXNManager sharedInstance].view.showingLatestRequest && identifier && 184 | [[[AXNManager sharedInstance].latestRequest notificationIdentifier] isEqualToString:identifier]) { 185 | %orig; 186 | } 187 | 188 | return YES; 189 | } 190 | 191 | -(bool)hasContent { 192 | if ([AXNManager sharedInstance].view.list && [[AXNManager sharedInstance].view.list count] > 0) return YES; 193 | return %orig; 194 | } 195 | 196 | -(void)viewDidAppear:(BOOL)animated { 197 | %orig; 198 | [[AXNManager sharedInstance].view reset]; 199 | [[AXNManager sharedInstance].view refresh]; 200 | } 201 | 202 | /* Fix pull to clear all tweaks. */ 203 | 204 | -(void)_clearAllPriorityListNotificationRequests { 205 | [[AXNManager sharedInstance].dispatcher destination:nil requestsClearingNotificationRequests:[self allNotificationRequests]]; 206 | } 207 | 208 | -(void)_clearAllNotificationRequests { 209 | [[AXNManager sharedInstance].dispatcher destination:nil requestsClearingNotificationRequests:[self allNotificationRequests]]; 210 | } 211 | 212 | -(void)clearAll { 213 | [[AXNManager sharedInstance].dispatcher destination:nil requestsClearingNotificationRequests:[self axnNotificationRequests]]; 214 | } 215 | 216 | /* Compatibility thing for other tweaks. */ 217 | 218 | %new 219 | -(id)axnNotificationRequests { 220 | NSMutableOrderedSet *allRequests = [NSMutableOrderedSet new]; 221 | for (NSString *key in [[AXNManager sharedInstance].notificationRequests allKeys]) { 222 | [allRequests addObjectsFromArray:[[AXNManager sharedInstance] requestsForBundleIdentifier:key]]; 223 | } 224 | return allRequests; 225 | } 226 | 227 | %new 228 | -(void)revealNotificationHistory:(BOOL)revealed { 229 | [self setDidPlayRevealHaptic:YES]; 230 | [self forceNotificationHistoryRevealed:revealed animated:NO]; 231 | [self setNotificationHistorySectionNeedsReload:YES]; 232 | [self _reloadNotificationHistorySectionIfNecessary]; 233 | if (!revealed && [self respondsToSelector:@selector(clearAllCoalescingControlsCells)]) [self clearAllCoalescingControlsCells]; 234 | } 235 | 236 | %new 237 | -(void)updateNotifications { 238 | [self _resetNotificationsHistory]; 239 | } 240 | 241 | %end 242 | 243 | // iOS13 Support 244 | @interface NCNotificationMasterList 245 | @property(retain, nonatomic) NSMutableArray *notificationSections; 246 | @end 247 | @interface NCNotificationStructuredSectionList 248 | @property (nonatomic,readonly) NSArray * allNotificationRequests; 249 | @end 250 | @interface NCNotificationStructuredListViewController : UIViewController 251 | @property (nonatomic,assign) BOOL axnAllowChanges; 252 | @property (nonatomic,retain) NCNotificationMasterList * masterList; 253 | -(void)revealNotificationHistory:(BOOL)arg1 animated:(BOOL)arg2 ; 254 | -(void)_resetCellWithRevealedActions; 255 | @end 256 | %hook NCNotificationStructuredListViewController 257 | %property (nonatomic,assign) BOOL axnAllowChanges; 258 | -(id)init { 259 | %orig; 260 | [AXNManager sharedInstance].clvc = self; 261 | self.axnAllowChanges = NO; 262 | return self; 263 | } 264 | -(bool)insertNotificationRequest:(NCNotificationRequest *)req { 265 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 266 | [[AXNManager sharedInstance] insertNotificationRequest:req]; 267 | [[AXNManager sharedInstance].view refresh]; 268 | 269 | if (req.bulletin.sectionID) { 270 | NSString *bundleIdentifier = req.bulletin.sectionID; 271 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 272 | } 273 | 274 | if (![AXNManager sharedInstance].view.selectedBundleIdentifier && showByDefault == 1) { 275 | [[AXNManager sharedInstance].view reset]; 276 | } 277 | 278 | return YES; 279 | } 280 | 281 | -(bool)removeNotificationRequest:(NCNotificationRequest *)req { 282 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 283 | 284 | NSString *identifier = [[req notificationIdentifier] copy]; 285 | 286 | [[AXNManager sharedInstance] removeNotificationRequest:req]; 287 | [[AXNManager sharedInstance].view refresh]; 288 | 289 | if (req.bulletin.sectionID) { 290 | NSString *bundleIdentifier = req.bulletin.sectionID; 291 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 292 | } 293 | 294 | if ([AXNManager sharedInstance].view.showingLatestRequest && identifier && 295 | [[[AXNManager sharedInstance].latestRequest notificationIdentifier] isEqualToString:identifier]) { 296 | %orig; 297 | } 298 | 299 | return YES; 300 | } 301 | 302 | -(bool)modifyNotificationRequest:(NCNotificationRequest *)req { 303 | if (self.axnAllowChanges) return %orig; // This condition is true when Axon is updating filtered notifications for display. 304 | 305 | NSString *identifier = [[req notificationIdentifier] copy]; 306 | 307 | [[AXNManager sharedInstance] modifyNotificationRequest:req]; 308 | [[AXNManager sharedInstance].view refresh]; 309 | 310 | if (req.bulletin.sectionID) { 311 | NSString *bundleIdentifier = req.bulletin.sectionID; 312 | if ([bundleIdentifier isEqualToString:[AXNManager sharedInstance].view.selectedBundleIdentifier]) %orig; 313 | } 314 | 315 | if ([AXNManager sharedInstance].view.showingLatestRequest && identifier && 316 | [[[AXNManager sharedInstance].latestRequest notificationIdentifier] isEqualToString:identifier]) { 317 | %orig; 318 | } 319 | 320 | return YES; 321 | } 322 | 323 | -(void)viewDidAppear:(BOOL)animated { 324 | %orig; 325 | [[AXNManager sharedInstance].view reset]; 326 | [[AXNManager sharedInstance].view refresh]; 327 | } 328 | 329 | %new 330 | -(id)axnNotificationRequests { 331 | NSMutableOrderedSet *allRequests = [NSMutableOrderedSet new]; 332 | for (NSString *key in [[AXNManager sharedInstance].notificationRequests allKeys]) { 333 | [allRequests addObjectsFromArray:[[AXNManager sharedInstance] requestsForBundleIdentifier:key]]; 334 | } 335 | return allRequests; 336 | } 337 | 338 | %new 339 | -(NSSet *)allNotificationRequests { 340 | NSArray *array = [NSMutableArray new]; 341 | NCNotificationMasterList *masterList = [self masterList]; 342 | for(NCNotificationStructuredSectionList *item in [masterList notificationSections]) { 343 | array = [array arrayByAddingObjectsFromArray:[item allNotificationRequests]]; 344 | } 345 | return [[NSSet alloc] initWithArray:array]; 346 | } 347 | 348 | %new 349 | -(void)revealNotificationHistory:(BOOL)revealed { 350 | [self revealNotificationHistory:revealed animated:true]; 351 | } 352 | 353 | %new 354 | -(void)updateNotifications { 355 | [self _resetCellWithRevealedActions]; 356 | } 357 | 358 | %end 359 | 360 | #pragma mark Compatibility stuff 361 | 362 | %hook NCNotificationListViewController 363 | 364 | /* FastUnlockX */ 365 | 366 | -(BOOL)hasVisibleContent { 367 | if ([AXNManager sharedInstance].view && [[AXNManager sharedInstance].view.list count] > 0) return YES; 368 | return %orig; 369 | } 370 | 371 | %end 372 | 373 | %hook SparkAutoUnlockX 374 | 375 | /* The only way I know of... AutoUnlockX */ 376 | 377 | -(BOOL)externalBlocksUnlock { 378 | if ([AXNManager sharedInstance].view && [[AXNManager sharedInstance].view.list count] > 0) return YES; 379 | return %orig; 380 | } 381 | 382 | %end 383 | 384 | %hook NCNotificationListSectionRevealHintView 385 | 386 | /* Hide "No older notifications." */ 387 | 388 | -(void)layoutSubviews { 389 | %orig; 390 | MSHookIvar(self, "_revealHintTitle").hidden = YES; 391 | } 392 | 393 | %end 394 | 395 | %hook SBDashBoardViewController 396 | 397 | /* Hide all notifications on open. */ 398 | 399 | -(void)viewWillAppear:(BOOL)animated { 400 | %orig; 401 | [[AXNManager sharedInstance].view reset]; 402 | [[AXNManager sharedInstance].view refresh]; 403 | } 404 | 405 | %end 406 | 407 | // iOS13 Support 408 | %hook CSPageViewController 409 | -(void)viewWillAppear:(BOOL)animated { 410 | %orig; 411 | [[AXNManager sharedInstance].view reset]; 412 | [[AXNManager sharedInstance].view refresh]; 413 | } 414 | %end 415 | 416 | 417 | %end 418 | @interface NCNotificationContentView : NSObject 419 | @end 420 | @interface UIView (Private) 421 | -(NSArray *)allSubviews; 422 | @end 423 | %group AxonVertical 424 | 425 | %hook NCNotificationCombinedListViewController 426 | 427 | %property (nonatomic,assign) BOOL axnAllowChanges; 428 | 429 | -(UIEdgeInsets)insetMargins { 430 | if (verticalPosition == 0) return UIEdgeInsetsMake(0, -96, 0, 0); 431 | else return UIEdgeInsetsMake(0, 0, 0, -96); 432 | } 433 | 434 | -(CGSize)collectionView:(UICollectionView *)arg1 layout:(UICollectionViewLayout*)arg2 sizeForItemAtIndexPath:(id)arg3 { 435 | CGSize orig = %orig; 436 | UIView *view = [arg1 cellForItemAtIndexPath:arg3].contentView; 437 | for(id item in view.allSubviews) { 438 | if([item isKindOfClass:[objc_getClass("NCNotificationContentView") class]]) { 439 | return CGSizeMake(orig.width - 96, ((UIView *)item).frame.size.height+30); 440 | } 441 | } 442 | return CGSizeMake(orig.width - 96, orig.height); 443 | } 444 | 445 | %end 446 | 447 | // iOS 13 Support 448 | %hook NCNotificationStructuredListViewController 449 | %property (nonatomic,assign) BOOL axnAllowChanges; 450 | -(UIEdgeInsets)insetMargins { 451 | if (verticalPosition == 0) return UIEdgeInsetsMake(0, -96, 0, 0); 452 | else return UIEdgeInsetsMake(0, 0, 0, -96); 453 | } 454 | %end 455 | 456 | %hook SBDashBoardCombinedListViewController 457 | 458 | %property (nonatomic, retain) AXNView *axnView; 459 | 460 | -(void)viewDidLoad{ 461 | %orig; 462 | if (!initialized) { 463 | initialized = YES; 464 | self.axnView = [[AXNView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 96, 0, 96, 500)]; 465 | self.axnView.translatesAutoresizingMaskIntoConstraints = NO; 466 | self.axnView.collectionViewLayout.scrollDirection = UICollectionViewScrollDirectionVertical; 467 | [AXNManager sharedInstance].view = self.axnView; 468 | updateViewConfiguration(); 469 | 470 | [self.view addSubview:self.axnView]; 471 | 472 | [NSLayoutConstraint activateConstraints:@[ 473 | [self.axnView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], 474 | [self.axnView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], 475 | [self.axnView.widthAnchor constraintEqualToConstant:90] 476 | ]]; 477 | 478 | if (verticalPosition == 0) { 479 | [NSLayoutConstraint activateConstraints:@[ 480 | [self.axnView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], 481 | ]]; 482 | } else { 483 | [NSLayoutConstraint activateConstraints:@[ 484 | [self.axnView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], 485 | ]]; 486 | } 487 | } 488 | [AXNManager sharedInstance].sbclvc = self; 489 | } 490 | 491 | %end 492 | 493 | // iOS 13 Support 494 | %hook CSCombinedListViewController 495 | %property (nonatomic, retain) AXNView *axnView; 496 | -(void)viewDidLoad{ 497 | %orig; 498 | if (!initialized) { 499 | initialized = YES; 500 | self.axnView = [[AXNView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 96, 0, 96, 500)]; 501 | self.axnView.translatesAutoresizingMaskIntoConstraints = NO; 502 | self.axnView.collectionViewLayout.scrollDirection = UICollectionViewScrollDirectionVertical; 503 | [AXNManager sharedInstance].view = self.axnView; 504 | updateViewConfiguration(); 505 | 506 | [self.view addSubview:self.axnView]; 507 | 508 | [NSLayoutConstraint activateConstraints:@[ 509 | [self.axnView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], 510 | [self.axnView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], 511 | [self.axnView.widthAnchor constraintEqualToConstant:90] 512 | ]]; 513 | 514 | if (verticalPosition == 0) { 515 | [NSLayoutConstraint activateConstraints:@[ 516 | [self.axnView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], 517 | ]]; 518 | } else { 519 | [NSLayoutConstraint activateConstraints:@[ 520 | [self.axnView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], 521 | ]]; 522 | } 523 | } 524 | [AXNManager sharedInstance].sbclvc = self; 525 | } 526 | %end 527 | 528 | %end 529 | 530 | 531 | 532 | 533 | 534 | 535 | %group AxonHorizontal 536 | 537 | %hook SBDashBoardCombinedListViewController 538 | 539 | -(void)viewDidLoad{ 540 | %orig; 541 | [AXNManager sharedInstance].sbclvc = self; 542 | } 543 | 544 | %end 545 | 546 | // iOS 13 Support 547 | %hook CSCombinedListViewController 548 | -(void)viewDidLoad{ 549 | %orig; 550 | [AXNManager sharedInstance].sbclvc = self; 551 | } 552 | %end 553 | 554 | %hook SBDashBoardNotificationAdjunctListViewController 555 | 556 | %property (nonatomic, retain) AXNView *axnView; 557 | 558 | -(void)viewDidLoad { 559 | %orig; 560 | 561 | if (!initialized && location == 0) { 562 | initialized = YES; 563 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 564 | self.axnView = [[AXNView alloc] initWithFrame:CGRectMake(0,0,64,90)]; 565 | self.axnView.translatesAutoresizingMaskIntoConstraints = NO; 566 | [AXNManager sharedInstance].view = self.axnView; 567 | updateViewConfiguration(); 568 | 569 | NSMutableArray *constraints = [@[ 570 | [self.axnView.centerXAnchor constraintEqualToAnchor:stackView.centerXAnchor], 571 | [self.axnView.leadingAnchor constraintEqualToAnchor:stackView.leadingAnchor constant:10], 572 | [self.axnView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor constant:-10], 573 | [self.axnView.heightAnchor constraintEqualToConstant:style == 4 ? 30 : (style == 5 ? 36 : 90)] 574 | ] mutableCopy]; 575 | 576 | [stackView addArrangedSubview:self.axnView]; 577 | [NSLayoutConstraint activateConstraints:constraints]; 578 | } 579 | } 580 | 581 | /* This is used to make the Axon view last, e.g. when media controls are presented. */ 582 | 583 | -(void)_updatePresentingContent { 584 | %orig; 585 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 586 | [stackView removeArrangedSubview:self.axnView]; 587 | [stackView addArrangedSubview:self.axnView]; 588 | } 589 | 590 | -(void)_insertItem:(id)arg1 animated:(BOOL)arg2 { 591 | %orig; 592 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 593 | [stackView removeArrangedSubview:self.axnView]; 594 | [stackView addArrangedSubview:self.axnView]; 595 | } 596 | 597 | /* Let Springboard know we have a little surprise for it. */ 598 | 599 | -(BOOL)isPresentingContent { 600 | return YES; 601 | } 602 | 603 | %end 604 | 605 | %hook NCNotificationCombinedListViewController 606 | -(void)viewDidLoad{ 607 | %orig; 608 | if (!initialized && location == 1) { 609 | initialized = YES; 610 | AXNView *axnView = [[AXNView alloc] initWithFrame:CGRectMake(0,0,64,90)]; 611 | axnView.translatesAutoresizingMaskIntoConstraints = NO; 612 | [AXNManager sharedInstance].view = axnView; 613 | updateViewConfiguration(); 614 | 615 | NSMutableArray *constraints = [@[ 616 | [axnView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], 617 | [axnView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:10], 618 | [axnView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-10], 619 | [axnView.heightAnchor constraintEqualToConstant:style == 4 ? 30 : (style == 5 ? 36 : 90)] 620 | ] mutableCopy]; 621 | 622 | if(autoLayout) [constraints addObject:[axnView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-55]]; 623 | else [constraints addObject:[axnView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:yAxis]]; 624 | 625 | [self.view addSubview:axnView]; 626 | [NSLayoutConstraint activateConstraints:constraints]; 627 | } 628 | } 629 | %end 630 | %hook NCNotificationStructuredListViewController 631 | -(void)viewDidLoad{ 632 | %orig; 633 | if (!initialized && location == 1) { 634 | initialized = YES; 635 | AXNView *axnView = [[AXNView alloc] initWithFrame:CGRectMake(0,0,64,90)]; 636 | axnView.translatesAutoresizingMaskIntoConstraints = NO; 637 | [AXNManager sharedInstance].view = axnView; 638 | updateViewConfiguration(); 639 | 640 | NSMutableArray *constraints = [@[ 641 | [axnView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], 642 | [axnView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:10], 643 | [axnView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-10], 644 | [axnView.heightAnchor constraintEqualToConstant:style == 4 ? 30 : (style == 5 ? 36 : 90)] 645 | ] mutableCopy]; 646 | 647 | if(autoLayout) [constraints addObject:[axnView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-55]]; 648 | else [constraints addObject:[axnView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:yAxis]]; 649 | 650 | [self.view addSubview:axnView]; 651 | [NSLayoutConstraint activateConstraints:constraints]; 652 | } 653 | } 654 | %end 655 | 656 | %hook CSNotificationAdjunctListViewController 657 | %property (nonatomic, retain) AXNView *axnView; 658 | -(void)viewDidLoad { 659 | %orig; 660 | 661 | if (!initialized && location == 0) { 662 | initialized = YES; 663 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 664 | self.axnView = [[AXNView alloc] initWithFrame:CGRectMake(0,0,64,90)]; 665 | self.axnView.translatesAutoresizingMaskIntoConstraints = NO; 666 | [AXNManager sharedInstance].view = self.axnView; 667 | updateViewConfiguration(); 668 | 669 | NSMutableArray *constraints = [@[ 670 | [self.axnView.centerXAnchor constraintEqualToAnchor:stackView.centerXAnchor], 671 | [self.axnView.leadingAnchor constraintEqualToAnchor:stackView.leadingAnchor constant:10], 672 | [self.axnView.trailingAnchor constraintEqualToAnchor:stackView.trailingAnchor constant:-10], 673 | [self.axnView.heightAnchor constraintEqualToConstant:style == 4 ? 30 : (style == 5 ? 36 : 90)] 674 | ] mutableCopy]; 675 | 676 | [stackView addArrangedSubview:self.axnView]; 677 | [NSLayoutConstraint activateConstraints:constraints]; 678 | } 679 | } 680 | 681 | -(void)_updatePresentingContent { 682 | %orig; 683 | if(location == 1) return; 684 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 685 | [stackView removeArrangedSubview:self.axnView]; 686 | [stackView addArrangedSubview:self.axnView]; 687 | } 688 | -(void)_insertItem:(id)arg1 animated:(BOOL)arg2 { 689 | %orig; 690 | if(location == 1) return; 691 | UIStackView *stackView = [self valueForKey:@"_stackView"]; 692 | [stackView removeArrangedSubview:self.axnView]; 693 | [stackView addArrangedSubview:self.axnView]; 694 | } 695 | 696 | -(BOOL)isPresentingContent { 697 | return YES; 698 | } 699 | %end 700 | 701 | 702 | %end 703 | 704 | /* Hide all notifications on open. */ 705 | 706 | static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 707 | [[AXNManager sharedInstance].view reset]; 708 | [[AXNManager sharedInstance].view refresh]; 709 | } 710 | 711 | 712 | void loadPrefs() { 713 | prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/me.nepeta.axon.plist"]; 714 | enabled = prefs[@"Enabled"] != nil ? [prefs[@"Enabled"] boolValue] : true; 715 | vertical = prefs[@"Vertical"] != nil ? [prefs[@"Vertical"] boolValue] : false; 716 | hapticFeedback = prefs[@"HapticFeedback"] != nil ? [prefs[@"HapticFeedback"] boolValue] : true; 717 | badgesEnabled = prefs[@"BadgesEnabled"] != nil ? [prefs[@"BadgesEnabled"] boolValue] : true; 718 | badgesShowBackground = prefs[@"BadgesShowBackground"] != nil ? [prefs[@"BadgesShowBackground"] boolValue] : true; 719 | darkMode = [prefs[@"DarkMode"] intValue] ?: 0; 720 | sortingMode = [prefs[@"SortingMode"] intValue] ?: 0; 721 | selectionStyle = [prefs[@"SelectionStyle"] intValue] ?: 0; 722 | addBlur = prefs[@"addBlur"] != nil ? [prefs[@"addBlur"] boolValue] : false; 723 | style = [prefs[@"Style"] intValue] ?: 0; 724 | showByDefault = [prefs[@"ShowByDefault"] intValue] ?: 0; 725 | alignment = [prefs[@"Alignment"] intValue] ?: 0; 726 | iconStyle = [prefs[@"iconStyle"] intValue] ?: 0; 727 | verticalPosition = [prefs[@"VerticalPosition"] intValue] ?: 0; 728 | spacing = [prefs[@"Spacing"] floatValue] ?: 10; 729 | autoLayout = prefs[@"autoLayout"] != nil ? [prefs[@"autoLayout"] boolValue] : true; 730 | location = [prefs[@"location"] intValue] ?: 0; 731 | if(autoLayout == false) location = 1; 732 | yAxis = [prefs[@"yAxis"] intValue] ?: 0; 733 | if(style > 5) style = 4; 734 | updateViewConfiguration(); 735 | } 736 | 737 | 738 | %ctor { 739 | NSLog(@"[Axon] init"); 740 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)loadPrefs, CFSTR("me.nepeta.axon/ReloadPrefs"), NULL, CFNotificationSuspensionBehaviorCoalesce); 741 | loadPrefs(); 742 | 743 | if(enabled) { 744 | %init(Axon); 745 | if (!vertical) %init(AxonHorizontal); 746 | else %init(AxonVertical); 747 | } 748 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, displayStatusChanged, CFSTR("com.apple.iokit.hid.displayStatus"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 749 | } 750 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: me.nepeta.axon 2 | Name: Axon 3 | Depends: mobilesubstrate, firmware (>= 11.0) 4 | Conflicts: io.ominousness.stackxi, com.thomasfinch.priorityhub, com.ioscreatix.intelixbeta, com.ioscreatix.intelix, com.spiritoflogic.ncunify, com.spiritoflogic.unifyx, com.hidan.nclink10, org.coolstar.ventana-modern, org.coolstar.ventana, org.s1ris.spinxi 5 | Version: 1.4 6 | Architecture: iphoneos-arm 7 | Description: Priority Hub for iOS 11 and 12 8 | Maintainer: Baw Appie 9 | Author: Nepeta & Baw Appie 10 | Section: Tweaks 11 | --------------------------------------------------------------------------------