1
0
mirror of https://github.com/Burrit0z/kai synced 2025-07-02 06:46:47 +00:00

Compare commits

15 Commits

Author SHA1 Message Date
ded80ae5a6 rebrand 2021-05-16 16:38:00 -04:00
df58fc48a7 Merge pull request #3 from evanknapke/master
Fix grammar issues and improve formatting
2021-01-03 10:22:26 -05:00
f8092f7b0d Update LICENSE 2021-01-02 21:03:17 -05:00
4e971ed592 Update Kai.h 2020-12-31 10:29:03 -05:00
dfe38157b1 layout properly 2020-12-25 11:07:05 -05:00
2250468f6f better placement options 2020-12-25 00:23:34 -05:00
c5add0a58a fix shit, other stuff. reformat comments 2020-12-24 23:24:17 -05:00
08027c7e9c Fix grammar issues and improve formatting 2020-10-01 11:38:06 -04:00
be1399f3d2 changed default preferences 2020-09-25 13:40:53 -04:00
e7f00664cd fix ios 14.0.1 crash (temp fix) 2020-09-25 13:25:40 -04:00
cee2aa6a0f Update KAIBatteryCell.mm 2020-09-24 20:00:55 -04:00
b734b0681b finish ios 14 (works ios 14.0) 2020-09-24 13:46:37 -04:00
1ef3ed3576 start ios 14 work 2020-09-22 19:20:19 -04:00
67bec552b4 Create LICENSE 2020-09-01 22:31:43 -04:00
52a4f5aa9a manually update control file 2020-08-30 09:38:32 -04:00
13 changed files with 565 additions and 367 deletions

View File

@ -51,3 +51,11 @@
- Fix very unoptimized code, made it more-ish optimized
- Below music option now moves kai just below the media controls, and not to the very bottom.
- Fixed kai going below Axon with below music player option on
1.4.0:
- Adds iOS 14 support
1.5.0:
- Replace the code that handles hiding kai when media plays
- Fix edge cases where battery info would not update completely until an update was called for again
- There are now 3 placement options: Top, Below Media Player, and Bottom

View File

@ -9,16 +9,18 @@
NSString *deviceName = device.name;
double batteryPercentage = device.percentCharge;
BOOL charging = MSHookIvar<long long>(device, "_charging");
BOOL LPM = MSHookIvar<BOOL>(device, "_batterySaverModeActive");
BOOL charging = [device isCharging];
BOOL LPM = [device isBatterySaverModeActive];
UIView *blur;
UIView *blurPlatter = [[UIView alloc] init];
if (bannerStyle == 1) {
if (kCFCoreFoundationVersionNumber > 1600) {
if (kCFCoreFoundationVersionNumber > 1600 && kCFCoreFoundationVersionNumber < 1740) {
blur = [[[objc_getClass("MTMaterialView") class] alloc] _initWithRecipe:1 configuration:1 initialWeighting:1 scaleAdjustment:nil];
} else if (kCFCoreFoundationVersionNumber < 1600) {
} else if (kCFCoreFoundationVersionNumber < 1600) { // ios 12
blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
} else if(kCFCoreFoundationVersionNumber >= 1740) { // ios 14 :fr:
blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]];
}
} else if (bannerStyle == 2) {
blur = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
@ -75,10 +77,13 @@
[self.battery setPinColorAlpha:1.0];
}
UIImage *glyph = [device glyph];
UIImage *glyph = ios13 ? [device glyph] : [device batteryWidgetGlyph];
glyph = [glyph imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.glyphView = [[UIImageView alloc] init];
self.glyphView.contentMode = UIViewContentModeScaleAspectFit;
[self.glyphView setImage:glyph];
self.glyphView.tintColor = [UIColor whiteColor];
[self addSubview:blurPlatter];
[blurPlatter addSubview:blur];
@ -193,10 +198,10 @@
- (void)updateInfo {
if (self.device != nil) {
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");
NSString *deviceName = [self.device name];
double batteryPercentage = [self.device percentCharge];
BOOL charging = [self.device isCharging];
BOOL LPM = [self.device isBatterySaverModeActive];
self.label.text = [NSString stringWithFormat:@"%@", deviceName];
[self.percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger)batteryPercentage)]];
@ -218,9 +223,6 @@
}
[self.percentLabel setText:[NSString stringWithFormat:@"%ld%%", (long)((NSInteger)batteryPercentage)]];
self.battery.chargePercent = (batteryPercentage * 0.01);
[self.glyphView setImage:[self.device glyph]];
} else {
}
}

View File

