From 1f6adf8c7341c3fac52fd5fb6c463fb56881e0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erast=20=EF=A3=BF?= <78802792+MatoiDev@users.noreply.github.com> Date: Fri, 5 Jul 2024 17:08:59 +0300 Subject: [PATCH] [+][f] added the functionality of the xmark button, fixed the error with the springboard crash when closing applications --- Extensions/Extensions.h | 1 - README.md | 4 +- UI/Router/RouterView.m | 3 +- Witcher.x | 87 +++++++++++++------ .../UI/Cells/AuthorCell/AuthorCell.m | 2 - WitcherPreferences/WTRRootListController.m | 31 ++++++- control | 2 +- 7 files changed, 93 insertions(+), 37 deletions(-) diff --git a/Extensions/Extensions.h b/Extensions/Extensions.h index dd5339a..cb38d27 100644 --- a/Extensions/Extensions.h +++ b/Extensions/Extensions.h @@ -2,7 +2,6 @@ #import #import #import -#include #define WITCHER_PLIST_SETTINGS ROOT_PATH_NS(@"/var/mobile/Library/Preferences/dr.erast.witcherprefs.plist") #define WITCHER_PREFERENCES_BUNDLE_PATH ROOT_PATH_NS(@"/Library/PreferenceBundles/WitcherPreferences.bundle") diff --git a/README.md b/README.md index 672329b..b068afe 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ https://github.com/MatoiDev/Witcher/assets/78802792/9b2195ae-b183-4e2c-b4de-7560 - [X] Make Logo - [X] Preferences integration - [X] Add support to hardware-button devices -- [ ] Add options to preferences +- [X] Add options to preferences +- [X] Add xmark button functional - [ ] Add support to iOS 16+ -- [ ] Add xmark button functional ### For testers diff --git a/UI/Router/RouterView.m b/UI/Router/RouterView.m index 4fd4a0a..3fe5da9 100644 --- a/UI/Router/RouterView.m +++ b/UI/Router/RouterView.m @@ -93,7 +93,6 @@ -(void)setupStaticCell { -(void)setupQuickActionButtons { closeAppButton = [[UIButton alloc] init]; - [closeAppButton setEnabled:NO]; [closeAppButton addTarget:self action:@selector(closeApp) forControlEvents:UIControlEventTouchUpInside]; [closeAppButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal]; @@ -156,6 +155,7 @@ -(void)updateCellsWithNewApplications:(NSArray } [goToPreviousAppButton setEnabled:[layoutStructs count] > 0]; + [closeAppButton setEnabled:[layoutStructs count] + flag > 0]; [self updateStaticCellPosition]; @@ -394,7 +394,6 @@ -(void)updateActionButtonsWithState:(_Bool)state { [searchButton setHidden:state]; [closeAppButton setHidden:state]; - [searchButton setUserInteractionEnabled:NO]; actionButtonsIsActive = !state; } diff --git a/Witcher.x b/Witcher.x index 7678f0e..4907049 100644 --- a/Witcher.x +++ b/Witcher.x @@ -1,10 +1,6 @@ #import "Witcher.h" -/* TODO - - (Not implemented) Kill aplications with quick action button: https://www.reddit.com/r/jailbreakdevelopers/comments/d6wbla/remove_app_from_app_switcher/ -*/ - #pragma mark - Views RouterView *router = nil; WitcherApplicationLayoutContainer *container = nil; @@ -17,6 +13,7 @@ SBMainSwitcherViewController *mainAppSwitcherVC; #pragma mark - Generators UIImpactFeedbackGenerator *impactFeedbackGenerator = nil; +UIImpactFeedbackGenerator *heavyImpactFeedbackGenerator = nil; #pragma mark - Data NSMutableDictionary *mutableReusableContainersData = nil; @@ -35,6 +32,7 @@ NSUserDefaults *prefs; _Bool isEnabled; _Bool hardwareButtonMode; +_Bool killNowPlayingApplication; static UIColor* colorFromHex(NSString *hexString, BOOL useAlpha); static void updateSettings(); @@ -68,12 +66,33 @@ static void updateSettings(); } else if ([[notification name] isEqualToString: @"ReleaseFrontMostApplication"]) { SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication]; - if (!frontApp) { - NSArray *recentAppLayouts = [self performSelector:@selector(getApps)]; - for (SBAppLayout *appLayout in recentAppLayouts) { - [self performSelector:@selector(removeAppLayout:) withObject:appLayout]; - } + + if (!heavyImpactFeedbackGenerator) { + heavyImpactFeedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy]; + [heavyImpactFeedbackGenerator prepare]; } + + [heavyImpactFeedbackGenerator impactOccurred]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.35 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.5 + delay:0 + usingSpringWithDamping:0.7 + initialSpringVelocity:0.2 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + if (!frontApp) { + NSArray *recentAppLayouts = [self performSelector:@selector(getApps)]; + for (SBAppLayout *appLayout in recentAppLayouts) { + [self performSelector:@selector(removeAppLayout:) withObject:appLayout]; + } + } else { + [self performSelector:@selector(removeFrontMostApplication:) withObject:frontApp]; + } + } + completion:nil]; + }); + } else if ([[notification name] isEqualToString: @"OpenRecentApplication"]) { SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication]; @@ -114,15 +133,17 @@ static void updateSettings(); } -(void)_deleteAppLayoutsMatchingBundleIdentifier:(id)arg1 { - - %orig; if (!mutableReusableContainersData) { mutableReusableContainersData = [[NSMutableDictionary alloc] init]; } [mutableReusableContainersData removeObjectForKey:arg1]; - if (sbfTouchPassThroughTransitionView) { - SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication]; - [sbfTouchPassThroughTransitionView performSelector:@selector(updateRouterWithFrontMostApplications:) withObject:frontApp]; - } - RLog(@"%@ removed from dictionary", arg1); + + // CAUSE OF CRASH + // ---------------------------------------------------------------------------------------------------------------- + // if (sbfTouchPassThroughTransitionView) { + // SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication]; + // [sbfTouchPassThroughTransitionView performSelector:@selector(updateRouterWithFrontMostApplications:) withObject:frontApp]; + // } + // ---------------------------------------------------------------------------------------------------------------- + %orig; } %new @@ -134,11 +155,10 @@ static void updateSettings(); -(void)logBundles { NSArray *layouts = [self performSelector:@selector(getApps)]; appLayouts = layouts; - int counter = 1; + __unused int counter = 1; for (SBAppLayout *appLayout in layouts) { NSString *bundleId = [self performSelector:@selector(getBundleIDFromAppLayout:) withObject:appLayout]; if (bundleId) { - RLog(@"%d) %@", counter, bundleId); counter += 1; } } @@ -151,17 +171,30 @@ static void updateSettings(); if (itemBundleID) { NSString *nowPlayingID = [[[%c(SBMediaController) sharedInstance] nowPlayingApplication] bundleIdentifier]; - if (![itemBundleID isEqualToString: nowPlayingID]) { - if (@available(iOS 14.0, *)) { - [self _deleteAppLayoutsMatchingBundleIdentifier:itemBundleID]; - } else { - [self _deleteAppLayout:item forReason: 1]; - } + if (!killNowPlayingApplication && [itemBundleID isEqualToString: nowPlayingID]) return; + + if (@available(iOS 14.0, *)) { + [self _deleteAppLayoutsMatchingBundleIdentifier:itemBundleID]; + } else { + [self _deleteAppLayout:item forReason: 1]; } + } } +%new +-(void)removeFrontMostApplication:(SBApplication *)application { + NSString *itemBundleID = [application bundleIdentifier]; + if (itemBundleID) { + NSString *nowPlayingID = [[[%c(SBMediaController) sharedInstance] nowPlayingApplication] bundleIdentifier]; + + if (!killNowPlayingApplication && [itemBundleID isEqualToString: nowPlayingID]) return; + if (@available(iOS 14.0, *)) { + [self _deleteAppLayoutsMatchingBundleIdentifier:itemBundleID]; + } + } +} %new -(NSString *_Nullable)getBundleIDFromAppLayout:(SBAppLayout *_Nullable)appLayout { @@ -276,12 +309,11 @@ static void updateSettings(); %new -(void)showWitcherView { - + if (!isEnabled) { return; } SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication]; // NOTE: This message also update data - WitcherApplicationLayoutStruct *applicationStruct = [self performSelector:@selector(getPackedLayoutStructForApplication:) withObject:frontApp]; + __unused WitcherApplicationLayoutStruct *applicationStruct = [self performSelector:@selector(getPackedLayoutStructForApplication:) withObject:frontApp]; - RLog(@"New layoutStruct! %@", applicationStruct); if (!isEnabled) { return; } [self performSelector:@selector(updateRouterWithFrontMostApplications:) withObject:frontApp]; @@ -602,6 +634,7 @@ static void updateSettings() { NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:WITCHER_PLIST_SETTINGS]; isEnabled = prefs[@"isEnabled"] ? [prefs[@"isEnabled"] boolValue] : YES; hardwareButtonMode = prefs[@"hardwareButtonMode"] ? [prefs[@"hardwareButtonMode"] boolValue] : NO; + killNowPlayingApplication = prefs[@"killNPA"] ? [prefs[@"killNPA"] boolValue] : NO; if (router) { [router updateMainColor:colorFromHex(prefs[@"mainTintColor"] ? prefs[@"mainTintColor"] : @"FFFFFF", YES)]; diff --git a/WitcherPreferences/UI/Cells/AuthorCell/AuthorCell.m b/WitcherPreferences/UI/Cells/AuthorCell/AuthorCell.m index 5284525..a9726dc 100644 --- a/WitcherPreferences/UI/Cells/AuthorCell/AuthorCell.m +++ b/WitcherPreferences/UI/Cells/AuthorCell/AuthorCell.m @@ -25,12 +25,10 @@ -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSStri } - (void)handleLeftTap { - RLog(@"left view was tapped"); [[UIApplication sharedApplication] openURL:[NSURL URLWithString:profileURL] options:@{} completionHandler:nil]; } - (void)handleRightTap { - RLog(@"right view was tapped"); [[UIApplication sharedApplication] openURL:[NSURL URLWithString:projectURL] options:@{} completionHandler:nil]; } diff --git a/WitcherPreferences/WTRRootListController.m b/WitcherPreferences/WTRRootListController.m index 24c4efb..662a945 100644 --- a/WitcherPreferences/WTRRootListController.m +++ b/WitcherPreferences/WTRRootListController.m @@ -81,7 +81,7 @@ -(NSArray *)specifiers { cell:PSGroupCell edit:Nil]; - [spec setProperty:@"No need for respring" forKey:@"footerText"]; + // [spec setProperty:@"No need for respring" forKey:@"footerText"]; [specifiers addObject:spec]; // ColorPicker for Router @@ -118,6 +118,17 @@ -(NSArray *)specifiers { [spec setProperty:@60 forKey:@"height"]; [specifiers addObject:spec]; + // Actions + spec = [PSSpecifier preferenceSpecifierNamed:@"Actions" + target:self + set:Nil + get:Nil + detail:Nil + cell:PSGroupCell + edit:Nil]; + + [specifiers addObject:spec]; + // Hide/Show action buttons switch cell spec = [PSSpecifier preferenceSpecifierNamed:@"" target:self @@ -134,6 +145,22 @@ -(NSArray *)specifiers { [spec setProperty:@"actionButtons" forKey:@"key"]; [specifiers addObject:spec]; + // Kill playing application + spec = [PSSpecifier preferenceSpecifierNamed:@"" + target:self + set:@selector(setPreferenceValue:specifier:) + get:@selector(readPreferenceValue:) + detail:Nil + cell:[PSTableCell cellTypeFromString:@""] + edit:Nil]; + + [spec setProperty:[WitcherSwitchCell class] forKey:@"cellClass"]; + [spec setProperty:@"Kill now playing app" forKey:@"title"]; + [spec setProperty:@"Music, video players, etc." forKey:@"subtitle"]; + [spec setProperty:@NO forKey:@"default"]; + [spec setProperty:@"killNPA" forKey:@"key"]; + [specifiers addObject:spec]; + _specifiers = [specifiers copy]; } @@ -173,7 +200,7 @@ -(void)setupTitleView { self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; [[self titleLabel] setFont:[UIFont fontWithName:@"UbuntuSans-Bold" size:17]]; - [[self titleLabel] setText:@"1.0.0"]; + [[self titleLabel] setText:@"1.0.1"]; [[self titleLabel] setTextColor:[UIColor labelColor]]; [[self titleLabel] setTextAlignment:NSTextAlignmentCenter]; [[[self navigationItem] titleView] addSubview:[self titleLabel]]; diff --git a/control b/control index 8b68bea..d52ac84 100644 --- a/control +++ b/control @@ -1,6 +1,6 @@ Package: dr.erast.witcher Name: Witcher -Version: 1.0.0 +Version: 1.0.1 Architecture: iphoneos-arm Description: Magical iOS App Switcher Maintainer: Erast