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.

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