├── .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 |
--------------------------------------------------------------------------------