mirror of
https://github.com/Burrit0z/kai
synced 2025-07-01 14:06:47 +00:00
light dark
This commit is contained in:
@ -37,7 +37,11 @@
|
||||
} else if(hideDeviceLabel) {
|
||||
[self.label setFont:[UIFont systemFontOfSize:0]];
|
||||
}
|
||||
if(textColor==1) {
|
||||
[self.label setTextColor:[UIColor whiteColor]];
|
||||
} else {
|
||||
[self.label setTextColor:[UIColor blackColor]];
|
||||
}
|
||||
self.label.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
self.label.numberOfLines = 1;
|
||||
[self.label setText:labelText];
|
||||
@ -51,7 +55,11 @@
|
||||
} else {
|
||||
[self.percentLabel setFont:[UIFont systemFontOfSize:14]];
|
||||
}
|
||||
if(textColor==1) {
|
||||
[self.percentLabel setTextColor:[UIColor whiteColor]];
|
||||
} else {
|
||||
[self.percentLabel setTextColor:[UIColor blackColor]];
|
||||
}
|
||||
self.percentLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
[self.percentLabel setTextAlignment:NSTextAlignmentRight];
|
||||
self.percentLabel.numberOfLines = 1;
|
||||
@ -116,6 +124,21 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)traitCollectionDidChange:(id)arg1 {
|
||||
[super traitCollectionDidChange:arg1];
|
||||
if(textColor==0) {
|
||||
if(@available(iOS 12.0, *)) {
|
||||
if(self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
||||
[self.label setTextColor:[UIColor whiteColor]];
|
||||
[self.percentLabel setTextColor:[UIColor whiteColor]];
|
||||
} else if(self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight) {
|
||||
[self.label setTextColor:[UIColor blackColor]];
|
||||
[self.percentLabel setTextColor:[UIColor blackColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)updateInfo {
|
||||
//NSLog(@"kai: updating cell info");
|
||||
|
||||
|
@ -32,7 +32,7 @@ long long lastPercentage;
|
||||
BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
|
||||
NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
|
||||
|
||||
if(self.oldCountOfDevices == -100) {
|
||||
/*if(self.oldCountOfDevices == -100) {
|
||||
self.oldCountOfDevices = [devices count] + 1;
|
||||
}
|
||||
self.oldCountOfDevices = [devices count];
|
||||
@ -43,7 +43,8 @@ long long lastPercentage;
|
||||
[cell updateInfo];
|
||||
}
|
||||
|
||||
if(!self.isUpdating && self.oldCountOfDevices != 0 && ([devices count] + 1 == self.oldCountOfDevices || [devices count] - 1 == self.oldCountOfDevices || [devices count] == self.oldCountOfDevices)) {
|
||||
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;
|
||||
|
||||
@ -79,19 +80,97 @@ long long lastPercentage;
|
||||
|
||||
}
|
||||
|
||||
queueTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(dispatchQueue) userInfo:nil repeats:NO];
|
||||
for(KAIBatteryCell *cell in self.subviews) {
|
||||
if(![devices containsObject:cell.device]) {
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
cell.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[cell removeFromSuperview];
|
||||
[self removeArrangedSubview:cell];
|
||||
cell.alpha = 1;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
//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.number = [self.subviews count];
|
||||
[(CSAdjunctListView *)self.superview.superview KaiUpdate];
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
-(void)addArrangedSubview:(UIView *)view {
|
||||
[super addArrangedSubview:view];
|
||||
self.number = [self.subviews count];
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
|
||||
if(!self.heightConstraint) {
|
||||
|
||||
self.heightConstraint.active = NO;
|
||||
self.heightConstraint = [self.heightAnchor constraintEqualToConstant:85];
|
||||
//set an initial constraint
|
||||
self.heightConstraint.active = YES;
|
||||
|
||||
} else {
|
||||
int height = (self.number * (bannerHeight + spacing)); //big brain math
|
||||
//self.heightConstraint.active = NO; //deactivation
|
||||
self.heightConstraint.constant = height;
|
||||
//self.heightConstraint.active = YES; //forcing reactivation
|
||||
|
||||
UIStackView *s = (UIStackView *)(self.superview);
|
||||
s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
|
||||
//literally does nothing but makes the stack view lay itself out (doesnt adjust frame because translatesAutoreszingMaskIntoConstraints = NO on stack views)
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
if(textColor==0) {
|
||||
KAIBatteryCell *cell = (KAIBatteryCell *)view;
|
||||
if(@available(iOS 12.0, *)) {
|
||||
if(self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
||||
[cell.label setTextColor:[UIColor whiteColor]];
|
||||
[cell.percentLabel setTextColor:[UIColor whiteColor]];
|
||||
} else if(self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight) {
|
||||
[cell.label setTextColor:[UIColor blackColor]];
|
||||
[cell.percentLabel setTextColor:[UIColor blackColor]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)removeArrangedSubview:(UIView *)view {
|
||||
[super removeArrangedSubview:view];
|
||||
self.number = [self.subviews count];
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
|
||||
if(!self.heightConstraint) {
|
||||
|
||||
self.heightConstraint.active = NO;
|
||||
self.heightConstraint = [self.heightAnchor constraintEqualToConstant:85];
|
||||
//set an initial constraint
|
||||
self.heightConstraint.active = YES;
|
||||
|
||||
} else {
|
||||
int height = (self.number * (bannerHeight + spacing)); //big brain math
|
||||
//self.heightConstraint.active = NO; //deactivation
|
||||
self.heightConstraint.constant = height;
|
||||
//self.heightConstraint.active = YES; //forcing reactivation
|
||||
|
||||
UIStackView *s = (UIStackView *)(self.superview);
|
||||
s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
|
||||
//literally does nothing but makes the stack view lay itself out (doesnt adjust frame because translatesAutoreszingMaskIntoConstraints = NO on stack views)
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)refreshForPrefs {
|
||||
for( UIView *view in self.subviews ) {
|
||||
@try {
|
||||
|
20
Kai.h
20
Kai.h
@ -14,7 +14,6 @@
|
||||
@property (nonatomic, assign) BOOL hasKai;
|
||||
-(UIStackView *)stackView;
|
||||
-(void)setStackView:(UIStackView *)arg1;
|
||||
-(void)KaiUpdate;
|
||||
@end
|
||||
|
||||
@interface CALayer (kai)
|
||||
@ -43,6 +42,7 @@ BOOL hideDeviceLabel;
|
||||
BOOL hideChargingAnimation;
|
||||
NSInteger bannerStyle;
|
||||
NSInteger bannerAlign;
|
||||
NSInteger textColor;
|
||||
double spacing;
|
||||
double glyphSize;
|
||||
double bannerHeight;
|
||||
@ -115,6 +115,7 @@ static void preferencesChanged()
|
||||
horizontalOffset = numberForValue(@"horizontalOffset", 0);
|
||||
belowMusic = boolValueForKey(@"belowMusic", NO);
|
||||
hideChargingAnimation = boolValueForKey(@"hideChargingAnimation", YES);
|
||||
textColor = numberForValue(@"textColor", 0);
|
||||
|
||||
if(disableGlyphs) {
|
||||
glyphSize = 0;
|
||||
@ -127,23 +128,8 @@ static void applyPrefs()
|
||||
|
||||
isUpdating = YES;
|
||||
|
||||
[[KAIBatteryStack sharedInstance] refreshForPrefs];
|
||||
[(CSAdjunctListView *)([KAIBatteryStack sharedInstance].superview.superview) KaiUpdate];
|
||||
[[KAIBatteryStack sharedInstance] refreshForPrefs]; //so hard (not)
|
||||
|
||||
isUpdating = NO;
|
||||
|
||||
//here I remotely refresh the KAIView.
|
||||
/*isUpdating = YES;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
[KAIBatteryStack sharedInstance].alpha = 0;
|
||||
} completion:^(BOOL finished){
|
||||
[[KAIBatteryStack sharedInstance] updateBattery];
|
||||
[(CSAdjunctListView *)([KAIBatteryStack sharedInstance].superview.superview) KaiUpdate];
|
||||
[UIView animateWithDuration:0.35 animations:^{
|
||||
[KAIBatteryStack sharedInstance].alpha = 1;
|
||||
} completion:^(BOOL finished){
|
||||
isUpdating = NO;
|
||||
}];
|
||||
}];*/
|
||||
|
||||
}
|
167
Kai.xm
167
Kai.xm
@ -17,10 +17,6 @@
|
||||
[[self stackView] insertArrangedSubview:[KAIBatteryStack sharedInstance] atIndex:lastSlot];
|
||||
}
|
||||
|
||||
//makes kai lay itself out when the stack does
|
||||
NSLog(@"kai: laying out stack view");
|
||||
[self KaiUpdate];
|
||||
|
||||
%orig;
|
||||
}
|
||||
|
||||
@ -48,50 +44,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
%new
|
||||
-(void)KaiUpdate {
|
||||
KAIBatteryStack *battery = [KAIBatteryStack sharedInstance];
|
||||
//battery.number = [battery.subviews count];
|
||||
BCBatteryDeviceController *bcb = [BCBatteryDeviceController sharedInstance];
|
||||
NSArray *devices = MSHookIvar<NSArray *>(bcb, "_sortedDevices");
|
||||
for(KAIBatteryCell *cell in battery.subviews) {
|
||||
//BCBatteryDevice *device = cell.device;
|
||||
[cell updateInfo];
|
||||
if(![devices containsObject:cell.device]) {
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
cell.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[cell removeFromSuperview];
|
||||
[battery removeArrangedSubview:cell];
|
||||
cell.alpha = 1;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
|
||||
if(!battery.heightConstraint) {
|
||||
|
||||
battery.heightConstraint.active = NO;
|
||||
battery.heightConstraint = [battery.heightAnchor constraintEqualToConstant:85];
|
||||
//set an initial constraint
|
||||
battery.heightConstraint.active = YES;
|
||||
|
||||
} else {
|
||||
int height = (battery.number * (bannerHeight + spacing)); //big brain math
|
||||
//battery.heightConstraint.active = NO; //deactivation
|
||||
battery.heightConstraint.constant = height;
|
||||
//battery.heightConstraint.active = YES; //forcing reactivation
|
||||
|
||||
UIStackView *s = [self stackView];
|
||||
s.frame = CGRectMake(s.frame.origin.x, s.frame.origin.y, s.frame.size.width, (s.frame.size.height - 1));
|
||||
//literally does nothing but makes the stack view lay itself out (doesnt adjust frame because translatesAutoreszingMaskIntoConstraints = NO on stack views)
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
%new
|
||||
-(void)KaiInfo {
|
||||
|
||||
@ -103,7 +55,6 @@
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
[[KAIBatteryStack sharedInstance] updateBattery];
|
||||
[self KaiUpdate];
|
||||
|
||||
isUpdating = NO;
|
||||
});
|
||||
@ -180,83 +131,13 @@
|
||||
|
||||
%group drm
|
||||
|
||||
%hook SBCoverSheetPrimarySlidingViewController
|
||||
%hook SBIconController
|
||||
|
||||
-(void)viewDidAppear:(BOOL)arg1 {
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/kai.txt"])
|
||||
[[NSFileManager defaultManager] createFileAtPath:@"/var/mobile/Documents/kai.txt" contents:nil attributes:nil];
|
||||
|
||||
CFStringRef response = (CFStringRef)MGCopyAnswer(kMGUniqueDeviceID);
|
||||
NSString *udid = (__bridge NSString *)response;
|
||||
NSString *contents = [NSString stringWithContentsOfFile:@"/var/mobile/Documents/kai.txt" encoding:NSUTF8StringEncoding error:nil];
|
||||
if(![contents isEqualToString:udid]) {
|
||||
%orig;
|
||||
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Downloading kai License..."
|
||||
message:@"You must have bought Multipla to use the kai beta."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
//Here is the dev key renai sent me: DfHPCsLPWt7HxMnivCl20LjrAHI42NfU
|
||||
NSString *EVTDD = @"20LjrAHI"; //four
|
||||
NSString *DEVTU = @"42NfU"; //five
|
||||
NSString *DEGY = @"DfHPC"; //one
|
||||
NSString *ECYUIF = @"sLPWt7Hx"; //two
|
||||
NSString *DVWVR = @"MnivCl"; //three
|
||||
|
||||
//NEW
|
||||
NSDictionary *jsonBodyDict = @{@"authorization":[NSString stringWithFormat:@"%@%@%@%@%@", DEGY, ECYUIF, DVWVR, EVTDD, DEVTU], @"platform":@"chariz", @"udid":udid, @"model":[UIDevice.currentDevice _currentProduct], @"identifier":@"xyz.burritoz.thomz.multipla"};
|
||||
NSError *genError;
|
||||
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:&genError];
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest new];
|
||||
request.HTTPMethod = @"POST";
|
||||
if(genError==nil) {
|
||||
[request setURL:[NSURL URLWithString:@"https://renai.me/api/v1/ios/validate"]];
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
|
||||
[request setHTTPBody:jsonBodyData];
|
||||
}
|
||||
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
|
||||
delegate:nil
|
||||
delegateQueue:[NSOperationQueue mainQueue]];
|
||||
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
|
||||
completionHandler:^(NSData * _Nullable data,
|
||||
NSURLResponse * _Nullable response,
|
||||
NSError * _Nullable error) {
|
||||
if(error == nil) {
|
||||
[alert dismissViewControllerAnimated:YES completion:nil];
|
||||
NSError *newError;
|
||||
NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
|
||||
options:kNilOptions
|
||||
error:&newError];
|
||||
//NSLog(@"[Multipla]: Got %@ from link: %@ with post: %@", forJSONObject, request.URL,jsonBodyDict);
|
||||
NSDictionary *subDict = [forJSONObject objectForKey:@"data"];
|
||||
NSString *status = [NSString stringWithFormat:@"%@", [subDict objectForKey:@"check"]];
|
||||
NSString *c = @"completed";
|
||||
if([status isEqualToString:c]) {
|
||||
|
||||
[udid writeToFile:@"/var/mobile/Documents/kai.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
[alert dismissViewControllerAnimated:YES completion:nil];
|
||||
UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"License Downloaded"
|
||||
message:@"Thank you for testing kai. Would you like to respring to use the tweak now, or wait until later?"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertAction* no = [UIAlertAction actionWithTitle:@"Later" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
|
||||
|
||||
UIAlertAction* yes = [UIAlertAction actionWithTitle:@"Respring" style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
NSTask *t = [[NSTask alloc] init];
|
||||
[t setLaunchPath:@"usr/bin/killall"];
|
||||
[t setArguments:[NSArray arrayWithObjects:@"backboardd", nil]];
|
||||
[t launch];
|
||||
}];
|
||||
[alert2 addAction:no];
|
||||
[alert2 addAction:yes];
|
||||
[self presentViewController:alert2 animated:YES completion:nil];
|
||||
|
||||
} else {
|
||||
[alert dismissViewControllerAnimated:YES completion:nil];
|
||||
UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"Pirated 🏴☠️"
|
||||
UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"kai"
|
||||
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!"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
@ -265,26 +146,6 @@
|
||||
}];
|
||||
[alert2 addAction:yes];
|
||||
[self presentViewController:alert2 animated:YES completion:nil];
|
||||
}
|
||||
} else {
|
||||
[alert dismissViewControllerAnimated:YES completion:nil];
|
||||
UIAlertController* alert2 = [UIAlertController alertControllerWithTitle:@"Error"
|
||||
message:@"Woops! Looks like kai was unable to connect to the server. Please check your internet connection and respring to try again."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* yes = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction * action) {
|
||||
}];
|
||||
[alert2 addAction:yes];
|
||||
[self presentViewController:alert2 animated:YES completion:nil];
|
||||
}
|
||||
|
||||
|
||||
}];
|
||||
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -308,25 +169,13 @@
|
||||
|
||||
Class CSCls = kCFCoreFoundationVersionNumber > 1600 ? ([objc_getClass("CSCoverSheetViewController") class]) : ([objc_getClass("SBDashBoardViewController") class]);
|
||||
|
||||
CFStringRef response = (CFStringRef)MGCopyAnswer(kMGUniqueDeviceID);
|
||||
NSString *udid = (__bridge NSString *)response;
|
||||
//BOOL bypass = YES;
|
||||
BOOL bypass = NO;
|
||||
|
||||
BOOL licenseValid = NO;
|
||||
BOOL licenseDownloaded = NO;
|
||||
if([[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/kai.txt"]) licenseDownloaded = YES;
|
||||
NSError *openError;
|
||||
NSString *contents;
|
||||
|
||||
if(licenseDownloaded) contents = [NSString stringWithContentsOfFile:@"/var/mobile/Documents/kai.txt" encoding:NSUTF8StringEncoding error:&openError];
|
||||
if(openError == nil) {
|
||||
if([udid isEqualToString:contents]) {
|
||||
licenseValid = YES;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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"]) || bypass) {
|
||||
%init(main, KAITarget = cls, KAICSTarget = CSCls); //BIG BRAIN BRO!!
|
||||
} else if(!licenseDownloaded || !licenseValid) {
|
||||
} else if(!bypass && !([[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/xyz.burritoz.thomz.multipla.list"] && [[NSFileManager defaultManager] fileExistsAtPath:@"/var/lib/dpkg/info/xyz.burritoz.thomz.multipla.md5sums"])) {
|
||||
//if(0==1)
|
||||
%init(drm);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
Package: com.burritoz.kai
|
||||
Name: Kai
|
||||
Version: 0.2.6~alpha
|
||||
Version: 0.2.6~alpha3
|
||||
Architecture: iphoneos-arm
|
||||
Description: Show charging banners on your lock screen!
|
||||
Maintainer: burrit0z
|
||||
|
@ -115,6 +115,34 @@
|
||||
<string>Dark</string>
|
||||
<string>Light</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSGroupCell</string>
|
||||
<key>label</key>
|
||||
<string>Text Color</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
<string>PSSegmentCell</string>
|
||||
<key>defaults</key>
|
||||
<string>com.burritoz.kaiprefs</string>
|
||||
<key>default</key>
|
||||
<string>0</string>
|
||||
<key>key</key>
|
||||
<string>textColor</string>
|
||||
<key>validValues</key>
|
||||
<array>
|
||||
<string>0</string>
|
||||
<string>1</string>
|
||||
<string>2</string>
|
||||
</array>
|
||||
<key>validTitles</key>
|
||||
<array>
|
||||
<string>Adaptive</string>
|
||||
<string>White</string>
|
||||
<string>Black</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>cell</key>
|
||||
|
Reference in New Issue
Block a user