Device battery indicators on your Lock Screen
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

361 lines
13KB

  1. KAIBatteryPlatter *instance;
  2. NSTimer *queueTimer = nil;
  3. NSMutableArray *deviceNames = [[NSMutableArray alloc] init];
  4. NSMutableArray *cellsForDeviceNames = [[NSMutableArray alloc] init];
  5. @implementation KAIBatteryPlatter
  6. - (instancetype)initWithFrame:(CGRect)arg1 {
  7. self = [super initWithFrame:arg1];
  8. instance = self;
  9. if (self) {
  10. self.stackHolder = [[UIView alloc] initWithFrame:arg1];
  11. self.stack = [[KAIStackView alloc] init];
  12. self.stack.axis = kaiAlign == 0 ? 1 : 0;
  13. self.stack.distribution = UIStackViewDistributionFillEqually;
  14. self.stack.spacing = kaiAlign == 0 ? 0 : spacingHorizontal;
  15. self.stack.alignment = 0;
  16. self.oldCountOfDevices = -100;
  17. self.queued = NO;
  18. [self setShowsHorizontalScrollIndicator:NO];
  19. [self setShowsVerticalScrollIndicator:NO];
  20. [self setMinimumZoomScale:1];
  21. [self setMaximumZoomScale:1];
  22. [self addSubview:self.stackHolder];
  23. [self.stackHolder addSubview:self.stack];
  24. [self setContentSize:self.stack.frame.size];
  25. [self resetOffset];
  26. //Add noti observer
  27. [[NSNotificationCenter defaultCenter] addObserver:self
  28. selector:@selector(resetOffset)
  29. name:@"KaiResetOffset"
  30. object:nil];
  31. self.stackHolder.translatesAutoresizingMaskIntoConstraints = NO;
  32. [self.stackHolder.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES;
  33. [self.stackHolder.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES;
  34. [self.stackHolder.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = YES;
  35. if (kaiAlign == 0) {
  36. if (bannerAlign == 2) { //center
  37. self.subviewAligner = [self.stack.centerXAnchor constraintEqualToAnchor:self.stackHolder.centerXAnchor constant:horizontalOffset];
  38. } else if (bannerAlign == 1) { //left
  39. self.subviewAligner = [self.stack.leftAnchor constraintEqualToAnchor:self.stackHolder.leftAnchor constant:horizontalOffset];
  40. } else if (bannerAlign == 3) { //right
  41. self.subviewAligner = [self.stack.rightAnchor constraintEqualToAnchor:self.stackHolder.rightAnchor constant:horizontalOffset];
  42. }
  43. self.subviewAligner.active = YES;
  44. }
  45. [self updateBattery];
  46. }
  47. return self;
  48. }
  49. - (void)resetOffset {
  50. if (kaiAlign != 0 && reAlignSelf) {
  51. [UIView animateWithDuration:0.2
  52. animations:^{
  53. if (bannerAlign == 1) { //left
  54. [self setContentOffset:CGPointMake(0 + horizontalOffset, self.contentOffset.y)];
  55. self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
  56. } else if (bannerAlign == 2) { //center
  57. [self setContentOffset:CGPointMake(((-1 * self.stackHolder.frame.size.width) / 2) + (self.stack.frame.size.width / 2) + horizontalOffset, self.contentOffset.y)];
  58. CGFloat top = 0, left = 0;
  59. if (self.contentSize.width < self.bounds.size.width) {
  60. left = (self.bounds.size.width - self.contentSize.width) * 0.5f;
  61. }
  62. if (self.contentSize.height < self.bounds.size.height) {
  63. top = (self.bounds.size.height - self.contentSize.height) * 0.5f;
  64. }
  65. self.contentInset = UIEdgeInsetsMake(top, left, top, left);
  66. } else if (bannerAlign == 3) { //right
  67. [self setContentOffset:CGPointMake((-1 * self.stackHolder.frame.size.width) + self.stack.frame.size.width + horizontalOffset, self.contentOffset.y)];
  68. CGFloat top = 0, left = 0;
  69. if (self.contentSize.width < self.bounds.size.width) {
  70. left = (self.bounds.size.width - self.contentSize.width);
  71. }
  72. if (self.contentSize.height < self.bounds.size.height) {
  73. top = (self.bounds.size.height - self.contentSize.height);
  74. }
  75. self.contentInset = UIEdgeInsetsMake(top, left, top, left);
  76. }
  77. }];
  78. }
  79. }
  80. - (void)setClipsToBounds:(BOOL)arg1 {
  81. [super setClipsToBounds:NO];
  82. }
  83. - (void)updateBattery {
  84. dispatch_async(dispatch_get_main_queue(), ^{
  85. BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
  86. NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
  87. if (self.oldCountOfDevices == -100) {
  88. self.oldCountOfDevices = [devices count] + 1;
  89. }
  90. for (KAIBatteryCell *cell in self.stack.subviews) {
  91. [cell updateInfo];
  92. }
  93. if (!self.isUpdating && self.oldCountOfDevices != 0 && ([devices count] + 1 == self.oldCountOfDevices || [devices count] - 1 == self.oldCountOfDevices || [devices count] == self.oldCountOfDevices)) {
  94. //if(!self.isUpdating) {
  95. self.isUpdating = YES;
  96. NSMutableArray *cellsToAdd = [[NSMutableArray alloc] init];
  97. NSMutableArray *cellsToRemove = [[NSMutableArray alloc] init];
  98. for (BCBatteryDevice *device in devices) {
  99. KAIBatteryCell *cell = [device kaiCellForDevice];
  100. BOOL charging = MSHookIvar<long long>(device, "_charging");
  101. BOOL internal = MSHookIvar<BOOL>(device, "_internal");
  102. BOOL shouldAdd = NO;
  103. BOOL fake = MSHookIvar<BOOL>(device, "_fake");
  104. NSString *deviceName = MSHookIvar<NSString *>(device, "_name");
  105. if (!fake) {
  106. if (showAll) {
  107. shouldAdd = YES;
  108. } else if (showAllMinusInternal && !internal) {
  109. shouldAdd = YES;
  110. } else if (!showAll && charging) {
  111. shouldAdd = YES;
  112. }
  113. }
  114. if (!showPhone && internal) {
  115. shouldAdd = NO;
  116. }
  117. if (![self.stack.subviews containsObject:cell] && shouldAdd && [devices containsObject:device]) {
  118. if (![deviceNames containsObject:deviceName]) {
  119. [cellsToAdd addObject:cell];
  120. [deviceNames addObject:deviceName];
  121. [cellsForDeviceNames addObject:cell];
  122. } else {
  123. for (int i = 0; i < [deviceNames count]; i++) {
  124. if ([[deviceNames objectAtIndex:i] isEqualToString:deviceName]) {
  125. KAIBatteryCell *cell = [cellsForDeviceNames objectAtIndex:i];
  126. cell.device = device;
  127. if ([cellsToRemove containsObject:cell])
  128. [cellsToRemove removeObject:cell];
  129. [cell updateInfo];
  130. }
  131. }
  132. }
  133. } else if ([self.stack.subviews containsObject:cell] && !shouldAdd) {
  134. [cellsToRemove addObject:cell];
  135. // this is where i stupidly removed from deviceName names :kekw:
  136. }
  137. }
  138. for (KAIBatteryCell *cell in cellsToAdd) {
  139. if ([cellsToRemove containsObject:cell])
  140. [cellsToRemove removeObject:cell];
  141. if (![self.stack.subviews containsObject:cell] && [devices containsObject:cell.device]) {
  142. // add cell
  143. cell.alpha = 0;
  144. [self.stack addSubview:cell];
  145. [self.stack addArrangedSubview:cell];
  146. [UIView animateWithDuration:0.3
  147. animations:^{
  148. cell.alpha = 1;
  149. }];
  150. }
  151. }
  152. for (KAIBatteryCell *cell in cellsToRemove) {
  153. // remove cell
  154. [UIView animateWithDuration:0.3
  155. animations:^{
  156. cell.alpha = 0;
  157. }
  158. completion:^(BOOL finished) {
  159. [cell removeFromSuperview];
  160. [self.stack removeArrangedSubview:cell];
  161. cell.alpha = 1;
  162. }];
  163. NSString *deviceName = MSHookIvar<NSString *>(cell.device, "_name");
  164. [deviceNames removeObject:deviceName];
  165. [cellsForDeviceNames removeObject:cell];
  166. }
  167. for (KAIBatteryCell *cell in self.stack.subviews) {
  168. if (![devices containsObject:cell.device] || cell.device == nil) { //not existing, remove
  169. NSString *deviceName = cell.label.text;
  170. [UIView animateWithDuration:0.3
  171. animations:^{
  172. cell.alpha = 0;
  173. }
  174. completion:^(BOOL finished) {
  175. [cell removeFromSuperview];
  176. [self.stack removeArrangedSubview:cell];
  177. cell.alpha = 1;
  178. }];
  179. [deviceNames removeObject:deviceName];
  180. [cellsForDeviceNames removeObject:cell];
  181. }
  182. }
  183. queueTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(dispatchQueue) userInfo:nil repeats:NO];
  184. //self.isUpdating = NO;
  185. } else if (self.isUpdating) {
  186. self.queued = YES;
  187. }
  188. self.oldCountOfDevices = [devices count];
  189. [self calculateHeight];
  190. if ([self.superview.superview.superview respondsToSelector:@selector(fixComplicationsViewFrame)]) {
  191. [(NCNotificationListView *)(self.superview.superview.superview) fixComplicationsViewFrame];
  192. }
  193. [self setContentSize:self.stack.frame.size];
  194. [self performSelector:@selector(resetOffset) withObject:self afterDelay:0.2];
  195. });
  196. }
  197. - (void)setContentOffset:(CGPoint)arg1 {
  198. [self setContentSize:self.stack.frame.size]; //sometimes the view gets "stuck", this fixes it
  199. [super setContentOffset:CGPointMake(arg1.x, 0)];
  200. }
  201. - (void)calculateHeight {
  202. self.number = [self.stack.subviews count];
  203. if (self.number == 0) {
  204. UIStackView *s = (UIStackView *)(self.superview);
  205. s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
  206. [s removeArrangedSubview:self];
  207. [self removeFromSuperview];
  208. } else if (self.number != 0 && self.superview == nil && shouldBeAdded == YES) {
  209. [[[[objc_getClass("CSAdjunctListView") class] sharedListViewForKai] stackView] addArrangedSubview:self];
  210. //[self performSelector:@selector(calculateHeight) withObject:self afterDelay:0.1];
  211. }
  212. [UIView animateWithDuration:0.3
  213. animations:^{
  214. if (!self.heightConstraint) {
  215. int height = (self.number * (bannerHeight + spacing));
  216. if (kaiAlign != 0) {
  217. height = bannerHeight + spacing;
  218. }
  219. if ([self.superview.subviews count] > 1) {
  220. height = (height - spacing) + 1;
  221. }
  222. self.heightConstraint = [self.heightAnchor constraintEqualToConstant:height];
  223. self.stack.heightConstraint = [self.stack.heightAnchor constraintEqualToConstant:height];
  224. self.heightConstraint.active = YES;
  225. self.stack.heightConstraint.active = YES;
  226. [self setContentSize:self.stack.frame.size];
  227. [self resetOffset];
  228. } else {
  229. int height = (self.number * (bannerHeight + spacing));
  230. int extra = extraPaddingAfter ? spacing : 0;
  231. if (kaiAlign == 0) {
  232. //self.stack.widthConstraint.constant = bannerWidthFactor;
  233. } else {
  234. height = bannerHeight + spacing;
  235. }
  236. height = height + extra;
  237. if ([self.superview.subviews count] > 1) {
  238. height = (height - spacing + 1);
  239. }
  240. self.heightConstraint.constant = height;
  241. self.stack.heightConstraint.constant = height - extra; //minus extra because it will stretch cell spacing otherwise
  242. UIStackView *s = (UIStackView *)(self.superview);
  243. s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
  244. //literally does nothing but makes the stack view lay itself out (doesnt adjust frame because translatesAutoreszingMaskIntoConstraints = NO on stack views)
  245. }
  246. [self setContentSize:self.stack.frame.size];
  247. [self resetOffset];
  248. }];
  249. }
  250. - (void)removeFromSuperview {
  251. [self.superview setNeedsLayout];
  252. [super removeFromSuperview];
  253. }
  254. - (void)refreshForPrefs {
  255. self.stack.spacing = kaiAlign == 0 ? 0 : spacingHorizontal;
  256. [self setContentSize:self.stack.frame.size];
  257. for (UIView *view in self.stack.subviews) {
  258. @try {
  259. [view removeFromSuperview];
  260. } @catch (NSException *exception) {
  261. //Panik
  262. }
  263. }
  264. BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
  265. NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
  266. for (BCBatteryDevice *device in devices) {
  267. [device resetKaiCellForNewPrefs];
  268. }
  269. if (kaiAlign == 0) {
  270. self.subviewAligner.active = NO;
  271. if (bannerAlign == 2) { //center
  272. self.subviewAligner = [self.stack.centerXAnchor constraintEqualToAnchor:self.stackHolder.centerXAnchor constant:horizontalOffset];
  273. } else if (bannerAlign == 1) { //left
  274. self.subviewAligner = [self.stack.leftAnchor constraintEqualToAnchor:self.stackHolder.leftAnchor constant:horizontalOffset];
  275. } else if (bannerAlign == 3) { //right
  276. self.subviewAligner = [self.stack.rightAnchor constraintEqualToAnchor:self.stackHolder.rightAnchor constant:horizontalOffset];
  277. }
  278. self.subviewAligner.active = YES;
  279. }
  280. [cellsForDeviceNames removeAllObjects];
  281. [deviceNames removeAllObjects];
  282. [self updateBattery];
  283. }
  284. - (void)dispatchQueue {
  285. self.isUpdating = NO;
  286. if (self.queued) {
  287. [self updateBattery];
  288. if ([self.superview.superview.superview respondsToSelector:@selector(fixComplicationsViewFrame)]) {
  289. [(NCNotificationListView *)(self.superview.superview.superview) fixComplicationsViewFrame];
  290. }
  291. self.queued = NO;
  292. }
  293. [queueTimer invalidate];
  294. queueTimer = nil;
  295. }
  296. + (KAIBatteryPlatter *)sharedInstance {
  297. return instance;
  298. }
  299. //This is for compatibility (did i spell that right?)
  300. //basically this fixes it crashing in landscape:
  301. - (void)setSizeToMimic:(CGSize)arg1 {
  302. }
  303. @end