185 lines
7.3 KiB
Objective-C
185 lines
7.3 KiB
Objective-C
//
|
|
// KBInputProfileManager.m
|
|
// KeyBoard
|
|
//
|
|
|
|
#import "KBInputProfileManager.h"
|
|
|
|
@implementation KBInputProfileLayout
|
|
@end
|
|
|
|
@implementation KBInputProfile
|
|
@end
|
|
|
|
@interface KBInputProfileManager ()
|
|
@property (nonatomic, strong) NSArray<KBInputProfile *> *profiles;
|
|
@end
|
|
|
|
@implementation KBInputProfileManager
|
|
|
|
+ (instancetype)sharedManager {
|
|
static KBInputProfileManager *instance = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
instance = [[self alloc] init];
|
|
});
|
|
return instance;
|
|
}
|
|
|
|
- (instancetype)init {
|
|
if (self = [super init]) {
|
|
[self loadProfiles];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)loadProfiles {
|
|
NSString *path = [[NSBundle mainBundle] pathForResource:@"kb_input_profiles" ofType:@"json"];
|
|
if (path.length == 0) {
|
|
path = [[NSBundle mainBundle] pathForResource:@"kb_input_profiles" ofType:@"json" inDirectory:@"Resource"];
|
|
}
|
|
if (path.length == 0) {
|
|
path = [[NSBundle mainBundle] pathForResource:@"kb_input_profiles" ofType:@"json" inDirectory:@"Shared/Resource"];
|
|
}
|
|
if (!path) {
|
|
NSLog(@"[KBInputProfileManager] kb_input_profiles.json not found");
|
|
self.profiles = [self defaultProfiles];
|
|
return;
|
|
}
|
|
|
|
NSData *data = [NSData dataWithContentsOfFile:path];
|
|
if (!data) {
|
|
NSLog(@"[KBInputProfileManager] Failed to read kb_input_profiles.json");
|
|
self.profiles = [self defaultProfiles];
|
|
return;
|
|
}
|
|
|
|
NSError *error = nil;
|
|
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
|
|
if (error || ![json isKindOfClass:NSDictionary.class]) {
|
|
NSLog(@"[KBInputProfileManager] Failed to parse JSON: %@", error);
|
|
self.profiles = [self defaultProfiles];
|
|
return;
|
|
}
|
|
|
|
NSArray *profilesArray = json[@"profiles"];
|
|
if (![profilesArray isKindOfClass:NSArray.class]) {
|
|
NSLog(@"[KBInputProfileManager] Invalid profiles array");
|
|
self.profiles = [self defaultProfiles];
|
|
return;
|
|
}
|
|
|
|
self.profiles = [self parseProfilesFromJSONArray:profilesArray];
|
|
if (self.profiles.count == 0) {
|
|
NSLog(@"[KBInputProfileManager] Parsed profiles is empty, fallback to default");
|
|
self.profiles = [self defaultProfiles];
|
|
}
|
|
NSLog(@"[KBInputProfileManager] Loaded %lu profiles", (unsigned long)self.profiles.count);
|
|
}
|
|
|
|
- (NSArray<KBInputProfile *> *)parseProfilesFromJSONArray:(NSArray *)profilesArray {
|
|
NSMutableArray<KBInputProfile *> *result = [NSMutableArray array];
|
|
for (NSDictionary *profileDict in profilesArray) {
|
|
if (![profileDict isKindOfClass:NSDictionary.class]) { continue; }
|
|
|
|
KBInputProfile *profile = [[KBInputProfile alloc] init];
|
|
profile.code = [profileDict[@"code"] isKindOfClass:NSString.class] ? profileDict[@"code"] : @"";
|
|
profile.name = [profileDict[@"name"] isKindOfClass:NSString.class] ? profileDict[@"name"] : @"";
|
|
profile.defaultSkinZip = [profileDict[@"defaultSkinZip"] isKindOfClass:NSString.class] ? profileDict[@"defaultSkinZip"] : @"";
|
|
|
|
NSArray *layoutsArray = profileDict[@"layouts"];
|
|
NSMutableArray<KBInputProfileLayout *> *layouts = [NSMutableArray array];
|
|
if ([layoutsArray isKindOfClass:NSArray.class]) {
|
|
for (NSDictionary *layoutDict in layoutsArray) {
|
|
if (![layoutDict isKindOfClass:NSDictionary.class]) { continue; }
|
|
KBInputProfileLayout *layout = [[KBInputProfileLayout alloc] init];
|
|
layout.variant = [layoutDict[@"variant"] isKindOfClass:NSString.class] ? layoutDict[@"variant"] : @"";
|
|
layout.title = [layoutDict[@"title"] isKindOfClass:NSString.class] ? layoutDict[@"title"] : @"";
|
|
layout.profileId = [layoutDict[@"profileId"] isKindOfClass:NSString.class] ? layoutDict[@"profileId"] : @"";
|
|
layout.layoutJsonId = [layoutDict[@"layoutJsonId"] isKindOfClass:NSString.class] ? layoutDict[@"layoutJsonId"] : @"";
|
|
layout.suggestionEngine = [layoutDict[@"suggestionEngine"] isKindOfClass:NSString.class] ? layoutDict[@"suggestionEngine"] : @"";
|
|
[layouts addObject:layout];
|
|
}
|
|
}
|
|
profile.layouts = [layouts copy];
|
|
[result addObject:profile];
|
|
}
|
|
return [result copy];
|
|
}
|
|
|
|
- (NSArray<KBInputProfile *> *)defaultProfiles {
|
|
NSArray *fallback = @[
|
|
@{
|
|
@"code": @"en",
|
|
@"name": @"English",
|
|
@"defaultSkinZip": @"normal_them.zip",
|
|
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"en_US_qwerty", @"layoutJsonId": @"letters", @"suggestionEngine": @"latin"}]
|
|
},
|
|
@{
|
|
@"code": @"es",
|
|
@"name": @"Español (Latinoamérica)",
|
|
@"defaultSkinZip": @"西班牙初始皮肤.zip",
|
|
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"es_419_qwerty", @"layoutJsonId": @"letters_es", @"suggestionEngine": @"spanish"}]
|
|
},
|
|
@{
|
|
@"code": @"pt",
|
|
@"name": @"Português",
|
|
@"defaultSkinZip": @"葡萄牙初始皮肤.zip",
|
|
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"pt_PT_qwerty", @"layoutJsonId": @"letters_pt", @"suggestionEngine": @"latin"}]
|
|
},
|
|
@{
|
|
@"code": @"zh-Hant",
|
|
@"name": @"繁體中文(台灣)",
|
|
@"defaultSkinZip": @"",
|
|
@"layouts": @[
|
|
@{@"variant": @"pinyin", @"title": @"拼音(繁體)", @"profileId": @"zh_Hant_TW_pinyin", @"layoutJsonId": @"letters_zh_hant_pinyin", @"suggestionEngine": @"pinyin_traditional"},
|
|
@{@"variant": @"bopomofo_full", @"title": @"注音全鍵盤", @"profileId": @"zh_Hant_TW_bopomofo_full", @"layoutJsonId": @"letters_bopomofo_full", @"suggestionEngine": @"bopomofo"},
|
|
@{@"variant": @"bopomofo_standard", @"title": @"注音標準", @"profileId": @"zh_Hant_TW_bopomofo_standard", @"layoutJsonId": @"letters_bopomofo_standard", @"suggestionEngine": @"bopomofo"}
|
|
]
|
|
},
|
|
@{
|
|
@"code": @"id",
|
|
@"name": @"Bahasa Indonesia",
|
|
@"defaultSkinZip": @"",
|
|
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"id_ID_qwerty", @"layoutJsonId": @"letters_id", @"suggestionEngine": @"latin"}]
|
|
}
|
|
];
|
|
return [self parseProfilesFromJSONArray:fallback];
|
|
}
|
|
|
|
- (NSArray<KBInputProfile *> *)allProfiles {
|
|
return self.profiles;
|
|
}
|
|
|
|
- (nullable KBInputProfile *)profileForLanguageCode:(NSString *)languageCode {
|
|
for (KBInputProfile *profile in self.profiles) {
|
|
if ([profile.code isEqualToString:languageCode]) {
|
|
return profile;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (nullable KBInputProfileLayout *)layoutForProfileId:(NSString *)profileId {
|
|
for (KBInputProfile *profile in self.profiles) {
|
|
for (KBInputProfileLayout *layout in profile.layouts) {
|
|
if ([layout.profileId isEqualToString:profileId]) {
|
|
return layout;
|
|
}
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (nullable NSString *)layoutJsonIdForProfileId:(NSString *)profileId {
|
|
KBInputProfileLayout *layout = [self layoutForProfileId:profileId];
|
|
return layout.layoutJsonId;
|
|
}
|
|
|
|
- (nullable NSString *)suggestionEngineForProfileId:(NSString *)profileId {
|
|
KBInputProfileLayout *layout = [self layoutForProfileId:profileId];
|
|
return layout.suggestionEngine;
|
|
}
|
|
|
|
@end
|