diff --git a/.github/workflows/update-submodules.yml b/.github/workflows/update-submodules.yml index fabdbb1..264309c 100644 --- a/.github/workflows/update-submodules.yml +++ b/.github/workflows/update-submodules.yml @@ -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 diff --git a/.gitmodules b/.gitmodules index fab10e8..7123c54 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/Bundles/YTWKS.bundle b/Bundles/YTWKS.bundle new file mode 120000 index 0000000..e87b662 --- /dev/null +++ b/Bundles/YTWKS.bundle @@ -0,0 +1 @@ +../Tweaks/YTweaks/layout/Library/Application Support/YTWKS.bundle \ No newline at end of file diff --git a/Localizations/uYouPlus.bundle/UI/notifications_selected_2025.png b/Localizations/uYouPlus.bundle/UI/notifications_selected_2025.png new file mode 100644 index 0000000..14ff5be Binary files /dev/null and b/Localizations/uYouPlus.bundle/UI/notifications_selected_2025.png differ diff --git a/Localizations/uYouPlus.bundle/UI/notifications_unselected_2025.png b/Localizations/uYouPlus.bundle/UI/notifications_unselected_2025.png new file mode 100644 index 0000000..3a25f2d Binary files /dev/null and b/Localizations/uYouPlus.bundle/UI/notifications_unselected_2025.png differ diff --git a/Makefile b/Makefile index f04e1e2..00ced5f 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/Sources/AppIconOptionsController.h b/Sources/AppIconOptionsController.h index ef845d7..022b8d9 100644 --- a/Sources/AppIconOptionsController.h +++ b/Sources/AppIconOptionsController.h @@ -1,6 +1,6 @@ #import -@interface AppIconOptionsController : UIViewController +@interface AppIconOptionsController : UIViewController @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 diff --git a/Sources/AppIconOptionsController.m b/Sources/AppIconOptionsController.m index 9bcac2d..b757cfe 100644 --- a/Sources/AppIconOptionsController.m +++ b/Sources/AppIconOptionsController.m @@ -1,10 +1,32 @@ #import "AppIconOptionsController.h" -#import +#import + +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 () @property (strong, nonatomic) UITableView *tableView; @property (strong, nonatomic) NSArray *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 *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]; - - UIImage *iconImage = [UIImage imageWithContentsOfFile:iconPath]; - cell.imageView.image = iconImage; - cell.imageView.layer.cornerRadius = 16.0; + + NSString *iconName = self.appIcons[indexPath.row - 1]; + cell.textLabel.text = iconName; + cell.detailTextLabel.text = @"Tap to apply this icon"; + + UIImage *preview = nil; + NSArray *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]; - - self.selectedIconIndex = indexPath.row; - [self saveIcon]; - [self.tableView reloadData]; -} +- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [tv deselectRowAtIndexPath:indexPath animated:YES]; -- (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]; - } - }]; -} + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", kPrefDomain]; + NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:prefsPath] ?: [NSMutableDictionary dictionary]; -- (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]; } diff --git a/Sources/LowContrastMode.xm b/Sources/LowContrastMode.xm index 4ff79b5..66f4335 100644 --- a/Sources/LowContrastMode.xm +++ b/Sources/LowContrastMode.xm @@ -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 *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 *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 *)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 *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 *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 *)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 *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 *)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]; } } } diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 4f36219..06f37b3 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -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 *HideToggleMap(void) { + static NSDictionary *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 *identifiers) { - for (id child in [nodeController children]) { - NSLog(@"Child: %@", [child description]); - - if ([child isKindOfClass:%c(ELMNodeController)]) { - NSArray *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 *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 *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 *filteredArray(NSArray *filteredArray(NSArray *filteredArray(NSArray *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]; } diff --git a/Sources/uYouPlusSettings.xm b/Sources/uYouPlusSettings.xm index 85fd794..3635dd0 100644 --- a/Sources/uYouPlusSettings.xm +++ b/Sources/uYouPlusSettings.xm @@ -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 *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 *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]]; diff --git a/Sources/uYouPlusVersionSpoofer.xm b/Sources/uYouPlusVersionSpoofer.xm index 34be216..f3f59a6 100644 --- a/Sources/uYouPlusVersionSpoofer.xm +++ b/Sources/uYouPlusVersionSpoofer.xm @@ -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() { diff --git a/Tweaks/DontEatMyContent b/Tweaks/DontEatMyContent index b9b0cd5..63c099f 160000 --- a/Tweaks/DontEatMyContent +++ b/Tweaks/DontEatMyContent @@ -1 +1 @@ -Subproject commit b9b0cd5784ef63922b9424c9c32b0e7f10898d49 +Subproject commit 63c099f62eb479883a4f3df212fb495af49fca05 diff --git a/Tweaks/Return-YouTube-Dislikes b/Tweaks/Return-YouTube-Dislikes index f840113..842f935 160000 --- a/Tweaks/Return-YouTube-Dislikes +++ b/Tweaks/Return-YouTube-Dislikes @@ -1 +1 @@ -Subproject commit f840113b3820fe5b90a8b614c1a0876c5c9cc5cb +Subproject commit 842f93556427e208248c1f2bd94e432ce56405e5 diff --git a/Tweaks/YTABConfig b/Tweaks/YTABConfig index 634443f..6cd5adc 160000 --- a/Tweaks/YTABConfig +++ b/Tweaks/YTABConfig @@ -1 +1 @@ -Subproject commit 634443f699950a1dbc2a4a4a1730a788c8683ae2 +Subproject commit 6cd5adc700cd79de80f7b02d0d14f1e5a7ea64aa diff --git a/Tweaks/YTUHD b/Tweaks/YTUHD index 0f59b38..f799b70 160000 --- a/Tweaks/YTUHD +++ b/Tweaks/YTUHD @@ -1 +1 @@ -Subproject commit 0f59b38817d554ab692a0053456319847a6ab1a1 +Subproject commit f799b70cb40e32de6ba779529ad60ecd8f601cfd diff --git a/Tweaks/YTVideoOverlay b/Tweaks/YTVideoOverlay index 3060d66..f428a71 160000 --- a/Tweaks/YTVideoOverlay +++ b/Tweaks/YTVideoOverlay @@ -1 +1 @@ -Subproject commit 3060d66bfd86a85ab446ff9b04a1b6a2ddcb4d6f +Subproject commit f428a716021fd3e389e0ada5f05b3f215e079e24 diff --git a/Tweaks/YTweaks b/Tweaks/YTweaks new file mode 160000 index 0000000..9a6b4df --- /dev/null +++ b/Tweaks/YTweaks @@ -0,0 +1 @@ +Subproject commit 9a6b4df48981d69e36feb774852e46c49dd31b32 diff --git a/Tweaks/YouGroupSettings b/Tweaks/YouGroupSettings index 96c2a82..852a58d 160000 --- a/Tweaks/YouGroupSettings +++ b/Tweaks/YouGroupSettings @@ -1 +1 @@ -Subproject commit 96c2a82845acc43f8473b6ef46c2385301fda04e +Subproject commit 852a58dc2c53d1426557b25ac0ca53570338248b diff --git a/Tweaks/YouLoop b/Tweaks/YouLoop index eb33ec3..899a2fd 160000 --- a/Tweaks/YouLoop +++ b/Tweaks/YouLoop @@ -1 +1 @@ -Subproject commit eb33ec3b685a2e974272b971a559da795a1f6972 +Subproject commit 899a2fdd539ae308e5847bbb3d7212cfce30a3a6 diff --git a/Tweaks/YouMute b/Tweaks/YouMute index 0548225..8d6726e 160000 --- a/Tweaks/YouMute +++ b/Tweaks/YouMute @@ -1 +1 @@ -Subproject commit 0548225b0abd354f55d6b2e7f436504e6ce7bca8 +Subproject commit 8d6726e569a194d3f1c1ae973b290c66301087f1 diff --git a/Tweaks/YouPiP b/Tweaks/YouPiP index 041f95f..49ece8b 160000 --- a/Tweaks/YouPiP +++ b/Tweaks/YouPiP @@ -1 +1 @@ -Subproject commit 041f95f3bf795cbcf4c197a511821b2c574eb66c +Subproject commit 49ece8b0fac8465ee4fd8bf0b54790106e50cb88 diff --git a/Tweaks/YouQuality b/Tweaks/YouQuality index 08e9ff4..d56dccd 160000 --- a/Tweaks/YouQuality +++ b/Tweaks/YouQuality @@ -1 +1 @@ -Subproject commit 08e9ff49cfda6513d9f8823773692355902da944 +Subproject commit d56dccd4336f0902f05813f4af177360c69fe33f diff --git a/Tweaks/YouSlider b/Tweaks/YouSlider index 20eab96..cbd7e9d 160000 --- a/Tweaks/YouSlider +++ b/Tweaks/YouSlider @@ -1 +1 @@ -Subproject commit 20eab9638b4c19b6e9fa507ee3df5dbcec9303ee +Subproject commit cbd7e9daf765ecf5d9ceb27afac15cc3eec3ecc0 diff --git a/Tweaks/YouSpeed b/Tweaks/YouSpeed index d91d799..79b9ed4 160000 --- a/Tweaks/YouSpeed +++ b/Tweaks/YouSpeed @@ -1 +1 @@ -Subproject commit d91d799245f503ef8816024b09234117af1a5b9a +Subproject commit 79b9ed44958ad27fe75ee14ccc300aa99610c263 diff --git a/Tweaks/YouTubeHeader b/Tweaks/YouTubeHeader index d7253fd..3be0cc9 160000 --- a/Tweaks/YouTubeHeader +++ b/Tweaks/YouTubeHeader @@ -1 +1 @@ -Subproject commit d7253fd7fe9bc2d5c900b156aa0d613de3b867e8 +Subproject commit 3be0cc98b300b7870abc99e1e01566e1c4ef6e07 diff --git a/Tweaks/iSponsorBlock b/Tweaks/iSponsorBlock index 3e4157c..e0f97ef 160000 --- a/Tweaks/iSponsorBlock +++ b/Tweaks/iSponsorBlock @@ -1 +1 @@ -Subproject commit 3e4157c2a84576d175fc73ae422927e3d2531055 +Subproject commit e0f97ef5fe47c5c3728ce2ff7a6fb02bc085e86b diff --git a/Tweaks/libundirect b/Tweaks/libundirect new file mode 160000 index 0000000..35234fc --- /dev/null +++ b/Tweaks/libundirect @@ -0,0 +1 @@ +Subproject commit 35234fc8004e756772a12e22dee90b0b8a536143 diff --git a/Tweaks/protobuf b/Tweaks/protobuf index 8efdbbb..57093a8 160000 --- a/Tweaks/protobuf +++ b/Tweaks/protobuf @@ -1 +1 @@ -Subproject commit 8efdbbb991b27bbf49b425a98be9db45dd3c3b8c +Subproject commit 57093a8bd5cb44211f323519a0045b883475666f