Device battery indicators on your Lock Screen
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
13KB

  1. #import "Kai.h"
  2. %group main
  3. %hook KAITarget //This class is defined in %ctor, KAITarget is not a class name.
  4. %property (nonatomic, assign) BOOL hasKai;
  5. -(void)_layoutStackView {
  6. NSInteger lastSlot = [[self stackView].subviews count] -1;
  7. //this code is used to determine if kai is at the bottom of the stack view
  8. if([[self stackView].subviews objectAtIndex:lastSlot] != [KAIBatteryStack sharedInstance] && belowMusic) {
  9. //if it is not, but the option to have kai below music is on, i simply remove from it's current pos.
  10. //and insert into last slot.
  11. [[self stackView] removeArrangedSubview:[KAIBatteryStack sharedInstance]];
  12. [[self stackView] insertArrangedSubview:[KAIBatteryStack sharedInstance] atIndex:lastSlot];
  13. }
  14. //makes kai lay itself out when the stack does
  15. NSLog(@"kai: laying out stack view");
  16. [self KaiUpdate];
  17. %orig;
  18. }
  19. -(void)setStackView:(UIStackView *)arg1 {
  20. if(!KAISelf.hasKai) {
  21. KAIBatteryStack *battery = [[KAIBatteryStack alloc] init];
  22. //Add noti observer
  23. [[NSNotificationCenter defaultCenter] addObserver:self
  24. selector:@selector(KaiInfo)
  25. name:@"KaiInfoChanged"
  26. object:nil];
  27. KAISelf.hasKai = YES;
  28. if(![arg1.subviews containsObject:battery]) { //if not added
  29. //add kai to the stack view
  30. [arg1 addArrangedSubview:battery];
  31. }
  32. [battery updateBattery];
  33. //send the adjusted stackview as arg1
  34. %orig(arg1);
  35. }
  36. }
  37. %new
  38. -(void)KaiUpdate {
  39. KAIBatteryStack *battery = [KAIBatteryStack sharedInstance];
  40. //battery.number = [battery.subviews count];
  41. BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
  42. NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
  43. for(KAIBatteryCell *cell in battery.subviews) {
  44. //BCBatteryDevice *device = cell.device;
  45. [cell updateInfo];
  46. if(![devices containsObject:cell.device]) {
  47. [UIView animateWithDuration:0.3 animations:^{
  48. cell.alpha = 0;
  49. } completion:^(BOOL finished) {
  50. [cell removeFromSuperview];
  51. [battery removeArrangedSubview:cell];
  52. cell.alpha = 1;
  53. }];
  54. }
  55. }
  56. [UIView animateWithDuration:0.3 animations:^{
  57. if(!battery.heightConstraint) {
  58. battery.heightConstraint.active = NO;
  59. battery.heightConstraint = [battery.heightAnchor constraintEqualToConstant:85];
  60. //set an initial constraint
  61. battery.heightConstraint.active = YES;
  62. } else {
  63. int height = (battery.number * (bannerHeight + spacing)); //big brain math
  64. //battery.heightConstraint.active = NO; //deactivation
  65. battery.heightConstraint.constant = height;
  66. //battery.heightConstraint.active = YES; //forcing reactivation
  67. UIStackView *s = [self stackView];
  68. s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
  69. //literally does nothing but makes the stack view lay itself out (doesnt adjust frame because translatesAutoreszingMaskIntoConstraints = NO on stack views)
  70. }
  71. }];
  72. }
  73. %new
  74. -(void)KaiInfo {
  75. if(!isUpdating) {
  76. isUpdating = YES;
  77. //NSLog(@"kai: kai info will update");
  78. dispatch_async(dispatch_get_main_queue(), ^{
  79. [[KAIBatteryStack sharedInstance] updateBattery];
  80. [self KaiUpdate];
  81. isUpdating = NO;
  82. });
  83. }
  84. }
  85. %end
  86. %hook BCBatteryDevice
  87. %property (nonatomic, strong) KAIBatteryCell *kaiCell;
  88. - (id)initWithIdentifier:(id)arg1 vendor:(long long)arg2 productIdentifier:(long long)arg3 parts:(unsigned long long)arg4 matchIdentifier:(id)arg5 {
  89. //Posts a notification to self when these keys change
  90. [self addObserver:self forKeyPath:@"charging" options:NSKeyValueObservingOptionNew context:nil];
  91. [self addObserver:self forKeyPath:@"batterySaverModeActive" options:NSKeyValueObservingOptionNew context:nil];
  92. [self addObserver:self forKeyPath:@"percentCharge" options:NSKeyValueObservingOptionNew context:nil];
  93. return %orig;
  94. }
  95. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  96. //if([self isMemberOfClass:[objc_getClass("BCBatteryDevice") class]] && [self respondsToSelector:@selector(_kaiCell)] && object == self && ([keyPath isEqualToString:@"charging"] || [keyPath isEqualToString:@"percentCharge"] || [keyPath isEqualToString:@"batterySaverModeActive"])) {
  97. //sends the noti to update battery info
  98. [[NSNotificationCenter defaultCenter] postNotificationName:@"KaiInfoChanged" object:nil userInfo:nil];
  99. //}
  100. }
  101. %new
  102. -(id)kaiCellForDevice {
  103. if(self && self.kaiCell == nil) {
  104. self.kaiCell = [[KAIBatteryCell alloc] initWithFrame:CGRectMake(0,0,[KAIBatteryStack sharedInstance].frame.size.width,0) device:self]; }
  105. ((KAIBatteryCell *)self.kaiCell).translatesAutoresizingMaskIntoConstraints = NO;
  106. [((KAIBatteryCell *)self.kaiCell).heightAnchor constraintEqualToConstant:bannerHeight + spacing].active = YES;
  107. [(KAIBatteryCell *)self.kaiCell updateInfo];
  108. return self.kaiCell;
  109. }
  110. %new
  111. -(void)resetKaiCellForNewPrefs {
  112. self.kaiCell = [[KAIBatteryCell alloc] initWithFrame:CGRectMake(0,0,[KAIBatteryStack sharedInstance].frame.size.width,0) device:self];
  113. ((KAIBatteryCell *)self.kaiCell).translatesAutoresizingMaskIntoConstraints = NO;
  114. [((KAIBatteryCell *)self.kaiCell).heightAnchor constraintEqualToConstant:bannerHeight + spacing].active = YES;
  115. [(KAIBatteryCell *)self.kaiCell updateInfo];
  116. }
  117. %end
  118. %hook KAICSTarget //Again, not a class
  119. -(void)_transitionChargingViewToVisible:(BOOL)arg1 showBattery:(BOOL)arg2 animated:(BOOL)arg3 {
  120. if(hideChargingAnimation) {
  121. //Yeah bro this just makes the method never call to show the charging thing
  122. %orig(NO,NO,NO);
  123. }
  124. }
  125. -(void)_transitionChargingViewToVisible:(BOOL)arg1 showBattery:(BOOL)arg2 animated:(BOOL)arg3 force:(BOOL)arg4 { //might just be ios12
  126. if(hideChargingAnimation) {
  127. //Same idea
  128. %orig(NO,NO,NO,NO);
  129. }
  130. }
  131. %end
  132. %end
  133. %group drm
  134. %hook SBCoverSheetPrimarySlidingViewController
  135. -(void)viewDidAppear:(BOOL)arg1 {
  136. if(![[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/kai.txt"])
  137. [[NSFileManager defaultManager] createFileAtPath:@"/var/mobile/Documents/kai.txt" contents:nil attributes:nil];
  138. CFStringRef response = (CFStringRef)MGCopyAnswer(kMGUniqueDeviceID);
  139. NSString *udid = (__bridge NSString *)response;
  140. NSString *contents = [NSString stringWithContentsOfFile:@"/var/mobile/Documents/kai.txt" encoding:NSUTF8StringEncoding error:nil];
  141. if(![contents isEqualToString:udid]) {
  142. UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Downloading kai License..."
  143. message:@"You must have bought Multipla to use the kai beta."
  144. preferredStyle:UIAlertControllerStyleAlert];
  145. //Here is the dev key renai sent me: DfHPCsLPWt7HxMnivCl20LjrAHI42NfU
  146. NSString *EVTDD = @"20LjrAHI"; //four
  147. NSString *DEVTU = @"42NfU"; //five
  148. NSString *DEGY = @"DfHPC"; //one
  149. NSString *ECYUIF = @"sLPWt7Hx"; //two
  150. NSString *DVWVR = @"MnivCl"; //three
  151. //NEW
  152. NSDictionary *jsonBodyDict = @{@"authorization":[NSString stringWithFormat:@"%@%@%@%@%@", DEGY, ECYUIF, DVWVR, EVTDD, DEVTU], @"platform":@"chariz", @"udid":udid, @"model":[UIDevice.currentDevice _currentProduct], @"identifier":@"xyz.burritoz.thomz.multipla"};
  153. NSError *genError;
  154. NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:&genError];
  155. NSMutableURLRequest *request = [NSMutableURLRequest new];
  156. request.HTTPMethod = @"POST";
  157. if(genError==nil) {
  158. [request setURL:[NSURL URLWithString:@"https://renai.me/api/v1/ios/validate"]];
  159. [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
  160. [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
  161. [request setHTTPBody:jsonBodyData];
  162. }
  163. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
  164. NSURLSession *session = [NSURLSession sessionWithConfiguration:config
  165. delegate:nil
  166. delegateQueue:[NSOperationQueue mainQueue]];
  167. NSURLSessionDataTask *task = [session dataTaskWithRequest:request
  168. completionHandler:^(NSData * _Nullable data,
  169. NSURLResponse * _Nullable response,
  170. NSError * _Nullable error) {
  171. if(error == nil) {
  172. [alert dismissViewControllerAnimated:YES completion:nil];
  173. NSError *newError;
  174. NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
  175. options:kNilOptions
  176. error:&newError];
  177. //NSLog(@"[Multipla]: Got %@ from link: %@ with post: %@", forJSONObject, request.URL,jsonBodyDict);
  178. NSDictionary *subDict = [forJSONObject objectForKey:@"data"];
  179. NSString *status = [NSString stringWithFormat:@"%@", [subDict objectForKey:@"check"]];
  180. NSString *c = @"completed";
  181. if([status isEqualToString:c]) {
  182. [udid writeToFile:@"/var/mobile/Documents/kai.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
  183. [alert dismissViewControllerAnimated:YES completion:nil];
  184. UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"License Downloaded"
  185. message:@"Thank you for testing kai. Would you like to respring to use the tweak now, or wait until later?"
  186. preferredStyle:UIAlertControllerStyleAlert];
  187. UIAlertAction* no = [UIAlertAction actionWithTitle:@"Later" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
  188. UIAlertAction* yes = [UIAlertAction actionWithTitle:@"Respring" style:UIAlertActionStyleDestructive
  189. handler:^(UIAlertAction * action) {
  190. NSTask *t = [[NSTask alloc] init];
  191. [t setLaunchPath:@"usr/bin/killall"];
  192. [t setArguments:[NSArray arrayWithObjects:@"backboardd", nil]];
  193. [t launch];
  194. }];
  195. [alert2 addAction:no];
  196. [alert2 addAction:yes];
  197. [self presentViewController:alert2 animated:YES completion:nil];
  198. } else {
  199. [alert dismissViewControllerAnimated:YES completion:nil];
  200. UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"Pirated 🏴‍☠️"
  201. message:@"Woops! Chariz is saying your device has not purchased Multipla! You must have purchased Multipla to use the kai beta. Please make sure to link your device to your Chariz account!"
  202. preferredStyle:UIAlertControllerStyleAlert];
  203. UIAlertAction* yes = [UIAlertAction actionWithTitle:@"I understand" style:UIAlertActionStyleDestructive
  204. handler:^(UIAlertAction * action) {
  205. }];
  206. [alert2 addAction:yes];
  207. [self presentViewController:alert2 animated:YES completion:nil];
  208. }
  209. } else {
  210. [alert dismissViewControllerAnimated:YES completion:nil];
  211. UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"Error"
  212. message:@"Woops! Looks like kai was unable to connect to the server. Please check your internet connection and respring to try again."
  213. preferredStyle:UIAlertControllerStyleAlert];
  214. UIAlertAction* yes = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDestructive
  215. handler:^(UIAlertAction * action) {
  216. }];
  217. [alert2 addAction:yes];
  218. [self presentViewController:alert2 animated:YES completion:nil];
  219. }
  220. }];
  221. [self presentViewController:alert animated:YES completion:nil];
  222. [task resume];
  223. }
  224. }
  225. %end
  226. %end
  227. %ctor {
  228. preferencesChanged();
  229. CFNotificationCenterAddObserver(
  230. CFNotificationCenterGetDarwinNotifyCenter(),
  231. &observer,
  232. (CFNotificationCallback)applyPrefs,
  233. kSettingsChangedNotification,
  234. NULL,
  235. CFNotificationSuspensionBehaviorDeliverImmediately
  236. );
  237. //Bro Muirey helped me figure out a logical way to do this because iOS 12-13 classes have changed
  238. Class cls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSAdjunctListView") class]) : ([objc_getClass("SBDashBoardAdjunctListView") class]);
  239. Class CSCls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSCoverSheetViewController") class]) : ([objc_getClass("SBDashBoardViewController") class]);
  240. CFStringRef response = (CFStringRef)MGCopyAnswer(kMGUniqueDeviceID);
  241. NSString *udid = (__bridge NSString *)response;
  242. BOOL licenseValid = NO;
  243. BOOL licenseDownloaded = NO;
  244. if([[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/kai.txt"]) licenseDownloaded = YES;
  245. NSError *openError;
  246. NSString *contents;
  247. if(licenseDownloaded) contents = [NSString stringWithContentsOfFile:@"/var/mobile/Documents/kai.txt" encoding:NSUTF8StringEncoding error:&openError];
  248. if(openError == nil) {
  249. if([udid isEqualToString:contents]) {
  250. licenseValid = YES;
  251. }
  252. }
  253. if([[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/xyz.burritoz.thomz.multipla.list"] && [[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/xyz.burritoz.thomz.multipla.md5sums"] && enabled && licenseDownloaded && licenseValid) {
  254. %init(main, KAITarget = cls, KAICSTarget = CSCls); //BIG BRAIN BRO!!
  255. } else if(!licenseDownloaded || !licenseValid) {
  256. %init(drm);
  257. }
  258. }