1
This commit is contained in:
194
Shared/KBInputProfileManager.m
Normal file
194
Shared/KBInputProfileManager.m
Normal file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// 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",
|
||||
@"defaultSkinZip": @"",
|
||||
@"layouts": @[
|
||||
@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"es_ES_qwerty", @"layoutJsonId": @"letters", @"suggestionEngine": @"latin"},
|
||||
@{@"variant": @"azerty", @"title": @"AZERTY", @"profileId": @"es_ES_azerty", @"layoutJsonId": @"letters_azerty", @"suggestionEngine": @"latin"},
|
||||
@{@"variant": @"qwertz", @"title": @"QWERTZ", @"profileId": @"es_ES_qwertz", @"layoutJsonId": @"letters_qwertz", @"suggestionEngine": @"latin"}
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"code": @"pt",
|
||||
@"name": @"Português",
|
||||
@"defaultSkinZip": @"",
|
||||
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"pt_PT_qwerty", @"layoutJsonId": @"letters", @"suggestionEngine": @"latin"}]
|
||||
},
|
||||
@{
|
||||
@"code": @"zh-Hant",
|
||||
@"name": @"繁體中文(台灣)",
|
||||
@"defaultSkinZip": @"",
|
||||
@"layouts": @[
|
||||
@{@"variant": @"pinyin", @"title": @"拼音(繁體)", @"profileId": @"zh_Hant_TW_pinyin", @"layoutJsonId": @"letters", @"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", @"suggestionEngine": @"latin"}]
|
||||
},
|
||||
@{
|
||||
@"code": @"zh-Hans",
|
||||
@"name": @"简体中文",
|
||||
@"defaultSkinZip": @"",
|
||||
@"layouts": @[@{@"variant": @"qwerty", @"title": @"QWERTY", @"profileId": @"zh_Hans_CN_qwerty", @"layoutJsonId": @"letters", @"suggestionEngine": @"pinyin_simplified"}]
|
||||
}
|
||||
];
|
||||
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
|
||||
Reference in New Issue
Block a user