@ -57,38 +57,32 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
return self;
}
- (void)resetOffset {
- (void)resetOffset { // holy fucking shit i just read this method, what is this garbage????
if (kaiAlign != 0 && reAlignSelf) {
[UIView animateWithDuration:0.2
animations:^{
[UIView animateWithDuration:0.2 animations:^{
if (bannerAlign == 1) { // left
[self setContentOffset:CGPointMake(0 + horizontalOffset, self.contentOffset.y)];
[self setContentOffset:CGPointMake(0 + horizontalOffset, self.contentOffset.y)];
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
} else if (bannerAlign == 2) { // center
[self setContentOffset:CGPointMake(((-1 * self.stackHolder.frame.size.width) / 2) + (self.stack.frame.size.width / 2) + horizontalOffset, self.contentOffset.y)];
CGFloat top = 0, left = 0;
if (self.contentSize.width < self.bounds.size.width) {
left = (self.bounds.size.width - self.contentSize.width) * 0.5f;
}
if (self.contentSize.height < self.bounds.size.height) {
top = (self.bounds.size.height - self.contentSize.height) * 0.5f;
}
if (self.contentSize.width < self.bounds.size.width) left = (self.bounds.size.width - self.contentSize.width) * 0.5f;
if (self.contentSize.height < self.bounds.size.height) top = (self.bounds.size.height - self.contentSize.height) * 0.5f;
self.contentInset = UIEdgeInsetsMake(top, left, top, left);
} else if (bannerAlign == 3) { // right
[self setContentOffset:CGPointMake((-1 * self.stackHolder.frame.size.width) + self.stack.frame.size.width + horizontalOffset, self.contentOffset.y)];
CGFloat top = 0, left = 0;
if (self.contentSize.width < self.bounds.size.width) {
left = (self.bounds.size.width - self.contentSize.width);
}
if (self.contentSize.height < self.bounds.size.height) {
top = (self.bounds.size.height - self.contentSize.height);
}
if(self.contentSize.width < self.bounds.size.width) left = (self.bounds.size.width - self.contentSize.width);
if(self.contentSize.height < self.bounds.size.height) top = (self.bounds.size.height - self.contentSize.height);
self.contentInset = UIEdgeInsetsMake(top, left, top, left);
}
}];
}
}
@ -98,9 +92,14 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
}
- (void)updateBattery {
if(self.isUpdating == YES) {
self.queued = YES;
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
NSArray *devices = [bcb connectedDevices];
if (self.oldCountOfDevices == -100) {
self.oldCountOfDevices = [devices count] + 1;
@ -110,7 +109,6 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
}
if (!self.isUpdating && self.oldCountOfDevices != 0 && ([devices count] + 1 == self.oldCountOfDevices || [devices count] - 1 == self.oldCountOfDevices || [devices count] == self.oldCountOfDevices)) {
//if(!self.isUpdating) {
self.isUpdating = YES;
@ -119,11 +117,11 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
for (BCBatteryDevice *device in devices) {
KAIBatteryCell *cell = [device kaiCellForDevice];
BOOL charging = MSHookIvar<long long>(device, "_charging");
BOOL internal = MSHookIvar<BOOL>(device, "_internal");
BOOL charging = [device isCharging];
BOOL internal = [device isInternal];
BOOL shouldAdd = NO;
BOOL fake = MSHookIvar<BOOL>(device, "_fake");
NSString *deviceName = MSHookIvar<NSString *>(device, "_name");
BOOL fake = [device isFake];
NSString *deviceName = [device name];
if (!fake) {
if (showAll) {
@ -187,7 +185,7 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
[self.stack removeArrangedSubview:cell];
cell.alpha = 1;
}];
NSString *deviceName = MSHookIvar<NSString *>(cell.device, "_name");
NSString *deviceName = [cell.device name];
[deviceNames removeObject:deviceName];
[cellsForDeviceNames removeObject:cell];
}
@ -209,11 +207,10 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
}
}
// isUpdating is set to NO in this block
// adds a cooldown, essentially
queueTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(dispatchQueue) userInfo:nil repeats:NO];
//self.isUpdating = NO;
} else if (self.isUpdating) {
self.queued = YES;
}
self.oldCountOfDevices = [devices count];
@ -243,8 +240,8 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
[s removeArrangedSubview:self];
[self removeFromSuperview];
} else if (self.number != 0 && self.superview == nil && shouldBeAdded == YES) {
[[[[objc_getClass("CSAdjunctListView") class] sharedListViewForKai] stackView] addArrangedSubview:self];
//[self performSelector:@selector(calculateHeight) withObject:self afterDelay:0.1];
Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
[cls reorderKai];
}
[UIView animateWithDuration:0.3
@ -311,7 +308,7 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
}
BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
NSArray *devices = [bcb connectedDevices];
for (BCBatteryDevice *device in devices) {
[device resetKaiCellForNewPrefs];
}
@ -336,16 +333,17 @@ NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
}
- (void)dispatchQueue {
[queueTimer invalidate];
queueTimer = nil;
self.isUpdating = NO;
if (self.queued) {
self.queued = NO;
[self updateBattery];
if ([self.superview.superview.superview respondsToSelector:@selector(fixComplicationsViewFrame)]) {
[(NCNotificationListView *)(self.superview.superview.superview) fixComplicationsViewFrame];
}
self.queued = NO;
}
[queueTimer invalidate];
queueTimer = nil;
}
+ (KAIBatteryPlatter *)sharedInstance {

View File

@ -19,7 +19,7 @@
@interface BCBatteryDeviceController : NSObject
@property (nonatomic, strong) NSArray *sortedDevices;
- (id)_sortedDevices;
- (id)connectedDevices;
+ (id)sharedInstance;
@end
@ -27,12 +27,13 @@
@property (nonatomic, strong) id kaiCell;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) long long percentCharge;
@property (nonatomic, assign) BOOL charging;
@property (nonatomic, assign) BOOL fake;
@property (nonatomic, assign) BOOL internal;
@property (nonatomic, assign) BOOL batterySaverModeActive;
@property (nonatomic, assign, getter=isCharging) BOOL charging;
@property (nonatomic, assign, getter=isFake) BOOL fake;
@property (nonatomic, assign, getter=isInternal) BOOL internal;
@property (nonatomic, assign, getter=isBatterySaverModeActive) BOOL batterySaverModeActive;
@property (nonatomic, strong) NSString *identifier;
- (id)glyph;
- (id)glyph; // ios 13
- (id)batteryWidgetGlyph; // ios 14
- (id)kaiCellForDevice;
- (void)resetKaiCellForNewPrefs;
@end

