#import <UIKit/UIKit.h> | |||||
#import <substrate.h> | |||||
@interface _UIBatteryView : UIView | |||||
@property (nonatomic, assign) CGFloat chargePercent; | |||||
@property (nonatomic, assign) CGFloat bodyColorAlpha; | |||||
@property (nonatomic, assign) CGFloat pinColorAlpha; | |||||
@property (nonatomic, assign) BOOL showsPercentage; | |||||
@property (nonatomic, assign) BOOL saverModeActive; | |||||
@property (nonatomic, assign) BOOL showsInlineChargingIndicator; | |||||
@property (nonatomic, assign) NSInteger chargingState; | |||||
@end | |||||
@interface MTMaterialView : UIView | |||||
@property (nonatomic, assign) BOOL recipeDynamic; | |||||
-(id)_initWithRecipe:(NSInteger)arg1 configuration:(NSInteger)arg2 initialWeighting:(CGFloat)arg3 scaleAdjustment:(id)arg4; | |||||
+(id)materialViewWithRecipe:(NSInteger)arg1 options:(NSInteger)arg2 initialWeighting:(CGFloat)arg3 scaleAdjustment:(id)arg4; | |||||
@end | |||||
@interface BCBatteryDeviceController | |||||
@property (nonatomic, strong) NSArray *sortedDevices; | |||||
-(id)_sortedDevices; | |||||
+(id)sharedInstance; | |||||
@end | |||||
@interface BCBatteryDevice : NSObject | |||||
-(id)glyph; | |||||
@end | |||||
@interface KAIBattery : UIView | @interface KAIBattery : UIView | ||||
@property (nonatomic, strong) NSMutableArray *displayingDevices; | |||||
@property (nonatomic, strong) NSArray *devices; | @property (nonatomic, strong) NSArray *devices; | ||||
@property (nonatomic, assign) NSInteger number; | @property (nonatomic, assign) NSInteger number; | ||||
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint; | @property (nonatomic, strong) NSLayoutConstraint *heightConstraint; |
} | } | ||||
for (BCBatteryDevice *device in devices) { | for (BCBatteryDevice *device in devices) { | ||||
NSString *deviceName = MSHookIvar<NSString *>(device, "_name"); | |||||
//NSString *deviceName = MSHookIvar<NSString *>(device, "_name"); | |||||
double batteryPercentage = MSHookIvar<long long>(device, "_percentCharge"); | double batteryPercentage = MSHookIvar<long long>(device, "_percentCharge"); | ||||
BOOL charging = MSHookIvar<long long>(device, "_charging"); | BOOL charging = MSHookIvar<long long>(device, "_charging"); | ||||
BOOL LPM = MSHookIvar<BOOL>(device, "_batterySaverModeActive"); | BOOL LPM = MSHookIvar<BOOL>(device, "_batterySaverModeActive"); | ||||
shouldAdd = YES; | shouldAdd = YES; | ||||
} | } | ||||
BOOL shouldRefresh = NO; | |||||
KAIBatteryCell *cell = [KAIBatteryCell cellForDeviceIfExists:device]; | |||||
/* | |||||
@property (nonatomic, assign) BOOL lastChargingState; | |||||
@property (nonatomic, assign) BOOL lastLPM; | |||||
@property (nonatomic, assign) double lastPercent; | |||||
*/ | |||||
if(cell.lastChargingState != charging || cell.lastLPM != LPM || cell.lastPercent != batteryPercentage) { | |||||
shouldRefresh = YES; | |||||
} | |||||
if(shouldAdd) { | if(shouldAdd) { | ||||
UIView *blank; | |||||
if(bannerStyle==1) { | |||||
if(kCFCoreFoundationVersionNumber > 1600) { | |||||
blank = [[[objc_getClass("MTMaterialView") class] alloc] _initWithRecipe:1 configuration:1 initialWeighting:1 scaleAdjustment:nil]; | |||||
} else if(kCFCoreFoundationVersionNumber < 1600) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; | |||||
} | |||||
} else if(bannerStyle==2) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; | |||||
} else if(bannerStyle==3) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; | |||||
if([self.displayingDevices containsObject:device] && shouldRefresh) { | |||||
[cell updateInfo]; | |||||
} else if(![self.displayingDevices containsObject:device]) { | |||||
KAIBatteryCell *newCell = [[KAIBatteryCell alloc] initWithFrame:CGRectMake(0, y, self.frame.size.width, self.frame.size.width)]; | |||||
[self addSubview:newCell]; | |||||
[self.displayingDevices addObject:device]; | |||||
y+=bannerHeight + spacing; | |||||
self.number +=1; | |||||
} | } | ||||
blank.layer.masksToBounds = YES; | |||||
blank.layer.continuousCorners = YES; | |||||
blank.layer.cornerRadius = cornerRadius; | |||||
NSString *labelText = [NSString stringWithFormat:@"%@", deviceName]; | |||||
} else if(!shouldAdd) { | |||||
UILabel *label = [[UILabel alloc] init]; | |||||
if(!hideDeviceLabel) { | |||||
[label setFont:[UIFont systemFontOfSize:16]]; | |||||
} else if(hideDeviceLabel) { | |||||
[label setFont:[UIFont systemFontOfSize:0]]; | |||||
} | |||||
[label setTextColor:[UIColor whiteColor]]; | |||||
label.lineBreakMode = NSLineBreakByWordWrapping; | |||||
label.numberOfLines = 1; | |||||
[label setText:labelText]; | |||||
_UIBatteryView *battery = [[_UIBatteryView alloc] init]; | |||||
battery.chargePercent = (batteryPercentage*0.01); | |||||
UILabel *percentLabel = [[UILabel alloc] init]; | |||||
battery.showsPercentage = NO; | |||||
if(hidePercent) { | |||||
[percentLabel setFont:[UIFont systemFontOfSize:0]]; | |||||
} else { | |||||
[percentLabel setFont:[UIFont systemFontOfSize:14]]; | |||||
} | |||||
[percentLabel setTextColor:[UIColor whiteColor]]; | |||||
percentLabel.lineBreakMode = NSLineBreakByWordWrapping; | |||||
[percentLabel setTextAlignment:NSTextAlignmentRight]; | |||||
percentLabel.numberOfLines = 1; | |||||
[percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger) batteryPercentage)]]; | |||||
if(charging) battery.chargingState = 1; | |||||
battery.showsInlineChargingIndicator = YES; | |||||
if(LPM) battery.saverModeActive = YES; | |||||
if(kCFCoreFoundationVersionNumber > 1600) { | |||||
[battery setBodyColorAlpha:1.0]; | |||||
[battery setPinColorAlpha:1.0]; | |||||
} | |||||
if([self.displayingDevices containsObject:device]) { | |||||
[cell removeFromSuperview]; | |||||
[self.displayingDevices removeObject:device]; | |||||
} | |||||
UIImage *glyph = [device glyph]; | |||||
UIImageView *glyphView = [[UIImageView alloc] init]; | |||||
glyphView.contentMode = UIViewContentModeScaleAspectFit; | |||||
[glyphView setImage:glyph]; | |||||
[self addSubview:blank]; | |||||
[self addSubview:percentLabel]; | |||||
[self addSubview:label]; | |||||
[self addSubview:battery]; | |||||
[self addSubview:glyphView]; | |||||
blank.translatesAutoresizingMaskIntoConstraints = NO; | |||||
if(bannerAlign==2) { //center | |||||
[blank.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:horizontalOffset].active = YES; | |||||
} else if(bannerAlign==1) { //left | |||||
[blank.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:horizontalOffset].active = YES; | |||||
} else if(bannerAlign==3) { //right | |||||
[blank.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:horizontalOffset].active = YES; | |||||
} | } | ||||
[blank.topAnchor constraintEqualToAnchor:self.topAnchor constant:y].active = YES; | |||||
[blank.widthAnchor constraintEqualToConstant:((self.superview.bounds.size.width - 16) + bannerWidthFactor)].active = YES; | |||||
[blank.heightAnchor constraintEqualToConstant:bannerHeight].active = YES; | |||||
//percentLabel.frame = CGRectMake(self.superview.bounds.size.width - 16 - 94,35 + y,36,12); | |||||
percentLabel.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[percentLabel.leftAnchor constraintEqualToAnchor:blank.rightAnchor constant:(- 96)].active = YES; | |||||
[percentLabel.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[percentLabel.widthAnchor constraintEqualToConstant:37].active = YES; | |||||
[percentLabel.heightAnchor constraintEqualToConstant:12].active = YES; | |||||
//label.frame = CGRectMake(65.5,27.5 + y,275,25); | |||||
label.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[label.leftAnchor constraintEqualToAnchor:glyphView.rightAnchor constant:4.5].active = YES; | |||||
[label.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[label.rightAnchor constraintEqualToAnchor:percentLabel.leftAnchor constant:-4.5].active = YES; | |||||
[label.heightAnchor constraintEqualToConstant:25].active = YES; | |||||
//glyphView.frame = CGRectMake(20.5,18.5 + y,40,40); | |||||
glyphView.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[glyphView.leftAnchor constraintEqualToAnchor:blank.leftAnchor constant:20.5].active = YES; | |||||
[glyphView.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[glyphView.widthAnchor constraintEqualToConstant:glyphSize].active = YES; | |||||
[glyphView.heightAnchor constraintEqualToConstant:glyphSize].active = YES; | |||||
//battery.frame = CGRectMake(self.superview.bounds.size.width - 16 - 49,35 + y,20,10); | |||||
battery.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[battery.leftAnchor constraintEqualToAnchor:blank.rightAnchor constant:(- 49)].active = YES; | |||||
[battery.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[battery.widthAnchor constraintEqualToConstant:20].active = YES; | |||||
[battery.heightAnchor constraintEqualToConstant:10].active = YES; | |||||
y+=bannerHeight + spacing; | |||||
self.number +=1; | |||||
//blank.alpha = 0.8; | |||||
} | |||||
//[self.heightAnchor constraintEqualToConstant:(self.number * 85)].active = YES; | |||||
self.isUpdating = NO; | |||||
} | } | ||||
} | |||||
//[self.heightAnchor constraintEqualToConstant:(self.number * 85)].active = YES; | |||||
self.isUpdating = NO; | |||||
} | |||||
}); | }); | ||||
} | } | ||||
#import <UIKit/UIKit.h> | |||||
#import <substrate.h> | |||||
@interface _UIBatteryView : UIView | |||||
@property (nonatomic, assign) CGFloat chargePercent; | |||||
@property (nonatomic, assign) CGFloat bodyColorAlpha; | |||||
@property (nonatomic, assign) CGFloat pinColorAlpha; | |||||
@property (nonatomic, assign) BOOL showsPercentage; | |||||
@property (nonatomic, assign) BOOL saverModeActive; | |||||
@property (nonatomic, assign) BOOL showsInlineChargingIndicator; | |||||
@property (nonatomic, assign) NSInteger chargingState; | |||||
@end | |||||
@interface MTMaterialView : UIView | |||||
@property (nonatomic, assign) BOOL recipeDynamic; | |||||
-(id)_initWithRecipe:(NSInteger)arg1 configuration:(NSInteger)arg2 initialWeighting:(CGFloat)arg3 scaleAdjustment:(id)arg4; | |||||
+(id)materialViewWithRecipe:(NSInteger)arg1 options:(NSInteger)arg2 initialWeighting:(CGFloat)arg3 scaleAdjustment:(id)arg4; | |||||
@end | |||||
@interface BCBatteryDeviceController | |||||
@property (nonatomic, strong) NSArray *sortedDevices; | |||||
-(id)_sortedDevices; | |||||
+(id)sharedInstance; | |||||
@end | |||||
@interface BCBatteryDevice : NSObject | |||||
-(id)glyph; | |||||
@end | |||||
@interface KAIBatteryCell : UIView | |||||
@property (nonatomic, strong) BCBatteryDevice *device; | |||||
@property (nonatomic, strong) UILabel *label; | |||||
@property (nonatomic, strong) UILabel *percentLabel; | |||||
@property (nonatomic, strong) UIImageView *glyphView; | |||||
@property (nonatomic, strong) _UIBatteryView *battery; | |||||
@property (nonatomic, assign) BOOL lastChargingState; | |||||
@property (nonatomic, assign) BOOL lastLPM; | |||||
@property (nonatomic, assign) double lastPercent; | |||||
-(instancetype)initWithFrame:(CGRect)arg1 device:(BCBatteryDevice *)device; | |||||
-(void)updateInfo; | |||||
+(instancetype)cellForDeviceIfExists:(BCBatteryDevice *)device; | |||||
@end |
#import "KAIBatteryCell.h" | |||||
NSMutableArray *deviceInstances; | |||||
@implementation KAIBatteryCell | |||||
-(instancetype)initWithFrame:(CGRect)arg1 device:(BCBatteryDevice *)device { | |||||
self = [super initWithFrame:arg1]; | |||||
if(self) { | |||||
self.device = device; | |||||
NSString *deviceName = MSHookIvar<NSString *>(device, "_name"); | |||||
double batteryPercentage = MSHookIvar<long long>(device, "_percentCharge"); | |||||
BOOL charging = MSHookIvar<long long>(device, "_charging"); | |||||
BOOL LPM = MSHookIvar<BOOL>(device, "_batterySaverModeActive"); | |||||
UIView *blank; | |||||
if(bannerStyle==1) { | |||||
if(kCFCoreFoundationVersionNumber > 1600) { | |||||
blank = [[[objc_getClass("MTMaterialView") class] alloc] _initWithRecipe:1 configuration:1 initialWeighting:1 scaleAdjustment:nil]; | |||||
} else if(kCFCoreFoundationVersionNumber < 1600) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; | |||||
} | |||||
} else if(bannerStyle==2) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; | |||||
} else if(bannerStyle==3) { | |||||
blank = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]]; | |||||
} | |||||
blank.layer.masksToBounds = YES; | |||||
blank.layer.continuousCorners = YES; | |||||
blank.layer.cornerRadius = cornerRadius; | |||||
NSString *labelText = [NSString stringWithFormat:@"%@", deviceName]; | |||||
self.label = [[UILabel alloc] init]; | |||||
if(!hideDeviceLabel) { | |||||
[self.label setFont:[UIFont systemFontOfSize:16]]; | |||||
} else if(hideDeviceLabel) { | |||||
[self.label setFont:[UIFont systemFontOfSize:0]]; | |||||
} | |||||
[self.label setTextColor:[UIColor whiteColor]]; | |||||
self.label.lineBreakMode = NSLineBreakByWordWrapping; | |||||
self.label.numberOfLines = 1; | |||||
[self.label setText:labelText]; | |||||
self.battery = [[_UIBatteryView alloc] init]; | |||||
self.battery.chargePercent = (batteryPercentage*0.01); | |||||
self.percentLabel = [[UILabel alloc] init]; | |||||
self.battery.showsPercentage = NO; | |||||
if(hidePercent) { | |||||
[self.percentLabel setFont:[UIFont systemFontOfSize:0]]; | |||||
} else { | |||||
[self.percentLabel setFont:[UIFont systemFontOfSize:14]]; | |||||
} | |||||
[self.percentLabel setTextColor:[UIColor whiteColor]]; | |||||
self.percentLabel.lineBreakMode = NSLineBreakByWordWrapping; | |||||
[self.percentLabel setTextAlignment:NSTextAlignmentRight]; | |||||
self.percentLabel.numberOfLines = 1; | |||||
[self.percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger) batteryPercentage)]]; | |||||
if(charging) self.battery.chargingState = 1; | |||||
self.battery.showsInlineChargingIndicator = YES; | |||||
if(LPM) self.battery.saverModeActive = YES; | |||||
if(kCFCoreFoundationVersionNumber > 1600) { | |||||
[self.battery setBodyColorAlpha:1.0]; | |||||
[self.battery setPinColorAlpha:1.0]; | |||||
} | |||||
UIImage *glyph = [device glyph]; | |||||
self.glyphView = [[UIImageView alloc] init]; | |||||
self.glyphView.contentMode = UIViewContentModeScaleAspectFit; | |||||
[self.glyphView setImage:glyph]; | |||||
[self addSubview:blank]; | |||||
[self addSubview:self.percentLabel]; | |||||
[self addSubview:self.label]; | |||||
[self addSubview:self.battery]; | |||||
[self addSubview:self.glyphView]; | |||||
blank.translatesAutoresizingMaskIntoConstraints = NO; | |||||
if(bannerAlign==2) { //center | |||||
[blank.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:horizontalOffset].active = YES; | |||||
} else if(bannerAlign==1) { //left | |||||
[blank.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:horizontalOffset].active = YES; | |||||
} else if(bannerAlign==3) { //right | |||||
[blank.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:horizontalOffset].active = YES; | |||||
} | |||||
[blank.topAnchor constraintEqualToAnchor:self.topAnchor constant:self.frame.origin.y].active = YES; | |||||
[blank.widthAnchor constraintEqualToConstant:((self.superview.bounds.size.width - 16) + bannerWidthFactor)].active = YES; | |||||
[blank.heightAnchor constraintEqualToConstant:bannerHeight].active = YES; | |||||
self.percentLabel.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[self.percentLabel.leftAnchor constraintEqualToAnchor:blank.rightAnchor constant:(- 96)].active = YES; | |||||
[self.percentLabel.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[self.percentLabel.widthAnchor constraintEqualToConstant:37].active = YES; | |||||
[self.percentLabel.heightAnchor constraintEqualToConstant:12].active = YES; | |||||
self.label.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[self.label.leftAnchor constraintEqualToAnchor:self.glyphView.rightAnchor constant:4.5].active = YES; | |||||
[self.label.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[self.label.rightAnchor constraintEqualToAnchor:self.percentLabel.leftAnchor constant:-4.5].active = YES; | |||||
[self.label.heightAnchor constraintEqualToConstant:25].active = YES; | |||||
self.glyphView.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[self.glyphView.leftAnchor constraintEqualToAnchor:blank.leftAnchor constant:20.5].active = YES; | |||||
[self.glyphView.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[self.glyphView.widthAnchor constraintEqualToConstant:glyphSize].active = YES; | |||||
[self.glyphView.heightAnchor constraintEqualToConstant:glyphSize].active = YES; | |||||
self.battery.translatesAutoresizingMaskIntoConstraints = NO; | |||||
[self.battery.leftAnchor constraintEqualToAnchor:blank.rightAnchor constant:(- 49)].active = YES; | |||||
[self.battery.centerYAnchor constraintEqualToAnchor:blank.centerYAnchor].active = YES; | |||||
[self.battery.widthAnchor constraintEqualToConstant:20].active = YES; | |||||
[self.battery.heightAnchor constraintEqualToConstant:10].active = YES; | |||||
self.lastChargingState = charging; | |||||
self.lastLPM = LPM; | |||||
self.lastPercent = batteryPercentage; | |||||
} | |||||
return self; | |||||
} | |||||
-(void)updateInfo { | |||||
NSString *deviceName = MSHookIvar<NSString *>(self.device, "_name"); | |||||
double batteryPercentage = MSHookIvar<long long>(self.device, "_percentCharge"); | |||||
BOOL charging = MSHookIvar<long long>(self.device, "_charging"); | |||||
BOOL LPM = MSHookIvar<BOOL>(self.device, "_batterySaverModeActive"); | |||||
self.label.text = [NSString stringWithFormat:@"%@", deviceName]; | |||||
[self.percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger) batteryPercentage)]]; | |||||
self.battery.chargePercent = (batteryPercentage*0.01); | |||||
if(charging) self.battery.chargingState = 1; | |||||
self.battery.showsInlineChargingIndicator = YES; | |||||
if(LPM) self.battery.saverModeActive = YES; | |||||
if(kCFCoreFoundationVersionNumber > 1600) { | |||||
[self.battery setBodyColorAlpha:1.0]; | |||||
[self.battery setPinColorAlpha:1.0]; | |||||
} | |||||
[self.percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger) batteryPercentage)]]; | |||||
self.battery.chargePercent = (batteryPercentage*0.01); | |||||
[self.glyphView setImage:[self.device glyph]]; | |||||
self.lastChargingState = charging; | |||||
self.lastLPM = LPM; | |||||
self.lastPercent = batteryPercentage; | |||||
} | |||||
-(void)removeFromSuperview { | |||||
[super removeFromSuperview]; | |||||
[deviceInstances removeObject:self]; | |||||
} | |||||
+(instancetype)cellForDeviceIfExists:(BCBatteryDevice *)device { | |||||
KAIBatteryCell *foundCell; | |||||
for(KAIBatteryCell *cell in deviceInstances) { | |||||
if(cell.device == device) { | |||||
foundCell = cell; | |||||
break; | |||||
} | |||||
} | |||||
return foundCell; | |||||
} | |||||
@end |
double bannerWidthFactor; | double bannerWidthFactor; | ||||
double horizontalOffset; | double horizontalOffset; | ||||
//by importing here, I can use vars in the .mm of KAIBattery | |||||
//by importing here, I can use vars in the .mm files | |||||
#import "KAIBatteryCell.mm" | |||||
#import "KAIBattery.mm" | #import "KAIBattery.mm" | ||||
#define PLIST_PATH @"/User/Library/Preferences/com.burritoz.kaiprefs.plist" | #define PLIST_PATH @"/User/Library/Preferences/com.burritoz.kaiprefs.plist" |