1
This commit is contained in:
@@ -16,6 +16,328 @@
|
||||
#import "KBMyVM.h"
|
||||
#import "KBAlert.h"
|
||||
#import "KBCancelAccountVC.h"
|
||||
#import "KBLocalizationManager.h"
|
||||
#import "KBConfig.h"
|
||||
#import "KBSkinInstallBridge.h"
|
||||
#import "KBInputProfileManager.h"
|
||||
|
||||
static NSInteger const kKBPersonInfoRowNickname = 0;
|
||||
static NSInteger const kKBPersonInfoRowGender = 1;
|
||||
static NSInteger const kKBPersonInfoRowLanguage = 2;
|
||||
static NSInteger const kKBPersonInfoRowUserID = 3;
|
||||
|
||||
typedef void(^KBInputProfileSelectHandler)(NSString *languageCode, NSString *layoutVariant, NSString *profileId);
|
||||
|
||||
@interface KBKeyboardLayoutSelectVC : BaseViewController <UITableViewDelegate, UITableViewDataSource>
|
||||
@property (nonatomic, strong) BaseTableView *tableView;
|
||||
@property (nonatomic, strong) UIButton *confirmButton;
|
||||
@property (nonatomic, copy) NSDictionary *languageConfig;
|
||||
@property (nonatomic, copy) NSString *selectedLayoutVariant;
|
||||
@property (nonatomic, copy) NSString *selectedProfileId;
|
||||
@property (nonatomic, copy) NSString *pendingLayoutVariant;
|
||||
@property (nonatomic, copy) NSString *pendingProfileId;
|
||||
@property (nonatomic, copy) KBInputProfileSelectHandler onSelect;
|
||||
@end
|
||||
|
||||
@implementation KBKeyboardLayoutSelectVC
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
/// 1:控件初始化
|
||||
[self setupUI];
|
||||
/// 2:初始化选中态
|
||||
[self prepareDefaultSelection];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
self.kb_titleLabel.text = KBLocalized(@"Choose Layout");
|
||||
self.view.backgroundColor = [UIColor colorWithHex:0xF8F8F8];
|
||||
[self.view addSubview:self.tableView];
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.view);
|
||||
make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT + 10);
|
||||
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-72);
|
||||
}];
|
||||
[self.view addSubview:self.confirmButton];
|
||||
[self.confirmButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.view).offset(16);
|
||||
make.right.equalTo(self.view).offset(-16);
|
||||
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-12);
|
||||
make.height.mas_equalTo(50);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)prepareDefaultSelection {
|
||||
NSArray *layouts = [self.languageConfig[@"layouts"] isKindOfClass:NSArray.class] ? self.languageConfig[@"layouts"] : @[];
|
||||
NSDictionary *matched = nil;
|
||||
for (NSDictionary *layout in layouts) {
|
||||
NSString *variant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"";
|
||||
if (self.selectedLayoutVariant.length > 0 && [variant isEqualToString:self.selectedLayoutVariant]) {
|
||||
matched = layout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
matched = layouts.firstObject;
|
||||
}
|
||||
self.pendingLayoutVariant = [matched[@"variant"] isKindOfClass:NSString.class] ? matched[@"variant"] : @"";
|
||||
self.pendingProfileId = [matched[@"profileId"] isKindOfClass:NSString.class] ? matched[@"profileId"] : @"";
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
NSArray *layouts = [self.languageConfig[@"layouts"] isKindOfClass:NSArray.class] ? self.languageConfig[@"layouts"] : @[];
|
||||
return layouts.count;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return 56.0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
static NSString *cid = @"KBKeyboardLayoutCell";
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cid];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cid];
|
||||
cell.textLabel.font = [KBFont medium:16];
|
||||
cell.detailTextLabel.font = [KBFont regular:12];
|
||||
cell.detailTextLabel.textColor = [UIColor colorWithHex:0x999999];
|
||||
}
|
||||
NSArray *layouts = [self.languageConfig[@"layouts"] isKindOfClass:NSArray.class] ? self.languageConfig[@"layouts"] : @[];
|
||||
NSDictionary *layout = (indexPath.row < layouts.count) ? layouts[indexPath.row] : @{};
|
||||
NSString *title = [layout[@"title"] isKindOfClass:NSString.class] ? layout[@"title"] : @"";
|
||||
NSString *variant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"";
|
||||
NSString *profileId = [layout[@"profileId"] isKindOfClass:NSString.class] ? layout[@"profileId"] : @"";
|
||||
cell.textLabel.text = title;
|
||||
cell.detailTextLabel.text = profileId;
|
||||
BOOL selected = (self.pendingLayoutVariant.length > 0 && [self.pendingLayoutVariant isEqualToString:variant]);
|
||||
cell.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
NSArray *layouts = [self.languageConfig[@"layouts"] isKindOfClass:NSArray.class] ? self.languageConfig[@"layouts"] : @[];
|
||||
NSDictionary *layout = (indexPath.row < layouts.count) ? layouts[indexPath.row] : nil;
|
||||
if (![layout isKindOfClass:NSDictionary.class]) { return; }
|
||||
self.pendingLayoutVariant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"";
|
||||
self.pendingProfileId = [layout[@"profileId"] isKindOfClass:NSString.class] ? layout[@"profileId"] : @"";
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)onTapConfirm {
|
||||
NSString *code = [self.languageConfig[@"code"] isKindOfClass:NSString.class] ? self.languageConfig[@"code"] : KBLanguageCodeEnglish;
|
||||
if (self.onSelect && code.length > 0 && self.pendingLayoutVariant.length > 0 && self.pendingProfileId.length > 0) {
|
||||
self.onSelect(code, self.pendingLayoutVariant, self.pendingProfileId);
|
||||
}
|
||||
}
|
||||
|
||||
- (BaseTableView *)tableView {
|
||||
if (!_tableView) {
|
||||
_tableView = [[BaseTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
_tableView.backgroundColor = UIColor.clearColor;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.delegate = self;
|
||||
_tableView.separatorInset = UIEdgeInsetsMake(0, 16, 0, 16);
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
- (UIButton *)confirmButton {
|
||||
if (!_confirmButton) {
|
||||
_confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_confirmButton setTitle:KBLocalized(@"Confirm") forState:UIControlStateNormal];
|
||||
[_confirmButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
_confirmButton.titleLabel.font = [KBFont medium:16];
|
||||
_confirmButton.backgroundColor = [UIColor colorWithHex:0x111111];
|
||||
_confirmButton.layer.cornerRadius = 12;
|
||||
_confirmButton.layer.masksToBounds = YES;
|
||||
[_confirmButton addTarget:self action:@selector(onTapConfirm) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _confirmButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface KBKeyboardLanguageSelectVC : BaseViewController <UITableViewDelegate, UITableViewDataSource>
|
||||
@property (nonatomic, strong) BaseTableView *tableView;
|
||||
@property (nonatomic, strong) UIButton *confirmButton;
|
||||
@property (nonatomic, copy) NSArray<NSDictionary *> *languageConfigs;
|
||||
@property (nonatomic, copy) NSString *selectedLanguageCode;
|
||||
@property (nonatomic, copy) NSString *selectedLayoutVariant;
|
||||
@property (nonatomic, copy) NSString *pendingLanguageCode;
|
||||
@property (nonatomic, copy) NSString *pendingLayoutVariant;
|
||||
@property (nonatomic, copy) NSString *pendingProfileId;
|
||||
@property (nonatomic, copy) KBInputProfileSelectHandler onSelect;
|
||||
@end
|
||||
|
||||
@implementation KBKeyboardLanguageSelectVC
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
/// 1:控件初始化
|
||||
[self setupUI];
|
||||
/// 2:初始化选中态
|
||||
[self prepareDefaultSelection];
|
||||
[self updateConfirmVisibility];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
self.kb_titleLabel.text = KBLocalized(@"Input Language");
|
||||
self.view.backgroundColor = [UIColor colorWithHex:0xF8F8F8];
|
||||
[self.view addSubview:self.tableView];
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.equalTo(self.view);
|
||||
make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT + 10);
|
||||
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-72);
|
||||
}];
|
||||
[self.view addSubview:self.confirmButton];
|
||||
[self.confirmButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.view).offset(16);
|
||||
make.right.equalTo(self.view).offset(-16);
|
||||
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-12);
|
||||
make.height.mas_equalTo(50);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)prepareDefaultSelection {
|
||||
NSDictionary *config = [self languageConfigForCode:self.selectedLanguageCode];
|
||||
if (!config) {
|
||||
config = self.languageConfigs.firstObject;
|
||||
}
|
||||
NSString *code = [config[@"code"] isKindOfClass:NSString.class] ? config[@"code"] : KBLanguageCodeEnglish;
|
||||
NSArray *layouts = [config[@"layouts"] isKindOfClass:NSArray.class] ? config[@"layouts"] : @[];
|
||||
NSDictionary *layoutMatched = nil;
|
||||
for (NSDictionary *layout in layouts) {
|
||||
NSString *variant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"";
|
||||
if (self.selectedLayoutVariant.length > 0 && [variant isEqualToString:self.selectedLayoutVariant]) {
|
||||
layoutMatched = layout;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!layoutMatched) {
|
||||
layoutMatched = layouts.firstObject;
|
||||
}
|
||||
self.pendingLanguageCode = code;
|
||||
self.pendingLayoutVariant = [layoutMatched[@"variant"] isKindOfClass:NSString.class] ? layoutMatched[@"variant"] : @"qwerty";
|
||||
self.pendingProfileId = [layoutMatched[@"profileId"] isKindOfClass:NSString.class] ? layoutMatched[@"profileId"] : @"en_US_qwerty";
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)languageConfigForCode:(NSString *)code {
|
||||
for (NSDictionary *item in self.languageConfigs) {
|
||||
NSString *langCode = [item[@"code"] isKindOfClass:NSString.class] ? item[@"code"] : @"";
|
||||
if ([langCode isEqualToString:code]) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)updateConfirmVisibility {
|
||||
NSDictionary *config = [self languageConfigForCode:self.pendingLanguageCode];
|
||||
NSArray *layouts = [config[@"layouts"] isKindOfClass:NSArray.class] ? config[@"layouts"] : @[];
|
||||
BOOL hasMultiLayout = (layouts.count > 1);
|
||||
self.confirmButton.hidden = hasMultiLayout;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.languageConfigs.count;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return 56.0;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
static NSString *cid = @"KBKeyboardLanguageCell";
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cid];
|
||||
if (!cell) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cid];
|
||||
cell.textLabel.font = [KBFont medium:16];
|
||||
cell.detailTextLabel.font = [KBFont regular:12];
|
||||
cell.detailTextLabel.textColor = [UIColor colorWithHex:0x999999];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
}
|
||||
NSDictionary *lang = (indexPath.row < self.languageConfigs.count) ? self.languageConfigs[indexPath.row] : @{};
|
||||
NSString *name = [lang[@"name"] isKindOfClass:NSString.class] ? lang[@"name"] : @"";
|
||||
NSString *code = [lang[@"code"] isKindOfClass:NSString.class] ? lang[@"code"] : @"";
|
||||
NSArray *layouts = [lang[@"layouts"] isKindOfClass:NSArray.class] ? lang[@"layouts"] : @[];
|
||||
BOOL multi = layouts.count > 1;
|
||||
BOOL isSelected = (self.pendingLanguageCode.length > 0 && [self.pendingLanguageCode isEqualToString:code]);
|
||||
cell.textLabel.text = name;
|
||||
cell.detailTextLabel.text = multi ? KBLocalized(@"Multiple Keyboard Layouts") : @"QWERTY";
|
||||
cell.accessoryType = multi ? UITableViewCellAccessoryDisclosureIndicator : (isSelected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone);
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
NSDictionary *lang = (indexPath.row < self.languageConfigs.count) ? self.languageConfigs[indexPath.row] : nil;
|
||||
if (![lang isKindOfClass:NSDictionary.class]) { return; }
|
||||
NSString *code = [lang[@"code"] isKindOfClass:NSString.class] ? lang[@"code"] : KBLanguageCodeEnglish;
|
||||
NSArray *layouts = [lang[@"layouts"] isKindOfClass:NSArray.class] ? lang[@"layouts"] : @[];
|
||||
if (layouts.count > 1) {
|
||||
self.pendingLanguageCode = code;
|
||||
[self updateConfirmVisibility];
|
||||
[self.tableView reloadData];
|
||||
KBKeyboardLayoutSelectVC *layoutVC = [[KBKeyboardLayoutSelectVC alloc] init];
|
||||
layoutVC.languageConfig = lang;
|
||||
layoutVC.selectedLayoutVariant = self.selectedLanguageCode.length > 0 && [self.selectedLanguageCode isEqualToString:code] ? self.selectedLayoutVariant : @"";
|
||||
__weak typeof(self) weakSelf = self;
|
||||
layoutVC.onSelect = ^(NSString *languageCode, NSString *layoutVariant, NSString *profileId) {
|
||||
weakSelf.pendingLanguageCode = languageCode;
|
||||
weakSelf.pendingLayoutVariant = layoutVariant;
|
||||
weakSelf.pendingProfileId = profileId;
|
||||
if (weakSelf.onSelect) {
|
||||
weakSelf.onSelect(languageCode, layoutVariant, profileId);
|
||||
}
|
||||
};
|
||||
[self.navigationController pushViewController:layoutVC animated:YES];
|
||||
return;
|
||||
}
|
||||
NSDictionary *layout = layouts.firstObject;
|
||||
self.pendingLanguageCode = code;
|
||||
self.pendingLayoutVariant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"qwerty";
|
||||
self.pendingProfileId = [layout[@"profileId"] isKindOfClass:NSString.class] ? layout[@"profileId"] : @"en_US_qwerty";
|
||||
[self updateConfirmVisibility];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (BaseTableView *)tableView {
|
||||
if (!_tableView) {
|
||||
_tableView = [[BaseTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
_tableView.backgroundColor = UIColor.clearColor;
|
||||
_tableView.dataSource = self;
|
||||
_tableView.delegate = self;
|
||||
_tableView.separatorInset = UIEdgeInsetsMake(0, 16, 0, 16);
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
|
||||
- (void)onTapConfirm {
|
||||
if (self.confirmButton.hidden) {
|
||||
return;
|
||||
}
|
||||
if (self.onSelect && self.pendingLanguageCode.length > 0 && self.pendingLayoutVariant.length > 0 && self.pendingProfileId.length > 0) {
|
||||
self.onSelect(self.pendingLanguageCode, self.pendingLayoutVariant, self.pendingProfileId);
|
||||
}
|
||||
}
|
||||
|
||||
- (UIButton *)confirmButton {
|
||||
if (!_confirmButton) {
|
||||
_confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_confirmButton setTitle:KBLocalized(@"Confirm") forState:UIControlStateNormal];
|
||||
[_confirmButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
|
||||
_confirmButton.titleLabel.font = [KBFont medium:16];
|
||||
_confirmButton.backgroundColor = [UIColor colorWithHex:0x111111];
|
||||
_confirmButton.layer.cornerRadius = 12;
|
||||
_confirmButton.layer.masksToBounds = YES;
|
||||
[_confirmButton addTarget:self action:@selector(onTapConfirm) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _confirmButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface KBPersonInfoVC () <UITableViewDelegate, UITableViewDataSource, PHPickerViewControllerDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate>
|
||||
|
||||
// 列表
|
||||
@@ -38,6 +360,9 @@
|
||||
@property (nonatomic, strong) KBMyVM *myVM;
|
||||
@property (nonatomic, strong) KBMyVM *viewModel; // 我的页面 VM
|
||||
@property (nonatomic, strong) KBUser *userModel;
|
||||
@property (nonatomic, copy) NSString *selectedLanguageCode;
|
||||
@property (nonatomic, copy) NSString *selectedLayoutVariant;
|
||||
@property (nonatomic, copy) NSString *selectedProfileId;
|
||||
|
||||
@end
|
||||
|
||||
@@ -45,18 +370,25 @@
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
/// 1:控件初始化
|
||||
[self setupUI];
|
||||
/// 2:恢复输入配置
|
||||
[self restoreInputProfile];
|
||||
/// 3:加载用户资料
|
||||
[self loadData];
|
||||
/// 4:监听语言变化
|
||||
[self bindNotifications];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)setupUI {
|
||||
self.kb_titleLabel.text = KBLocalized(@"Settings"); // 导航标题
|
||||
self.kb_navView.backgroundColor = [UIColor clearColor];
|
||||
self.view.backgroundColor = [UIColor colorWithHex:0xF8F8F8];
|
||||
|
||||
// 构造数据
|
||||
// self.items = @[
|
||||
// @{ @"title": KBLocalized(@"Nickname"), @"value": @"", @"arrow": @YES, @"copy": @NO },
|
||||
// @{ @"title": KBLocalized(@"Gender"), @"value": @"Choose", @"arrow": @YES, @"copy": @NO },
|
||||
// @{ @"title": KBLocalized(@"User ID"), @"value": @"", @"arrow": @NO, @"copy": @YES },
|
||||
// ];
|
||||
|
||||
|
||||
[self.view addSubview:self.tableView];
|
||||
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.bottom.equalTo(self.view);
|
||||
@@ -79,6 +411,9 @@
|
||||
UIEdgeInsets inset = self.tableView.contentInset;
|
||||
inset.bottom = 56 + 24; // 按钮高度 + 额外间距
|
||||
self.tableView.contentInset = inset;
|
||||
}
|
||||
|
||||
- (void)loadData {
|
||||
self.viewModel = [[KBMyVM alloc] init];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self.viewModel fetchUserDetailWithCompletion:^(KBUser * _Nullable user, NSError * _Nullable error) {
|
||||
@@ -86,18 +421,38 @@
|
||||
weakSelf.userModel = user;
|
||||
[weakSelf.avatarView kb_setAvatarURL:weakSelf.userModel.avatarUrl placeholder:KBAvatarPlaceholderImage];
|
||||
weakSelf.modifyLabel.text = weakSelf.userModel.nickName;
|
||||
// 根据用户模型的 gender 显示当前性别,支持多语言
|
||||
NSString *genderText = [weakSelf kb_genderDisplayText];
|
||||
weakSelf.items = @[
|
||||
@{ @"title": KBLocalized(@"Nickname"), @"value": weakSelf.userModel.nickName, @"arrow": @YES, @"copy": @NO },
|
||||
@{ @"title": KBLocalized(@"Gender"), @"value": genderText, @"arrow": @YES, @"copy": @NO },
|
||||
@{ @"title": KBLocalized(@"User ID"), @"value": weakSelf.userModel.userId, @"arrow": @NO, @"copy": @YES },
|
||||
];
|
||||
[weakSelf.tableView reloadData];
|
||||
}
|
||||
[weakSelf rebuildItems];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)bindNotifications {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleLanguageChanged)
|
||||
name:KBLocalizationDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)handleLanguageChanged {
|
||||
self.kb_titleLabel.text = KBLocalized(@"Settings");
|
||||
[self.logoutBtn setTitle:KBLocalized(@"Log Out") forState:UIControlStateNormal];
|
||||
[self rebuildItems];
|
||||
}
|
||||
|
||||
- (void)rebuildItems {
|
||||
NSString *nickname = self.userModel.nickName ?: @"";
|
||||
NSString *genderText = [self kb_genderDisplayText];
|
||||
NSString *languageText = [self currentInputProfileDisplayText];
|
||||
NSString *userId = self.userModel.userId ?: @"";
|
||||
self.items = @[
|
||||
@{ @"title": KBLocalized(@"Nickname"), @"value": nickname, @"arrow": @YES, @"copy": @NO },
|
||||
@{ @"title": KBLocalized(@"Gender"), @"value": genderText, @"arrow": @YES, @"copy": @NO },
|
||||
@{ @"title": KBLocalized(@"Input Language"), @"value": languageText, @"arrow": @YES, @"copy": @NO },
|
||||
@{ @"title": KBLocalized(@"User ID"), @"value": userId, @"arrow": @NO, @"copy": @YES },
|
||||
];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
|
||||
/// 根据 userModel.gender 生成展示用的性别文案(带多语言)
|
||||
- (NSString *)kb_genderDisplayText {
|
||||
@@ -116,6 +471,194 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)restoreInputProfile {
|
||||
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
|
||||
NSString *savedCode = [shared stringForKey:AppGroup_SelectedKeyboardLanguageCode];
|
||||
NSString *savedVariant = [shared stringForKey:AppGroup_SelectedKeyboardLayoutVariant];
|
||||
NSString *savedProfile = [shared stringForKey:AppGroup_SelectedKeyboardProfileId];
|
||||
|
||||
NSString *currentCode = [KBLocalizationManager shared].currentLanguageCode ?: KBLanguageCodeEnglish;
|
||||
NSDictionary *config = [self languageConfigForCode:(savedCode.length ? savedCode : currentCode)];
|
||||
if (!config) {
|
||||
config = [self languageConfigForCode:KBLanguageCodeEnglish];
|
||||
}
|
||||
|
||||
NSArray *layouts = [config[@"layouts"] isKindOfClass:NSArray.class] ? config[@"layouts"] : @[];
|
||||
NSDictionary *layout = nil;
|
||||
for (NSDictionary *item in layouts) {
|
||||
NSString *variant = [item[@"variant"] isKindOfClass:NSString.class] ? item[@"variant"] : @"";
|
||||
if (savedVariant.length > 0 && [variant isEqualToString:savedVariant]) {
|
||||
layout = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!layout) { layout = layouts.firstObject; }
|
||||
|
||||
self.selectedLanguageCode = [config[@"code"] isKindOfClass:NSString.class] ? config[@"code"] : KBLanguageCodeEnglish;
|
||||
self.selectedLayoutVariant = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"qwerty";
|
||||
self.selectedProfileId = savedProfile.length > 0 ? savedProfile : ([layout[@"profileId"] isKindOfClass:NSString.class] ? layout[@"profileId"] : @"en_US_qwerty");
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary *> *)languageConfigs {
|
||||
NSArray<KBInputProfile *> *profiles = [[KBInputProfileManager sharedManager] allProfiles];
|
||||
NSMutableArray<NSDictionary *> *configs = [NSMutableArray array];
|
||||
|
||||
for (KBInputProfile *profile in profiles) {
|
||||
NSMutableArray<NSDictionary *> *layouts = [NSMutableArray array];
|
||||
for (KBInputProfileLayout *layout in profile.layouts) {
|
||||
[layouts addObject:@{
|
||||
@"variant": layout.variant,
|
||||
@"title": layout.title,
|
||||
@"profileId": layout.profileId
|
||||
}];
|
||||
}
|
||||
|
||||
[configs addObject:@{
|
||||
@"code": profile.code,
|
||||
@"name": profile.name,
|
||||
@"layouts": [layouts copy]
|
||||
}];
|
||||
}
|
||||
|
||||
return [configs copy];
|
||||
}
|
||||
|
||||
- (nullable NSDictionary *)languageConfigForCode:(NSString *)languageCode {
|
||||
for (NSDictionary *item in [self languageConfigs]) {
|
||||
NSString *code = [item[@"code"] isKindOfClass:NSString.class] ? item[@"code"] : @"";
|
||||
if ([code isEqualToString:languageCode]) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)layoutTitleForLanguageCode:(NSString *)languageCode variant:(NSString *)variant {
|
||||
NSDictionary *config = [self languageConfigForCode:languageCode];
|
||||
NSArray *layouts = [config[@"layouts"] isKindOfClass:NSArray.class] ? config[@"layouts"] : @[];
|
||||
for (NSDictionary *layout in layouts) {
|
||||
NSString *v = [layout[@"variant"] isKindOfClass:NSString.class] ? layout[@"variant"] : @"";
|
||||
if ([v isEqualToString:variant]) {
|
||||
return [layout[@"title"] isKindOfClass:NSString.class] ? layout[@"title"] : @"";
|
||||
}
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)currentInputProfileDisplayText {
|
||||
NSDictionary *config = [self languageConfigForCode:self.selectedLanguageCode ?: KBLanguageCodeEnglish];
|
||||
NSString *languageName = [config[@"name"] isKindOfClass:NSString.class] ? config[@"name"] : @"English";
|
||||
NSString *layoutTitle = [self layoutTitleForLanguageCode:self.selectedLanguageCode variant:self.selectedLayoutVariant];
|
||||
if (layoutTitle.length == 0) {
|
||||
return languageName;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@ · %@", languageName, layoutTitle];
|
||||
}
|
||||
|
||||
- (void)openLanguageSelector {
|
||||
KBKeyboardLanguageSelectVC *vc = [[KBKeyboardLanguageSelectVC alloc] init];
|
||||
vc.languageConfigs = [self languageConfigs];
|
||||
vc.selectedLanguageCode = self.selectedLanguageCode ?: KBLanguageCodeEnglish;
|
||||
vc.selectedLayoutVariant = self.selectedLayoutVariant ?: @"qwerty";
|
||||
__weak typeof(self) weakSelf = self;
|
||||
vc.onSelect = ^(NSString *languageCode, NSString *layoutVariant, NSString *profileId) {
|
||||
[weakSelf applyInputProfileWithLanguageCode:languageCode
|
||||
layoutVariant:layoutVariant
|
||||
profileId:profileId
|
||||
completion:^(BOOL success) {
|
||||
if (success) {
|
||||
[weakSelf.navigationController popToViewController:weakSelf animated:YES];
|
||||
}
|
||||
}];
|
||||
};
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)applyInputProfileWithLanguageCode:(NSString *)languageCode
|
||||
layoutVariant:(NSString *)layoutVariant
|
||||
profileId:(NSString *)profileId
|
||||
completion:(void(^ _Nullable)(BOOL success))completion {
|
||||
if (languageCode.length == 0 || layoutVariant.length == 0 || profileId.length == 0) {
|
||||
if (completion) { completion(NO); }
|
||||
return;
|
||||
}
|
||||
|
||||
// 严格策略:该语言未配置默认皮肤时,不允许切换语言。
|
||||
KBInputProfile *profile = [[KBInputProfileManager sharedManager] profileForLanguageCode:languageCode];
|
||||
NSString *zipName = profile.defaultSkinZip;
|
||||
if (zipName.length == 0) {
|
||||
[KBHUD showInfo:KBLocalized(@"Please configure a default skin for this language before switching.")];
|
||||
if (completion) { completion(NO); }
|
||||
return;
|
||||
}
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self installDefaultSkinForLanguageCode:languageCode completion:^(BOOL skinOK) {
|
||||
if (!skinOK) {
|
||||
[KBHUD showInfo:KBLocalized(@"Default skin install failed. Please check skin resource configuration.")];
|
||||
if (completion) { completion(NO); }
|
||||
return;
|
||||
}
|
||||
[weakSelf commitInputProfileSwitchWithLanguageCode:languageCode
|
||||
layoutVariant:layoutVariant
|
||||
profileId:profileId];
|
||||
if (completion) { completion(YES); }
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)commitInputProfileSwitchWithLanguageCode:(NSString *)languageCode
|
||||
layoutVariant:(NSString *)layoutVariant
|
||||
profileId:(NSString *)profileId {
|
||||
self.selectedLanguageCode = languageCode;
|
||||
self.selectedLayoutVariant = layoutVariant;
|
||||
self.selectedProfileId = profileId;
|
||||
[self rebuildItems];
|
||||
|
||||
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
|
||||
[shared setObject:languageCode forKey:AppGroup_SelectedKeyboardLanguageCode];
|
||||
[shared setObject:layoutVariant forKey:AppGroup_SelectedKeyboardLayoutVariant];
|
||||
[shared setObject:profileId forKey:AppGroup_SelectedKeyboardProfileId];
|
||||
[shared synchronize];
|
||||
|
||||
[[KBLocalizationManager shared] setCurrentLanguageCode:languageCode persist:YES];
|
||||
|
||||
NSString *message = KBLocalized(@"Changing language will reload the Home screen.");
|
||||
[KBHUD showInfo:message];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.35 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[appDelegate performSelector:@selector(setupRootVC)];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)installDefaultSkinForLanguageCode:(NSString *)languageCode completion:(void(^)(BOOL success))completion {
|
||||
KBInputProfile *profile = [[KBInputProfileManager sharedManager] profileForLanguageCode:languageCode];
|
||||
NSString *zipName = profile.defaultSkinZip;
|
||||
if (zipName.length == 0) {
|
||||
if (completion) { completion(NO); }
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *skinId = [NSString stringWithFormat:@"bundle_skin_default_%@", languageCode];
|
||||
[KBSkinInstallBridge publishBundleSkinRequestWithId:skinId
|
||||
name:skinId
|
||||
zipName:zipName
|
||||
iconShortNames:nil];
|
||||
[KBSkinInstallBridge consumePendingRequestFromBundle:NSBundle.mainBundle
|
||||
completion:^(BOOL success, NSError * _Nullable error) {
|
||||
if (!success && error) {
|
||||
NSLog(@"[KBPersonInfoVC] default skin install failed: %@", error);
|
||||
} else if (success) {
|
||||
NSLog(@"[KBPersonInfoVC] default skin installed: %@", skinId);
|
||||
}
|
||||
if (completion) { completion(success); }
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - UITableView
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 2; }
|
||||
@@ -165,7 +708,7 @@
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
return;
|
||||
}
|
||||
if (indexPath.row == 0) {
|
||||
if (indexPath.row == kKBPersonInfoRowNickname) {
|
||||
// 昵称编辑 -> 弹窗
|
||||
CGFloat width = KB_SCREEN_WIDTH;
|
||||
KBChangeNicknamePopView *content = [[KBChangeNicknamePopView alloc] initWithFrame:CGRectMake(0, 0, width, 230)];
|
||||
@@ -189,12 +732,7 @@
|
||||
// 更新本地模型,避免返回再进入还是旧数据
|
||||
weakSelf.userModel.nickName = nickname;
|
||||
weakSelf.modifyLabel.text = nickname;
|
||||
|
||||
// 更新第一行展示
|
||||
NSMutableArray *m = [weakSelf.items mutableCopy];
|
||||
NSMutableDictionary *d0 = [m.firstObject mutableCopy];
|
||||
d0[@"value"] = nickname; m[0] = d0; weakSelf.items = m;
|
||||
[weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
|
||||
[weakSelf rebuildItems];
|
||||
|
||||
// 将修改后的用户信息同步到服务端
|
||||
[weakSelf.myVM updateUserInfo:weakSelf.userModel completion:^(BOOL success, NSError * _Nullable error) {
|
||||
@@ -208,7 +746,7 @@
|
||||
|
||||
[pop pop];
|
||||
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [content focusInput]; });
|
||||
} else if (indexPath.row == 1) {
|
||||
} else if (indexPath.row == kKBPersonInfoRowGender) {
|
||||
// 性别选择 -> 弹窗(性别文案支持多语言)
|
||||
NSArray *genders = @[
|
||||
@{@"id":@"1",@"name":KBLocalized(@"Male")},
|
||||
@@ -219,7 +757,7 @@
|
||||
KBGenderPickerPopView *content = [[KBGenderPickerPopView alloc] initWithFrame:CGRectMake(0, 0, width, 300)];
|
||||
content.items = genders;
|
||||
// 取当前展示值对应的 id(如果有的话)
|
||||
NSString *curName = self.items[1][@"value"];
|
||||
NSString *curName = self.items[kKBPersonInfoRowGender][@"value"];
|
||||
NSString *selId = nil;
|
||||
for (NSDictionary *d in genders) { if ([d[@"name"] isEqualToString:curName]) { selId = d[@"id"]; break; } }
|
||||
content.selectedId = selId;
|
||||
@@ -251,11 +789,7 @@
|
||||
|
||||
// 同步更新本地 userModel,避免再次进入页面还是旧的性别
|
||||
weakSelf.userModel.gender = (UserSex)genderValue;
|
||||
|
||||
NSMutableArray *m = [weakSelf.items mutableCopy];
|
||||
NSMutableDictionary *d1 = [m[1] mutableCopy];
|
||||
d1[@"value"] = name; m[1] = d1; weakSelf.items = m;
|
||||
[weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
|
||||
[weakSelf rebuildItems];
|
||||
|
||||
// 将修改后的用户信息同步到服务端
|
||||
[weakSelf.myVM updateUserInfo:weakSelf.userModel completion:^(BOOL success, NSError * _Nullable error) {
|
||||
@@ -268,8 +802,10 @@
|
||||
};
|
||||
|
||||
[pop pop];
|
||||
}else if (indexPath.row == 2){
|
||||
NSString *userID = self.items[2][@"value"];
|
||||
} else if (indexPath.row == kKBPersonInfoRowLanguage) {
|
||||
[self openLanguageSelector];
|
||||
} else if (indexPath.row == kKBPersonInfoRowUserID) {
|
||||
NSString *userID = self.items[kKBPersonInfoRowUserID][@"value"];
|
||||
if (userID.length == 0) return;
|
||||
UIPasteboard.generalPasteboard.string = userID;
|
||||
[KBHUD showInfo:KBLocalized(@"Copy Success")];
|
||||
|
||||
Reference in New Issue
Block a user