2025-11-04 21:01:46 +08:00
|
|
|
|
//
|
|
|
|
|
|
// KBSkinCenterVC.m
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#import "KBSkinCenterVC.h"
|
|
|
|
|
|
#import "Masonry.h"
|
|
|
|
|
|
#import "KBNetworkManager.h"
|
|
|
|
|
|
#import "KBSkinManager.h"
|
|
|
|
|
|
#import "KBHUD.h"
|
2025-11-18 20:53:47 +08:00
|
|
|
|
#import "KBConfig.h"
|
|
|
|
|
|
#import "KBSkinService.h"
|
2025-11-04 21:01:46 +08:00
|
|
|
|
|
|
|
|
|
|
@interface KBSkinCell : UITableViewCell
|
|
|
|
|
|
@property (nonatomic, strong) UIButton *applyBtn;
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation KBSkinCell
|
|
|
|
|
|
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
|
|
|
|
|
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
|
|
|
|
|
|
self.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
|
|
|
|
_applyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
|
2025-11-17 20:07:39 +08:00
|
|
|
|
[_applyBtn setTitle:KBLocalized(@"Download & Apply") forState:UIControlStateNormal];
|
2025-11-04 21:01:46 +08:00
|
|
|
|
_applyBtn.layer.cornerRadius = 6; _applyBtn.layer.borderWidth = 1;
|
|
|
|
|
|
_applyBtn.layer.borderColor = [UIColor colorWithWhite:0.85 alpha:1].CGColor;
|
|
|
|
|
|
[self.contentView addSubview:_applyBtn];
|
|
|
|
|
|
[_applyBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
|
make.right.equalTo(self.contentView).offset(-16);
|
|
|
|
|
|
make.centerY.equalTo(self.contentView);
|
|
|
|
|
|
make.width.mas_equalTo(110);
|
|
|
|
|
|
make.height.mas_equalTo(34);
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
return self;
|
|
|
|
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@interface KBSkinCenterVC () <UITableViewDelegate, UITableViewDataSource>
|
|
|
|
|
|
@property (nonatomic, strong) UITableView *tableView;
|
2025-11-18 20:53:47 +08:00
|
|
|
|
@property (nonatomic, copy) NSArray<NSDictionary *> *skins; // 每个元素即一套皮肤的 JSON(与后端约定格式一致)
|
2025-11-04 21:01:46 +08:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation KBSkinCenterVC
|
|
|
|
|
|
|
|
|
|
|
|
- (void)viewDidLoad {
|
|
|
|
|
|
[super viewDidLoad];
|
2025-11-18 13:48:22 +08:00
|
|
|
|
// self.title = KBLocalized(@"皮肤中心");
|
2025-11-04 21:01:46 +08:00
|
|
|
|
self.view.backgroundColor = [UIColor whiteColor];
|
2025-11-18 20:53:47 +08:00
|
|
|
|
|
|
|
|
|
|
// 本地测试用的皮肤数据:结构与后端最终返回的 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")
|
2025-11-19 14:54:45 +08:00
|
|
|
|
// * 当 KB_SKIN_ICON_USE_REMOTE==1 时,value 写 Zip 包内的图标“短文件名”(如 "key_space";解压后路径为 Skins/<skinId>/icons/key_space.png)
|
2025-11-04 21:01:46 +08:00
|
|
|
|
self.skins = @[
|
2025-11-18 20:53:47 +08:00
|
|
|
|
@{
|
|
|
|
|
|
@"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 名称。
|
2025-11-19 14:54:45 +08:00
|
|
|
|
// 如果开启远程 Zip 模式,可改为 Zip 内对应的图标短文件名(如 "key_space")。
|
2025-11-18 20:53:47 +08:00
|
|
|
|
@"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" // 发送/换行键
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-04 21:01:46 +08:00
|
|
|
|
];
|
|
|
|
|
|
|
2025-11-18 13:48:22 +08:00
|
|
|
|
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, KB_NAV_TOTAL_HEIGHT, KB_SCREEN_WIDTH, KB_SCREEN_HEIGHT - KB_NAV_TOTAL_HEIGHT) style:UITableViewStyleInsetGrouped];
|
2025-11-04 21:01:46 +08:00
|
|
|
|
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
|
|
|
|
self.tableView.delegate = self; self.tableView.dataSource = self;
|
|
|
|
|
|
[self.view addSubview:self.tableView];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - UITableView
|
|
|
|
|
|
|
|
|
|
|
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; }
|
|
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.skins.count; }
|
|
|
|
|
|
|
|
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
|
|
|
static NSString *cid = @"skin.cell";
|
|
|
|
|
|
KBSkinCell *cell = [tableView dequeueReusableCellWithIdentifier:cid];
|
|
|
|
|
|
if (!cell) { cell = [[KBSkinCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cid]; }
|
|
|
|
|
|
NSDictionary *skin = self.skins[indexPath.row];
|
|
|
|
|
|
cell.textLabel.text = skin[@"name"]; cell.detailTextLabel.text = skin[@"id"];
|
|
|
|
|
|
[cell.applyBtn removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
[cell.applyBtn addTarget:self action:@selector(onApplyBtn:) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
|
cell.applyBtn.tag = indexPath.row;
|
|
|
|
|
|
return cell;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)onApplyBtn:(UIButton *)sender {
|
|
|
|
|
|
NSInteger idx = sender.tag;
|
|
|
|
|
|
if (idx < 0 || idx >= self.skins.count) return;
|
|
|
|
|
|
NSDictionary *skin = self.skins[idx];
|
2025-11-18 20:53:47 +08:00
|
|
|
|
if (!skin) return;
|
|
|
|
|
|
[[KBSkinService shared] applySkinWithJSON:skin fromViewController:self completion:nil];
|
2025-11-04 21:01:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@end
|