24
Kai.h
View File

@ -4,14 +4,21 @@
#import <objc/runtime.h>
#define KAISelf ((CSAdjunctListView *)self) // for use when calling self in KAITarget
#define afterMusicIndex(cls, obj) [[[cls sharedListViewForKai] stackView].subviews indexOfObject:obj]
@interface CSAdjunctListView : UIView
@property (nonatomic, assign) BOOL hasKai;
- (UIStackView *)stackView;
- (void)_layoutStackView;
- (void)setStackView:(UIStackView *)arg1;
- (NSInteger)getMediaIndexForClass:(Class)cls;
- (void)performReorder;
+ (id)sharedListViewForKai;
+ (void)reorderKai;
@end
@interface SBMediaController : NSObject
@property (nonatomic, strong) id nowPlayingApplication;
- (BOOL)isPlaying;
@end
@interface CALayer (kai)
@ -26,10 +33,16 @@
+ (APEPlatter *)sharedInstance;
@end
@interface APEPlacceholder : UIView
+ (APEPlacceholder *)sharedInstance;
@end
@interface NCNotificationListView : UIView
- (void)fixComplicationsViewFrame;
@end
BOOL ios13 = NO;
BOOL isUpdating = NO;
BOOL shouldBeAdded = YES;
@ -38,7 +51,6 @@ BOOL enabled;
BOOL disableGlyphs;
BOOL hidePercent;
BOOL showAll;
BOOL belowMusic;
BOOL hideDeviceLabel;
BOOL hideChargingAnimation;
BOOL showAllMinusInternal;
@ -50,6 +62,7 @@ BOOL extraPaddingAfter;
NSInteger bannerStyle;
NSInteger bannerAlign;
NSInteger textColor;
NSInteger placement;
double spacing;
double glyphSize;
double bannerHeight;
@ -111,12 +124,12 @@ static void preferencesChanged() {
disableGlyphs = boolValueForKey(@"disableGlyphs", NO);
hidePercent = boolValueForKey(@"hidePercent", NO);
bannerStyle = numberForValue(@"bannerStyle", 1);
showAll = boolValueForKey(@"showAll", NO);
showAll = boolValueForKey(@"showAll", YES);
bannerWidthFactor = numberForValue(@"bannerWidthFactor", 0);
hideDeviceLabel = boolValueForKey(@"hideDeviceLabel", NO);
bannerAlign = numberForValue(@"bannerAlign", 2);
horizontalOffset = numberForValue(@"horizontalOffset", 0);
belowMusic = boolValueForKey(@"belowMusic", NO);
placement = numberForValue(@"placement", 1);
hideChargingAnimation = boolValueForKey(@"hideChargingAnimation", YES);
textColor = numberForValue(@"textColor", 0);
bannerAlpha = numberForValue(@"bannerAlpha", 1);
@ -136,11 +149,12 @@ static void preferencesChanged() {
static void applyPrefs() {
preferencesChanged();
Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
isUpdating = YES;
[[KAIBatteryPlatter sharedInstance] refreshForPrefs]; // so hard (not)
[(CSAdjunctListView *)([KAIBatteryPlatter sharedInstance].superview.superview) _layoutStackView];
[cls reorderKai];
[[NSNotificationCenter defaultCenter] postNotificationName:@"KaiResetOffset" object:nil userInfo:nil];
isUpdating = NO;

114
Kai.xm
View File

@ -1,49 +1,40 @@
#import "Kai.h"
CSAdjunctListView *list;
Class mediaClass;
%group main
%hook Media
- (void)dealloc {
%orig;
if(removeForMedia) {
shouldBeAdded = YES;
[[KAIBatteryPlatter sharedInstance] updateBattery];
%hook SBMediaController
- (BOOL)isPlaying {
Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
BOOL playing = %orig;
if(!belowMusic) { //cursed
[[[cls sharedListViewForKai] stackView] removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[[[cls sharedListViewForKai] stackView] insertArrangedSubview:[KAIBatteryPlatter sharedInstance] atIndex:0];
}
}
if(!removeForMedia) {
[cls reorderKai];
return playing;
}
- (void)didMoveToSuperview {
%orig;
Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
if([[[cls sharedListViewForKai] stackView].arrangedSubviews containsObject:self]) {
if(belowMusic) {//cursed
[[[cls sharedListViewForKai] stackView] removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[[[cls sharedListViewForKai] stackView] insertArrangedSubview:[KAIBatteryPlatter sharedInstance] atIndex:afterMusicIndex(cls, self)];
} else {
[[[cls sharedListViewForKai] stackView] removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[[[cls sharedListViewForKai] stackView] insertArrangedSubview:[KAIBatteryPlatter sharedInstance] atIndex:0];
}
if(removeForMedia) {
// if removeForMedia
if(self.nowPlayingApplication && shouldBeAdded) {
// a valid playing app, and it was shown
shouldBeAdded = NO;
[[KAIBatteryPlatter sharedInstance] removeFromSuperview];
[[[cls sharedListViewForKai] stackView] removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
}
[[cls sharedListViewForKai] _layoutStackView];
return playing;
} else if(!playing && self.nowPlayingApplication == nil) {
// not playing and the app is nil
shouldBeAdded = YES;
// if we don't want to hide kai, fix its order
[cls reorderKai];
}
return playing;
}
%end
@ -74,7 +65,7 @@ Class mediaClass;
if(![arg1.subviews containsObject:battery]) { // if not added
// add kai to the stack view
[arg1 addArrangedSubview:battery];
[self performReorder];
}
[battery updateBattery];
@ -91,7 +82,6 @@ Class mediaClass;
isUpdating = YES;
//NSLog(@"kai: kai info will update");
dispatch_async(dispatch_get_main_queue(), ^{
[[KAIBatteryPlatter sharedInstance] updateBattery];
@ -113,11 +103,59 @@ Class mediaClass;
}
%new
- (NSInteger)getMediaIndexForClass:(Class)cls {
UIView *mediaPlayer;
int index = 0;
for(UIView *subview in [self stackView].subviews) {
if([subview isKindOfClass:cls]) {
return index;
}
index++;
}
return NSNotFound;
}
%new
- (void)performReorder {
UIStackView *stack = [self stackView];
if(placement == 1) { //top
BOOL isAperio = NO;
@try {
isAperio = [stack.subviews[0] isKindOfClass:%c(APEPlatter)];
// index 0 would be the platter, 1 would be placeholder
} @catch(NSException *exc) {}
[stack removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[stack insertArrangedSubview:[KAIBatteryPlatter sharedInstance] atIndex:isAperio];
// so, 0 if not aperio, 1 if aperio
} else if(placement == 2) { //after media
Class mediaClass = kCFCoreFoundationVersionNumber > 1600 ? %c(CSAdjunctItemView) : %c(SBDashBoardAdjunctItemView);
NSInteger mediaIndex = [self getMediaIndexForClass:mediaClass];
if(mediaIndex == NSNotFound) mediaIndex = 0;
[stack removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[stack insertArrangedSubview:[KAIBatteryPlatter sharedInstance] atIndex:mediaIndex];
} else if(placement == 3) { // bottom
[stack removeArrangedSubview:[KAIBatteryPlatter sharedInstance]];
[stack addArrangedSubview:[KAIBatteryPlatter sharedInstance]];
}
[self _layoutStackView];
}
%new
+ (id)sharedListViewForKai {
return list;
}
%new
+ (void)reorderKai {
NSLog(@"[Kai]: Reordering kai");
[[self sharedListViewForKai] performReorder];
}
%end
%hook SBCoverSheetPrimarySlidingViewController
@ -188,6 +226,8 @@ Class mediaClass;
if(hideChargingAnimation) {
// Yeah bro this just makes the method never call to show the charging thing
%orig(NO,NO,NO);
} else {
%orig(arg1, arg2, arg3);
}
}
@ -195,6 +235,8 @@ Class mediaClass;
if(hideChargingAnimation) {
// Same idea
%orig(NO,NO,NO,NO);
} else {
%orig(arg1, arg2, arg3, arg4);
}
}
@ -215,14 +257,16 @@ Class mediaClass;
// Bro Muirey helped me figure out a logical way to do this because iOS 12-13 classes have changed
mediaClass = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctItemView") class]) : ([objc_getClass("SBDashBoardAdjunctItemView") class]);
Class cls = kCFCoreFoundationVersionNumber > 1600 ? %c(CSAdjunctListView) : %c(SBDashBoardAdjunctListView);
Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
Class CSCls = kCFCoreFoundationVersionNumber > 1600 ? %c(CSCoverSheetViewController) : %c(SBDashBoardViewController);
Class CSCls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSCoverSheetViewController") class]) : ([objc_getClass("SBDashBoardViewController") class]);
if(kCFCoreFoundationVersionNumber < 1740) {
ios13 = YES; // wow very pog version you have
}
if(enabled) {
%init(main, Media = mediaClass, KAITarget = cls, KAICSTarget = CSCls); //BIG BRAIN BRO!!
%init(main, KAITarget = cls, KAICSTarget = CSCls); // BIG BRAIN BRO!!
}
NSLog(@"[kai]: loaded into %@", [NSBundle mainBundle].bundleIdentifier);

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 ren7995
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,9 +1,12 @@
Package: com.burritoz.kai
Name: Kai
Version: 1.3.1
Version: 1.5.1
Architecture: iphoneos-arm
Description: Device battery indicators on your lock screen!
Maintainer: burrit0z
Author: burrit0z
Maintainer: ren7995
Author: ren7995
Section: Tweaks
Depends: mobilesubstrate (>= 0.9.5000), preferenceloader, ws.hbang.common (>=1.14)
Icon: https://chariz.com/cdn/icon/kai/icon@3x.png
Depiction: https://repo.chariz.com/package/com.burritoz.kai/
SileoDepiction: https://repo.chariz.com/api/sileo/package/com.burritoz.kai/depiction.json

View File

@ -1,25 +1,36 @@
# kai
Oh my gosh this code is so bad
## All your batteries, at a glance
kai will show any Bluetooth device that provides battery information, meaning you can check the battery of your phone, your watch, your AirPods, and your AirPods case, all from the lock screen. Quickly and easily.
## All Your Batteries, at a Glance
kai will show any Bluetooth device that provides battery information, meaning you can check the battery of your iPhone, your Apple Watch, your AirPods, and your AirPods case, all from the lockscreen. Quickly and easily.
## Compatibility
kai works with many, many lock screen tweaks, such as Kalm, Grupi, Axon, Quart, Complications, Watermelon, Veza, QuickLS, Jellyfish, and way more!
kai works with many, many lockscreen tweak:
- Kalm
- Grupi
- Axon
- Quart
- Complications
- Watermelon
- Veza
- QuickLS
- Jellyfish
- And more!
## Make it yours
## Make it Yours
kai comes with a multitude of customization options, so you can fine-tune your settings to fit you and your setup.
## Big and Bold, or small and simple
## Big and Bold, or Small and Simple
kai offers two main options for displaying battery information. (a) Vertical mode, to make kai fit in with your notifications, and (b) horizontal mode, an unobtrusive, scrollable, and tiny mode that doesn't take up any more space on your lock screen than it needs to.
## Full feature/option list
## Full Feature/Option List
- Option to hide the large battery view coversheet charging animations on the lock screen
- Show all or just charging devices on kai
- Option to show Bluetooth devices always, and the phone just when charging
- Option to show Bluetooth devices always, and the phone only when charging
- Option to hide device glyphs on kai cells
- Option to hide percent label on kai cells
- Option to hide the device name label on kai cells
- Two-axis options, a vertical mode, or horizontal mode
- Two-axis options: vertical mode, or horizontal mode
- Choose between adaptive, light, or dark mode for kai's cells
- Choose between adaptive, white, or black text for labels on kai's cells
- Choose to align kai to the left, right, or center for vertical mode
@ -37,4 +48,4 @@ kai offers two main options for displaying battery information. (a) Vertical mod
Special thanks to my amazing beta testers in the server I co-own with Thomz. I could not have tested kai so extensively and brought it to where it is today without them. Thanks to Thomz (@Thomzi07 on Twitter) for making kai's icon, and depiction screenshots, and Thenatis (@thenatis1 on Twitter) for helping with design, and for making the banner for kai. Additionally, kai is inspired by LaughingQuoll's Maple tweak series and Apple's AirPower design. kai was built with inspiration from this. However, the main reason I made kai is because the Maple series does not work with notification grouping tweaks like Axon and Grupi. Additionally, kai features a wider range of customization options.
## Socials and Support
If you are encountering issues, or simply wish to reach out, you can contact me at my email (burrit0ztweaks@gmail.com) or join the discord server I co-own with Thomz to get support. Discord server invite link: https://discord.gg/NQ3uXtJ
If you are encountering issues, or simply wish to reach out, you can contact me at my email (lau7995ren@gmail.com) or join the discord server I co-own with Thomz to get support. Discord server invite link: https://discord.gg/NQ3uXtJ

View File

@ -9,14 +9,24 @@ static inline NSString *getPackageVersion() {
int status;
NSMutableArray<NSString *> *argsv0 = [NSMutableArray array];
for (NSString *string in @[ @"/usr/bin/dpkg-query", @"-Wf", packageVersion, @"com.burritoz.kai" ]) {
for (NSString *string in @[
@"/usr/bin/dpkg-query", @"-Wf", packageVersion, @"com.burritoz.kai"
]) {
[argsv0
addObject:[NSString stringWithFormat:@"'%@'",
[string stringByReplacingOccurrencesOfString:@"'"
addObject:
[NSString
stringWithFormat:
@"'%@'",
[string
stringByReplacingOccurrencesOfString:@"'"
withString:@"\\'"
options:NSRegularExpressionSearch
range:NSMakeRange(
0, string.length)]]];
options:
NSRegularExpressionSearch
range:
NSMakeRange(
0,
string
.length)]]];
}
NSString *argsv1 = [argsv0 componentsJoinedByString:@" "];
@ -45,16 +55,20 @@ static inline NSString *getPackageVersion() {
////////
static void respringNeeded() {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Respring"
message:@"Changing this requires a respring for it to take effect. Would you like to respring now?"
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Respring"
message:@"Changing this requires a respring for it to "
@"take effect. Would you like to respring now?"
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"No"
UIAlertAction *defaultAction =
[UIAlertAction actionWithTitle:@"No"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action){
}];
UIAlertAction *yes = [UIAlertAction actionWithTitle:@"Respring"
UIAlertAction *yes = [UIAlertAction
actionWithTitle:@"Respring"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
NSTask *t = [[NSTask alloc] init];
@ -69,7 +83,9 @@ static void respringNeeded() {
}
static void applyPrefs() {
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.burritoz.kaiprefs/reload"), nil, nil, true);
CFNotificationCenterPostNotification(
CFNotificationCenterGetDarwinNotifyCenter(),
CFSTR("com.burritoz.kaiprefs/reload"), nil, nil, true);
}
@implementation KAIRootListController
@ -83,9 +99,16 @@ static void applyPrefs() {
}
- (void)viewWillAppear:(BOOL)arg1 {
[[UISegmentedControl appearanceWhenContainedInInstancesOfClasses:@[ self.class ]] setTintColor:[UIColor colorWithRed:0.00 green:0.82 blue:1.00 alpha:1.00]];
[[UISwitch appearanceWhenContainedInInstancesOfClasses:@[ self.class ]] setOnTintColor:[UIColor colorWithRed:0.00 green:0.82 blue:1.00 alpha:1.00]];
[[UISlider appearanceWhenContainedInInstancesOfClasses:@[ self.class ]] setTintColor:[UIColor colorWithRed:0.00 green:0.82 blue:1.00 alpha:1.00]];
[[UISegmentedControl
appearanceWhenContainedInInstancesOfClasses:@[ self.class ]]
setTintColor:[UIColor colorWithRed:0.00 green:0.82 blue:1.00 alpha:1.00]];
[[UISwitch appearanceWhenContainedInInstancesOfClasses:@[ self.class ]]
setOnTintColor:[UIColor colorWithRed:0.00
green:0.82
blue:1.00
alpha:1.00]];
[[UISlider appearanceWhenContainedInInstancesOfClasses:@[ self.class ]]
setTintColor:[UIColor colorWithRed:0.00 green:0.82 blue:1.00 alpha:1.00]];
}
- (void)viewWillDisappear:(BOOL)arg1 {
@ -106,52 +129,79 @@ static void applyPrefs() {
self.iconView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
self.iconView.contentMode = UIViewContentModeScaleAspectFit;
self.iconView.image = [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/kaiPrefs.bundle/icon.png"];
self.iconView.image =
[UIImage imageWithContentsOfFile:
@"/Library/PreferenceBundles/kaiPrefs.bundle/icon.png"];
self.iconView.translatesAutoresizingMaskIntoConstraints = NO;
self.iconView.alpha = 1.0;
[self.navigationItem.titleView addSubview:self.iconView];
[NSLayoutConstraint activateConstraints:@[
[self.titleLabel.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
[self.titleLabel.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
[self.titleLabel.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
[self.titleLabel.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
[self.iconView.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
[self.iconView.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
[self.iconView.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
[self.iconView.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
[self.titleLabel.topAnchor
constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
[self.titleLabel.leadingAnchor
constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
[self.titleLabel.trailingAnchor
constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
[self.titleLabel.bottomAnchor
constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
[self.iconView.topAnchor
constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
[self.iconView.leadingAnchor
constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
[self.iconView.trailingAnchor
constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
[self.iconView.bottomAnchor
constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
]];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Pirated :("
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Pirated :("
message:@"Please install kai from Chariz repository."
preferredStyle:UIAlertControllerStyleAlert];
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/com.burritoz.kai.list"] && [[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/com.burritoz.kai.md5sums"]) {
if ([[NSFileManager defaultManager]
fileExistsAtPath:@"/var/lib/dpkg/info/com.burritoz.kai.list"] &&
[[NSFileManager defaultManager]
fileExistsAtPath:@"/var/lib/dpkg/info/com.burritoz.kai.md5sums"]) {
// nothing
} else {
[self presentViewController:alert animated:YES completion:nil];
}
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)respringNeeded, CFSTR("com.burritoz.kaiprefs.respringneeded"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(
CFNotificationCenterGetDarwinNotifyCenter(), NULL,
(CFNotificationCallback)respringNeeded,
CFSTR("com.burritoz.kaiprefs.respringneeded"), NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)applyPrefs, CFSTR("com.burritoz.kaiprefs.apply"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
CFNotificationCenterAddObserver(
CFNotificationCenterGetDarwinNotifyCenter(), NULL,
(CFNotificationCallback)applyPrefs, CFSTR("com.burritoz.kaiprefs.apply"),
NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
controller = self;
}
- (void)resetPrefs:(id)sender {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Reset Preferences"
message:@"Are you sure you want to reset all of your preferences? This action CANNOT be undone! Your device will respring."
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Reset Preferences"
message:@"Are you sure you want to reset all of your "
@"preferences? This action CANNOT be undone! "
@"Your device will respring."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"No"
UIAlertAction *defaultAction =
[UIAlertAction actionWithTitle:@"No"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action){
}];
UIAlertAction *yes = [UIAlertAction actionWithTitle:@"Yes"
UIAlertAction *yes = [UIAlertAction
actionWithTitle:@"Yes"
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *action) {
NSUserDefaults *prefs = [[NSUserDefaults standardUserDefaults] init];
NSUserDefaults *prefs =
[[NSUserDefaults standardUserDefaults] init];
[prefs removePersistentDomainForName:@"com.burritoz.kaiprefs"];
NSTask *f = [[NSTask alloc] init];
@ -183,45 +233,62 @@ static void applyPrefs() {
}
}
- (void)followMeBurritoz {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://twitter.com/burrit0ztweaks"]];
- (void)followMeRen {
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"https://twitter.com/ren7995"]];
}
- (void)followMeOnTwitterThomz {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://twitter.com/thomzi07"]];
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:@"https://twitter.com/thomzi07"]];
}
@end
@implementation KaiHeaderCell // Header Cell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)reuseIdentifier specifier:(id)specifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier];
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(id)reuseIdentifier
specifier:(id)specifier {
self = [super initWithStyle:style
reuseIdentifier:reuseIdentifier
specifier:specifier];
if (self) {
UILabel *tweakLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, self.contentView.bounds.size.width + 30, 50)];
UILabel *tweakLabel = [[UILabel alloc]
initWithFrame:CGRectMake(20, 30,
self.contentView.bounds.size.width + 30, 50)];
[tweakLabel setTextAlignment:NSTextAlignmentLeft];
[tweakLabel setFont:[UIFont systemFontOfSize:50 weight:UIFontWeightRegular]];
[tweakLabel setFont:[UIFont systemFontOfSize:50
weight:UIFontWeightRegular]];
tweakLabel.text = @"kai";
UILabel *devLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 70, self.contentView.bounds.size.width + 30, 50)];
UILabel *devLabel = [[UILabel alloc]
initWithFrame:CGRectMake(20, 70,
self.contentView.bounds.size.width + 30, 50)];
[devLabel setTextAlignment:NSTextAlignmentLeft];
[devLabel setFont:[UIFont systemFontOfSize:20 weight:UIFontWeightMedium]];
devLabel.alpha = 0.8;
devLabel.text = getPackageVersion();
NSBundle *bundle = [[NSBundle alloc] initWithPath:@"/Library/PreferenceBundles/kaiPrefs.bundle"];
UIImage *logo = [UIImage imageWithContentsOfFile:[bundle pathForResource:@"iconFullSize" ofType:@"png"]];
NSBundle *bundle = [[NSBundle alloc]
initWithPath:@"/Library/PreferenceBundles/kaiPrefs.bundle"];
UIImage *logo =
[UIImage imageWithContentsOfFile:[bundle pathForResource:@"iconFullSize"
ofType:@"png"]];
UIImageView *icon = [[UIImageView alloc] initWithImage:logo];
icon.frame = CGRectMake(self.contentView.bounds.size.width - 35, 35, 70, 70);
icon.frame =
CGRectMake(self.contentView.bounds.size.width - 35, 35, 70, 70);
icon.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:tweakLabel];
[self addSubview:devLabel];
[self addSubview:icon];
[icon.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:-20].active = YES;
[icon.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = YES;
[icon.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:-20]
.active = YES;
[icon.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active =
YES;
[icon.widthAnchor constraintEqualToConstant:70].active = YES;
[icon.heightAnchor constraintEqualToConstant:70].active = YES;
@ -233,7 +300,9 @@ static void applyPrefs() {
}
- (instancetype)initWithSpecifier:(PSSpecifier *)specifier {
return [self initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"KaiHeaderCell" specifier:specifier];
return [self initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"KaiHeaderCell"
specifier:specifier];
}
- (void)setFrame:(CGRect)frame {
@ -248,23 +317,34 @@ static void applyPrefs() {
@end
@implementation Thomz_TwitterCell // lil copy of HBTwitterCell from Cephei
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier];
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
specifier:(PSSpecifier *)specifier {
self = [super initWithStyle:style
reuseIdentifier:reuseIdentifier
specifier:specifier];
if (self) {
UILabel *User = [[UILabel alloc] initWithFrame:CGRectMake(70, 15, 200, 20)];
[User setText:specifier.properties[@"user"]];
[User setFont:[User.font fontWithSize:15]];
UILabel *Description = [[UILabel alloc] initWithFrame:CGRectMake(70, 35, 200, 20)];
UILabel *Description =
[[UILabel alloc] initWithFrame:CGRectMake(70, 35, 200, 20)];
[Description setText:specifier.properties[@"description"]];
[Description setFont:[Description.font fontWithSize:10]];
NSBundle *bundle = [[NSBundle alloc] initWithPath:@"/Library/PreferenceBundles/kaiPrefs.bundle"];
NSBundle *bundle = [[NSBundle alloc]
initWithPath:@"/Library/PreferenceBundles/kaiPrefs.bundle"];
UIImage *profilePicture;
profilePicture = [UIImage imageWithContentsOfFile:[bundle pathForResource:specifier.properties[@"image"] ofType:@"jpg"]];
UIImageView *profilePictureView = [[UIImageView alloc] initWithImage:profilePicture];
profilePicture = [UIImage
imageWithContentsOfFile:[bundle
pathForResource:specifier
.properties[@"image"]
ofType:@"jpg"]];
UIImageView *profilePictureView =
[[UIImageView alloc] initWithImage:profilePicture];
[profilePictureView.layer setMasksToBounds:YES];
[profilePictureView.layer setCornerRadius:20];
[profilePictureView setFrame:CGRectMake(15, 15, 40, 40)];

View File

@ -18,15 +18,15 @@
<key>cellClass</key>
<string>Thomz_TwitterCell</string>
<key>user</key>
<string>Burrit0z</string>
<string>ren7995</string>
<key>description</key>
<string>Developer</string>
<key>height</key>
<integer>70</integer>
<key>image</key>
<string>burritoz</string>
<string>ren7995</string>
<key>action</key>
<string>followMeBurritoz</string>
<string>followMeRen</string>
</dict>
<dict>
<key>cell</key>
@ -104,7 +104,7 @@
<key>cell</key>
<string>PSSwitchCell</string>
<key>default</key>
<false/>
<true/>
<key>defaults</key>
<string>com.burritoz.kaiprefs</string>
<key>key</key>
@ -332,15 +332,31 @@
</dict>
<dict>
<key>cell</key>
<string>PSSwitchCell</string>
<key>default</key>
<false/>
<string>PSGroupCell</string>
<key>label</key>
<string>Vertical Placement</string>
</dict>
<dict>
<key>cell</key>
<string>PSSegmentCell</string>
<key>defaults</key>
<string>com.burritoz.kaiprefs</string>
<key>default</key>
<string>1</string>
<key>key</key>
<string>belowMusic</string>
<key>label</key>
<string>Show kai Below Music</string>
<string>placement</string>
<key>validValues</key>
<array>
<string>1</string>
<string>2</string>
<string>3</string>
</array>
<key>validTitles</key>
<array>
<string>Top</string>
<string>Below Media Player</string>
<string>Bottom</string>
</array>
<key>PostNotification</key>
<string>com.burritoz.kaiprefs.apply</string>
</dict>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB