uYouEnhanced v20.44.2: QOL UPDATE

This commit is contained in:
aricloverEXTRA 2026-02-24 17:51:57 -06:00 committed by GitHub
parent 8aca84cc4f
commit c56628e3f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 1152 additions and 1106 deletions

View file

@ -62,6 +62,8 @@ jobs:
git add .
git submodule update --init --recursive --remote Tweaks/YTVideoOverlay
git add .
git submodule update --init --recursive --remote Tweaks/YTweaks
git add .
git submodule update --init --recursive
git commit -m "updated submodules"
git push

9
.gitmodules vendored
View file

@ -76,8 +76,7 @@
url = https://github.com/PoomSmart/YTIcons.git
[submodule "Tweaks/YTUHD"]
path = Tweaks/YTUHD
url = https://github.com/aricloverEXTRA/YTUHD.git
branch = master
url = https://github.com/Tonwalter888/YTUHD.git
[submodule "Tweaks/YTVideoOverlay"]
path = Tweaks/YTVideoOverlay
url = https://github.com/PoomSmart/YTVideoOverlay.git
@ -92,3 +91,9 @@
[submodule "Tweaks/uYouLocalization"]
path = Tweaks/uYouLocalization
url = https://github.com/dayanch96/uYouLocalization.git
[submodule "Tweaks/libundirect"]
path = Tweaks/libundirect
url = https://github.com/opa334/libundirect.git
[submodule "Tweaks/YTweaks"]
path = Tweaks/YTweaks
url = https://github.com/fosterbarnes/YTweaks.git

1
Bundles/YTWKS.bundle Symbolic link
View file

