This commit is contained in:
2025-11-18 20:53:47 +08:00
parent 254e65906a
commit 3dcc4932c3
109 changed files with 1432 additions and 84 deletions

View File

@@ -7,6 +7,8 @@
#import "KBNetworkManager.h"
#import "KBSkinManager.h"
#import "KBHUD.h"
#import "KBConfig.h"
#import "KBSkinService.h"
@interface KBSkinCell : UITableViewCell
@property (nonatomic, strong) UIButton *applyBtn;
@@ -34,7 +36,7 @@
@interface KBSkinCenterVC () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, copy) NSArray<NSDictionary *> *skins; // id, name, img(url relative to KB_BASE_URL)
@property (nonatomic, copy) NSArray<NSDictionary *> *skins; // JSON
@end
@implementation KBSkinCenterVC
@@ -43,12 +45,103 @@
[super viewDidLoad];
// self.title = KBLocalized(@"皮肤中心");
self.view.backgroundColor = [UIColor whiteColor];
// URL KB_BASE_URL
//
// JSON
//
// - background_image URL使 picsum
// - background/key_bg/key_text/key_highlight/accent KBSkinManager.applyThemeFromJSON
// - hidden_keys identifier
// - key_icons
// * KB_SKIN_ICON_USE_REMOTE==0 value Assets "kb_space_melon"
// * KB_SKIN_ICON_USE_REMOTE==1 value URL "https://.../icons/space.png"
self.skins = @[
@{ @"id": @"aurora", @"name": KBLocalized(@"极光"), @"img": @"https://picsum.photos/id/1018/800/450.jpg" },
@{ @"id": @"alps", @"name": KBLocalized(@"雪山"), @"img": @"https://picsum.photos/id/1016/800/450.jpg" },
@{ @"id": @"lake", @"name": KBLocalized(@"湖面"), @"img": @"https://picsum.photos/id/1039/800/450.jpg" },
@{
@"id": @"melon",
@"name": KBLocalized(@"蜜瓜主题"),
@"background_image": @"https://picsum.photos/id/1018/800/450.jpg",
@"background": @"#F5FFE8",
@"key_bg": @"#FFFFFF",
@"key_text": @"#4A4A4A",
@"key_highlight": @"#D9F4C4",
@"accent": @"#A4D68A",
@"hidden_keys": @[
@"letter_q",@"letter_w",@"letter_e",@"letter_r",@"letter_t",
@"letter_y",@"letter_u",@"letter_i",@"letter_o",@"letter_p",
@"letter_a",@"letter_s",@"letter_d",@"letter_f",@"letter_g",
@"letter_h",@"letter_j",@"letter_k",@"letter_l",
@"letter_z",@"letter_x",@"letter_c",@"letter_v",
@"letter_b",@"letter_n",@"letter_m",
@"space"
],
// Assets
// URL
@"key_icons": @{
//
// *_lower / *_upper
@"letter_q_lower": @"key_q",
@"letter_q_upper": @"key_q",
@"letter_w_lower": @"key_w",
@"letter_w_upper": @"key_w",
@"letter_e_lower": @"key_e",
@"letter_e_upper": @"key_e",
@"letter_r_lower": @"key_r",
@"letter_r_upper": @"key_r",
@"letter_t_lower": @"key_t",
@"letter_t_upper": @"key_t",
@"letter_y_lower": @"key_y",
@"letter_y_upper": @"key_y",
@"letter_u_lower": @"key_u",
@"letter_u_upper": @"key_u",
@"letter_i_lower": @"key_i",
@"letter_i_upper": @"key_i",
@"letter_o_lower": @"key_o",
@"letter_o_upper": @"key_o",
@"letter_p_lower": @"key_p",
@"letter_p_upper": @"key_p",
@"letter_a_lower": @"key_a",
@"letter_a_upper": @"key_a",
@"letter_s_lower": @"key_s",
@"letter_s_upper": @"key_s",
@"letter_d_lower": @"key_d",
@"letter_d_upper": @"key_d",
@"letter_f_lower": @"key_f",
@"letter_f_upper": @"key_f",
@"letter_g_lower": @"key_g",
@"letter_g_upper": @"key_g",
@"letter_h_lower": @"key_h",
@"letter_h_upper": @"key_h",
@"letter_j_lower": @"key_j",
@"letter_j_upper": @"key_j",
@"letter_k_lower": @"key_k",
@"letter_k_upper": @"key_k",
@"letter_l_lower": @"key_l",
@"letter_l_upper": @"key_l",
@"letter_z_lower": @"key_z",
@"letter_z_upper": @"key_z",
@"letter_x_lower": @"key_x",
@"letter_x_upper": @"key_x",
@"letter_c_lower": @"key_c",
@"letter_c_upper": @"key_c",
@"letter_v_lower": @"key_v",
@"letter_v_upper": @"key_v",
@"letter_b_lower": @"key_b",
@"letter_b_upper": @"key_b",
@"letter_n_lower": @"key_n",
@"letter_n_upper": @"key_n",
@"letter_m_lower": @"key_m",
@"letter_m_upper": @"key_m",
//
@"space": @"key_space", //
@"backspace": @"key_del", //
@"shift": @"key_up", // Shift
@"mode_123": @"key_123", // "123"
@"ai": @"key_ai", // AI
@"return": @"key_send" // /
}
}
];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, KB_NAV_TOTAL_HEIGHT, KB_SCREEN_WIDTH, KB_SCREEN_HEIGHT - KB_NAV_TOTAL_HEIGHT) style:UITableViewStyleInsetGrouped];
@@ -78,55 +171,8 @@
NSInteger idx = sender.tag;
if (idx < 0 || idx >= self.skins.count) return;
NSDictionary *skin = self.skins[idx];
NSString *path = skin[@"img"] ?: @""; // KB_BASE_URL
// JSON NSData
[[KBNetworkManager shared] GET:path parameters:nil headers:nil completion:^(id jsonOrData, NSURLResponse *response, NSError *error) {
NSData *data = ([jsonOrData isKindOfClass:NSData.class] ? (NSData *)jsonOrData : nil);
// Keychain 1500px
if (data && data.length > 0) {
UIImage *img = [UIImage imageWithData:data];
if (img) {
CGFloat maxW = 1500.0;
if (img.size.width > maxW) {
CGFloat scale = maxW / img.size.width;
CGSize newSize = CGSizeMake(maxW, floor(img.size.height * scale));
UIGraphicsBeginImageContextWithOptions(newSize, YES, 1.0);
[img drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *resized = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
img = resized ?: img;
}
data = UIImageJPEGRepresentation(img, 0.85) ?: data; // JPEG
}
}
dispatch_async(dispatch_get_main_queue(), ^{
NSData *payload = data;
if (payload.length == 0) {
//
CGSize size = CGSizeMake(1200, 600);
UIGraphicsBeginImageContextWithOptions(size, YES, 1.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
UIColor *c1 = [UIColor colorWithRed:0.76 green:0.91 blue:0.86 alpha:1];
UIColor *c2 = [UIColor colorWithRed:0.93 green:0.97 blue:0.91 alpha:1];
if ([skin[@"id"] hasPrefix:@"dark"]) {
c1 = [UIColor colorWithRed:0.1 green:0.12 blue:0.16 alpha:1];
c2 = [UIColor colorWithRed:0.22 green:0.24 blue:0.28 alpha:1];
}
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
NSArray *colors = @[(__bridge id)c1.CGColor, (__bridge id)c2.CGColor];
CGFloat locs[] = {0,1};
CGGradientRef grad = CGGradientCreateWithColors(space, (__bridge CFArrayRef)colors, locs);
CGContextDrawLinearGradient(ctx, grad, CGPointZero, CGPointMake(size.width, size.height), 0);
CGGradientRelease(grad); CGColorSpaceRelease(space);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
payload = UIImageJPEGRepresentation(img, 0.9);
}
BOOL ok = (payload.length > 0) ? [[KBSkinManager shared] applyImageSkinWithData:payload skinId:skin[@"id"] name:skin[@"name"]] : NO;
[KBHUD showInfo:(ok ? KBLocalized(@"已应用,切到键盘查看") : KBLocalized(@"应用失败"))];
});
}];
if (!skin) return;
[[KBSkinService shared] applySkinWithJSON:skin fromViewController:self completion:nil];
}
@end