diff --git a/Ampere.h b/Ampere.h new file mode 100644 index 0000000..00b9c25 --- /dev/null +++ b/Ampere.h @@ -0,0 +1,171 @@ +#import +#import "spawn.h" +#import +#include + +#ifndef kCFCoreFoundationVersionNumber_iOS_16_0 +#define kCFCoreFoundationVersionNumber_iOS_16_0 1946.10 +#endif +#define kSLSystemVersioniOS16 kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_16_0 + +#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) + +#define WIDTH [UIScreen mainScreen].bounds.size.width +#define HEIGHT [UIScreen mainScreen].bounds.size.height + +extern NSString *const kCAFilterDestOut; + +static NSString *domain = @"com.mtac.amp"; +static NSString *preferencesNotification = @"com.mtac.amp/preferences.changed"; +static NSString *statusBarNotification = @"com.mtac.amp/statusbar.changed"; +static BOOL enabled; +static BOOL showBolt; +static BOOL useGesture; +static BOOL useStatsModule; +static BOOL overrideColorStandard; +static BOOL overrideColorCharging; +static BOOL overrideColorLowPower; +static BOOL overrideColorCritical; +static NSInteger textStyle; +static NSInteger fontSize; +static NSInteger batterySizing; + +@interface CALayer (Ampere) +@property (nonatomic, retain) NSString *compositingFilter; +@property (nonatomic, assign) BOOL allowsGroupOpacity; +@property (nonatomic, assign) BOOL allowsGroupBlending; +@property (copy) NSString *cornerCurve; +@end + +@interface _CDBatterySaver : NSObject ++ (id)batterySaver; +- (NSInteger)getPowerMode; +- (BOOL)setPowerMode:(NSInteger)arg0 error:(id)arg1; +@end + +@interface _PMLowPowerMode : NSObject ++ (id)sharedInstance; +- (NSInteger)getPowerMode; +- (void)setPowerMode:(NSInteger)arg0 fromSource:(id)arg1; +- (void)setPowerMode:(NSInteger)arg0 fromSource:(id)arg1 withCompletion:(id)arg2; +@end + +@interface NSUserDefaults (Ampere) +- (id)objectForKey:(NSString *)key inDomain:(NSString *)domain; +- (void)setObject:(id)value forKey:(NSString *)key inDomain:(NSString *)domain; +@end + +@interface _UIBatteryView : UIView +@property (readonly, nonatomic, getter=isLowBattery) BOOL lowBattery; +@property (retain, nonatomic) UIImageView *ampereImageView; +@property (retain, nonatomic) UILabel *percentageLabel; +@property (retain, nonatomic) CALayer *fillLayer; +@property (retain, nonatomic) CALayer *pinLayer; +@property (copy, nonatomic) UIColor *pinColor; +@property (nonatomic) CGFloat pinColorAlpha; +@property (nonatomic) CGFloat bodyColorAlpha; +@property (nonatomic) CGFloat chargePercent; +@property (nonatomic) BOOL saverModeActive; +@property (nonatomic) NSInteger chargingState; +@property (nonatomic) NSInteger iconSize; +- (CGRect)_bodyRectForTraitCollection:(id)arg0; +- (id)_batteryFillColor; +- (id)_batteryTextColor; +- (void)_updateBatteryFillColor; +- (void)_updatePercentage; +- (id)initWithSizeCategory:(NSInteger)arg0; +- (UIColor *)ampereFillColor; +@end + +@interface BCUIRowView : UIView +@property (nonatomic, strong) _UIBatteryView *ampereBatteryView; +@property (nonatomic) NSInteger percentCharge; +@end + +@interface BCUIBatteryView : _UIBatteryView +@end + +@interface _UIStaticBatteryView : _UIBatteryView +- (void)setShowsPercentage:(BOOL)arg0; +@end + +@interface UIStatusBarItem : NSObject +@end + +@interface _UIStatusBarDisplayItem : NSObject +@property (nonatomic, getter=isEnabled) BOOL enabled; +@end + +@interface _UIStatusBarStringView : UIView +- (void)setText:(id)arg0; +@end + +@interface _UIStatusBarBatteryItem : UIStatusBarItem +@property (retain, nonatomic) _UIStatusBarStringView *percentView; ++ (id)staticIconDisplayIdentifier; ++ (id)iconDisplayIdentifier; +- (void)toggleLowPower:(id)sender; +@end + +@interface _UIStatusBarDataBatteryEntry : NSObject +@property (nonatomic) NSInteger state; +@end + +@interface MTMaterialView : UIView +@end + +@protocol CCUIContentModuleContentViewController +@end + +@protocol CCUIContentModuleBackgroundViewController +@end + +@interface CCUIContentModuleContentContainerView : UIView { + MTMaterialView *_moduleMaterialView; +} +@end + +@interface CCUIContentModuleContainerViewController : UIViewController +@property (retain, nonatomic) UIViewController *contentViewController; +@property (retain, nonatomic) UIViewController *backgroundViewController; +@property (retain, nonatomic) CCUIContentModuleContentContainerView *contentContainerView; +@property (copy, nonatomic) NSString *moduleIdentifier; +@end + +@interface CCUIToggleModule : NSObject +@end + +@interface CCUIButtonModuleView : UIControl +@end + +@interface CCUIButtonModuleViewController : UIViewController +@property (readonly, nonatomic) CCUIButtonModuleView *buttonView; +@end + +@interface CCUIToggleViewController : CCUIButtonModuleViewController +@property (weak, nonatomic) CCUIToggleModule *module; +@property (readonly, nonatomic) CGFloat preferredExpandedContentHeight; +@property (readonly, nonatomic) CGFloat preferredExpandedContentWidth; +@property (readonly, nonatomic) BOOL providesOwnPlatter; +@property (readonly, nonatomic) BOOL shouldPerformClickInteraction; +@property (readonly, nonatomic) BOOL shouldPerformHoverInteraction; +@end + +@interface CCUIContentModuleContext : NSObject +@property (readonly, copy, nonatomic) NSString *moduleIdentifier; +@end + +@interface CCUIMenuModuleViewController : CCUIButtonModuleViewController +@property (weak, nonatomic) CCUIContentModuleContext *contentModuleContext; +@end + +@interface CCUILowPowerModuleViewController : CCUIMenuModuleViewController +@end + +@interface CCUILowPowerModule : NSObject +@end + +@interface AMPStatsController : UIViewController +@property (nonatomic, strong) UITableView *tableView; +@end \ No newline at end of file diff --git a/Ampere.plist b/Ampere.plist index 3fd447f..85363fa 100644 --- a/Ampere.plist +++ b/Ampere.plist @@ -1 +1,14 @@ -{ Filter = { Bundles = ( "com.apple.springboard", "com.apple.Preferences"); }; } + + + + + Filter + + Bundles + + com.apple.CarPlayApp + com.apple.springboard + + + + \ No newline at end of file diff --git a/Ampere.xm b/Ampere.xm index d6e09bc..c428670 100644 --- a/Ampere.xm +++ b/Ampere.xm @@ -1,92 +1,237 @@ -#import -#import "spawn.h" - -#define ROOT_PATH_NS(path)([[NSFileManager defaultManager] fileExistsAtPath:path] ? path : [@"/var/jb" stringByAppendingPathComponent:path]) -#ifndef kCFCoreFoundationVersionNumber_iOS_16_0 -#define kCFCoreFoundationVersionNumber_iOS_16_0 1946.10 -#endif -#define kSLSystemVersioniOS16 kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_16_0 - -extern NSString *const kCAFilterDestOut; - -static NSString *domain = @"com.mtac.amp"; -static NSString *preferencesNotification = @"com.mtac.amp/preferences.changed"; -static NSString *statusBarNotification = @"com.mtac.amp/statusbar.changed"; -static BOOL enabled; -static BOOL showBolt; -static BOOL useGesture; -static BOOL overrideColorStandard; -static BOOL overrideColorCharging; -static BOOL overrideColorLowPower; -static BOOL overrideColorCritical; -static NSInteger textStyle; -static NSInteger fontSize; -static NSInteger batterySizing; - -@interface CALayer (Ampere) -@property (nonatomic, retain) NSString *compositingFilter; -@property (nonatomic, assign) BOOL allowsGroupOpacity; -@property (nonatomic, assign) BOOL allowsGroupBlending; -@end +#import "Ampere.h" -@interface _CDBatterySaver : NSObject -+ (id)batterySaver; -- (NSInteger)getPowerMode; -- (BOOL)setPowerMode:(NSInteger)arg0 error:(id)arg1; -@end +NSString *batteryCharging() { + UIDevice *device = [UIDevice currentDevice]; + device.batteryMonitoringEnabled = YES; + switch ([device batteryState]) { + case UIDeviceBatteryStateCharging: + return @"Yes"; + case UIDeviceBatteryStateFull: + case UIDeviceBatteryStateUnplugged: + case UIDeviceBatteryStateUnknown: + default: + return @"No"; + } +} -@interface _PMLowPowerMode : NSObject -+ (id)sharedInstance; -- (NSInteger)getPowerMode; -- (void)setPowerMode:(NSInteger)arg0 fromSource:(id)arg1; -- (void)setPowerMode:(NSInteger)arg0 fromSource:(id)arg1 withCompletion:(id)arg2; -@end +NSString *celsiusTemperature() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + float temperature = -1; + CFNumberRef temperatureRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("Temperature"), kCFAllocatorDefault, 0); + CFNumberGetValue(temperatureRef, kCFNumberFloatType, &temperature); + CFRelease(temperatureRef); + return [NSString stringWithFormat:@"%.1f°C", temperature / 100]; + } + } + return @"--°C"; +} -@interface NSUserDefaults (Ampere) -- (id)objectForKey:(NSString *)key inDomain:(NSString *)domain; -- (void)setObject:(id)value forKey:(NSString *)key inDomain:(NSString *)domain; -@end +NSString *fahrenheitTemperature() { + NSString *celsiusMethod = celsiusTemperature(); + NSString *celsius = [celsiusMethod substringToIndex:celsiusMethod.length - 2]; + if ([celsius isEqualToString:@"--"]) + return [celsius stringByAppendingString:@"°F"]; + return [NSString stringWithFormat:@"%.1f°F", [celsius floatValue] * 1.8 + 32.0]; +} -@interface _UIBatteryView : UIView -@property (readonly, nonatomic, getter=isLowBattery) BOOL lowBattery; -@property (retain, nonatomic) UIImageView *ampereImageView; -@property (retain, nonatomic) UILabel *percentageLabel; -@property (retain, nonatomic) CALayer *fillLayer; -@property (retain, nonatomic) CALayer *pinLayer; -@property (copy, nonatomic) UIColor *pinColor; -@property (nonatomic) CGFloat pinColorAlpha; -@property (nonatomic) CGFloat bodyColorAlpha; -@property (nonatomic) CGFloat chargePercent; -@property (nonatomic) BOOL saverModeActive; -@property (nonatomic) NSInteger chargingState; -@property (nonatomic) NSInteger iconSize; -- (CGRect)_bodyRectForTraitCollection:(id)arg0; -- (id)_batteryFillColor; -- (id)_batteryTextColor; -- (void)_updateBatteryFillColor; -- (void)_updatePercentage; -@end +NSString *cycles() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + int cycles = -1; + CFNumberRef cyclesRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("CycleCount"), kCFAllocatorDefault, 0); + CFNumberGetValue(cyclesRef, kCFNumberIntType, &cycles); + CFRelease(cyclesRef); + return [NSString stringWithFormat:@"%d", cycles]; + } + } + return @"-"; +} -@interface UIStatusBarItem : NSObject -@end +int maxCapacity() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + int maxCapacity = -1; + CFNumberRef maxCapRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("AppleRawMaxCapacity"), kCFAllocatorDefault, 0); + CFNumberGetValue(maxCapRef, kCFNumberIntType, &maxCapacity); + CFRelease(maxCapRef); + return maxCapacity; + } + } + return -1; +} -@interface _UIStatusBarDisplayItem : NSObject -@property (nonatomic, getter=isEnabled) BOOL enabled; -@end +int designCapacity() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + int designCapacity = -1; + CFNumberRef designCapRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("DesignCapacity"), kCFAllocatorDefault, 0); + CFNumberGetValue(designCapRef, kCFNumberIntType, &designCapacity); + CFRelease(designCapRef); + return designCapacity; + } + } + return -1; +} -@interface _UIStatusBarStringView : UIView -- (void)setText:(id)arg0; -@end +NSString *amperage() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + int amperage = -1; + CFNumberRef amperageRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("InstantAmperage"), kCFAllocatorDefault, 0); + CFNumberGetValue(amperageRef, kCFNumberIntType, &erage); + CFRelease(amperageRef); + return [NSString stringWithFormat:@"%d mA", amperage]; + } + } + return @"- mA"; +} -@interface _UIStatusBarBatteryItem : UIStatusBarItem -@property (retain, nonatomic) _UIStatusBarStringView *percentView; -+ (id)staticIconDisplayIdentifier; -+ (id)iconDisplayIdentifier; -- (void)toggleLowPower:(id)sender; -@end +NSString *voltage() { + io_service_t powerSource = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMPowerSource")); + if (powerSource) { + CFMutableDictionaryRef batteryDictionaryRef = NULL; + if (IORegistryEntryCreateCFProperties(powerSource, &batteryDictionaryRef, 0, 0) == KERN_SUCCESS) { + float voltage = -1; + CFNumberRef voltageRef = (CFNumberRef)IORegistryEntryCreateCFProperty(powerSource, CFSTR("Voltage"), kCFAllocatorDefault, 0); + CFNumberGetValue(voltageRef, kCFNumberFloatType, &voltage); + CFRelease(voltageRef); + return [NSString stringWithFormat:@"%.1f V", voltage / 1000]; + } + } + return @"- V"; +} + +@implementation AMPStatsController +- (id)init { + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadData) name:@"AMPReloadStatsController" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadData) name:@"SBUIACStatusChangedNotification" object:nil]; + } + return self; +} +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped]; + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + self.tableView.delegate = self; + self.tableView.dataSource = self; + self.tableView.separatorColor = [UIColor clearColor]; + self.tableView.backgroundColor = [UIColor clearColor]; + self.tableView.userInteractionEnabled = NO; + [self.view addSubview:self.tableView]; -@interface _UIStatusBarDataBatteryEntry : NSObject -@property (nonatomic) NSInteger state; + [NSLayoutConstraint activateConstraints:@[ + [self.tableView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + ]]; +} +- (double)tableView:(id)arg1 heightForRowAtIndexPath:(id)arg2 { + return 44.0; +} +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 8; +} +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *identifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + if (!cell) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; + } + cell.backgroundColor = [UIColor clearColor]; + UIListContentConfiguration *content = [cell defaultContentConfiguration]; + [content setText:[self titleForRow:indexPath.row]]; + [content.textProperties setColor:[UIColor whiteColor]]; + [content setSecondaryText:[self detailForRow:indexPath.row]]; + [content.secondaryTextProperties setColor:[UIColor colorWithWhite:1.0 alpha:0.75]]; + [content.secondaryTextProperties setFont:[UIFont systemFontOfSize:18]]; + [content setPrefersSideBySideTextAndSecondaryText:YES]; + [cell setContentConfiguration:content]; + + return cell; +} +- (NSString *)titleForRow:(NSInteger)row { + NSString *title; + switch (row) { + case 0: + title = @"Charging"; + break; + case 1: + title = @"Cycles"; + break; + case 2: + title = @"Temperature"; + break; + case 3: + title = @"Health"; + break; + case 4: + title = @"Max Capacity"; + break; + case 5: + title = @"Design Capacity"; + break; + case 6: + title = @"Amperage"; + break; + case 7: + title = @"Voltage"; + } + return title; +} +- (NSString *)detailForRow:(NSInteger)row { + NSString *detail; + switch (row) { + case 0: + detail = batteryCharging(); + break; + case 1: + detail = cycles(); + break; + case 2: + detail = [NSString stringWithFormat:@"%@/%@", celsiusTemperature(), fahrenheitTemperature()]; + break; + case 3: + detail = [NSString stringWithFormat:@"%0.f%%", (CGFloat)maxCapacity() / (CGFloat)designCapacity() * 100]; + break; + case 4: + detail = [NSString stringWithFormat:@"%d mAh", maxCapacity()]; + break; + case 5: + detail = [NSString stringWithFormat:@"%d mAh", designCapacity()]; + break; + case 6: + detail = amperage(); + break; + case 7: + detail = voltage(); + break; + } + return detail; +} +- (void)reloadData { + [self.tableView reloadData]; +} +- (BOOL)_canShowWhileLocked { + return YES; +} @end %group Ampere @@ -106,17 +251,17 @@ static NSInteger batterySizing; } %new - (void)toggleLowPower:(id)sender { - if (%c(_PMLowPowerMode)) { - _PMLowPowerMode *lowPowerMode = [%c(_PMLowPowerMode) sharedInstance]; + if (objc_getClass("_PMLowPowerMode")) { + _PMLowPowerMode *lowPowerMode = [objc_getClass("_PMLowPowerMode") sharedInstance]; BOOL active = [lowPowerMode getPowerMode] == 1; [lowPowerMode setPowerMode:!active fromSource:@"SpringBoard"]; } else { - long long state = [[%c(_CDBatterySaver) batterySaver] getPowerMode]; + long long state = [[objc_getClass("_CDBatterySaver") batterySaver] getPowerMode]; if (state == 0) { - [[%c(_CDBatterySaver) batterySaver] setPowerMode:1 error:nil]; + [[objc_getClass("_CDBatterySaver") batterySaver] setPowerMode:1 error:nil]; } if (state == 1) { - [[%c(_CDBatterySaver) batterySaver] setPowerMode:0 error:nil]; + [[objc_getClass("_CDBatterySaver") batterySaver] setPowerMode:0 error:nil]; } } } @@ -144,7 +289,8 @@ static NSInteger batterySizing; } return %orig; } -- (UIColor *)_batteryFillColor { // Return default or custom fill colors based on charging state +%new +- (UIColor *)ampereFillColor { NSDictionary *standardColorDict = [[NSUserDefaults standardUserDefaults] objectForKey:@"overrideColorStandardDict" inDomain:domain]; NSDictionary *lowPowerColorDict = [[NSUserDefaults standardUserDefaults] objectForKey:@"overrideColorLowPowerDict" inDomain:domain]; NSDictionary *chargingColorDict = [[NSUserDefaults standardUserDefaults] objectForKey:@"overrideColorChargingDict" inDomain:domain]; @@ -163,7 +309,9 @@ static NSInteger batterySizing; } else { // Low Power, overrides custom charging color return lowPowerColor; } - return %orig; +} +- (UIColor *)_batteryFillColor { // Return default or custom fill colors based on charging state + return [self ampereFillColor]; } %end @@ -172,6 +320,34 @@ static NSInteger batterySizing; return @""; // Return empty string to keep automatic sizing } %end + +%hook BCUIRowView +%property (nonatomic, strong) _UIBatteryView *ampereBatteryView; +- (void)_configureBatteryViewIfNecessary { + %orig; + BCUIBatteryView *batteryView = MSHookIvar(self, "_batteryView"); + + if (!(kSLSystemVersioniOS16)) { + if (!self.ampereBatteryView) self.ampereBatteryView = [[%c(_UIBatteryView) alloc] initWithSizeCategory:0]; + self.ampereBatteryView.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:self.ampereBatteryView]; + [NSLayoutConstraint activateConstraints:@[ + [self.ampereBatteryView.widthAnchor constraintEqualToAnchor:batteryView.widthAnchor constant:-1], + [self.ampereBatteryView.heightAnchor constraintEqualToAnchor:batteryView.heightAnchor], + [self.ampereBatteryView.centerXAnchor constraintEqualToAnchor:batteryView.centerXAnchor], + [self.ampereBatteryView.centerYAnchor constraintEqualToAnchor:batteryView.centerYAnchor], + ]]; + batteryView.hidden = YES; + + [self.ampereBatteryView setChargePercent:batteryView.chargePercent]; + [self.ampereBatteryView setChargingState:batteryView.chargingState]; + } +} +- (void)_configurePercentChargeLabelIfNecessary { + +} +%end %end %group XVI @@ -179,6 +355,10 @@ static NSInteger batterySizing; - (void)setShowsPercentage:(BOOL)arg0 { %orig(YES); } +- (void)_createFillLayer { + %orig; + [self setShowsPercentage:YES]; +} %end %hook _UIBatteryView @@ -202,7 +382,7 @@ static NSInteger batterySizing; } + (id)_pinBezierPathForSize:(struct CGSize )arg0 complex:(BOOL)arg1 { UIBezierPath *path = %orig; - if (batterySizing == 1) { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { [path applyTransform:CGAffineTransformMakeTranslation(1, 0)]; // Shift pin 1 px, done because setting line interspace width to fill body adds border } return path; @@ -210,11 +390,12 @@ static NSInteger batterySizing; - (void)_updateFillLayer { %orig; [self.fillLayer setCornerRadius:([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) ? 4.0 : 3.5]; // Set fill corner radius whenever layer updates + [self.fillLayer setCornerCurve:@"circular"]; } - (void)_updatePercentage { %orig; self.percentageLabel.font = [UIFont systemFontOfSize:((self.chargingState == 1 || self.chargePercent == 1.0) && fontSize > 10) ? 10 : fontSize weight:((batterySizing == 1) ? UIFontWeightHeavy : UIFontWeightBold)]; // Set custom percentage font size - if (showBolt && self.chargingState == 1) { // Show bolt next to percentage label text + if (showBolt && self.chargingState == 1 && self.chargePercent != 1.0) { // Show bolt next to percentage label text NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; [attachment setBounds:CGRectMake(0, 0, roundf(self.percentageLabel.font.capHeight * 0.6), roundf(self.percentageLabel.font.capHeight))]; [attachment setImage:[[UIImage systemImageNamed:@"bolt.fill"] imageWithTintColor:(self.saverModeActive) ? [UIColor blackColor] : [self _batteryTextColor]]]; @@ -235,6 +416,9 @@ static NSInteger batterySizing; - (CGFloat)_outsideCornerRadiusForTraitCollection:(id)arg0 { return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) ? 4.0 : 3.5; // Slightly adjust corner radius for expanded height } ++ (CGFloat)_lineWidthAndInterspaceForIconSize:(NSInteger)arg0 { + return 0; +} - (CGFloat)bodyColorAlpha { return 1.0; // Overrides default fill color alpha (normally 0.4) } @@ -245,13 +429,13 @@ static NSInteger batterySizing; } - (CALayer *)fillLayer { CALayer *fill = %orig; - fill.maskedCorners = (self.chargePercent > 0.9) ? (kCALayerMaxXMaxYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner) : (kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner); // Rounded corners always on leading edge, flat on trailing until above 92% to match stock radius - fill.bounds = CGRectMake(fill.bounds.origin.x, fill.bounds.origin.y - ((batterySizing == 1) ? 1 : 0), fill.bounds.size.width - 1, self.bounds.size.height + ((batterySizing == 1) ? 2 : 0)); + fill.maskedCorners = (self.chargePercent > 0.82) ? (kCALayerMaxXMaxYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner) : (kCALayerMinXMaxYCorner | kCALayerMinXMinYCorner); // Rounded corners always on leading edge, flat on trailing until above 92% to match stock radius + fill.bounds = CGRectMake(fill.bounds.origin.x - 1, fill.bounds.origin.y, fill.bounds.size.width, self.bounds.size.height); return fill; } - (CGRect)_bodyRectForTraitCollection:(id)arg0 { CGRect bodyRect = %orig; - return CGRectMake(bodyRect.origin.x, bodyRect.origin.y - ((batterySizing == 1) ? 1 : 0), bodyRect.size.width - 1, bodyRect.size.height + ((batterySizing == 1) ? 2 : 0)); // Resize view height to better replicate iOS 16 + return CGRectMake(bodyRect.origin.x, bodyRect.origin.y, bodyRect.size.width - 1, bodyRect.size.height); // Resize view height to better replicate iOS 16 } - (CGFloat)_lineWidthAndInterspaceForTraitCollection:(id)arg0 { return 0; // Disable space between fill layer and border of body layer @@ -271,6 +455,108 @@ static NSInteger batterySizing; %end %end +%group BatteryInfo +%hook CCUIToggleViewController +- (void)viewDidLoad { + %orig; + if ([self.module isKindOfClass:%c(CCUILowPowerModule)]) { + AMPStatsController *statsController = [[AMPStatsController alloc] init]; + if (![self.view.subviews containsObject:statsController.view]) { + statsController.view.translatesAutoresizingMaskIntoConstraints = NO; + statsController.view.tag = 9999; + statsController.view.hidden = YES; + [self addChildViewController:statsController]; + [self.view addSubview:statsController.view]; + + [NSLayoutConstraint activateConstraints:@[ + [statsController.view.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [statsController.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [statsController.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [statsController.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + ]]; + } + } +} +- (BOOL)shouldFinishTransitionToExpandedContentModule { + if ([self.module isKindOfClass:%c(CCUILowPowerModule)]) { + return YES; + } + return %orig; +} +- (CGFloat)preferredExpandedContentHeight { + if ([self.module isKindOfClass:%c(CCUILowPowerModule)]) { + return HEIGHT * 0.5; + } + return %orig; +} +- (CGFloat)preferredExpandedContentWidth { + if ([self.module isKindOfClass:%c(CCUILowPowerModule)]) { + return WIDTH * 0.6; + } + return %orig; +} +- (void)willTransitionToExpandedContentMode:(BOOL)arg0 { + %orig; + if ([self.module isKindOfClass:%c(CCUILowPowerModule)]) { + UIView *statsView = (UIView *)[self.view viewWithTag:9999]; + statsView.hidden = !arg0; + + self.buttonView.hidden = arg0; + + if (arg0) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"AMPReloadStatsController" object:nil]; + } + } +} +%end + +%hook CCUIContentModuleContainerViewController +- (BOOL)clickPresentationInteractionShouldPresent:(id)arg0 { + if ([self.moduleIdentifier isEqualToString:@"com.apple.control-center.LowPowerModule"] && SYSTEM_VERSION_GREATER_THAN(@"15.0")) { + return YES; + } + return %orig; +} +- (void)viewDidLoad { + %orig; + if ([self.moduleIdentifier isEqualToString:@"com.apple.control-center.LowPowerModule"] && SYSTEM_VERSION_GREATER_THAN(@"15.0")) { + AMPStatsController *statsController = [[AMPStatsController alloc] init]; + if (![self.view.subviews containsObject:statsController.view]) { + statsController.view.translatesAutoresizingMaskIntoConstraints = NO; + statsController.view.tag = 9999; + statsController.view.hidden = YES; + [self addChildViewController:statsController]; + [self.view addSubview:statsController.view]; + + [NSLayoutConstraint activateConstraints:@[ + [statsController.view.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [statsController.view.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor], + [statsController.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16], + [statsController.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16], + [statsController.view.heightAnchor constraintEqualToConstant:HEIGHT * 0.6], + ]]; + } + } +} +- (void)transitionToExpandedMode:(BOOL)arg0 { + %orig; + if ([self.moduleIdentifier isEqualToString:@"com.apple.control-center.LowPowerModule"] && SYSTEM_VERSION_GREATER_THAN(@"15.0")) { + UIView *statsView = (UIView *)[self.view viewWithTag:9999]; + statsView.hidden = !arg0; + + self.contentViewController.view.hidden = arg0; + CCUIContentModuleContentContainerView *containerView = self.contentContainerView; + MTMaterialView *materialView = MSHookIvar(containerView, "_moduleMaterialView"); + materialView.hidden = arg0; + + if (arg0) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"AMPReloadStatsController" object:nil]; + } + } +} +%end +%end + static void reloadStatusBar(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { [[NSNotificationCenter defaultCenter] postNotificationName:@"AmpereUpdate" object:nil]; // Post local update notification } @@ -290,13 +576,13 @@ static void loadPreferences(CFNotificationCenterRef center, void *observer, CFSt overrideColorCritical = (overrideColorCriticalValue) ? [overrideColorCriticalValue boolValue] : NO; NSNumber *useGestureValue = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"useGesture" inDomain:domain]; useGesture = (useGestureValue) ? [useGestureValue boolValue] : NO; + NSNumber *useStatsModuleValue = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"useStatsModule" inDomain:domain]; + useStatsModule = (useStatsModuleValue) ? [useStatsModuleValue boolValue] : YES; NSNumber *textStyleValue = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"textStyle" inDomain:domain]; textStyle = (textStyleValue) ? [textStyleValue integerValue] : 0; NSNumber *fontSizeValue = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"fontSize" inDomain:domain]; fontSize = (fontSizeValue) ? [fontSizeValue integerValue] : 8; - NSNumber *batterySizingValue = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"batterySizing" inDomain:domain]; - batterySizing = (batterySizingValue) ? [batterySizingValue integerValue] : 1; } %ctor { @@ -310,5 +596,8 @@ static void loadPreferences(CFNotificationCenterRef center, void *observer, CFSt } else { %init(XVI); } + if (useStatsModule) { + %init(BatteryInfo); + } } } \ No newline at end of file diff --git a/Makefile b/Makefile index b1b87f0..adfbd16 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,6 @@ TARGET := iphone:clang:latest:14.0 -INSTALL_TARGET_PROCESSES = SpringBoard +INSTALL_TARGET_PROCESSES = SpringBoard Preferences ARCHS = arm64 arm64e -DEBUG = 0 -FINALPACKAGE = 1 include $(THEOS)/makefiles/common.mk @@ -10,6 +8,7 @@ TWEAK_NAME = Ampere Ampere_CFLAGS = -fobjc-arc -Wdeprecated-declarations -Wno-deprecated-declarations Ampere_FILES = Ampere.xm +Ampere_FRAMEWORKS = IOKit include $(THEOS_MAKE_PATH)/tweak.mk SUBPROJECTS += amperesettings diff --git a/amperesettings/AMPRootListController.h b/amperesettings/AMPRootListController.h index 79bedfd..d8e93d7 100644 --- a/amperesettings/AMPRootListController.h +++ b/amperesettings/AMPRootListController.h @@ -1,5 +1,7 @@ #import #import +#import +#import #import "AmpSwitch.h" #import "spawn.h" @@ -24,24 +26,20 @@ static NSString *domain = @"com.mtac.amp"; @property (assign, nonatomic) UINavigationBar *navigationBar; @end -@interface PSSpecifier : NSObject -@property (nonatomic, retain) NSString *name; -- (NSDictionary *)properties; -- (void)setProperty:(id)arg0 forKey:(id)arg1; -@end - @interface PSTableCell (Ampere) - (void)setValue:(id)arg0; @end -@interface PSControlTableCell : PSTableCell -- (UIControl *)control; -- (void)controlChanged:(UIControl *)arg1; +@interface FBSSystemService : NSObject ++ (id)sharedService; +- (void)sendActions:(id)arg1 withResult:(id)arg2; +@end + +@interface BSAction : NSObject @end -@interface PSSwitchTableCell : PSControlTableCell -- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)identifier specifier:(id)specifier; -- (void)controlChanged:(id)arg1; +@interface SBSRelaunchAction : BSAction ++ (id)actionWithReason:(id)arg1 options:(unsigned long long)arg2 targetURL:(id)arg3; @end @interface AmpColorCell : PSControlTableCell diff --git a/amperesettings/AMPRootListController.m b/amperesettings/AMPRootListController.m index 59a4b8d..4c4fb4f 100644 --- a/amperesettings/AMPRootListController.m +++ b/amperesettings/AMPRootListController.m @@ -9,6 +9,15 @@ - (NSArray *)specifiers { if (!_specifiers) { _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self]; } + + for (PSSpecifier *specifier in _specifiers) { + if (specifier.properties[@"iconImageSystem"] != nil) { + NSDictionary *systemIconDict = specifier.properties[@"iconImageSystem"]; + UIImageSymbolConfiguration *configuration = [UIImageSymbolConfiguration configurationWithPointSize:18 weight:UIImageSymbolWeightSemibold scale:UIImageSymbolScaleMedium]; + UIImage *systemIcon = [[UIImage systemImageNamed:systemIconDict[@"name"] withConfiguration:configuration] imageWithTintColor:[UIColor systemGreenColor]]; + [specifier setProperty:systemIcon forKey:@"iconImage"]; + } + } return _specifiers; } - (UITableViewStyle)tableViewStyle { @@ -24,6 +33,9 @@ - (instancetype)init { self.enableSwitch.trackOnTintColor = [UIColor secondaryLabelColor]; self.enableSwitch.trackOffTintColor = [UIColor secondaryLabelColor]; [self setupButtonMenu]; + + self.navigationController.navigationBar.prefersLargeTitles = YES; + self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeAlways; } return self; } @@ -53,7 +65,7 @@ - (void)viewWillAppear:(BOOL)animated { self.view.tintColor = [UIColor systemGreenColor]; [[UIApplication sharedApplication] keyWindow].tintColor = [UIColor systemGreenColor]; - [self.navigationController.navigationBar setPrefersLargeTitles:NO]; + [self.navigationController.navigationItem.navigationBar sizeToFit]; _table.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } - (void)viewWillDisappear:(BOOL)animated { @@ -65,7 +77,7 @@ - (void)viewDidLoad { self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeAlways; - self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)]; + self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 280)]; self.enableSwitch.translatesAutoresizingMaskIntoConstraints = NO; self.batteryView = [[UIImageView alloc] initWithFrame:CGRectZero]; @@ -86,13 +98,6 @@ - (void)viewDidLoad { glowanimation.repeatCount = HUGE_VALF; [self.batteryView.layer addAnimation:glowanimation forKey:@"glow"]; - UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - titleLabel.text = @"Ampere"; - titleLabel.textColor = [UIColor labelColor]; - titleLabel.font = [UIFont systemFontOfSize:36.0f weight:UIFontWeightBold]; - titleLabel.textAlignment = NSTextAlignmentCenter; - titleLabel.translatesAutoresizingMaskIntoConstraints = NO; - self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Charging", @"Normal", @"Low Power", @"Critical"]]; self.segmentedControl.translatesAutoresizingMaskIntoConstraints = NO; self.segmentedControl.frame = CGRectZero; @@ -116,21 +121,16 @@ - (void)viewDidLoad { [self.headerView addSubview:self.batteryView]; [self.headerView addSubview:self.sectionSegmentLabel]; [self.headerView addSubview:self.segmentedControl]; - [self.headerView addSubview:titleLabel]; [NSLayoutConstraint activateConstraints:@[ [self.batteryView.widthAnchor constraintEqualToConstant:50], [self.batteryView.heightAnchor constraintEqualToConstant:75], - [self.batteryView.trailingAnchor constraintEqualToAnchor:self.headerView.centerXAnchor constant:-20], - [self.batteryView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor], - [self.enableSwitch.centerYAnchor constraintEqualToAnchor:self.batteryView.centerYAnchor], - [self.enableSwitch.leadingAnchor constraintEqualToAnchor:self.headerView.centerXAnchor constant:20], + [self.batteryView.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor], + [self.batteryView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor constant:8], + [self.enableSwitch.topAnchor constraintEqualToAnchor:self.batteryView.bottomAnchor constant:8], + [self.enableSwitch.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor], [self.enableSwitch.widthAnchor constraintEqualToConstant:50], [self.enableSwitch.heightAnchor constraintEqualToConstant:40], - [titleLabel.topAnchor constraintEqualToAnchor:self.batteryView.bottomAnchor constant:10], - [titleLabel.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor], - [titleLabel.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor], - [titleLabel.heightAnchor constraintEqualToConstant:50], [self.segmentedControl.bottomAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:-30], [self.segmentedControl.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:16], [self.segmentedControl.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-16], @@ -182,48 +182,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N return [super tableView:tableView cellForRowAtIndexPath:indexPath]; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { - UIView *sectionHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; - UIImage *sectionImage; - UIImageView *sectionImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)]; - sectionImageView.translatesAutoresizingMaskIntoConstraints = NO; - sectionImageView.contentMode = UIViewContentModeScaleAspectFit; - - switch (section) { - case 0: - sectionImage = [[UIImage systemImageNamed:@"percent"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 1: - sectionImage = [[UIImage systemImageNamed:@"battery.100"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 2: - sectionImage = [[UIImage systemImageNamed:@"textformat"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 3: - sectionImage = [[UIImage systemImageNamed:@"square.fill.on.square.fill"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 4: - sectionImage = [[UIImage systemImageNamed:@"bolt.fill"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 5: - sectionImage = [[UIImage systemImageNamed:@"hand.point.up.fill"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - case 6: - sectionImage = [[UIImage systemImageNamed:@"link"] imageWithTintColor:[UIColor systemGreenColor]]; - break; - default: - break; + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; + NSString *title = [self tableView:tableView titleForHeaderInSection:section]; + if (title != nil) { + titleLabel.textColor = [UIColor secondaryLabelColor]; + titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + titleLabel.text = [NSString stringWithFormat:@" %@", title]; } - sectionImageView.image = sectionImage; - [sectionHeader addSubview:sectionImageView]; - - [NSLayoutConstraint activateConstraints:@[ - [sectionImageView.leadingAnchor constraintEqualToAnchor:sectionHeader.leadingAnchor constant:8], - [sectionImageView.centerYAnchor constraintEqualToAnchor:sectionHeader.centerYAnchor], - [sectionImageView.widthAnchor constraintEqualToConstant:20], - [sectionImageView.heightAnchor constraintEqualToConstant:20], - ]]; - - return sectionHeader; + return titleLabel; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if ([self tableView:tableView titleForHeaderInSection:section] != nil) { @@ -239,7 +205,7 @@ - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger titleLabel.textAlignment = NSTextAlignmentCenter; NSString *primary = @"Ampere"; - NSString *secondary = @"v1.0.8 © MTAC"; + NSString *secondary = @"v1.2 © MTAC"; NSMutableAttributedString *final = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@\n%@", primary, secondary]]; [final addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:18 weight:UIFontWeightSemibold] range:[final.string rangeOfString:primary]]; @@ -363,9 +329,10 @@ - (void)respring { [self presentViewController:applyAlert animated:true completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.75 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){ - pid_t pid; - const char *args[] = {"killall", "backboardd", NULL}; - posix_spawn(&pid, "/usr/bin/killall", NULL, NULL, (char *const *)args, NULL); + SBSRelaunchAction *respringAction = [NSClassFromString(@"SBSRelaunchAction") actionWithReason:@"RestartRenderServer" options:4 targetURL:[NSURL URLWithString:@"prefs:root=Bridge"]]; + FBSSystemService *frontBoardService = [NSClassFromString(@"FBSSystemService") sharedService]; + NSSet *actions = [NSSet setWithObject:respringAction]; + [frontBoardService sendActions:actions withResult:nil]; }); } - (void)reset { @@ -557,7 +524,9 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)identifier s if (self) { self.accessoryView = self.control; self.detailTextLabel.text = specifier.properties[@"subtitle"] ?: @""; - self.detailTextLabel.numberOfLines = 1; + self.detailTextLabel.numberOfLines = 2; + + [self _updateControl]; } return self; } @@ -568,75 +537,50 @@ - (id)newControl { selectorButton.showsMenuAsPrimaryAction = YES; selectorButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; [selectorButton setTitleColor:[UIColor secondaryLabelColor] forState:UIControlStateNormal]; - + [self _updateControl]; return selectorButton; } - (UIMenu *)menu { - UIAction *defaultAction = [UIAction actionWithTitle:@"Default" image:[UIImage systemImageNamed:@"applelogo"] identifier:nil handler:^(__kindof UIAction *_Nonnull action) { - [[NSUserDefaults standardUserDefaults] setObject:@0 forKey:@"textStyle" inDomain:domain]; - [self setValue:@0]; - [self _updateControl]; - }]; - UIAction *transparentAction = [UIAction actionWithTitle:@"Transparent" image:[UIImage systemImageNamed:@"circle"] identifier:nil handler:^(__kindof UIAction *_Nonnull action) { - [[NSUserDefaults standardUserDefaults] setObject:@1 forKey:@"textStyle" inDomain:domain]; - [self setValue:@1]; - [self _updateControl]; - }]; - UIAction *customAction = [UIAction actionWithTitle:@"Custom" image:[UIImage systemImageNamed:@"paintpalette.fill"] identifier:nil handler:^(__kindof UIAction *_Nonnull action) { - [[NSUserDefaults standardUserDefaults] setObject:@2 forKey:@"textStyle" inDomain:domain]; - [self setValue:@2]; - [self _updateControl]; - }]; - - switch ([[[NSUserDefaults standardUserDefaults] objectForKey:@"textStyle" inDomain:domain] integerValue]) { - case 0: - defaultAction.state = UIMenuElementStateOn; - transparentAction.state = UIMenuElementStateOff; - customAction.state = UIMenuElementStateOff; - break; - default: - case 1: - defaultAction.state = UIMenuElementStateOff; - transparentAction.state = UIMenuElementStateOn; - customAction.state = UIMenuElementStateOff; - break; - case 2: - defaultAction.state = UIMenuElementStateOff; - transparentAction.state = UIMenuElementStateOff; - customAction.state = UIMenuElementStateOn; - break; + NSMutableArray *menuItems = [NSMutableArray new]; + NSArray *values = self.specifier.properties[@"values"]; + NSArray *titles = self.specifier.properties[@"titles"]; + NSArray *images = self.specifier.properties[@"images"]; + // NSString *key = [self.specifier.properties objectForKey:@"key"]; + for (NSInteger i = 0; i < values.count; i++) { + UIAction *action = [UIAction actionWithTitle:titles[i] image:[UIImage systemImageNamed:images[i]] identifier:nil handler:^(__kindof UIAction *_Nonnull action) { + NSInteger valueIndex = [[values objectAtIndex:i] integerValue]; + [self setValue:[NSNumber numberWithInteger:valueIndex]]; + [self _updateControl]; + }]; + if ([[self value] integerValue] == i) { + action.state = UIMenuElementStateOn; + } else { + action.state = UIMenuElementStateOff; + } + [menuItems addObject:action]; } - UIMenu *menuActions = [UIMenu menuWithTitle:@"" children:@[customAction, transparentAction, defaultAction]]; + UIMenu *menuActions = [UIMenu menuWithTitle:@"" children:menuItems]; return menuActions; } -- (void)setValue:(id)arg0 { - [super setValue:arg0]; -} - (void)refreshCellContentsWithSpecifier:(PSSpecifier *)specifier { [super refreshCellContentsWithSpecifier:specifier]; [self _updateControl]; } - (void)_updateControl { - [[self _viewControllerForAncestor] reloadSpecifiers]; + NSArray *titles = self.specifier.properties[@"titles"]; + NSInteger value = [[self value] integerValue]; CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)@"com.mtac.amp/preferences.changed", nil, nil, true); CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)@"com.mtac.amp/statusbar.changed", nil, nil, true); - NSString *title; - switch ([[[NSUserDefaults standardUserDefaults] objectForKey:@"textStyle" inDomain:domain] integerValue]) { - case 0: - title = @"Default ›"; - break; - default: - case 1: - title = @"Transparent ›"; - break; - case 2: - title = @"Custom ›"; - break; - } - [(UIButton *)self.control setTitle:title forState:UIControlStateNormal]; + [(UIButton *)self.control setMenu:[self menu]]; + [(UIButton *)self.control setTitle:[titles[value] stringByAppendingString:@" ›"] forState:UIControlStateNormal]; +} +- (void)setValue:(id)arg0 { + [super setValue:arg0]; + NSString *key = [self.specifier.properties objectForKey:@"key"]; + [[NSUserDefaults standardUserDefaults] setObject:arg0 forKey:key inDomain:domain]; } @end diff --git a/amperesettings/Resources/Root.plist b/amperesettings/Resources/Root.plist index d8b6eb1..6f2c2ec 100644 --- a/amperesettings/Resources/Root.plist +++ b/amperesettings/Resources/Root.plist @@ -18,13 +18,36 @@ defaults com.mtac.amp label - Percentage Color + Percent Color subtitle Swipe for more info key textStyle + values + + 0 + 1 + 2 + + titles + + Default + Transparent + Custom + + images + + applelogo + shadow + paintpalette.fill + PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + percent + cellClass @@ -43,6 +66,11 @@ textColor PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + paintbrush.pointed.fill + cell @@ -64,13 +92,18 @@ subtitle Override normal color. Swipe cell to set color key - + overrideColorStandard id overrideColorStandard height 85 PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + battery.100 + cell @@ -93,6 +126,11 @@ 85 PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + battery.100 + cell @@ -115,6 +153,11 @@ 85 PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + battery.100 + cell @@ -137,6 +180,11 @@ 85 PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + battery.100 + cell @@ -167,36 +215,11 @@ 65 PostNotification com.mtac.amp/preferences.changed - + iconImageSystem - cell - PSGroupCell - label - Sizing - - - cell - PSSegmentCell - default - 1 - defaults - com.mtac.amp - key - batterySizing - validValues - - 0 - 1 - - validTitles - - Regular - Increased - - alignment - 4 - PostNotification - com.mtac.amp/preferences.changed + name + textformat + cell @@ -225,6 +248,11 @@ 85 PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + bolt.fill + cell @@ -244,7 +272,7 @@ label Use Low Power Gesture subtitle - Tap to toggle Low Power mode. SpringBoard only + Tap battery icon to toggle Low Power mode key useGesture height @@ -253,6 +281,44 @@ lowPower PostNotification com.mtac.amp/preferences.changed + iconImageSystem + + name + hand.point.up.fill + + + + cell + PSGroupCell + label + Control Center + + + cell + PSSwitchCell + cellClass + AmpSwitchCell + default + + defaults + com.mtac.amp + label + Enable Battery Info + subtitle + Force Touch on Low Power Mode module in Control Center to view + key + useStatsModule + height + 85 + id + statsModule + PostNotification + com.mtac.amp/preferences.changed + iconImageSystem + + name + switch.2 + cell @@ -273,6 +339,11 @@ https://github.com/MTACS/Ampere height 70 + iconImageSystem + + name + link + cell @@ -288,6 +359,6 @@ title - + Ampere diff --git a/control b/control index 899c40e..3324c7e 100644 --- a/control +++ b/control @@ -1,9 +1,9 @@ Package: com.mtac.ampere Name: Ampere -Version: 1.0.8 +Version: 1.2 Architecture: iphoneos-arm Description: iOS 16 Style Battery Indicator Maintainer: MTAC Author: MTAC Section: Tweaks -Depends: mobilesubstrate, firmware (>= 14.0) +Depends: mobilesubstrate, firmware (>= 14.0), preferenceloader