Skip to content

Commit

Permalink
[+][f] added the functionality of the xmark button, fixed the error w…
Browse files Browse the repository at this point in the history
…ith the springboard crash when closing applications
  • Loading branch information
MatoiDev committed Jul 5, 2024
1 parent ab8dde0 commit 1f6adf8
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 37 deletions.
1 change: 0 additions & 1 deletion Extensions/Extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#import <UIKit/UIKit.h>
#import <CoreText/CoreText.h>
#import <rootless.h>
#include <RemoteLog.h>

#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")
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions UI/Router/RouterView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -156,6 +155,7 @@ -(void)updateCellsWithNewApplications:(NSArray<WitcherApplicationLayoutStruct *>
}

[goToPreviousAppButton setEnabled:[layoutStructs count] > 0];
[closeAppButton setEnabled:[layoutStructs count] + flag > 0];

[self updateStaticCellPosition];

Expand Down Expand Up @@ -394,7 +394,6 @@ -(void)updateActionButtonsWithState:(_Bool)state {
[searchButton setHidden:state];
[closeAppButton setHidden:state];

[searchButton setUserInteractionEnabled:NO];

actionButtonsIsActive = !state;
}
Expand Down
87 changes: 60 additions & 27 deletions Witcher.x
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,6 +13,7 @@ SBMainSwitcherViewController *mainAppSwitcherVC;

#pragma mark - Generators
UIImpactFeedbackGenerator *impactFeedbackGenerator = nil;
UIImpactFeedbackGenerator *heavyImpactFeedbackGenerator = nil;

#pragma mark - Data
NSMutableDictionary<NSString *, WitcherApplicationLayoutStruct *> *mutableReusableContainersData = nil;
Expand All @@ -35,6 +32,7 @@ NSUserDefaults *prefs;

_Bool isEnabled;
_Bool hardwareButtonMode;
_Bool killNowPlayingApplication;

static UIColor* colorFromHex(NSString *hexString, BOOL useAlpha);
static void updateSettings();
Expand Down Expand Up @@ -68,12 +66,33 @@ static void updateSettings();
}
else if ([[notification name] isEqualToString: @"ReleaseFrontMostApplication"]) {
SBApplication *frontApp = [(SpringBoard*)[UIApplication sharedApplication] _accessibilityFrontMostApplication];
if (!frontApp) {
NSArray<SBAppLayout *> *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<SBAppLayout *> *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];
Expand Down Expand Up @@ -114,15 +133,17 @@ static void updateSettings();
}

-(void)_deleteAppLayoutsMatchingBundleIdentifier:(id)arg1 {

%orig;
if (!mutableReusableContainersData) { mutableReusableContainersData = [[NSMutableDictionary<NSString *, WitcherApplicationLayoutStruct *> 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
Expand All @@ -134,11 +155,10 @@ static void updateSettings();
-(void)logBundles {
NSArray<SBAppLayout *> *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;
}
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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)];
Expand Down
2 changes: 0 additions & 2 deletions WitcherPreferences/UI/Cells/AuthorCell/AuthorCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}

Expand Down
31 changes: 29 additions & 2 deletions WitcherPreferences/WTRRootListController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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];

}
Expand Down Expand Up @@ -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]];
Expand Down
2 changes: 1 addition & 1 deletion control
Original file line number Diff line number Diff line change
@@ -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 <applewormdev@gmail.com>
Expand Down

0 comments on commit 1f6adf8

Please sign in to comment.