├── .gitignore ├── Resources ├── badge03.png ├── badge13.png ├── badge23.png ├── badge30.png ├── badge31.png ├── badge32.png ├── badge33.png ├── badge34.png ├── badge43.png ├── badge03@2x.png ├── badge13@2x.png ├── badge23@2x.png ├── badge30@2x.png ├── badge31@2x.png ├── badge32@2x.png ├── badge33@2x.png ├── badge34@2x.png ├── badge43@2x.png ├── BackdropBadgePref.png ├── BackdropBadgePref@2x.png └── Info.plist ├── README.md ├── entry.plist ├── BackdropBadge.plist ├── control ├── LICENSE ├── Makefile ├── Header.h ├── BackdropBadgePref.m └── Tweak.xm /.gitignore: -------------------------------------------------------------------------------- 1 | .theos 2 | packages 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /Resources/badge03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge03.png -------------------------------------------------------------------------------- /Resources/badge13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge13.png -------------------------------------------------------------------------------- /Resources/badge23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge23.png -------------------------------------------------------------------------------- /Resources/badge30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge30.png -------------------------------------------------------------------------------- /Resources/badge31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge31.png -------------------------------------------------------------------------------- /Resources/badge32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge32.png -------------------------------------------------------------------------------- /Resources/badge33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge33.png -------------------------------------------------------------------------------- /Resources/badge34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge34.png -------------------------------------------------------------------------------- /Resources/badge43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge43.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BlurryBadges 2 | =========== 3 | 4 | Colored blur for SpringBoard icon badges on iOS 13+. 5 | -------------------------------------------------------------------------------- /Resources/badge03@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge03@2x.png -------------------------------------------------------------------------------- /Resources/badge13@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge13@2x.png -------------------------------------------------------------------------------- /Resources/badge23@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge23@2x.png -------------------------------------------------------------------------------- /Resources/badge30@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge30@2x.png -------------------------------------------------------------------------------- /Resources/badge31@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge31@2x.png -------------------------------------------------------------------------------- /Resources/badge32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge32@2x.png -------------------------------------------------------------------------------- /Resources/badge33@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge33@2x.png -------------------------------------------------------------------------------- /Resources/badge34@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge34@2x.png -------------------------------------------------------------------------------- /Resources/badge43@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/badge43@2x.png -------------------------------------------------------------------------------- /Resources/BackdropBadgePref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/BackdropBadgePref.png -------------------------------------------------------------------------------- /Resources/BackdropBadgePref@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoomSmart/BlurryBadges/HEAD/Resources/BackdropBadgePref@2x.png -------------------------------------------------------------------------------- /entry.plist: -------------------------------------------------------------------------------- 1 | { 2 | entry = { 3 | bundle = "BackdropBadgePref"; 4 | cell = PSLinkCell; 5 | detail = "BackdropBadgePrefController"; 6 | icon = "BackdropBadgePref.png"; 7 | isController = 1; 8 | label = "BlurryBadges"; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /BackdropBadge.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Filter 6 | 7 | Bundles 8 | 9 | com.apple.springboard 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Name: BlurryBadges (iOS 13+) 2 | Package: com.ps.blurrybadges 3 | Conflicts: org.thebigboss.blurrybadges, com.spicat.blurrybadges 4 | Author: PoomSmart 5 | Maintainer: PoomSmart 6 | Depends: firmware (>= 13.0), mobilesubstrate, preferenceloader 7 | Section: Tweaks 8 | Version: 1.0.0 9 | Architecture: iphoneos-arm 10 | Description: Colored blur for SpringBoard icon badges. 11 | Depiction: https://poomsmart.github.io/repo/depictions/blurrybadges.html 12 | SileoDepiction: https://poomsmart.github.io/repo/sileodepictions/blurrybadges.json 13 | -------------------------------------------------------------------------------- /Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | BackdropBadgePref 9 | CFBundleIdentifier 10 | com.PS.BackdropBadgePref 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1.0 21 | DTPlatformName 22 | iphoneos 23 | NSPrincipalClass 24 | BackdropBadgePrefController 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 - 2025 PoomSmart 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE_VERSION = 1.5.3 2 | INSTALL_TARGET_PROCESSES = SpringBoard 3 | 4 | ifeq ($(SIMULATOR),1) 5 | TARGET = simulator:clang:latest:15.0 6 | ARCHS = arm64 x86_64 7 | else 8 | ifeq ($(THEOS_PACKAGE_SCHEME),rootless) 9 | TARGET = iphone:clang:16.5:15.0 10 | else ifeq ($(THEOS_PACKAGE_SCHEME),roothide) 11 | TARGET = iphone:clang:16.5:15.0 12 | else 13 | TARGET = iphone:clang:14.5:13.0 14 | export PREFIX = $(THEOS)/toolchain/Xcode11.xctoolchain/usr/bin/ 15 | endif 16 | endif 17 | 18 | include $(THEOS)/makefiles/common.mk 19 | TWEAK_NAME = BackdropBadge 20 | $(TWEAK_NAME)_FILES = Tweak.xm 21 | $(TWEAK_NAME)_FRAMEWORKS = CoreGraphics QuartzCore 22 | $(TWEAK_NAME)_USE_SUBSTRATE = 1 23 | 24 | include $(THEOS_MAKE_PATH)/tweak.mk 25 | 26 | BUNDLE_NAME = BackdropBadgePref 27 | $(BUNDLE_NAME)_FILES = BackdropBadgePref.m 28 | $(BUNDLE_NAME)_CFLAGS = -fobjc-arc 29 | $(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles 30 | $(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences 31 | 32 | include $(THEOS_MAKE_PATH)/bundle.mk 33 | 34 | internal-stage:: 35 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 36 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/$(BUNDLE_NAME).plist$(ECHO_END) 37 | 38 | all:: 39 | ifeq ($(SIMULATOR),1) 40 | @rm -f /opt/simject/$(TWEAK_NAME).dylib 41 | @cp -v $(THEOS_OBJ_DIR)/$(TWEAK_NAME).dylib /opt/simject 42 | @cp -v $(PWD)/$(TWEAK_NAME).plist /opt/simject 43 | endif 44 | -------------------------------------------------------------------------------- /Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | #import 9 | #import 10 | 11 | @interface NSObject (Private) 12 | - (id)safeValueForKey:(NSString *)key; 13 | @end 14 | 15 | @interface MTMaterialView : UIView 16 | @end 17 | 18 | @interface SBWallpaperController : NSObject 19 | + (instancetype)sharedInstance; 20 | - (NSInteger)variant; 21 | - (UIColor *)averageColorForVariant:(NSInteger)variant; 22 | @end 23 | 24 | @interface SBIcon (Additions) 25 | - (void)noteBadgeDidChange; 26 | @end 27 | 28 | @interface SBIconImageView : UIView 29 | @end 30 | 31 | @interface SBIconView (Additions) 32 | + (CGSize)defaultIconImageSize; 33 | + (MTMaterialView *)componentBackgroundView; 34 | + (MTMaterialView *)componentBackgroundViewOfType:(NSInteger)type compatibleWithTraitCollection:(UITraitCollection *)traitCollection initialWeighting:(CGFloat)initialWeighting; // iOS 14+ 35 | - (CGPoint)_centerForCloseBoxRelativeToVisibleImageFrame:(CGRect)visibleImageFrame; 36 | - (SBIconImageView *)_iconImageView; 37 | @end 38 | 39 | @interface SBIconModel (Additions) 40 | - (NSArray *)leafIcons; 41 | @end 42 | 43 | @interface SBIconBadgeView : UIView 44 | - (BOOL)displayingAccessory; 45 | @end 46 | 47 | @interface SBIconBadgeView (BlurryBadges) 48 | @property(retain, nonatomic) UIColor *dominantColor; 49 | @end 50 | 51 | @interface SBIconContinuityBadgeView : UIView 52 | @end 53 | 54 | @interface SBIconContinuityAccessoryView : UIView 55 | @end 56 | 57 | @interface SBIconContinuityBadgeView (BlurryBadges) 58 | @property(retain, nonatomic) UIColor *dominantColor; 59 | @end 60 | 61 | @interface SBIconContinuityAccessoryView (BlurryBadges) 62 | @property(retain, nonatomic) UIColor *dominantColor; 63 | @end 64 | 65 | @interface SBIconAccessoryImage : UIImage 66 | @end 67 | 68 | @interface SBDarkeningImageView : UIImageView 69 | @end 70 | 71 | @interface SBHIconAccessoryCountedMapImageTuple : NSObject 72 | @end 73 | 74 | @interface SBHomeScreenMaterialView : UIView 75 | @end 76 | 77 | @interface SBHomeScreenButton : UIButton 78 | - (instancetype)initWithFrame:(CGRect)frame backgroundView:(UIView *)backgroundView; 79 | - (SBHomeScreenMaterialView *)materialView; 80 | @property (nonatomic, strong, readwrite) UIView *backgroundView; 81 | @end 82 | -------------------------------------------------------------------------------- /BackdropBadgePref.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | #import 8 | 9 | #define SB CFSTR("com.apple.springboard") 10 | #define BorderWidth CFSTR("SBBadgeBorderWidth") 11 | #define BorderColor CFSTR("SBBadgeBorderColorMode") 12 | #define BadgeTintOpacity CFSTR("SBBadgeTintOpacity") 13 | #define PostNotification CFSTR("com.ps.backdropbadge.update") 14 | 15 | @interface BackdropBadgePrefController : PSListController { 16 | int badgeBorderSize; 17 | int badgeBorderColorMode; 18 | int badgeOpacity; 19 | } 20 | @end 21 | 22 | static int integerValueForKey(CFStringRef key, int defaultValue) { 23 | CFPreferencesAppSynchronize(SB); 24 | Boolean valid; 25 | CFIndex value = CFPreferencesGetAppIntegerValue(key, SB, &valid); 26 | return valid ? value : defaultValue; 27 | } 28 | 29 | @implementation BackdropBadgePrefController 30 | 31 | - (NSArray *)borderSizes { 32 | return @[@"No Border", @"Little", @"Medium", @"Pre-iOS 7", @"Huge"]; 33 | } 34 | 35 | - (NSArray *)borderColors { 36 | return @[@"Lighter", @"Darker", @"White", @"Black", @"Random"]; 37 | } 38 | 39 | - (NSArray *)opacitys { 40 | return @[@"20%", @"40%", @"60%", @"80%", @"100%"]; 41 | } 42 | 43 | - (NSMutableArray *)specifiers { 44 | if (!_specifiers) { 45 | _specifiers = [NSMutableArray new]; 46 | PSSpecifier *borderSizeGroupSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Border Size" target:nil set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 47 | [_specifiers addObject:borderSizeGroupSpecifier]; 48 | for (NSString *borderSize in [self borderSizes]) { 49 | PSSpecifier *borderSizeSpecifier = [PSSpecifier preferenceSpecifierNamed:borderSize target:nil set:nil get:nil detail:nil cell:PSStaticTextCell edit:nil]; 50 | [borderSizeSpecifier setProperty:@([[self borderSizes] indexOfObject:borderSize]) forKey:@"borderSize"]; 51 | [borderSizeSpecifier setProperty:@YES forKey:@"enabled"]; 52 | [_specifiers addObject:borderSizeSpecifier]; 53 | } 54 | PSSpecifier *borderColorGroupSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Border Color" target:nil set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 55 | [_specifiers addObject:borderColorGroupSpecifier]; 56 | for (NSString *borderColor in [self borderColors]) { 57 | PSSpecifier *borderColorSpecifier = [PSSpecifier preferenceSpecifierNamed:borderColor target:nil set:nil get:nil detail:nil cell:PSStaticTextCell edit:nil]; 58 | [borderColorSpecifier setProperty:@([[self borderColors] indexOfObject:borderColor]) forKey:@"borderColor"]; 59 | [borderColorSpecifier setProperty:@YES forKey:@"enabled"]; 60 | [_specifiers addObject:borderColorSpecifier]; 61 | } 62 | 63 | PSSpecifier *badgeTintOpacitySpecifier = [PSSpecifier preferenceSpecifierNamed:@"Badge Tint Opacity" target:nil set:nil get:nil detail:nil cell:PSGroupCell edit:nil]; 64 | [_specifiers addObject:badgeTintOpacitySpecifier]; 65 | for (NSString *opacity in [self opacitys]) { 66 | PSSpecifier *opacitySpecifier = [PSSpecifier preferenceSpecifierNamed:opacity target:nil set:nil get:nil detail:nil cell:PSStaticTextCell edit:nil]; 67 | [opacitySpecifier setProperty:@([[self opacitys] indexOfObject:opacity]) forKey:@"opacity"]; 68 | [opacitySpecifier setProperty:@YES forKey:@"enabled"]; 69 | [_specifiers addObject:opacitySpecifier]; 70 | } 71 | 72 | PSSpecifier *footerSpecifier = [PSSpecifier emptyGroupSpecifier]; 73 | [footerSpecifier setProperty:@"© 2013 - 2017, 2021 - 2025 PoomSmart" forKey:@"footerText"]; 74 | [footerSpecifier setProperty:@1 forKey:@"footerAlignment"]; 75 | [_specifiers addObject:footerSpecifier]; 76 | } 77 | 78 | return _specifiers; 79 | } 80 | 81 | - (void)setSpecifier:(PSSpecifier *)specifier { 82 | [super setSpecifier:specifier]; 83 | self.navigationItem.title = [specifier name]; 84 | badgeBorderSize = integerValueForKey(BorderWidth, 3); 85 | badgeBorderColorMode = integerValueForKey(BorderColor, 2); 86 | badgeOpacity = integerValueForKey(BadgeTintOpacity, 2); 87 | } 88 | 89 | - (NSBundle *)bundle { 90 | return [NSBundle bundleWithPath:PS_ROOT_PATH_NS(@"/Library/PreferenceBundles/BackdropBadgePref.bundle")]; 91 | } 92 | 93 | - (UIImage *)badgeForSizeMode:(int)size colorMode:(int)color { 94 | return [UIImage imageNamed:[NSString stringWithFormat:@"badge%d%d", size, color] inBundle:[self bundle]]; 95 | } 96 | 97 | - (PSTableCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 98 | PSTableCell *cell = (PSTableCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath]; 99 | 100 | if (indexPath.section <= 2) { 101 | PSSpecifier *specifier = [cell specifier]; 102 | switch (indexPath.section) { 103 | case 0: { 104 | NSNumber *value = [specifier propertyForKey:@"borderSize"]; 105 | [cell setChecked:badgeBorderSize == [value intValue]]; 106 | cell.imageView.image = [self badgeForSizeMode:indexPath.row colorMode:3]; 107 | break; 108 | } 109 | case 1: { 110 | NSNumber *value = [specifier propertyForKey:@"borderColor"]; 111 | [cell setChecked:badgeBorderColorMode == [value intValue]]; 112 | if (indexPath.row == 2) 113 | cell.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1]; 114 | cell.imageView.image = [self badgeForSizeMode:3 colorMode:indexPath.row]; 115 | break; 116 | } 117 | case 2: { 118 | NSNumber *value = [specifier propertyForKey:@"opacity"]; 119 | [cell setChecked:badgeOpacity == [value intValue]]; 120 | cell.imageView.image = nil; 121 | break; 122 | } 123 | } 124 | } 125 | 126 | return cell; 127 | } 128 | 129 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 130 | [super tableView:tableView didSelectRowAtIndexPath:indexPath]; 131 | NSInteger section = indexPath.section; 132 | if (section > 2) return; 133 | NSInteger value = indexPath.row; 134 | CFStringRef key; 135 | switch (section) { 136 | case 0: 137 | key = BorderWidth; 138 | badgeBorderSize = value; 139 | break; 140 | case 1: 141 | key = BorderColor; 142 | badgeBorderColorMode = value; 143 | break; 144 | case 2: 145 | key = BadgeTintOpacity; 146 | badgeOpacity = value; 147 | break; 148 | } 149 | for (NSInteger i = 0; i <= 4; ++i) 150 | [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:section]].accessoryType = (value == i) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; 151 | CFPreferencesSetAppValue(key, (CFTypeRef)@(value), SB); 152 | CFPreferencesAppSynchronize(SB); 153 | notify_post("com.ps.backdropbadge.update"); 154 | } 155 | 156 | - (void)suspend { 157 | notify_post("com.ps.backdropbadge.update"); 158 | [super suspend]; 159 | } 160 | 161 | @end 162 | -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #import "Header.h" 2 | #import 3 | #import 4 | #import 5 | 6 | struct pixel { 7 | unsigned char r, g, b, a; 8 | }; 9 | 10 | static UIColor *dominantColorFromIcon(SBIcon *icon) { 11 | UIImage *iconImage = [icon generateIconImageWithInfo:(SBIconImageInfo) { .size = CGSizeMake(60, 60), .scale = 1, .continuousCornerRadius = 12 }]; 12 | if (iconImage == nil) 13 | return [UIColor blackColor]; 14 | NSUInteger red = 0, green = 0, blue = 0; 15 | CGImageRef iconCGImage = iconImage.CGImage; 16 | struct pixel *pixels = (struct pixel *)calloc(1, iconImage.size.width * iconImage.size.height * sizeof(struct pixel)); 17 | if (pixels != nil) { 18 | CGContextRef context = CGBitmapContextCreate((void *)pixels, iconImage.size.width, iconImage.size.height, 8, iconImage.size.width * 4, CGImageGetColorSpace(iconCGImage), kCGImageAlphaPremultipliedLast); 19 | if (context != NULL) { 20 | CGContextDrawImage(context, CGRectMake(0.0, 0.0, iconImage.size.width, iconImage.size.height), iconCGImage); 21 | NSUInteger numberOfPixels = iconImage.size.width * iconImage.size.height; 22 | for (int i = 0; i < numberOfPixels; ++i) { 23 | red += pixels[i].r; 24 | green += pixels[i].g; 25 | blue += pixels[i].b; 26 | } 27 | red /= numberOfPixels; 28 | green /= numberOfPixels; 29 | blue /= numberOfPixels; 30 | CGContextRelease(context); 31 | } 32 | free(pixels); 33 | } 34 | return [UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0]; 35 | } 36 | 37 | static UIColor *colorShiftedBy(UIColor *color, CGFloat shift) { 38 | CGFloat red, green, blue, alpha; 39 | [color getRed:&red green:&green blue:&blue alpha:&alpha]; 40 | return [UIColor colorWithRed:red + shift green:green + shift blue:blue + shift alpha:alpha]; 41 | } 42 | 43 | static UIColor *lighterColor(UIColor *color) { 44 | return colorShiftedBy(color, 0.25); 45 | } 46 | 47 | static UIColor *darkerColor(UIColor *color) { 48 | return colorShiftedBy(color, -0.25); 49 | } 50 | 51 | static CGFloat borderSizeFromMode(int mode) { 52 | switch (mode) { 53 | case 0: 54 | return 0.0; 55 | case 1: 56 | return 2.0; 57 | case 2: 58 | return 2.5; 59 | case 3: 60 | return 3.0; 61 | case 4: 62 | return 4.0; 63 | } 64 | return 0; 65 | } 66 | 67 | static UIColor *randomColor() { 68 | CGFloat hue = (arc4random() % 256 / 256.0); 69 | CGFloat saturation = (arc4random() % 256 / 256.0); 70 | CGFloat brightness = (arc4random() % 256 / 256.0); 71 | UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1]; 72 | return color; 73 | } 74 | 75 | static UIColor *borderColorFromMode(int mode, UIColor *color) { 76 | switch (mode) { 77 | case 0: 78 | return lighterColor(color); 79 | case 1: 80 | return darkerColor(color); 81 | case 2: 82 | return [UIColor whiteColor]; 83 | case 3: 84 | return [UIColor blackColor]; 85 | case 4: 86 | return randomColor(); 87 | } 88 | return [UIColor clearColor]; 89 | } 90 | 91 | static UIImage *roundedRectMask(CGSize size) { 92 | CGFloat realCornerRadius = size.height / 2; 93 | CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height); 94 | UIGraphicsBeginImageContextWithOptions(size, NO, 0); 95 | CGContextRef context = UIGraphicsGetCurrentContext(); 96 | CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 97 | [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:realCornerRadius] addClip]; 98 | CGContextFillRect(context, rect); 99 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 100 | UIGraphicsEndImageContext(); 101 | return image; 102 | } 103 | 104 | int borderColorMode; 105 | int borderWidthMode; 106 | CGFloat tintAlpha; 107 | 108 | static void loadSettings() { 109 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 110 | id r = [defaults objectForKey:@"SBBadgeBorderColorMode"]; 111 | borderColorMode = r ? [r intValue] : 2; 112 | id r2 = [defaults objectForKey:@"SBBadgeBorderWidth"]; 113 | borderWidthMode = r2 ? [r2 intValue] : 3; 114 | id r3 = [defaults objectForKey:@"SBBadgeTintOpacity"]; 115 | tintAlpha = r3 ? (([r3 intValue] + 1) * 0.2) : 0.6; 116 | } 117 | 118 | static void bbHook(SBIconBadgeView *self, SBIcon *icon) { 119 | if (self.dominantColor == nil) 120 | self.dominantColor = dominantColorFromIcon(icon); 121 | SBDarkeningImageView *bgView = [self valueForKey:@"_backgroundView"]; 122 | CGFloat shift = 2; 123 | CGRect frame = CGRectMake(1, 1, self.frame.size.width - shift, self.frame.size.height - shift); 124 | CALayer *maskLayer = [CALayer layer]; 125 | maskLayer.frame = frame; 126 | maskLayer.contents = (id)[roundedRectMask(frame.size) CGImage]; 127 | UIColor *borderColor = borderColorFromMode(borderColorMode, self.dominantColor); 128 | if ([icon isFolderIcon]) { 129 | SBWallpaperController *wallpaperCont = [%c(SBWallpaperController) sharedInstance]; 130 | self.dominantColor = [wallpaperCont averageColorForVariant:1]; 131 | switch (borderColorMode) { 132 | case 0: 133 | borderColor = lighterColor(self.dominantColor); 134 | break; 135 | case 1: 136 | borderColor = darkerColor(self.dominantColor); 137 | break; 138 | } 139 | } 140 | CGFloat borderWidth = borderSizeFromMode(borderWidthMode); 141 | SBHomeScreenButton *blurView = [bgView viewWithTag:9596]; 142 | CGFloat blurShift = IS_IOS_OR_NEWER(iOS_16_0) ? -1 : 0; 143 | blurView.frame = CGRectMake(blurShift, blurShift, self.frame.size.width, self.frame.size.height); 144 | blurView.layer.mask = maskLayer; 145 | blurView.layer.borderColor = borderWidthMode == 0 ? nil : borderColor.CGColor; 146 | blurView.layer.borderWidth = borderWidth; 147 | 148 | UIView *tint = [blurView viewWithTag:9597]; 149 | if (tint == nil) tint = [bgView viewWithTag:9597]; 150 | tint.backgroundColor = self.dominantColor; 151 | tint.alpha = tintAlpha; 152 | 153 | [blurView sendSubviewToBack:[blurView materialView]]; 154 | } 155 | 156 | static void hookBadge(SBIconView *iconView) { 157 | if ([iconView valueForKey:@"_icon"]) { 158 | SBIconBadgeView *badgeView = [iconView valueForKey:@"_accessoryView"]; 159 | if (badgeView) 160 | bbHook(badgeView, iconView.icon); 161 | } 162 | } 163 | 164 | %hook SBIconView 165 | 166 | - (void)_updateAccessoryViewWithAnimation:(id)arg1 { 167 | %orig; 168 | hookBadge(self); 169 | } 170 | 171 | - (void)_updateAccessoryViewAnimated:(BOOL)animated { 172 | %orig; 173 | hookBadge(self); 174 | } 175 | 176 | %end 177 | 178 | static void initBadgeView(UIView *self) { 179 | if (self == nil) 180 | return; 181 | SBDarkeningImageView *bgView = [self valueForKey:@"_backgroundView"]; 182 | bgView.backgroundColor = nil; 183 | bgView.image = nil; 184 | CGRect defaultFrame = CGRectMake(0, 0, 24, 24); 185 | UIView *tintView = [[UIView alloc] initWithFrame:defaultFrame]; 186 | tintView.tag = 9597; 187 | UIView *textView = [self safeValueForKey:@"_textView"]; 188 | if (textView) { 189 | MTMaterialView *blurBgView = IS_IOS_OR_NEWER(iOS_14_0) ? [%c(SBIconView) componentBackgroundViewOfType:1 compatibleWithTraitCollection:self.traitCollection initialWeighting:1] : [%c(SBIconView) componentBackgroundView]; 190 | SBHomeScreenButton *blurView = [[%c(SBHomeScreenButton) alloc] initWithFrame:defaultFrame backgroundView:blurBgView]; 191 | blurView.tag = 9596; 192 | blurView.layer.cornerRadius = 12; 193 | blurView.layer.masksToBounds = YES; 194 | [bgView insertSubview:blurView belowSubview:textView]; 195 | tintView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 196 | [blurView addSubview:tintView]; 197 | [blurView release]; 198 | } else { 199 | tintView.layer.cornerRadius = 12; 200 | tintView.layer.masksToBounds = YES; 201 | tintView.frame = CGRectMake(1, 1, 24, 24); 202 | [bgView addSubview:tintView]; 203 | } 204 | [tintView release]; 205 | } 206 | 207 | %hook SBIconBadgeView 208 | 209 | %property (retain, nonatomic) UIColor *dominantColor; 210 | 211 | - (id)init { 212 | self = %orig; 213 | initBadgeView(self); 214 | return self; 215 | } 216 | 217 | - (SBHIconAccessoryCountedMapImageTuple *)_checkoutBackgroundImageTuple { 218 | SBHIconAccessoryCountedMapImageTuple *tuple = %orig; 219 | [tuple setValue:nil forKey:@"_image"]; 220 | return tuple; 221 | } 222 | 223 | - (void)prepareForReuse { 224 | %orig; 225 | SBDarkeningImageView *bgView = [self valueForKey:@"_backgroundView"]; 226 | bgView.image = nil; 227 | self.dominantColor = nil; 228 | } 229 | 230 | %end 231 | 232 | %hook SBIconContinuityBadgeView 233 | 234 | %property (retain, nonatomic) UIColor *dominantColor; 235 | 236 | - (id)init { 237 | self = %orig; 238 | initBadgeView(self); 239 | return self; 240 | } 241 | 242 | - (void)prepareForReuse { 243 | %orig; 244 | SBDarkeningImageView *bgView = [self valueForKey:@"_backgroundView"]; 245 | bgView.image = nil; 246 | self.dominantColor = nil; 247 | } 248 | 249 | %end 250 | 251 | %hook SBIconContinuityAccessoryView 252 | 253 | %property (retain, nonatomic) UIColor *dominantColor; 254 | 255 | - (id)init { 256 | self = %orig; 257 | initBadgeView(self); 258 | return self; 259 | } 260 | 261 | - (void)prepareForReuse { 262 | %orig; 263 | SBDarkeningImageView *bgView = [self valueForKey:@"_backgroundView"]; 264 | bgView.image = nil; 265 | self.dominantColor = nil; 266 | } 267 | 268 | %end 269 | 270 | static void bbSettingsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 271 | loadSettings(); 272 | SBIconController *cont = [%c(SBIconController) sharedInstance]; 273 | SBIconModel *model = [cont model]; 274 | NSArray *icons = [model leafIcons]; 275 | for (SBIcon *icon in icons) 276 | [icon noteBadgeDidChange]; 277 | } 278 | 279 | %ctor { 280 | loadSettings(); 281 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, bbSettingsChanged, CFSTR("com.ps.backdropbadge.update"), NULL, CFNotificationSuspensionBehaviorCoalesce); 282 | %init; 283 | } 284 | --------------------------------------------------------------------------------