@ -0,0 +1 @@
../Tweaks/YTweaks/layout/Library/Application Support/YTWKS.bundle

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -16,7 +16,7 @@ MODULES = jailed
endif
ifndef YOUTUBE_VERSION
YOUTUBE_VERSION = 20.50.9
YOUTUBE_VERSION = 20.44.2
endif
ifndef UYOU_VERSION
UYOU_VERSION = 3.0.4
@ -33,8 +33,27 @@ $(TWEAK_NAME)_FILES := $(wildcard Sources/*.xm) $(wildcard Sources/*.x) $(wildca
$(TWEAK_NAME)_FRAMEWORKS = UIKit Foundation AVFoundation AVKit Photos Accelerate CoreMotion GameController VideoToolbox Security
$(TWEAK_NAME)_LIBRARIES = bz2 c++ iconv z
$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wno-unused-but-set-variable -DTWEAK_VERSION=\"$(PACKAGE_VERSION)\"
#uYouLocalization $(TWEAK_NAME)_INJECT_DYLIBS = Tweaks/uYou/Library/MobileSubstrate/DynamicLibraries/uYou.dylib $(THEOS_OBJ_DIR)/uYouLocalization.dylib
$(TWEAK_NAME)_INJECT_DYLIBS = Tweaks/uYou/Library/MobileSubstrate/DynamicLibraries/uYou.dylib $(THEOS_OBJ_DIR)/libFLEX.dylib $(THEOS_OBJ_DIR)/iSponsorBlock.dylib $(THEOS_OBJ_DIR)/YTABConfig.dylib $(THEOS_OBJ_DIR)/YTIcons.dylib $(THEOS_OBJ_DIR)/YouGroupSettings.dylib $(THEOS_OBJ_DIR)/YouLoop.dylib $(THEOS_OBJ_DIR)/YouMute.dylib $(THEOS_OBJ_DIR)/YouPiP.dylib $(THEOS_OBJ_DIR)/YouQuality.dylib $(THEOS_OBJ_DIR)/YouSlider.dylib $(THEOS_OBJ_DIR)/YouSpeed.dylib $(THEOS_OBJ_DIR)/YouTimeStamp.dylib $(THEOS_OBJ_DIR)/YouTubeDislikesReturn.dylib $(THEOS_OBJ_DIR)/DontEatMyContent.dylib $(THEOS_OBJ_DIR)/YTHoldForSpeed.dylib $(THEOS_OBJ_DIR)/YTUHD.dylib $(THEOS_OBJ_DIR)/YTVideoOverlay.dylib
$(TWEAK_NAME)_INJECT_DYLIBS = \
Tweaks/uYou/Library/MobileSubstrate/DynamicLibraries/uYou.dylib \
$(THEOS_OBJ_DIR)/libFLEX.dylib \
$(THEOS_OBJ_DIR)/iSponsorBlock.dylib \
$(THEOS_OBJ_DIR)/YTABConfig.dylib \
$(THEOS_OBJ_DIR)/YTIcons.dylib \
$(THEOS_OBJ_DIR)/YouGroupSettings.dylib \
$(THEOS_OBJ_DIR)/YouLoop.dylib \
$(THEOS_OBJ_DIR)/YouMute.dylib \
$(THEOS_OBJ_DIR)/YouPiP.dylib \
$(THEOS_OBJ_DIR)/YouQuality.dylib \
$(THEOS_OBJ_DIR)/YouSlider.dylib \
$(THEOS_OBJ_DIR)/YouSpeed.dylib \
$(THEOS_OBJ_DIR)/YouTimeStamp.dylib \
$(THEOS_OBJ_DIR)/YouTubeDislikesReturn.dylib \
$(THEOS_OBJ_DIR)/DontEatMyContent.dylib \
$(THEOS_OBJ_DIR)/YTHoldForSpeed.dylib \
$(THEOS_OBJ_DIR)/YTUHD.dylib \
$(THEOS_OBJ_DIR)/YTVideoOverlay.dylib \
$(THEOS_OBJ_DIR)/YTweaks.dylib
$(TWEAK_NAME)_EMBED_LIBRARIES = $(THEOS_OBJ_DIR)/libcolorpicker.dylib
$(TWEAK_NAME)_EMBED_FRAMEWORKS = $(_THEOS_LOCAL_DATA_DIR)/$(THEOS_OBJ_DIR_NAME)/install_Alderis.xcarchive/Products/var/jb/Library/Frameworks/Alderis.framework
$(TWEAK_NAME)_EMBED_BUNDLES = $(wildcard Bundles/*.bundle)
@ -42,8 +61,7 @@ $(TWEAK_NAME)_EMBED_EXTENSIONS = $(wildcard Extensions/*.appex)
include $(THEOS)/makefiles/common.mk
ifneq ($(JAILBROKEN),1)
#uYouLocalization SUBPROJECTS += Tweaks/Alderis Tweaks/uYouLocalization
SUBPROJECTS += Tweaks/Alderis Tweaks/DontEatMyContent Tweaks/FLEXing/libflex Tweaks/iSponsorBlock Tweaks/Return-YouTube-Dislikes Tweaks/YTABConfig Tweaks/YouGroupSettings Tweaks/YTIcons Tweaks/YouLoop Tweaks/YouMute Tweaks/YouPiP Tweaks/YouQuality Tweaks/YouSlider Tweaks/YouSpeed Tweaks/YouTimeStamp Tweaks/YTHoldForSpeed Tweaks/YTUHD Tweaks/YTVideoOverlay
SUBPROJECTS += Tweaks/Alderis Tweaks/DontEatMyContent Tweaks/FLEXing/libflex Tweaks/iSponsorBlock Tweaks/Return-YouTube-Dislikes Tweaks/YTABConfig Tweaks/YouGroupSettings Tweaks/YTIcons Tweaks/YouLoop Tweaks/YouMute Tweaks/YouPiP Tweaks/YouQuality Tweaks/YouSlider Tweaks/YouSpeed Tweaks/YouTimeStamp Tweaks/YTHoldForSpeed Tweaks/YTUHD Tweaks/YTVideoOverlay Tweaks/YTweaks
include $(THEOS_MAKE_PATH)/aggregate.mk
endif
include $(THEOS_MAKE_PATH)/tweak.mk

View file

@ -1,6 +1,6 @@
#import <UIKit/UIKit.h>
@interface AppIconOptionsController : UIViewController
@interface AppIconOptionsController : UIViewController <UITableViewDataSource, UITableViewDelegate>
@property (strong, nonatomic) UIButton *backButton;
@ -11,12 +11,3 @@
+ (UIImage *)customBackButtonImage;
@end
@implementation UIImage (CustomImages)
+ (UIImage *)customBackButtonImage {
NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"uYouPlus" ofType:@"bundle"]];
return [UIImage imageNamed:@"Back.png" inBundle:bundle compatibleWithTraitCollection:nil];
}
@end

View file

@ -1,10 +1,32 @@
#import "AppIconOptionsController.h"
#import <YouTubeHeader/YTAssetLoader.h>
#import <notify.h>
static NSString *const kPrefDomain = @"com.arichornlover.uYouEnhanced";
static NSString *const kPrefEnableIconOverride = @"appIconCustomization_enabled";
static NSString *const kPrefIconName = @"customAppIcon_name";
static NSString *const kPrefNotifyName = @"com.arichornlover.uYouEnhanced.prefschanged";
static NSString *BundlePath(void) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"uYouPlus" ofType:@"bundle"];
if (path) return path;
return @"/Library/Application Support/uYouEnhanced";
}
@interface AppIconOptionsController ()
@interface AppIconOptionsController () <UITableViewDataSource, UITableViewDelegate>
@property (strong, nonatomic) UITableView *tableView;
@property (strong, nonatomic) NSArray<NSString *> *appIcons;
@property (assign, nonatomic) NSInteger selectedIconIndex;
@end
@implementation UIImage (CustomImages)
+ (UIImage *)customBackButtonImage {
NSBundle *bundle = [NSBundle bundleWithPath:BundlePath()];
return [UIImage imageNamed:@"Back.png" inBundle:bundle compatibleWithTraitCollection:nil];
}
@end
@implementation AppIconOptionsController
@ -14,102 +36,266 @@
self.title = @"Change App Icon";
self.selectedIconIndex = -1;
self.view.backgroundColor = [UIColor systemBackgroundColor];
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
if (@available(iOS 15.0, *)) {
self.tableView.sectionHeaderTopPadding = 0;
}
[self.view addSubview:self.tableView];
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
[NSLayoutConstraint activateConstraints:@[
[self.tableView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
]];
self.navigationItem.hidesBackButton = YES;
if (@available(iOS 14.0, *)) {
self.navigationItem.backButtonDisplayMode = UINavigationItemBackButtonDisplayModeMinimal;
}
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage customBackButtonImage] forState:UIControlStateNormal];
[self.backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithCustomView:self.backButton];
self.navigationItem.leftBarButtonItem = customBackButton;
NSString *path = [[NSBundle mainBundle] pathForResource:@"uYouPlus" ofType:@"bundle"];
NSBundle *bundle = [NSBundle bundleWithPath:path];
self.appIcons = [bundle pathsForResourcesOfType:@"png" inDirectory:@"AppIcons"];
NSMutableSet<NSString *> *iconNames = [NSMutableSet set];
NSFileManager *fm = [NSFileManager defaultManager];
if (![UIApplication sharedApplication].supportsAlternateIcons) {
NSLog(@"Alternate icons are not supported on this device.");
NSString *bundlePath = BundlePath();
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
if (bundle) {
NSString *appIconsDir = [bundle.bundlePath stringByAppendingPathComponent:@"AppIcons"];
BOOL isDir = NO;
if ([fm fileExistsAtPath:appIconsDir isDirectory:&isDir] && isDir) {
NSArray *contents = [fm contentsOfDirectoryAtPath:appIconsDir error:nil] ?: @[];
for (NSString *entry in contents) {
NSString *full = [appIconsDir stringByAppendingPathComponent:entry];
BOOL entryIsDir = NO;
if ([fm fileExistsAtPath:full isDirectory:&entryIsDir]) {
if (entryIsDir) {
[iconNames addObject:entry];
} else {
NSString *ext = entry.pathExtension.lowercaseString;
if ([ext isEqualToString:@"png"]) {
NSString *name = [entry stringByDeletingPathExtension];
if (name.length > 0) {
[iconNames addObject:name];
}
}
}
}
}
}
}
NSString *supportBase = @"/Library/Application Support/uYouEnhanced/AppIcons";
BOOL supportIsDir = NO;
if ([fm fileExistsAtPath:supportBase isDirectory:&supportIsDir] && supportIsDir) {
NSArray *contents = [fm contentsOfDirectoryAtPath:supportBase error:nil] ?: @[];
for (NSString *entry in contents) {
NSString *full = [supportBase stringByAppendingPathComponent:entry];
BOOL isDir = NO;
if ([fm fileExistsAtPath:full isDirectory:&isDir]) {
if (isDir) {
[iconNames addObject:entry];
} else {
NSString *ext = entry.pathExtension.lowercaseString;
if ([ext isEqualToString:@"png"]) {
NSString *name = [entry stringByDeletingPathExtension];
if (name.length > 0) {
[iconNames addObject:name];
}
}
}
}
}
}
self.appIcons = [[iconNames allObjects] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", kPrefDomain]] ?: @{};
NSString *savedIcon = prefs[kPrefIconName];
if (savedIcon) {
NSInteger idx = [self.appIcons indexOfObject:savedIcon];
if (idx != NSNotFound) self.selectedIconIndex = idx;
}
if (self.appIcons.count == 0) {
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectInset(self.view.bounds, 20, 20)];
lbl.text = @"No custom icons found. Place PNGs or icon folders in uYouPlus.bundle/AppIcons/ or /Library/Application Support/uYouEnhanced/AppIcons/";
lbl.numberOfLines = 0;
lbl.textAlignment = NSTextAlignmentCenter;
lbl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:lbl];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.appIcons.count;
return self.appIcons.count + 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"Cell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellId = @"AppIconCell";
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:CellId];
if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellId];
if (indexPath.row == 0) {
cell.textLabel.text = @"Reset to default";
cell.detailTextLabel.text = @"Restore the original app icon";
cell.imageView.image = nil;
cell.accessoryType = (self.selectedIconIndex == -1) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
NSString *iconPath = self.appIcons[indexPath.row];
cell.textLabel.text = [iconPath.lastPathComponent stringByDeletingPathExtension];
NSString *iconName = self.appIcons[indexPath.row - 1];
cell.textLabel.text = iconName;
cell.detailTextLabel.text = @"Tap to apply this icon";
UIImage *iconImage = [UIImage imageWithContentsOfFile:iconPath];
cell.imageView.image = iconImage;
cell.imageView.layer.cornerRadius = 16.0;
UIImage *preview = nil;
NSArray<NSString *> *candidates = @[
@"AppIcon60x60@3x.png",
@"AppIcon60x60@2x.png",
@"Icon@3x.png",
@"Icon@2x.png",
@"Icon.png"
];
NSString *bundlePath = BundlePath();
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
NSString *supportBase = @"/Library/Application Support/uYouEnhanced/AppIcons";
NSFileManager *fm = [NSFileManager defaultManager];
BOOL found = NO;
if (bundle) {
NSString *dir = [bundle.bundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"AppIcons/%@", iconName]];
BOOL isDir = NO;
if ([fm fileExistsAtPath:dir isDirectory:&isDir] && isDir) {
for (NSString *c in candidates) {
NSString *imagePath = [dir stringByAppendingPathComponent:c];
if ([fm fileExistsAtPath:imagePath]) {
preview = [UIImage imageWithContentsOfFile:imagePath];
found = YES;
break;
}
}
if (!found) {
NSArray *files = [fm contentsOfDirectoryAtPath:dir error:nil];
for (NSString *file in files) {
NSString *ext = file.pathExtension.lowercaseString;
if ([ext isEqualToString:@"png"]) {
NSString *path = [dir stringByAppendingPathComponent:file];
preview = [UIImage imageWithContentsOfFile:path];
found = YES;
break;
}
}
}
} else {
NSString *pngPath = [[bundle.bundlePath stringByAppendingPathComponent:@"AppIcons"] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", iconName]];
if ([fm fileExistsAtPath:pngPath]) {
preview = [UIImage imageWithContentsOfFile:pngPath];
found = YES;
}
}
}
if (!found) {
NSString *dir = [supportBase stringByAppendingPathComponent:iconName];
BOOL isDir = NO;
if ([fm fileExistsAtPath:dir isDirectory:&isDir] && isDir) {
for (NSString *c in candidates) {
NSString *imagePath = [dir stringByAppendingPathComponent:c];
if ([fm fileExistsAtPath:imagePath]) {
preview = [UIImage imageWithContentsOfFile:imagePath];
found = YES;
break;
}
}
if (!found) {
NSArray *files = [fm contentsOfDirectoryAtPath:dir error:nil];
for (NSString *file in files) {
NSString *ext = file.pathExtension.lowercaseString;
if ([ext isEqualToString:@"png"]) {
NSString *path = [dir stringByAppendingPathComponent:file];
preview = [UIImage imageWithContentsOfFile:path];
found = YES;
break;
}
}
}
} else {
NSString *pngPath = [supportBase stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", iconName]];
if ([fm fileExistsAtPath:pngPath]) {
preview = [UIImage imageWithContentsOfFile:pngPath];
found = YES;
}
}
}
cell.imageView.image = preview;
cell.imageView.layer.cornerRadius = 12.0;
cell.imageView.clipsToBounds = YES;
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
cell.accessoryType = (indexPath.row == self.selectedIconIndex) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
cell.accessoryType = ((indexPath.row - 1) == self.selectedIconIndex) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tv deselectRowAtIndexPath:indexPath animated:YES];
self.selectedIconIndex = indexPath.row;
[self saveIcon];
[self.tableView reloadData];
}
NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", kPrefDomain];
NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:prefsPath] ?: [NSMutableDictionary dictionary];
- (void)resetIcon {
[[UIApplication sharedApplication] setAlternateIconName:nil completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"Error resetting icon: %@", error.localizedDescription);
[self showAlertWithTitle:@"Error" message:@"Failed to reset icon"];
} else {
NSLog(@"Icon reset successfully");
[self showAlertWithTitle:@"Success" message:@"Icon reset successfully"];
[self.tableView reloadData];
}
}];
}
- (void)saveIcon {
if (self.selectedIconIndex < 0) {
[self showAlertWithTitle:@"Error" message:@"No icon selected"];
if (indexPath.row == 0) {
self.selectedIconIndex = -1;
prefs[kPrefEnableIconOverride] = @NO;
[prefs writeToFile:prefsPath atomically:YES];
notify_post([kPrefNotifyName UTF8String]);
[self.tableView reloadData];
[self showAlertWithTitle:@"Requested" message:@"Icon reset requested."];
return;
}
NSString *selectedIcon = self.appIcons[self.selectedIconIndex];
NSString *iconName = [selectedIcon.lastPathComponent stringByDeletingPathExtension];
self.selectedIconIndex = indexPath.row - 1;
NSString *iconName = self.appIcons[self.selectedIconIndex];
[[UIApplication sharedApplication] setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
if (error) {
NSLog(@"Error setting alternate icon: %@", error.localizedDescription);
[self showAlertWithTitle:@"Error" message:@"Failed to set alternate icon"];
} else {
NSLog(@"Alternate icon set successfully");
[self showAlertWithTitle:@"Success" message:@"Alternate icon set successfully"];
[self.tableView reloadData];
}
}];
prefs[kPrefEnableIconOverride] = @YES;
prefs[kPrefIconName] = iconName;
BOOL ok = [prefs writeToFile:prefsPath atomically:YES];
if (!ok) {
[self showAlertWithTitle:@"Error" message:@"Failed to save preference"];
return;
}
notify_post([kPrefNotifyName UTF8String]);
[self.tableView reloadData];
[self showAlertWithTitle:@"Requested" message:@"Icon change requested."];
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:okAction];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}

View file

@ -18,12 +18,19 @@ static inline BOOL customContrastMode() {
return IS_ENABLED(@"lowContrastMode_enabled") && contrastMode() == 1;
}
// static inline UIColor *activeColor() {
// return customContrastMode() && lcmHexColor ? lcmHexColor : kLowContrastColor;
// }
// Helper to get active contrast color
static inline UIColor *activeContrastColor() {
return customContrastMode() && lcmHexColor ? lcmHexColor : kLowContrastColor;
}
// Helper to check if dark mode is enabled
static inline BOOL isDarkMode() {
return UIScreen.mainScreen.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark;
}
// Low Contrast Mode v1.8.0 (Compatible with YouTube v19.21.2-v20.44.2)
%group gContrastModeShared
// Low Contrast Mode v1.7.1.1 (Compatible with only YouTube v19.01.1-v20.21.6)
%group gLowContrastMode
%hook UIColor
+ (UIColor *)colorNamed:(NSString *)name {
NSArray<NSString *> *targetColors = @[
@ -32,478 +39,294 @@ static inline BOOL customContrastMode() {
@"systemExtraLightGrayColor", @"labelColor", @"secondaryLabelColor",
@"tertiaryLabelColor", @"quaternaryLabelColor"
];
return [targetColors containsObject:name] ? kLowContrastColor : %orig;
return [targetColors containsObject:name] ? activeContrastColor() : %orig;
}
+ (UIColor *)whiteColor { return kLowContrastColor; }
+ (UIColor *)lightTextColor { return kLowContrastColor; }
+ (UIColor *)lightGrayColor { return kLowContrastColor; }
+ (UIColor *)whiteColor { return activeContrastColor(); }
+ (UIColor *)lightTextColor { return activeContrastColor(); }
+ (UIColor *)lightGrayColor { return activeContrastColor(); }
%end
%hook YTCommonColorPalette
+ (id)darkPalette {
id palette = %orig;
if (isDarkMode()) {
UIColor *contrastColor = activeContrastColor();
[palette setValue:contrastColor forKey:@"textPrimary"];
[palette setValue:contrastColor forKey:@"textSecondary"];
[palette setValue:contrastColor forKey:@"overlayTextPrimary"];
[palette setValue:contrastColor forKey:@"overlayTextSecondary"];
[palette setValue:contrastColor forKey:@"iconActive"];
[palette setValue:contrastColor forKey:@"iconActiveOther"];
[palette setValue:contrastColor forKey:@"brandIconActive"];
[palette setValue:contrastColor forKey:@"staticBrandWhite"];
[palette setValue:contrastColor forKey:@"overlayIconActiveOther"];
[palette setValue:[contrastColor colorWithAlphaComponent:0.7] forKey:@"overlayIconInactive"];
[palette setValue:[contrastColor colorWithAlphaComponent:0.3] forKey:@"overlayIconDisabled"];
[palette setValue:[contrastColor colorWithAlphaComponent:0.2] forKey:@"overlayFilledButtonActive"];
}
return palette;
}
+ (id)lightPalette {
return %orig;
}
- (UIColor *)textPrimary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)textSecondary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)overlayTextPrimary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)overlayTextSecondary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)iconActive {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)iconActiveOther {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)brandIconActive {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)staticBrandWhite {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)overlayIconActiveOther {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
return isDarkMode() ? activeContrastColor() : %orig;
}
- (UIColor *)overlayIconInactive {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.7] : %orig;
return isDarkMode() ? [activeContrastColor() colorWithAlphaComponent:0.7] : %orig;
}
- (UIColor *)overlayIconDisabled {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.3] : %orig;
return isDarkMode() ? [activeContrastColor() colorWithAlphaComponent:0.3] : %orig;
}
- (UIColor *)overlayFilledButtonActive {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.2] : %orig;
return isDarkMode() ? [activeContrastColor() colorWithAlphaComponent:0.2] : %orig;
}
%end
%hook YTColor
+ (BOOL)darkerPaletteTextColorEnabled { return NO; }
+ (UIColor *)white1 { return kLowContrastColor; }
+ (UIColor *)white2 { return kLowContrastColor; }
+ (UIColor *)white3 { return kLowContrastColor; }
+ (UIColor *)white4 { return kLowContrastColor; }
+ (UIColor *)white5 { return kLowContrastColor; }
+ (UIColor *)grey1 { return kLowContrastColor; }
+ (UIColor *)grey2 { return kLowContrastColor; }
+ (UIColor *)white1 { return activeContrastColor(); }
+ (UIColor *)white2 { return activeContrastColor(); }
+ (UIColor *)white3 { return activeContrastColor(); }
+ (UIColor *)white4 { return activeContrastColor(); }
+ (UIColor *)white5 { return activeContrastColor(); }
+ (UIColor *)grey1 { return activeContrastColor(); }
+ (UIColor *)grey2 { return activeContrastColor(); }
%end
%hook _ASDisplayView
- (void)layoutSubviews {
%orig;
NSArray<NSString *> *targetLabels = @[@"connect account", @"Thanks", @"Save to playlist", @"Report"];
for (UIView *subview in self.subviews) {
if ([targetLabels containsObject:subview.accessibilityLabel]) {
subview.backgroundColor = kLowContrastColor;
if ([subview isKindOfClass:[UILabel class]]) {
((UILabel *)subview).textColor = [UIColor blackColor];
}
}
}
}
%end
%hook QTMColorGroup
- (UIColor *)tint100 { return kDefaultTextColor; }
- (UIColor *)tint300 { return kDefaultTextColor; }
- (UIColor *)tint500 { return kDefaultTextColor; }
- (UIColor *)tint700 { return kDefaultTextColor; }
- (UIColor *)accent200 { return kDefaultTextColor; }
- (UIColor *)accent400 { return kDefaultTextColor; }
- (UIColor *)accentColor { return kDefaultTextColor; }
- (UIColor *)brightAccentColor { return kDefaultTextColor; }
- (UIColor *)regularColor { return kDefaultTextColor; }
- (UIColor *)darkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColor { return kDefaultTextColor; }
- (UIColor *)lightBodyTextColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnRegularColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnLighterColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnDarkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnAccentColor { return kDefaultTextColor; }
- (UIColor *)buttonBackgroundColor { return kDefaultTextColor; }
- (UIColor *)Color { return kDefaultTextColor; }
%end
%hook YTQTMButton
- (void)setImage:(UIImage *)image {
UIImage *tintedImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self setTintColor:kDefaultTextColor];
%orig(tintedImage);
}
%end
%hook UIExtendedSRGColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:0.9]);
}
%end
%hook UIExtendedSRGBColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook UIExtendedGrayColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook VideoTitleLabel
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UILabel
+ (void)load {
[[UILabel appearance] setTextColor:kDefaultTextColor];
}
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UITextField
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UITextView
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UISearchBar
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UISegmentedControl
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
}
%end
%hook UIButton
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state {
%orig(kDefaultTextColor, state);
}
%end
%hook UIBarButtonItem
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
}
%end
%hook NSAttributedString
- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSAttributedStringKey, id> *)attrs {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attrs];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
return %orig(str, modifiedAttributes);
}
%end
%hook CATextLayer
- (void)setTextColor:(CGColorRef)textColor {
%orig(kDefaultTextColor.CGColor);
}
%end
%hook ASTextNode
- (NSAttributedString *)attributedString {
NSAttributedString *original = %orig;
NSMutableAttributedString *modified = [original mutableCopy];
[modified addAttribute:NSForegroundColorAttributeName value:kDefaultTextColor range:NSMakeRange(0, modified.length)];
return modified;
}
%end
%hook ASTextFieldNode
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook ASTextView
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook ASButtonNode
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UIControl
- (UIColor *)backgroundColor {
return [UIColor blackColor];
}
%end
%end
// Custom Contrast Mode
%group gCustomContrastMode
%hook UIColor
+ (UIColor *)colorNamed:(NSString *)name {
NSArray<NSString *> *targetColors = @[
@"whiteColor", @"lightTextColor", @"lightGrayColor", @"ychGrey7",
@"skt_chipBackgroundColor", @"placeholderTextColor", @"systemLightGrayColor",
@"systemExtraLightGrayColor", @"labelColor", @"secondaryLabelColor",
@"tertiaryLabelColor", @"quaternaryLabelColor"
];
return [targetColors containsObject:name] ? lcmHexColor : %orig;
}
+ (UIColor *)whiteColor { return lcmHexColor; }
+ (UIColor *)lightTextColor { return lcmHexColor; }
+ (UIColor *)lightGrayColor { return lcmHexColor; }
%end
%hook YTCommonColorPalette
- (UIColor *)textPrimary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)textSecondary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)overlayTextPrimary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)overlayTextSecondary {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)iconActive {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)iconActiveOther {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)brandIconActive {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)staticBrandWhite {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)overlayIconActiveOther {
return self.pageStyle == 1 ? kDefaultTextColor : %orig;
}
- (UIColor *)overlayIconInactive {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.7] : %orig;
}
- (UIColor *)overlayIconDisabled {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.3] : %orig;
}
- (UIColor *)overlayFilledButtonActive {
return self.pageStyle == 1 ? [kDefaultTextColor colorWithAlphaComponent:0.2] : %orig;
}
%end
%hook YTColor
+ (BOOL)darkerPaletteTextColorEnabled { return NO; }
+ (UIColor *)white1 { return lcmHexColor; }
+ (UIColor *)white2 { return lcmHexColor; }
+ (UIColor *)white3 { return lcmHexColor; }
+ (UIColor *)white4 { return lcmHexColor; }
+ (UIColor *)white5 { return lcmHexColor; }
+ (UIColor *)grey1 { return lcmHexColor; }
+ (UIColor *)grey2 { return lcmHexColor; }
%end
%hook _ASDisplayView
- (void)layoutSubviews {
%orig;
NSArray<NSString *> *targetLabels = @[@"connect account", @"Thanks", @"Save to playlist", @"Report"];
for (UIView *subview in self.subviews) {
if ([targetLabels containsObject:subview.accessibilityLabel]) {
subview.backgroundColor = lcmHexColor;
if ([subview isKindOfClass:[UILabel class]]) {
((UILabel *)subview).textColor = [UIColor blackColor];
}
}
}
}
%end
%hook QTMColorGroup
- (UIColor *)tint100 { return kDefaultTextColor; }
- (UIColor *)tint300 { return kDefaultTextColor; }
- (UIColor *)tint500 { return kDefaultTextColor; }
- (UIColor *)tint700 { return kDefaultTextColor; }
- (UIColor *)accent200 { return kDefaultTextColor; }
- (UIColor *)accent400 { return kDefaultTextColor; }
- (UIColor *)accentColor { return kDefaultTextColor; }
- (UIColor *)brightAccentColor { return kDefaultTextColor; }
- (UIColor *)regularColor { return kDefaultTextColor; }
- (UIColor *)darkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColor { return kDefaultTextColor; }
- (UIColor *)lightBodyTextColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnRegularColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnLighterColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnDarkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnAccentColor { return kDefaultTextColor; }
- (UIColor *)buttonBackgroundColor { return kDefaultTextColor; }
- (UIColor *)Color { return kDefaultTextColor; }
%end
%hook YTQTMButton
- (void)setImage:(UIImage *)image {
UIImage *tintedImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self setTintColor:kDefaultTextColor];
%orig(tintedImage);
}
%end
%hook UIExtendedSRGColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:0.9]);
}
%end
%hook UIExtendedSRGBColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook UIExtendedGrayColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook VideoTitleLabel
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UILabel
+ (void)load {
[[UILabel appearance] setTextColor:kDefaultTextColor];
}
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UITextField
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UITextView
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UISearchBar
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UISegmentedControl
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
}
%end
%hook UIButton
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state {
%orig(kDefaultTextColor, state);
}
%end
%hook UIBarButtonItem
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
}
%end
%hook NSAttributedString
- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSAttributedStringKey, id> *)attrs {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attrs];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
return %orig(str, modifiedAttributes);
}
%end
%hook CATextLayer
- (void)setTextColor:(CGColorRef)color {
%orig(kDefaultTextColor.CGColor);
}
%end
%hook ASTextNode
- (NSAttributedString *)attributedString {
NSAttributedString *original = %orig;
NSMutableAttributedString *modified = [original mutableCopy];
[modified addAttribute:NSForegroundColorAttributeName value:kDefaultTextColor range:NSMakeRange(0, modified.length)];
return modified;
}
%end
%hook ASTextFieldNode
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook ASTextView
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook ASButtonNode
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UIControl
- (UIColor *)backgroundColor {
return [UIColor blackColor];
}
%end
%end
// Constructor
%ctor {
%init;
if (lowContrastMode()) {
%init(gLowContrastMode);
}
if (customContrastMode()) {
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:@"kCustomUIColor"];
if (colorData) {
NSError *error = nil;
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:colorData error:&error];
if (!error) {
[unarchiver setRequiresSecureCoding:NO];
lcmHexColor = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey];
if (lcmHexColor) {
%init(gCustomContrastMode);
if (isDarkMode()) {
NSArray<NSString *> *targetLabels = @[@"connect account", @"Thanks", @"Save to playlist", @"Report", @"Share", @"Like", @"Dislike"];
UIColor *contrastColor = activeContrastColor();
for (UIView *subview in self.subviews) {
if ([targetLabels containsObject:subview.accessibilityLabel]) {
subview.backgroundColor = contrastColor;
if ([subview isKindOfClass:[UILabel class]]) {
((UILabel *)subview).textColor = [UIColor blackColor];
}
}
}
}
}
%end
%hook QTMColorGroup
- (UIColor *)tint100 { return kDefaultTextColor; }
- (UIColor *)tint300 { return kDefaultTextColor; }
- (UIColor *)tint500 { return kDefaultTextColor; }
- (UIColor *)tint700 { return kDefaultTextColor; }
- (UIColor *)accent200 { return kDefaultTextColor; }
- (UIColor *)accent400 { return kDefaultTextColor; }
- (UIColor *)accentColor { return kDefaultTextColor; }
- (UIColor *)brightAccentColor { return kDefaultTextColor; }
- (UIColor *)regularColor { return kDefaultTextColor; }
- (UIColor *)darkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColor { return kDefaultTextColor; }
- (UIColor *)lightBodyTextColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnRegularColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnLighterColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnDarkerColor { return kDefaultTextColor; }
- (UIColor *)bodyTextColorOnAccentColor { return kDefaultTextColor; }
- (UIColor *)buttonBackgroundColor { return kDefaultTextColor; }
- (UIColor *)Color { return kDefaultTextColor; }
%end
%hook YTQTMButton
- (void)setImage:(UIImage *)image {
if (isDarkMode()) {
UIImage *tintedImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self setTintColor:kDefaultTextColor];
%orig(tintedImage);
} else {
%orig;
}
}
%end
%hook UIExtendedSRGColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:0.9]);
}
%end
%hook UIExtendedSRGBColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook UIExtendedGrayColorSpace
- (void)setTextColor:(UIColor *)textColor {
%orig([kDefaultTextColor colorWithAlphaComponent:1.0]);
}
%end
%hook VideoTitleLabel
- (void)setTextColor:(UIColor *)textColor {
%orig(kDefaultTextColor);
}
%end
%hook UILabel
+ (void)load {
if (@available(iOS 16.0, *)) {
[[UILabel appearance] setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[[UILabel appearance] setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
if (isDarkMode()) {
[[UILabel appearance] setTextColor:kDefaultTextColor];
}
}
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook UITextField
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook UITextView
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook UISearchBar
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook UISegmentedControl
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
if (isDarkMode()) {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
} else {
%orig;
}
}
%end
%hook UIButton
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state {
%orig(isDarkMode() ? kDefaultTextColor : color, state);
}
%end
%hook UIBarButtonItem
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state {
if (isDarkMode()) {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
%orig(modifiedAttributes, state);
} else {
%orig;
}
}
%end
%hook NSAttributedString
- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSAttributedStringKey, id> *)attrs {
if (isDarkMode()) {
NSMutableDictionary *modifiedAttributes = [NSMutableDictionary dictionaryWithDictionary:attrs];
modifiedAttributes[NSForegroundColorAttributeName] = kDefaultTextColor;
return %orig(str, modifiedAttributes);
}
return %orig;
}
%end
%hook CATextLayer
- (void)setTextColor:(CGColorRef)textColor {
%orig(isDarkMode() ? kDefaultTextColor.CGColor : textColor);
}
%end
%hook ASTextNode
- (NSAttributedString *)attributedString {
NSAttributedString *original = %orig;
if (isDarkMode()) {
NSMutableAttributedString *modified = [original mutableCopy];
[modified addAttribute:NSForegroundColorAttributeName value:kDefaultTextColor range:NSMakeRange(0, modified.length)];
return modified;
}
return original;
}
%end
%hook ASTextFieldNode
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook ASTextView
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook ASButtonNode
- (void)setTextColor:(UIColor *)textColor {
%orig(isDarkMode() ? kDefaultTextColor : textColor);
}
%end
%hook UIControl
- (UIColor *)backgroundColor {
return isDarkMode() ? [UIColor blackColor] : %orig;
}
%end
%end
// Constructor
%ctor {
%init;
if (lowContrastMode() || customContrastMode()) {
%init(gContrastModeShared);
if (customContrastMode()) {
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:@"kCustomUIColor"];
if (colorData) {
NSError *error = nil;
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:colorData error:&error];
if (!error) {
[unarchiver setRequiresSecureCoding:NO];
lcmHexColor = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey];
}
}
}

View file

@ -37,20 +37,24 @@ static int getNotificationIconStyle() {
NSString *imageName;
UIColor *iconColor;
switch (getNotificationIconStyle()) {
case 1: // Thin outline style (2020+)
case 1: // Bold outline style (2024+)
imageName = isSelected ? @"notifications_selected" : @"notifications_unselected";
iconColor = [%c(YTColor) white1];
break;
case 2: // Thin outline style (2020+)
imageName = isSelected ? @"notifications_selected" : @"notifications_24pt";
iconColor = [%c(YTColor) white1];
break;
case 2: // Filled style (2018+)
case 3: // Filled style (2018+)
imageName = @"notifications_selected";
iconColor = isSelected ? [%c(YTColor) white1] : [UIColor grayColor];
break;
case 3: // Inbox style (2014+)
case 4: // Inbox style (2014+)
imageName = @"inbox_selected";
iconColor = isSelected ? [%c(YTColor) white1] : [UIColor grayColor];
break;
default: // Default style
imageName = isSelected ? @"notifications_selected" : @"notifications_unselected";
default: // Default style (2025+)
imageName = isSelected ? @"notifications_selected_2025" : @"notifications_unselected_2025";
iconColor = [%c(YTColor) white1];
break;
}
@ -115,99 +119,178 @@ static int getNotificationIconStyle() {
%end
%end
// LEGACY VERSION ⚠️
// Hide the (Connect / Thanks / Save / Report) Buttons under the Video Player - 17.33.2 and up - @arichornlover (inspired by @PoomSmart's version)
%hook _ASDisplayView
- (void)layoutSubviews {
%orig;
BOOL hideConnectButton = IS_ENABLED(@"hideConnectButton_enabled");
BOOL hideThanksButton = IS_ENABLED(@"hideThanksButton_enabled");
BOOL hideSaveToPlaylistButton = IS_ENABLED(@"hideSaveToPlaylistButton_enabled");
BOOL hideReportButton = IS_ENABLED(@"hideReportButton_enabled");
for (UIView *subview in self.subviews) {
if ([subview.accessibilityLabel isEqualToString:@"connect account"]) {
subview.hidden = hideConnectButton;
} else if ([subview.accessibilityLabel isEqualToString:@"Thanks"]) {
subview.hidden = hideThanksButton;
} else if ([subview.accessibilityLabel isEqualToString:@"Save to playlist"]) {
subview.hidden = hideSaveToPlaylistButton;
} else if ([subview.accessibilityLabel isEqualToString:@"Report"]) {
subview.hidden = hideReportButton;
}
}
// YTHidePlayerButtons 1.0.0 - made by @aricloverEXTRA
static NSDictionary<NSString *, NSString *> *HideToggleMap(void) {
static NSDictionary<NSString *, NSString *> *map = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
map = @{
// identifiers
@"id.video.share.button": @"hideShareButton_enabled",
@"id.ui.add_to.offline.button": @"hideDownloadButton_enabled",
@"id.video.remix.button": @"hideRemixButton_enabled",
@"clip_button.eml": @"hideClipButton_enabled",
@"id.ui.carousel_header": @"hideCommentSection_enabled",
// fallbacks
@"Like": @"hideLikeButton_enabled", // unidentified identifier
@"Dislike": @"hideDislikeButton_enabled", // unidentified identifier
@"Share": @"hideShareButton_enabled", // Share Button
@"Ask": @"hideAskButton_enabled", // unidentified identifier
@"Download": @"hideDownloadButton_enabled", // Download Button
@"Hype": @"hideHypeButton_enabled", // unidentified identifier
@"Thanks": @"hideThanksButton_enabled", // unidentified identifier
@"Remix": @"hideRemixButton_enabled", // Remix Button
@"Clip": @"hideClipButton_enabled", // Clip Button
@"Save to playlist": @"hideSaveToPlaylistButton_enabled", // unidentified identifier
@"Report": @"hideReportButton_enabled", // unidentified identifier
@"connect account": @"hideConnectButton_enabled" // unidentified identifier
};
});
return map;
}
%end
// UPDATED VERSION
// Hide the (Connect / Share / Remix / Thanks / Download / Clip / Save / Report) Buttons under the Video Player - 17.33.2 and up - @PoomSmart (inspired by @arichornlover) - METHOD BROKE Server-Side on May 14th 2024
static BOOL findCell(ASNodeController *nodeController, NSArray <NSString *> *identifiers) {
for (id child in [nodeController children]) {
NSLog(@"Child: %@", [child description]);
if ([child isKindOfClass:%c(ELMNodeController)]) {
NSArray <ELMComponent *> *elmChildren = [(ELMNodeController * _Nullable)child children];
for (ELMComponent *elmChild in elmChildren) {
for (NSString *identifier in identifiers) {
if ([[elmChild description] containsString:identifier]) {
NSLog(@"Found identifier: %@", identifier);
return YES;
}
}
static BOOL shouldHideForKey(NSString *key) {
if (!key) return NO;
NSString *pref = HideToggleMap()[key];
if (!pref) return NO;
return IS_ENABLED(pref);
}
static void safeHideView(id view) {
if (!view) return;
dispatch_async(dispatch_get_main_queue(), ^{
@try {
if ([view respondsToSelector:@selector(setHidden:)]) {
[view setHidden:YES];
return;
}
if ([view isKindOfClass:[UIView class]]) {
((UIView *)view).hidden = YES;
return;
}
} @catch (NSException *ex) {
NSLog(@"[HidePlayerButtons] safeHideView exception: %@", ex);
}
});
}
static BOOL inspectAndHideIfMatch(id view) {
if (!view) return NO;
@try {
NSString *accId = nil;
if ([view respondsToSelector:@selector(accessibilityIdentifier)]) {
@try { accId = [view accessibilityIdentifier]; } @catch (NSException *e) { accId = nil; }
if (accId && shouldHideForKey(accId)) {
safeHideView(view);
return YES;
}
}
if ([child isKindOfClass:%c(ASNodeController)]) {
ASDisplayNode *childNode = ((ASNodeController * _Nullable)child).node; // ELMContainerNode
NSArray<id> *yogaChildren = childNode.yogaChildren;
for (ASDisplayNode *displayNode in yogaChildren) {
NSLog(@"Yoga Child: %@", displayNode.accessibilityIdentifier);
if ([identifiers containsObject:displayNode.accessibilityIdentifier]) {
NSLog(@"Found identifier: %@", displayNode.accessibilityIdentifier);
return YES;
}
if (findCell(child, identifiers)) {
NSString *accLabel = nil;
if ([view respondsToSelector:@selector(accessibilityLabel)]) {
@try { accLabel = [view accessibilityLabel]; } @catch (NSException *e) { accLabel = nil; }
if (accLabel && shouldHideForKey(accLabel)) {
safeHideView(view);
return YES;
}
}
NSString *desc = nil;
@try { desc = [[view description] copy]; } @catch (NSException *e) { desc = nil; }
if (desc) {
for (NSString *key in HideToggleMap().allKeys) {
if ([desc containsString:key] && shouldHideForKey(key)) {
safeHideView(view);
return YES;
}
}
}
} @catch (NSException *ex) {
NSLog(@"[HidePlayerButtons] inspectAndHideIfMatch exception: %@", ex);
}
return NO;
}
%hook ASCollectionView // This stopped working on May 14th 2024 due to a Server-Side Change from YouTube.
- (CGSize)sizeForElement:(ASCollectionElement * _Nullable)element {
if ([self.accessibilityIdentifier isEqualToString:@"id.video.scrollable_action_bar"]) {
ASCellNode *node = [element node];
ASNodeController *nodeController = [node controller];
if (IS_ENABLED(@"hideShareButton_enabled") && findCell(nodeController, @[@"id.video.share.button"])) {
return CGSizeZero;
}
if (IS_ENABLED(@"hideRemixButton_enabled") && findCell(nodeController, @[@"id.video.remix.button"])) {
return CGSizeZero;
}
if (IS_ENABLED(@"hideThanksButton_enabled") && findCell(nodeController, @[@"Thanks"])) {
return CGSizeZero;
}
if (IS_ENABLED(@"hideClipButton_enabled") && findCell(nodeController, @[@"clip_button.eml"])) {
return CGSizeZero;
}
if (IS_ENABLED(@"hideDownloadButton_enabled") && findCell(nodeController, @[@"id.ui.add_to.offline.button"])) {
return CGSizeZero;
}
if (IS_ENABLED(@"hideCommentSection_enabled") && findCell(nodeController, @[@"id.ui.carousel_header"])) {
return CGSizeZero;
static void traverseAndHideViews(UIView *root) {
if (!root) return;
@try {
inspectAndHideIfMatch(root);
NSArray<UIView *> *subs = nil;
@try { subs = root.subviews; } @catch (NSException *e) { subs = nil; }
if (subs && subs.count) {
for (UIView *sv in subs) {
if ([sv isKindOfClass:[UIView class]]) {
traverseAndHideViews(sv);
}
}
}
} @catch (NSException *ex) {
NSLog(@"[HidePlayerButtons] traverseAndHideViews exception: %@", ex);
}
return %orig;
}
static void hideButtonsInActionBarIfNeeded(id collectionView) {
if (!collectionView) return;
@try {
// Ensure the collectionView has accessibilityIdentifier and we only operate on the action bar
NSString *accId = nil;
if ([collectionView respondsToSelector:@selector(accessibilityIdentifier)]) {
@try { accId = [collectionView accessibilityIdentifier]; } @catch (NSException *e) { accId = nil; }
}
if (!accId) return;
if (![accId isEqualToString:@"id.video.scrollable_action_bar"]) return;
NSArray *cells = nil;
if ([collectionView respondsToSelector:@selector(visibleCells)]) {
@try { cells = [collectionView visibleCells]; } @catch (NSException *e) { cells = nil; }
}
if (!cells || cells.count == 0) {
@try { cells = [collectionView subviews]; } @catch (NSException *e) { cells = nil; }
}
if (!cells || cells.count == 0) return;
for (id cell in cells) {
if ([cell isKindOfClass:[UIView class]]) {
traverseAndHideViews((UIView *)cell);
} else {
@try {
if ([cell respondsToSelector:@selector(view)]) {
id view = [cell performSelector:@selector(view)];
if ([view isKindOfClass:[UIView class]]) {
traverseAndHideViews((UIView *)view);
}
} else if ([cell respondsToSelector:@selector(node)]) {
NSString *desc = nil;
@try { desc = [cell description]; } @catch (NSException *e) { desc = nil; }
if (desc) {
// Not ideal to act on description, but we keep this non-destructive: only log for debugging
// Uncomment logging for debug builds if needed.
// NSLog(@"[HidePlayerButtons] Non-UIView cell description: %@", desc);
}
}
} @catch (NSException *ex) {
NSLog(@"[HidePlayerButtons] Exception handling non-UIView cell: %@", ex);
}
}
}
} @catch (NSException *exception) {
NSLog(@"[HidePlayerButtons] hideButtonsInActionBarIfNeeded exception: %@", exception);
}
}
%hook ASCollectionView
- (id)nodeForItemAtIndexPath:(NSIndexPath *)indexPath {
id node = %orig;
id weakSelf = (id)self;
dispatch_async(dispatch_get_main_queue(), ^{
@try {
hideButtonsInActionBarIfNeeded(weakSelf);
} @catch (NSException *e) {
NSLog(@"[HidePlayerButtons] async hide exception: %@", e);
}
});
return node;
}
- (void)nodesDidRelayout:(NSArray *)nodes {
%orig;
id weakSelf = (id)self;
dispatch_async(dispatch_get_main_queue(), ^{
@try {
hideButtonsInActionBarIfNeeded(weakSelf);
} @catch (NSException *e) {
NSLog(@"[HidePlayerButtons] relayout hide exception: %@", e);
}
});
}
%end
@ -873,13 +956,6 @@ static NSMutableArray <YTIItemSectionRenderer *> *filteredArray(NSArray <YTIItem
%end
%end
// Disable Modern/Rounded Buttons (_ASDisplayView Version's not supported) - @arichornlover
%group gDisableModernButtons
%hook YTQTMButton // Disable Modern/Rounded Buttons
+ (BOOL)buttonModernizationEnabled { return NO; }
%end
%end
// Disable Rounded Hints with no Rounded Corners - @arichornlover
%group gDisableRoundedHints
%hook YTBubbleHintView // Disable Modern/Rounded Hints
@ -887,61 +963,6 @@ static NSMutableArray <YTIItemSectionRenderer *> *filteredArray(NSArray <YTIItem
%end
%end
// Disable Modern Flags - @arichornlover
%group gDisableModernFlags
%hook YTColdConfig
// Disable Modern Content
- (BOOL)creatorClientConfigEnableStudioModernizedMdeThumbnailPickerForClient { return NO; }
- (BOOL)cxClientEnableModernizedActionSheet { return NO; }
- (BOOL)enableClientShortsSheetsModernization { return NO; }
- (BOOL)enableTimestampModernizationForNative { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaFeedStretchBottom { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaFrostedBottomBar { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaFrostedPivotBar { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaFrostedPivotBarUpdatedBackdrop { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaFrostedTopBar { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaOpacityPivotBar { return NO; }
- (BOOL)mainAppCoreClientEnableModernIaTopAndBottomBarIconRefresh { return NO; }
- (BOOL)mainAppCoreClientEnableModernizedBedtimeReminderU18DefaultSettings { return NO; }
- (BOOL)modernizeCameoNavbar { return NO; }
- (BOOL)modernizeCollectionLockups { return NO; }
- (BOOL)modernizeCollectionLockupsShowVideoCount { return NO; }
- (BOOL)modernizeElementsBgColor { return NO; }
- (BOOL)modernizeElementsTextColor { return NO; }
- (BOOL)postsCreatorClientEnableModernButtonsUi { return NO; }
- (BOOL)pullToFullModernEdu { return NO; }
- (BOOL)showModernMiniplayerRedesign { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableModernButtonsForNative { return NO; }
- (BOOL)uiSystemsClientGlobalConfigIosEnableModernTabsForNative { return NO; }
- (BOOL)uiSystemsClientGlobalConfigIosEnableSnackbarModernization { return NO; }
- (BOOL)uiSystemsClientGlobalConfigModernizeNativeBgColor { return NO; }
- (BOOL)uiSystemsClientGlobalConfigModernizeNativeTextColor { return NO; }
// Disable Rounded Content
- (BOOL)enableIosFloatingMiniplayerRoundedCornerRadius { return YES; }
- (BOOL)iosDownloadsPageRoundedThumbs { return NO; }
- (BOOL)iosRoundedSearchBarSuggestZeroPadding { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableRoundedDialogForNative { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableRoundedThumbnailsForNative { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableRoundedThumbnailsForNativeLongTail { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableRoundedTimestampForNative { return NO; }
// Disable Optional Content
- (BOOL)elementsClientIosElementsEnableLayoutUpdateForIob { return NO; }
- (BOOL)supportElementsInMenuItemSupportedRenderers { return NO; }
- (BOOL)isNewRadioButtonStyleEnabled { return NO; }
- (BOOL)uiSystemsClientGlobalConfigEnableButtonSentenceCasingForNative { return NO; }
- (BOOL)mainAppCoreClientEnableClientYouTab { return NO; }
- (BOOL)mainAppCoreClientEnableClientYouLatency { return NO; }
- (BOOL)mainAppCoreClientEnableClientYouTabTablet { return NO; }
%end
%hook YTHotConfig
- (BOOL)liveChatIosUseModernRotationDetection { return NO; } // Disable Modern Content (YTHotConfig)
- (BOOL)liveChatModernizeClassicElementizeTextMessage { return NO; }
- (BOOL)iosShouldRepositionChannelBar { return NO; }
- (BOOL)enableElementRendererOnChannelCreation { return NO; }
%end
%end
// Disable Ambient Mode in Fullscreen - @arichornlover
%group gDisableAmbientMode
%hook YTCinematicContainerView
@ -1943,15 +1964,9 @@ static NSMutableArray <YTIItemSectionRenderer *> *filteredArray(NSArray <YTIItem
if (IS_ENABLED(kClassicVideoPlayer)) {
%init(gClassicVideoPlayer);
}
if (IS_ENABLED(kDisableModernButtons)) {
%init(gDisableModernButtons);
}
if (IS_ENABLED(kDisableRoundedHints)) {
%init(gDisableRoundedHints);
}
if (IS_ENABLED(kDisableModernFlags)) {
%init(gDisableModernFlags);
}
if (IS_ENABLED(kDisableAmbientMode)) {
%init(gDisableAmbientMode);
}

View file

@ -8,18 +8,8 @@
- (NSDictionary *)infoDictionary {
NSDictionary *orig = %orig;
if ([self isEqual:NSBundle.mainBundle]) {
NSArray<NSString *> *stack = [NSThread callStackSymbols];
BOOL needsSpoof = NO;
for (NSString *frame in stack) {
if ([frame containsString:@"GIDSignIn"] ||
[frame containsString:@"GTMSessionFetcher"] ||
[frame containsString:@"GoogleSignIn"]) {
needsSpoof = YES;
break;
}
}
if (needsSpoof) {
NSMutableDictionary *patched = [orig mutableCopy];
NSMutableDictionary *patched = [orig mutableCopy];
if (patched) {
patched[@"CFBundleIdentifier"] = @"com.google.ios.youtube";
return [patched copy];
}

View file

@ -565,12 +565,26 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
kLowContrastMode,
({
if (enable) {
if (@available(iOS 16.0, *)) {
} else {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Outdated iOS Version" message:@"LowContrastMode is designed for iOS 16 or higher. You are running an older iOS version. Enable anyway?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Enable" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[NSUserDefaults standardUserDefaults] setBool:enable forKey:kLowContrastMode];
[settingsViewController reloadData];
SHOW_RELAUNCH_YT_SNACKBAR;
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[alert addAction:okAction];
[alert addAction:cancelAction];
[settingsViewController presentViewController:alert animated:YES completion:nil];
return NO;
}
Class YTVersionUtilsClass = %c(YTVersionUtils);
NSString *appVersion = [YTVersionUtilsClass performSelector:@selector(appVersion)];
NSComparisonResult result1 = [appVersion compare:@"17.33.2" options:NSNumericSearch];
NSComparisonResult result2 = [appVersion compare:@"17.38.10" options:NSNumericSearch];
NSComparisonResult result1 = [appVersion compare:@"19.01.1" options:NSNumericSearch];
NSComparisonResult result2 = [appVersion compare:@"20.33.2" options:NSNumericSearch];
if (result1 == NSOrderedAscending) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Discontinued Version" message:[NSString stringWithFormat:@"You are using v%@, a discontinued version of YouTube that may not work with LowContrastMode. Supported versions are v17.33.2-v17.38.10. Enable anyway?", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Discontinued YouTube Version" message:[NSString stringWithFormat:@"You are using v%@, a discontinued version of YouTube that may not work with LowContrastMode. Supported versions are v19.01.1-v20.33.2. Enable anyway?", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Enable" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[NSUserDefaults standardUserDefaults] setBool:enable forKey:kLowContrastMode];
[settingsViewController reloadData];
@ -582,7 +596,7 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
[settingsViewController presentViewController:alert animated:YES completion:nil];
return NO;
} else if (result2 == NSOrderedDescending) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Incompatible Version" message:[NSString stringWithFormat:@"LowContrastMode is only available for app versions v17.33.2-v17.38.10. You are using v%@. Enable anyway?", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Incompatible YouTube Version" message:[NSString stringWithFormat:@"LowContrastMode is only available for app versions v19.01.1-v20.33.2. You are using v%@. Enable anyway?", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Enable" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[NSUserDefaults standardUserDefaults] setBool:enable forKey:kLowContrastMode];
[settingsViewController reloadData];
@ -594,7 +608,7 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
[settingsViewController presentViewController:alert animated:YES completion:nil];
return NO;
} else if (UIScreen.mainScreen.traitCollection.userInterfaceStyle != UIUserInterfaceStyleDark) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Light Mode Detected" message:@"LowContrastMode is only available in Dark Mode. Please switch to Dark Mode to be able to use LowContrastMode." preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Light Mode Detected" message:@"LowContrastMode is only designed for Dark Mode in mind. Please enable Dark Mode to be able to use LowContrastMode." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:okAction];
[settingsViewController presentViewController:alert animated:YES completion:nil];
@ -625,7 +639,7 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
Class YTVersionUtilsClass = %c(YTVersionUtils);
NSString *appVersion = [YTVersionUtilsClass performSelector:@selector(appVersion)];
// Alert the user that they need to enable the fix
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Incompatibile" message:[NSString stringWithFormat:@"LowContrastMode is only available for app versions v17.33.2-v17.38.10. \nYou are currently using v%@. \n\nWorkaround: if you want to use this then I recommend enabling \"Fix LowContrastMode\" Option.", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Incompatible YouTube Version" message:[NSString stringWithFormat:@"LowContrastMode is only available for app versions v19.01.1-v20.33.2. You are using v%@. Enable anyway?", appVersion] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:okAction];
[settingsViewController presentViewController:alert animated:YES completion:nil];
@ -642,7 +656,6 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
[settingsViewController reloadData];
return YES;
}]
];
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Low Contrast Mode Selector") pickerSectionTitle:nil rows:rows selectedItemIndex:contrastMode() parentResponder:[self parentResponder]];
[settingsViewController pushViewController:picker];
@ -652,16 +665,14 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
];
[sectionItems addObject:lowContrastModeButton];
SWITCH2(LOC(@"CLASSIC_VIDEO_PLAYER"), LOC(@"CLASSIC_VIDEO_PLAYER_DESC"), kClassicVideoPlayer);
SWITCH2(LOC(@"DISABLE_MODERN_BUTTONS"), LOC(@"DISABLE_MODERN_BUTTONS_DESC"), kDisableModernButtons);
SWITCH2(LOC(@"DISABLE_ROUNDED_CORNERS_ON_HINTS"), LOC(@"DISABLE_ROUNDED_CORNERS_ON_HINTS_DESC"), kDisableRoundedHints);
SWITCH2(LOC(@"DISABLE_MODERN_FLAGS"), LOC(@"DISABLE_MODERN_FLAGS_DESC"), kDisableModernFlags);
SWITCH3(
LOC(@"YTNOMODERNUI"),
LOC(@"YTNOMODERNUI_DESC"),
kYTNoModernUI,
({
if (enable) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"This will force-enable other settings on restart. To disable them, you must turn this setting off." preferredStyle:UIAlertControllerStyleAlert];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"This will force-enable other settings on restart. To disable them, you must turn this setting off. (YTNoModernUI is Deprecated)" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:okAction];
[settingsViewController presentViewController:alert animated:YES completion:nil];
@ -678,303 +689,267 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
accessibilityIdentifier:nil
detailTextBlock:^NSString *() {
switch (appVersionSpoofer()) {
case 0:
return @"v20.33.2";
case 1:
return @"v20.32.5";
case 2:
return @"v20.32.4";
case 3:
return @"v20.31.6";
case 4:
return @"v20.31.5";
case 5:
return @"v20.30.5";
case 6:
return @"v20.29.3";
case 7:
return @"v20.28.2";
case 8:
return @"v20.26.7";
case 9:
return @"v20.25.4";
case 10:
return @"v20.24.5";
case 11:
return @"v20.24.4";
case 12:
return @"v20.23.3";
case 13:
return @"v20.22.1";
case 14:
return @"v20.21.6";
case 15:
return @"v20.20.7";
case 16:
return @"v20.20.5";
case 17:
return @"v20.19.3";
case 18:
return @"v20.19.2";
case 19:
return @"v20.18.5";
case 20:
return @"v20.18.4";
case 21:
return @"v20.16.7";
case 22:
return @"v20.15.1";
case 23:
return @"v20.14.2";
case 24:
return @"v20.13.5";
case 25:
return @"v20.12.4";
case 26:
return @"v20.11.6";
case 27:
return @"v20.10.4";
case 28:
return @"v20.10.3";
case 29:
return @"v20.09.3";
case 30:
return @"v20.08.3";
case 31:
return @"v20.07.6";
case 32:
return @"v20.06.03";
case 33:
return @"v20.05.4";
case 34:
return @"v20.03.1";
case 35:
return @"v20.03.02";
case 36:
return @"v20.02.3";
case 37:
return @"v19.49.7";
case 38:
return @"v19.49.5";
case 39:
return @"v19.49.3";
case 40:
return @"v19.47.7";
case 41:
return @"v19.46.3";
case 42:
return @"v19.45.4";
case 43:
return @"v19.44.4";
case 44:
return @"v19.43.2";
case 45:
return @"v19.42.1";
case 46:
return @"v19.41.3";
case 47:
return @"v19.40.4";
case 48:
return @"v19.39.1";
case 49:
return @"v19.38.2";
case 50:
return @"v19.37.2";
case 51:
return @"v19.36.1";
case 52:
return @"v19.35.3";
case 53:
return @"v19.34.2";
case 54:
return @"v19.33.2";
case 55:
return @"v19.32.8";
case 56:
return @"v19.32.6";
case 57:
return @"v19.31.4";
case 58:
return @"v19.30.2";
case 59:
return @"v19.29.1";
case 60:
return @"v19.28.1";
case 61:
return @"v19.26.5";
case 62:
return @"v19.25.4";
case 63:
return @"v19.25.3";
case 64:
return @"v19.24.3";
case 65:
return @"v19.24.2";
case 66:
return @"v19.23.3";
case 67:
return @"v19.22.6";
case 68:
return @"v19.22.3";
case 69:
return @"v19.21.3";
case 70:
return @"v19.21.2";
case 71:
return @"v19.20.2";
case 72:
return @"v19.19.7";
case 73:
return @"v19.19.5";
case 74:
return @"v19.18.2";
case 75:
return @"v19.17.2";
case 76:
return @"v19.16.3";
case 77:
return @"v19.15.1";
case 78:
return @"v19.14.3";
case 79:
return @"v19.14.2";
case 80:
return @"v19.13.1";
case 81:
return @"v19.12.3";
case 82:
return @"v19.10.7";
case 83:
return @"v19.10.6";
case 84:
return @"v19.10.5";
case 85:
return @"v19.09.4";
case 86:
return @"v19.09.3";
case 87:
return @"v19.08.2";
case 88:
return @"v19.07.5";
case 89:
return @"v19.07.4";
case 90:
return @"v19.06.2";
case 91:
return @"v19.05.5";
case 92:
return @"v19.05.3";
case 93:
return @"v19.04.3";
case 94:
return @"v19.03.2";
case 95:
return @"v19.02.1";
case 96:
return @"v19.01.1";
default:
return @"v20.33.2";
case 0: return @"v21.08.3";
case 1: return @"v21.07.4";
case 2: return @"v21.06.2";
case 3: return @"v21.05.3";
case 4: return @"v21.04.2";
case 5: return @"v21.03.2";
case 6: return @"v21.02.3";
case 7: return @"v20.50.10";
case 8: return @"v20.50.9";
case 9: return @"v20.50.6";
case 10: return @"v20.49.5";
case 11: return @"v20.47.3";
case 12: return @"v20.46.3";
case 13: return @"v20.46.2";
case 14: return @"v20.45.3";
case 15: return @"v20.44.2";
case 16: return @"v20.43.3";
case 17: return @"v20.42.3";
case 18: return @"v20.41.5";
case 19: return @"v20.41.4";
case 20: return @"v20.40.4";
case 21: return @"v20.39.6";
case 22: return @"v20.39.5";
case 23: return @"v20.39.4";
case 24: return @"v20.38.4";
case 25: return @"v20.38.3";
case 26: return @"v20.37.5";
case 27: return @"v20.37.3";
case 28: return @"v20.36.3";
case 29: return @"v20.35.2";
case 30: return @"v20.34.2";
case 31: return @"v20.33.2";
case 32: return @"v20.32.5";
case 33: return @"v20.32.4";
case 34: return @"v20.31.6";
case 35: return @"v20.31.5";
case 36: return @"v20.30.5";
case 37: return @"v20.29.3";
case 38: return @"v20.28.2";
case 39: return @"v20.26.7";
case 40: return @"v20.25.4";
case 41: return @"v20.24.5";
case 42: return @"v20.24.4";
case 43: return @"v20.23.3";
case 44: return @"v20.22.1";
case 45: return @"v20.21.6";
case 46: return @"v20.20.7";
case 47: return @"v20.20.5";
case 48: return @"v20.19.3";
case 49: return @"v20.19.2";
case 50: return @"v20.18.5";
case 51: return @"v20.18.4";
case 52: return @"v20.16.7";
case 53: return @"v20.15.1";
case 54: return @"v20.14.2";
case 55: return @"v20.13.5";
case 56: return @"v20.12.4";
case 57: return @"v20.11.6";
case 58: return @"v20.10.4";
case 59: return @"v20.10.3";
case 60: return @"v20.09.3";
case 61: return @"v20.08.3";
case 62: return @"v20.07.6";
case 63: return @"v20.06.03";
case 64: return @"v20.05.4";
case 65: return @"v20.03.1";
case 66: return @"v20.03.02";
case 67: return @"v20.02.3";
case 68: return @"v19.49.7";
case 69: return @"v19.49.5";
case 70: return @"v19.49.3";
case 71: return @"v19.47.7";
case 72: return @"v19.46.3";
case 73: return @"v19.45.4";
case 74: return @"v19.44.4";
case 75: return @"v19.43.2";
case 76: return @"v19.42.1";
case 77: return @"v19.41.3";
case 78: return @"v19.40.4";
case 79: return @"v19.39.1";
case 80: return @"v19.38.2";
case 81: return @"v19.37.2";
case 82: return @"v19.36.1";
case 83: return @"v19.35.3";
case 84: return @"v19.34.2";
case 85: return @"v19.33.2";
case 86: return @"v19.32.8";
case 87: return @"v19.32.6";
case 88: return @"v19.31.4";
case 89: return @"v19.30.2";
case 90: return @"v19.29.1";
case 91: return @"v19.28.1";
case 92: return @"v19.26.5";
case 93: return @"v19.25.4";
case 94: return @"v19.25.3";
case 95: return @"v19.24.3";
case 96: return @"v19.24.2";
case 97: return @"v19.23.3";
case 98: return @"v19.22.6";
case 99: return @"v19.22.3";
case 100: return @"v19.21.3";
case 101: return @"v19.21.2";
case 102: return @"v19.20.2 (Deprecated)";
case 103: return @"v19.19.7 (Deprecated)";
case 104: return @"v19.19.5 (Deprecated)";
case 105: return @"v19.18.2 (Deprecated)";
case 106: return @"v19.17.2 (Deprecated)";
case 107: return @"v19.16.3 (Deprecated)";
case 108: return @"v19.15.1 (Deprecated)";
case 109: return @"v19.14.3 (Deprecated)";
case 110: return @"v19.14.2 (Deprecated)";
case 111: return @"v19.13.1 (Deprecated)";
case 112: return @"v19.12.3 (Deprecated)";
case 113: return @"v19.10.7 (Deprecated)";
case 114: return @"v19.10.6 (Deprecated)";
case 115: return @"v19.10.5 (Deprecated)";
case 116: return @"v19.09.4 (Deprecated)";
case 117: return @"v19.09.3 (Deprecated)";
case 118: return @"v19.08.2 (Deprecated)";
case 119: return @"v19.07.5 (Deprecated)";
case 120: return @"v19.07.4 (Deprecated)";
case 121: return @"v19.06.2 (Deprecated)";
case 122: return @"v19.05.5 (Deprecated)";
case 123: return @"v19.05.3 (Deprecated)";
case 124: return @"v19.04.3 (Deprecated)";
case 125: return @"v19.03.2 (Deprecated)";
case 126: return @"v19.02.1 (Deprecated)";
case 127: return @"v19.01.1 (Deprecated)";
default: return @"v21.08.3";
}
}
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
NSArray <YTSettingsSectionItem *> *rows = @[
SPOOFER_VERSION(@"v20.33.2", 0),
SPOOFER_VERSION(@"v20.32.5", 1),
SPOOFER_VERSION(@"v20.32.4", 2),
SPOOFER_VERSION(@"v20.31.6", 3),
SPOOFER_VERSION(@"v20.31.5", 4),
SPOOFER_VERSION(@"v20.30.5", 5),
SPOOFER_VERSION(@"v20.29.3", 6),
SPOOFER_VERSION(@"v20.28.2", 7),
SPOOFER_VERSION(@"v20.26.7", 8),
SPOOFER_VERSION(@"v20.25.4", 9),
SPOOFER_VERSION(@"v20.24.5", 10),
SPOOFER_VERSION(@"v20.24.4", 11),
SPOOFER_VERSION(@"v20.23.3", 12),
SPOOFER_VERSION(@"v20.22.1", 13),
SPOOFER_VERSION(@"v20.21.6", 14),
SPOOFER_VERSION(@"v20.20.7", 15),
SPOOFER_VERSION(@"v20.20.5", 16),
SPOOFER_VERSION(@"v20.19.3", 17),
SPOOFER_VERSION(@"v20.19.2", 18),
SPOOFER_VERSION(@"v20.18.5", 19),
SPOOFER_VERSION(@"v20.18.4", 20),
SPOOFER_VERSION(@"v20.16.7", 21),
SPOOFER_VERSION(@"v20.15.1", 22),
SPOOFER_VERSION(@"v20.14.2", 23),
SPOOFER_VERSION(@"v20.13.5", 24),
SPOOFER_VERSION(@"v20.12.4", 25),
SPOOFER_VERSION(@"v20.11.6", 26),
SPOOFER_VERSION(@"v20.10.4", 27),
SPOOFER_VERSION(@"v20.10.3", 28),
SPOOFER_VERSION(@"v20.09.3", 29),
SPOOFER_VERSION(@"v20.08.3", 30),
SPOOFER_VERSION(@"v20.07.6", 31),
SPOOFER_VERSION(@"v20.06.03", 32),
SPOOFER_VERSION(@"v20.05.4", 33),
SPOOFER_VERSION(@"v20.03.1", 34),
SPOOFER_VERSION(@"v20.03.02", 35),
SPOOFER_VERSION(@"v20.02.3", 36),
SPOOFER_VERSION(@"v19.49.7", 37),
SPOOFER_VERSION(@"v19.49.5", 38),
SPOOFER_VERSION(@"v19.49.3", 39),
SPOOFER_VERSION(@"v19.47.7", 40),
SPOOFER_VERSION(@"v19.46.3", 41),
SPOOFER_VERSION(@"v19.45.4", 42),
SPOOFER_VERSION(@"v19.44.4", 43),
SPOOFER_VERSION(@"v19.43.2", 44),
SPOOFER_VERSION(@"v19.42.1", 45),
SPOOFER_VERSION(@"v19.41.3", 46),
SPOOFER_VERSION(@"v19.40.4", 47),
SPOOFER_VERSION(@"v19.39.1", 48),
SPOOFER_VERSION(@"v19.38.2", 49),
SPOOFER_VERSION(@"v19.37.2", 50),
SPOOFER_VERSION(@"v19.36.1", 51),
SPOOFER_VERSION(@"v19.35.3", 52),
SPOOFER_VERSION(@"v19.34.2", 53),
SPOOFER_VERSION(@"v19.33.2", 54),
SPOOFER_VERSION(@"v19.32.8", 55),
SPOOFER_VERSION(@"v19.32.6", 56),
SPOOFER_VERSION(@"v19.31.4", 57),
SPOOFER_VERSION(@"v19.30.2", 58),
SPOOFER_VERSION(@"v19.29.1", 59),
SPOOFER_VERSION(@"v19.28.1", 60),
SPOOFER_VERSION(@"v19.26.5", 61),
SPOOFER_VERSION(@"v19.25.4", 62),
SPOOFER_VERSION(@"v19.25.3", 63),
SPOOFER_VERSION(@"v19.24.3", 64),
SPOOFER_VERSION(@"v19.24.2", 65),
SPOOFER_VERSION(@"v19.23.3", 66),
SPOOFER_VERSION(@"v19.22.6", 67),
SPOOFER_VERSION(@"v19.22.3", 68),
SPOOFER_VERSION(@"v19.21.3", 69),
SPOOFER_VERSION(@"v19.21.2", 70),
SPOOFER_VERSION(@"v19.20.2", 71),
SPOOFER_VERSION(@"v19.19.7", 72),
SPOOFER_VERSION(@"v19.19.5", 73),
SPOOFER_VERSION(@"v19.18.2", 74),
SPOOFER_VERSION(@"v19.17.2", 75),
SPOOFER_VERSION(@"v19.16.3", 76),
SPOOFER_VERSION(@"v19.15.1", 77),
SPOOFER_VERSION(@"v19.14.3", 78),
SPOOFER_VERSION(@"v19.14.2", 79),
SPOOFER_VERSION(@"v19.13.1", 80),
SPOOFER_VERSION(@"v19.12.3", 81),
SPOOFER_VERSION(@"v19.10.7", 82),
SPOOFER_VERSION(@"v19.10.6", 83),
SPOOFER_VERSION(@"v19.10.5", 84),
SPOOFER_VERSION(@"v19.09.4", 85),
SPOOFER_VERSION(@"v19.09.3", 86),
SPOOFER_VERSION(@"v19.08.2", 87),
SPOOFER_VERSION(@"v19.07.5", 88),
SPOOFER_VERSION(@"v19.07.4", 89),
SPOOFER_VERSION(@"v19.06.2", 90),
SPOOFER_VERSION(@"v19.05.5", 91),
SPOOFER_VERSION(@"v19.05.3", 92),
SPOOFER_VERSION(@"v19.04.3", 93),
SPOOFER_VERSION(@"v19.03.2", 94),
SPOOFER_VERSION(@"v19.02.1", 95),
SPOOFER_VERSION(@"v19.01.1", 96)
SPOOFER_VERSION(@"v21.08.3", 0),
SPOOFER_VERSION(@"v21.07.4", 1),
SPOOFER_VERSION(@"v21.06.2", 2),
SPOOFER_VERSION(@"v21.05.3", 3),
SPOOFER_VERSION(@"v21.04.2", 4),
SPOOFER_VERSION(@"v21.03.2", 5),
SPOOFER_VERSION(@"v21.02.3", 6),
SPOOFER_VERSION(@"v20.50.10", 7),
SPOOFER_VERSION(@"v20.50.9", 8),
SPOOFER_VERSION(@"v20.50.6", 9),
SPOOFER_VERSION(@"v20.49.5", 10),
SPOOFER_VERSION(@"v20.47.3", 11),
SPOOFER_VERSION(@"v20.46.3", 12),
SPOOFER_VERSION(@"v20.46.2", 13),
SPOOFER_VERSION(@"v20.45.3", 14),
SPOOFER_VERSION(@"v20.44.2", 15),
SPOOFER_VERSION(@"v20.43.3", 16),
SPOOFER_VERSION(@"v20.42.3", 17),
SPOOFER_VERSION(@"v20.41.5", 18),
SPOOFER_VERSION(@"v20.41.4", 19),
SPOOFER_VERSION(@"v20.40.4", 20),
SPOOFER_VERSION(@"v20.39.6", 21),
SPOOFER_VERSION(@"v20.39.5", 22),
SPOOFER_VERSION(@"v20.39.4", 23),
SPOOFER_VERSION(@"v20.38.4", 24),
SPOOFER_VERSION(@"v20.38.3", 25),
SPOOFER_VERSION(@"v20.37.5", 26),
SPOOFER_VERSION(@"v20.37.3", 27),
SPOOFER_VERSION(@"v20.36.3", 28),
SPOOFER_VERSION(@"v20.35.2", 29),
SPOOFER_VERSION(@"v20.34.2", 30),
SPOOFER_VERSION(@"v20.33.2", 31),
SPOOFER_VERSION(@"v20.32.5", 32),
SPOOFER_VERSION(@"v20.32.4", 33),
SPOOFER_VERSION(@"v20.31.6", 34),
SPOOFER_VERSION(@"v20.31.5", 35),
SPOOFER_VERSION(@"v20.30.5", 36),
SPOOFER_VERSION(@"v20.29.3", 37),
SPOOFER_VERSION(@"v20.28.2", 38),
SPOOFER_VERSION(@"v20.26.7", 39),
SPOOFER_VERSION(@"v20.25.4", 40),
SPOOFER_VERSION(@"v20.24.5", 41),
SPOOFER_VERSION(@"v20.24.4", 42),
SPOOFER_VERSION(@"v20.23.3", 43),
SPOOFER_VERSION(@"v20.22.1", 44),
SPOOFER_VERSION(@"v20.21.6", 45),
SPOOFER_VERSION(@"v20.20.7", 46),
SPOOFER_VERSION(@"v20.20.5", 47),
SPOOFER_VERSION(@"v20.19.3", 48),
SPOOFER_VERSION(@"v20.19.2", 49),
SPOOFER_VERSION(@"v20.18.5", 50),
SPOOFER_VERSION(@"v20.18.4", 51),
SPOOFER_VERSION(@"v20.16.7", 52),
SPOOFER_VERSION(@"v20.15.1", 53),
SPOOFER_VERSION(@"v20.14.2", 54),
SPOOFER_VERSION(@"v20.13.5", 55),
SPOOFER_VERSION(@"v20.12.4", 56),
SPOOFER_VERSION(@"v20.11.6", 57),
SPOOFER_VERSION(@"v20.10.4", 58),
SPOOFER_VERSION(@"v20.10.3", 59),
SPOOFER_VERSION(@"v20.09.3", 60),
SPOOFER_VERSION(@"v20.08.3", 61),
SPOOFER_VERSION(@"v20.07.6", 62),
SPOOFER_VERSION(@"v20.06.03", 63),
SPOOFER_VERSION(@"v20.05.4", 64),
SPOOFER_VERSION(@"v20.03.1", 65),
SPOOFER_VERSION(@"v20.03.02", 66),
SPOOFER_VERSION(@"v20.02.3", 67),
SPOOFER_VERSION(@"v19.49.7", 68),
SPOOFER_VERSION(@"v19.49.5", 69),
SPOOFER_VERSION(@"v19.49.3", 70),
SPOOFER_VERSION(@"v19.47.7", 71),
SPOOFER_VERSION(@"v19.46.3", 72),
SPOOFER_VERSION(@"v19.45.4", 73),
SPOOFER_VERSION(@"v19.44.4", 74),
SPOOFER_VERSION(@"v19.43.2", 75),
SPOOFER_VERSION(@"v19.42.1", 76),
SPOOFER_VERSION(@"v19.41.3", 77),
SPOOFER_VERSION(@"v19.40.4", 78),
SPOOFER_VERSION(@"v19.39.1", 79),
SPOOFER_VERSION(@"v19.38.2", 80),
SPOOFER_VERSION(@"v19.37.2", 81),
SPOOFER_VERSION(@"v19.36.1", 82),
SPOOFER_VERSION(@"v19.35.3", 83),
SPOOFER_VERSION(@"v19.34.2", 84),
SPOOFER_VERSION(@"v19.33.2", 85),
SPOOFER_VERSION(@"v19.32.8", 86),
SPOOFER_VERSION(@"v19.32.6", 87),
SPOOFER_VERSION(@"v19.31.4", 88),
SPOOFER_VERSION(@"v19.30.2", 89),
SPOOFER_VERSION(@"v19.29.1", 90),
SPOOFER_VERSION(@"v19.28.1", 91),
SPOOFER_VERSION(@"v19.26.5", 92),
SPOOFER_VERSION(@"v19.25.4", 93),
SPOOFER_VERSION(@"v19.25.3", 94),
SPOOFER_VERSION(@"v19.24.3", 95),
SPOOFER_VERSION(@"v19.24.2", 96),
SPOOFER_VERSION(@"v19.23.3", 97),
SPOOFER_VERSION(@"v19.22.6", 98),
SPOOFER_VERSION(@"v19.22.3", 99),
SPOOFER_VERSION(@"v19.21.3", 100),
SPOOFER_VERSION(@"v19.21.2", 101),
SPOOFER_VERSION(@"v19.20.2 (Deprecated)", 102),
SPOOFER_VERSION(@"v19.19.7 (Deprecated)", 103),
SPOOFER_VERSION(@"v19.19.5 (Deprecated)", 104),
SPOOFER_VERSION(@"v19.18.2 (Deprecated)", 105),
SPOOFER_VERSION(@"v19.17.2 (Deprecated)", 106),
SPOOFER_VERSION(@"v19.16.3 (Deprecated)", 107),
SPOOFER_VERSION(@"v19.15.1 (Deprecated)", 108),
SPOOFER_VERSION(@"v19.14.3 (Deprecated)", 109),
SPOOFER_VERSION(@"v19.14.2 (Deprecated)", 110),
SPOOFER_VERSION(@"v19.13.1 (Deprecated)", 111),
SPOOFER_VERSION(@"v19.12.3 (Deprecated)", 112),
SPOOFER_VERSION(@"v19.10.7 (Deprecated)", 113),
SPOOFER_VERSION(@"v19.10.6 (Deprecated)", 114),
SPOOFER_VERSION(@"v19.10.5 (Deprecated)", 115),
SPOOFER_VERSION(@"v19.09.4 (Deprecated)", 116),
SPOOFER_VERSION(@"v19.09.3 (Deprecated)", 117),
SPOOFER_VERSION(@"v19.08.2 (Deprecated)", 118),
SPOOFER_VERSION(@"v19.07.5 (Deprecated)", 119),
SPOOFER_VERSION(@"v19.07.4 (Deprecated)", 120),
SPOOFER_VERSION(@"v19.06.2 (Deprecated)", 121),
SPOOFER_VERSION(@"v19.05.5 (Deprecated)", 122),
SPOOFER_VERSION(@"v19.05.3 (Deprecated)", 123),
SPOOFER_VERSION(@"v19.04.3 (Deprecated)", 124),
SPOOFER_VERSION(@"v19.03.2 (Deprecated)", 125),
SPOOFER_VERSION(@"v19.02.1 (Deprecated)", 126),
SPOOFER_VERSION(@"v19.01.1 (Deprecated)", 127)
];
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"VERSION_SPOOFER_SELECTOR") pickerSectionTitle:nil rows:rows selectedItemIndex:appVersionSpoofer() parentResponder:[self parentResponder]];
[settingsViewController pushViewController:picker];
@ -1029,37 +1004,44 @@ NSString *cacheDescription = [NSString stringWithFormat:@"%@", GetCacheSize()];
detailTextBlock:^NSString *() {
switch (getNotificationIconStyle()) {
case 1:
return @"Thin Outline (2020+)";
return @"Bold Outline (2024+)";
case 2:
return @"Filled (2018+)";
return @"Thin Outline (2020+)";
case 3:
return @"Filled (2018+)";
case 4:
return @"Classic/Inbox (2014+)";
case 0:
default:
return @"Default";
return @"Default (2025+)";
}
}
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
NSArray <YTSettingsSectionItem *> *rows = @[
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Default" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Default (2025+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"notificationIconStyle"];
[settingsViewController reloadData];
return YES;
}],
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Thin Outline (2020+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Bold Outline (2024+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:@"notificationIconStyle"];
[settingsViewController reloadData];
return YES;
}],
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Filled (2018+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Thin Outline (2020+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[[NSUserDefaults standardUserDefaults] setInteger:2 forKey:@"notificationIconStyle"];
[settingsViewController reloadData];
return YES;
}],
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Classic/Inbox (2014+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Filled (2018+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[[NSUserDefaults standardUserDefaults] setInteger:3 forKey:@"notificationIconStyle"];
[settingsViewController reloadData];
return YES;
}],
[YTSettingsSectionItemClass checkmarkItemWithTitle:@"Classic/Inbox (2014+)" titleDescription:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
[[NSUserDefaults standardUserDefaults] setInteger:4 forKey:@"notificationIconStyle"];
[settingsViewController reloadData];
return YES;
}]
];
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Notifications Tab nostalgic customization") pickerSectionTitle:nil rows:rows selectedItemIndex:getNotificationIconStyle() parentResponder:[self parentResponder]];

View file

@ -6,103 +6,134 @@ typedef struct {
} VersionMapping;
static VersionMapping versionMappings[] = {
{0, @"20.33.2"},
{1, @"20.32.5"},
{2, @"20.32.4"},
{3, @"20.31.6"},
{4, @"20.31.5"},
{5, @"20.30.5"},
{6, @"20.29.3"},
{7, @"20.28.2"},
{8, @"20.26.7"},
{9, @"20.25.4"},
{10, @"20.24.5"},
{11, @"20.24.4"},
{12, @"20.23.3"},
{13, @"20.22.1"},
{14, @"20.21.6"},
{15, @"20.20.7"},
{16, @"20.20.5"},
{17, @"20.19.3"},
{18, @"20.19.2"},
{19, @"20.18.5"},
{20, @"20.18.4"},
{21, @"20.16.7"},
{22, @"20.15.1"},
{23, @"20.14.2"},
{24, @"20.13.5"},
{25, @"20.12.4"},
{26, @"20.11.6"},
{27, @"20.10.4"},
{28, @"20.10.3"},
{29, @"20.09.3"},
{30, @"20.08.3"},
{31, @"20.07.6"},
{32, @"20.06.03"},
{33, @"20.05.4"},
{34, @"20.03.1"},
{35, @"20.03.02"},
{36, @"20.02.3"},
{37, @"19.49.7"},
{38, @"19.49.5"},
{39, @"19.49.3"},
{40, @"19.47.7"},
{41, @"19.46.3"},
{42, @"19.45.4"},
{43, @"19.44.4"},
{44, @"19.43.2"},
{45, @"19.42.1"},
{46, @"19.41.3"},
{47, @"19.40.4"},
{48, @"19.39.1"},
{49, @"19.38.2"},
{50, @"19.37.2"},
{51, @"19.36.1"},
{52, @"19.35.3"},
{53, @"19.34.2"},
{54, @"19.33.2"},
{55, @"19.32.8"},
{56, @"19.32.6"},
{57, @"19.31.4"},
{58, @"19.30.2"},
{59, @"19.29.1"},
{60, @"19.28.1"},
{61, @"19.26.5"},
{62, @"19.25.4"},
{63, @"19.25.3"},
{64, @"19.24.3"},
{65, @"19.24.2"},
{66, @"19.23.3"},
{67, @"19.22.6"},
{68, @"19.22.3"},
{69, @"19.21.3"},
{70, @"19.21.2"},
{71, @"19.20.2"},
{72, @"19.19.7"},
{73, @"19.19.5"},
{74, @"19.18.2"},
{75, @"19.17.2"},
{76, @"19.16.3"},
{77, @"19.15.1"},
{78, @"19.14.3"},
{79, @"19.14.2"},
{80, @"19.13.1"},
{81, @"19.12.3"},
{82, @"19.10.7"},
{83, @"19.10.6"},
{84, @"19.10.5"},
{85, @"19.09.4"},
{86, @"19.09.3"},
{87, @"19.08.2"},
{88, @"19.07.5"},
{89, @"19.07.4"},
{90, @"19.06.2"},
{91, @"19.05.5"},
{92, @"19.05.3"},
{93, @"19.04.3"},
{94, @"19.03.2"},
{95, @"19.02.1"},
{96, @"19.01.1"}
{0, @"21.08.3"},
{1, @"21.07.4"},
{2, @"21.06.2"},
{3, @"21.05.3"},
{4, @"21.04.2"},
{5, @"21.03.2"},
{6, @"21.02.3"},
{7, @"20.50.10"},
{8, @"20.50.9"},
{9, @"20.50.6"},
{10, @"20.49.5"},
{11, @"20.47.3"},
{12, @"20.46.3"},
{13, @"20.46.2"},
{14, @"20.45.3"},
{15, @"20.44.2"},
{16, @"20.43.3"},
{17, @"20.42.3"},
{18, @"20.41.5"},
{19, @"20.41.4"},
{20, @"20.40.4"},
{21, @"20.39.6"},
{22, @"20.39.5"},
{23, @"20.39.4"},
{24, @"20.38.4"},
{25, @"20.38.3"},
{26, @"20.37.5"},
{27, @"20.37.3"},
{28, @"20.36.3"},
{29, @"20.35.2"},
{30, @"20.34.2"},
{31, @"20.33.2"},
{32, @"20.32.5"},
{33, @"20.32.4"},
{34, @"20.31.6"},
{35, @"20.31.5"},
{36, @"20.30.5"},
{37, @"20.29.3"},
{38, @"20.28.2"},
{39, @"20.26.7"},
{40, @"20.25.4"},
{41, @"20.24.5"},
{42, @"20.24.4"},
{43, @"20.23.3"},
{44, @"20.22.1"},
{45, @"20.21.6"},
{46, @"20.20.7"},
{47, @"20.20.5"},
{48, @"20.19.3"},
{49, @"20.19.2"},
{50, @"20.18.5"},
{51, @"20.18.4"},
{52, @"20.16.7"},
{53, @"20.15.1"},
{54, @"20.14.2"},
{55, @"20.13.5"},
{56, @"20.12.4"},
{57, @"20.11.6"},
{58, @"20.10.4"},
{59, @"20.10.3"},
{60, @"20.09.3"},
{61, @"20.08.3"},
{62, @"20.07.6"},
{63, @"20.06.03"},
{64, @"20.05.4"},
{65, @"20.03.1"},
{66, @"20.03.02"},
{67, @"20.02.3"},
{68, @"19.49.7"},
{69, @"19.49.5"},
{70, @"19.49.3"},
{71, @"19.47.7"},
{72, @"19.46.3"},
{73, @"19.45.4"},
{74, @"19.44.4"},
{75, @"19.43.2"},
{76, @"19.42.1"},
{77, @"19.41.3"},
{78, @"19.40.4"},
{79, @"19.39.1"},
{80, @"19.38.2"},
{81, @"19.37.2"},
{82, @"19.36.1"},
{83, @"19.35.3"},
{84, @"19.34.2"},
{85, @"19.33.2"},
{86, @"19.32.8"},
{87, @"19.32.6"},
{88, @"19.31.4"},
{89, @"19.30.2"},
{90, @"19.29.1"},
{91, @"19.28.1"},
{92, @"19.26.5"},
{93, @"19.25.4"},
{94, @"19.25.3"},
{95, @"19.24.3"},
{96, @"19.24.2"},
{97, @"19.23.3"},
{98, @"19.22.6"},
{99, @"19.22.3"},
{100, @"19.21.3"},
{101, @"19.21.2"},
{102, @"19.20.2"},
{103, @"19.19.7"},
{104, @"19.19.5"},
{105, @"19.18.2"},
{106, @"19.17.2"},
{107, @"19.16.3"},
{108, @"19.15.1"},
{109, @"19.14.3"},
{110, @"19.14.2"},
{111, @"19.13.1"},
{112, @"19.12.3"},
{113, @"19.10.7"},
{114, @"19.10.6"},
{115, @"19.10.5"},
{116, @"19.09.4"},
{117, @"19.09.3"},
{118, @"19.08.2"},
{119, @"19.07.5"},
{120, @"19.07.4"},
{121, @"19.06.2"},
{122, @"19.05.5"},
{123, @"19.05.3"},
{124, @"19.04.3"},
{125, @"19.03.2"},
{126, @"19.02.1"},
{127, @"19.01.1"}
};
static int appVersionSpoofer() {

@ -1 +1 @@
Subproject commit b9b0cd5784ef63922b9424c9c32b0e7f10898d49
Subproject commit 63c099f62eb479883a4f3df212fb495af49fca05

@ -1 +1 @@
Subproject commit f840113b3820fe5b90a8b614c1a0876c5c9cc5cb
Subproject commit 842f93556427e208248c1f2bd94e432ce56405e5

@ -1 +1 @@
Subproject commit 634443f699950a1dbc2a4a4a1730a788c8683ae2
Subproject commit 6cd5adc700cd79de80f7b02d0d14f1e5a7ea64aa

@ -1 +1 @@
Subproject commit 0f59b38817d554ab692a0053456319847a6ab1a1
Subproject commit f799b70cb40e32de6ba779529ad60ecd8f601cfd

@ -1 +1 @@
Subproject commit 3060d66bfd86a85ab446ff9b04a1b6a2ddcb4d6f
Subproject commit f428a716021fd3e389e0ada5f05b3f215e079e24

1
Tweaks/YTweaks Submodule

@ -0,0 +1 @@
Subproject commit 9a6b4df48981d69e36feb774852e46c49dd31b32

@ -1 +1 @@
Subproject commit 96c2a82845acc43f8473b6ef46c2385301fda04e
Subproject commit 852a58dc2c53d1426557b25ac0ca53570338248b

@ -1 +1 @@
Subproject commit eb33ec3b685a2e974272b971a559da795a1f6972
Subproject commit 899a2fdd539ae308e5847bbb3d7212cfce30a3a6

@ -1 +1 @@
Subproject commit 0548225b0abd354f55d6b2e7f436504e6ce7bca8
Subproject commit 8d6726e569a194d3f1c1ae973b290c66301087f1

@ -1 +1 @@
Subproject commit 041f95f3bf795cbcf4c197a511821b2c574eb66c
Subproject commit 49ece8b0fac8465ee4fd8bf0b54790106e50cb88

@ -1 +1 @@
Subproject commit 08e9ff49cfda6513d9f8823773692355902da944
Subproject commit d56dccd4336f0902f05813f4af177360c69fe33f

@ -1 +1 @@
Subproject commit 20eab9638b4c19b6e9fa507ee3df5dbcec9303ee
Subproject commit cbd7e9daf765ecf5d9ceb27afac15cc3eec3ecc0

@ -1 +1 @@
Subproject commit d91d799245f503ef8816024b09234117af1a5b9a
Subproject commit 79b9ed44958ad27fe75ee14ccc300aa99610c263

@ -1 +1 @@
Subproject commit d7253fd7fe9bc2d5c900b156aa0d613de3b867e8
Subproject commit 3be0cc98b300b7870abc99e1e01566e1c4ef6e07

@ -1 +1 @@
Subproject commit 3e4157c2a84576d175fc73ae422927e3d2531055
Subproject commit e0f97ef5fe47c5c3728ce2ff7a6fb02bc085e86b

1
Tweaks/libundirect Submodule

@ -0,0 +1 @@
Subproject commit 35234fc8004e756772a12e22dee90b0b8a536143

@ -1 +1 @@
Subproject commit 8efdbbb991b27bbf49b425a98be9db45dd3c3b8c
Subproject commit 57093a8bd5cb44211f323519a0045b883475666f