1
This commit is contained in:
96
CustomKeyboard/Model/KBKeyboardLayoutConfig.h
Normal file
96
CustomKeyboard/Model/KBKeyboardLayoutConfig.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// KBKeyboardLayoutConfig.h
|
||||||
|
// CustomKeyboard
|
||||||
|
//
|
||||||
|
// 键盘布局配置模型(由 JSON 驱动)
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface KBKeyboardLayoutMetrics : NSObject
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *rowSpacing;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *topInset;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *bottomInset;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *keyHeight;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *edgeInset;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *gap;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *letterWidth;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *controlWidth;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *sendWidth;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *symbolsWideWidth;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *symbolsSideWidth;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardLayoutFonts : NSObject
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *letter;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *digit;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *symbol;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *mode;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *space;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *send;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardKeyDef : NSObject
|
||||||
|
@property (nonatomic, copy, nullable) NSString *type;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *title;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *selectedTitle;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *symbolName;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *selectedSymbolName;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *font;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *width;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *widthValue;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *backgroundColor;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardRowItem : NSObject
|
||||||
|
@property (nonatomic, copy, nullable) NSString *itemId;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *width;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *widthValue;
|
||||||
|
+ (NSArray<KBKeyboardRowItem *> *)itemsFromRawArray:(NSArray *)raw;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardRowSegments : NSObject
|
||||||
|
@property (nonatomic, strong, nullable) NSArray *left;
|
||||||
|
@property (nonatomic, strong, nullable) NSArray *center;
|
||||||
|
@property (nonatomic, strong, nullable) NSArray *right;
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)leftItems;
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)centerItems;
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)rightItems;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardRowConfig : NSObject
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *height;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *insetLeft;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *insetRight;
|
||||||
|
@property (nonatomic, strong, nullable) NSNumber *gap;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *align;
|
||||||
|
@property (nonatomic, strong, nullable) NSArray *items;
|
||||||
|
@property (nonatomic, strong, nullable) KBKeyboardRowSegments *segments;
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)resolvedItems;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardLayout : NSObject
|
||||||
|
@property (nonatomic, strong, nullable) NSArray<KBKeyboardRowConfig *> *rows;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface KBKeyboardLayoutConfig : NSObject
|
||||||
|
@property (nonatomic, assign) CGFloat designWidth;
|
||||||
|
@property (nonatomic, strong, nullable) KBKeyboardLayoutMetrics *metrics;
|
||||||
|
@property (nonatomic, strong, nullable) KBKeyboardLayoutFonts *fonts;
|
||||||
|
@property (nonatomic, copy, nullable) NSString *defaultKeyBackground;
|
||||||
|
@property (nonatomic, strong, nullable) NSDictionary<NSString *, KBKeyboardKeyDef *> *keyDefs;
|
||||||
|
@property (nonatomic, strong, nullable) NSDictionary<NSString *, KBKeyboardLayout *> *layouts;
|
||||||
|
|
||||||
|
+ (nullable instancetype)sharedConfig;
|
||||||
|
+ (nullable instancetype)configFromJSONData:(NSData *)data;
|
||||||
|
- (CGFloat)scaledValue:(CGFloat)designValue;
|
||||||
|
- (CGFloat)keyboardAreaDesignHeight;
|
||||||
|
- (CGFloat)keyboardAreaScaledHeight;
|
||||||
|
- (nullable KBKeyboardLayout *)layoutForName:(NSString *)name;
|
||||||
|
- (nullable KBKeyboardKeyDef *)keyDefForIdentifier:(NSString *)identifier;
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
187
CustomKeyboard/Model/KBKeyboardLayoutConfig.m
Normal file
187
CustomKeyboard/Model/KBKeyboardLayoutConfig.m
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
//
|
||||||
|
// KBKeyboardLayoutConfig.m
|
||||||
|
// CustomKeyboard
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "KBKeyboardLayoutConfig.h"
|
||||||
|
#import <MJExtension/MJExtension.h>
|
||||||
|
#import "KBConfig.h"
|
||||||
|
|
||||||
|
static NSString * const kKBKeyboardLayoutConfigFileName = @"kb_keyboard_layout_config";
|
||||||
|
|
||||||
|
@implementation KBKeyboardLayoutMetrics
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardLayoutFonts
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardKeyDef
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardRowItem
|
||||||
|
|
||||||
|
+ (NSDictionary *)mj_replacedKeyFromPropertyName {
|
||||||
|
return @{ @"itemId": @"id" };
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray<KBKeyboardRowItem *> *)itemsFromRawArray:(NSArray *)raw {
|
||||||
|
if (![raw isKindOfClass:[NSArray class]] || raw.count == 0) {
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
NSMutableArray<KBKeyboardRowItem *> *items = [NSMutableArray arrayWithCapacity:raw.count];
|
||||||
|
for (id obj in raw) {
|
||||||
|
if ([obj isKindOfClass:[NSString class]]) {
|
||||||
|
KBKeyboardRowItem *item = [KBKeyboardRowItem new];
|
||||||
|
item.itemId = (NSString *)obj;
|
||||||
|
[items addObject:item];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ([obj isKindOfClass:[NSDictionary class]]) {
|
||||||
|
KBKeyboardRowItem *item = [KBKeyboardRowItem mj_objectWithKeyValues:obj];
|
||||||
|
if (item.itemId.length == 0) {
|
||||||
|
NSString *fallback = ((NSDictionary *)obj)[@"id"];
|
||||||
|
if ([fallback isKindOfClass:[NSString class]]) {
|
||||||
|
item.itemId = fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.itemId.length > 0) {
|
||||||
|
[items addObject:item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items.copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardRowSegments
|
||||||
|
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)leftItems {
|
||||||
|
return [KBKeyboardRowItem itemsFromRawArray:self.left ?: @[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)centerItems {
|
||||||
|
return [KBKeyboardRowItem itemsFromRawArray:self.center ?: @[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)rightItems {
|
||||||
|
return [KBKeyboardRowItem itemsFromRawArray:self.right ?: @[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardRowConfig
|
||||||
|
|
||||||
|
- (NSArray<KBKeyboardRowItem *> *)resolvedItems {
|
||||||
|
return [KBKeyboardRowItem itemsFromRawArray:self.items ?: @[]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardLayout
|
||||||
|
|
||||||
|
+ (NSDictionary *)mj_objectClassInArray {
|
||||||
|
return @{ @"rows": [KBKeyboardRowConfig class] };
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation KBKeyboardLayoutConfig
|
||||||
|
|
||||||
|
+ (instancetype)sharedConfig {
|
||||||
|
static KBKeyboardLayoutConfig *config = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
NSString *path = [[NSBundle mainBundle] pathForResource:kKBKeyboardLayoutConfigFileName ofType:@"json"];
|
||||||
|
NSData *data = path.length ? [NSData dataWithContentsOfFile:path] : nil;
|
||||||
|
config = data ? [KBKeyboardLayoutConfig configFromJSONData:data] : nil;
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)configFromJSONData:(NSData *)data {
|
||||||
|
if (data.length == 0) { return nil; }
|
||||||
|
NSError *error = nil;
|
||||||
|
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
|
||||||
|
if (error || ![json isKindOfClass:[NSDictionary class]]) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSDictionary *dict = (NSDictionary *)json;
|
||||||
|
KBKeyboardLayoutConfig *config = [KBKeyboardLayoutConfig mj_objectWithKeyValues:dict];
|
||||||
|
|
||||||
|
NSDictionary *keyDefsRaw = dict[@"keyDefs"];
|
||||||
|
if ([keyDefsRaw isKindOfClass:[NSDictionary class]]) {
|
||||||
|
NSMutableDictionary<NSString *, KBKeyboardKeyDef *> *defs = [NSMutableDictionary dictionaryWithCapacity:keyDefsRaw.count];
|
||||||
|
[keyDefsRaw enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||||
|
if (![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSDictionary class]]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KBKeyboardKeyDef *def = [KBKeyboardKeyDef mj_objectWithKeyValues:obj];
|
||||||
|
if (def) {
|
||||||
|
defs[key] = def;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
config.keyDefs = defs.copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *layoutsRaw = dict[@"layouts"];
|
||||||
|
if ([layoutsRaw isKindOfClass:[NSDictionary class]]) {
|
||||||
|
NSMutableDictionary<NSString *, KBKeyboardLayout *> *layouts = [NSMutableDictionary dictionaryWithCapacity:layoutsRaw.count];
|
||||||
|
[layoutsRaw enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||||
|
if (![key isKindOfClass:[NSString class]] || ![obj isKindOfClass:[NSDictionary class]]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KBKeyboardLayout *layout = [KBKeyboardLayout mj_objectWithKeyValues:obj];
|
||||||
|
if (layout) {
|
||||||
|
layouts[key] = layout;
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
config.layouts = layouts.copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)scaledValue:(CGFloat)designValue {
|
||||||
|
CGFloat baseWidth = (self.designWidth > 0.0) ? self.designWidth : KB_DESIGN_WIDTH;
|
||||||
|
CGFloat scale = KBScreenWidth() / baseWidth;
|
||||||
|
return designValue * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)keyboardAreaDesignHeight {
|
||||||
|
KBKeyboardLayout *layout = [self layoutForName:@"letters"] ?: self.layouts.allValues.firstObject;
|
||||||
|
NSUInteger rowCount = layout.rows.count;
|
||||||
|
if (rowCount == 0) { return 0.0; }
|
||||||
|
|
||||||
|
CGFloat rowSpacing = self.metrics.rowSpacing.doubleValue;
|
||||||
|
CGFloat topInset = self.metrics.topInset.doubleValue;
|
||||||
|
CGFloat bottomInset = self.metrics.bottomInset.doubleValue;
|
||||||
|
|
||||||
|
CGFloat total = topInset + bottomInset + rowSpacing * (rowCount - 1);
|
||||||
|
for (KBKeyboardRowConfig *row in layout.rows) {
|
||||||
|
CGFloat height = row.height.doubleValue;
|
||||||
|
if (height <= 0.0) {
|
||||||
|
height = self.metrics.keyHeight.doubleValue;
|
||||||
|
}
|
||||||
|
if (height <= 0.0) { height = 40.0; }
|
||||||
|
total += height;
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)keyboardAreaScaledHeight {
|
||||||
|
CGFloat designHeight = [self keyboardAreaDesignHeight];
|
||||||
|
return designHeight > 0.0 ? [self scaledValue:designHeight] : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyboardLayout *)layoutForName:(NSString *)name {
|
||||||
|
if (name.length == 0) { return nil; }
|
||||||
|
return self.layouts[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyboardKeyDef *)keyDefForIdentifier:(NSString *)identifier {
|
||||||
|
if (identifier.length == 0) { return nil; }
|
||||||
|
return self.keyDefs[identifier];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
196
CustomKeyboard/Resource/kb_keyboard_layout_config.json
Normal file
196
CustomKeyboard/Resource/kb_keyboard_layout_config.json
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
{
|
||||||
|
"designWidth": 375,
|
||||||
|
"defaultKeyBackground": "#FFFFFF",
|
||||||
|
"metrics": {
|
||||||
|
"rowSpacing": 8,
|
||||||
|
"topInset": 8,
|
||||||
|
"bottomInset": 6,
|
||||||
|
"keyHeight": 41,
|
||||||
|
"edgeInset": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"letterWidth": 32,
|
||||||
|
"controlWidth": 41,
|
||||||
|
"sendWidth": 88,
|
||||||
|
"symbolsWideWidth": 47,
|
||||||
|
"symbolsSideWidth": 41
|
||||||
|
},
|
||||||
|
"fonts": {
|
||||||
|
"letter": 20,
|
||||||
|
"digit": 20,
|
||||||
|
"symbol": 18,
|
||||||
|
"mode": 14,
|
||||||
|
"space": 18,
|
||||||
|
"send": 18
|
||||||
|
},
|
||||||
|
"keyDefs": {
|
||||||
|
"shift": { "type": "shift", "title": "⇧", "symbolName": "shift", "selectedSymbolName": "shift.fill", "font": "symbol", "width": "controlWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"backspace": { "type": "backspace", "title": "⌫", "font": "symbol", "width": "controlWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"mode_123": { "type": "mode", "title": "123", "font": "mode", "width": "controlWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"mode_abc": { "type": "mode", "title": "ABC", "font": "mode", "width": "controlWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"symbols_toggle_more": { "type": "symbolsToggle", "title": "#+=", "font": "mode", "width": "symbolsSideWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"symbols_toggle_123": { "type": "symbolsToggle", "title": "123", "font": "mode", "width": "symbolsSideWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"emoji": { "type": "custom", "title": "😁", "font": "symbol", "width": "controlWidth", "backgroundColor": "#B7BBC4" },
|
||||||
|
"space": { "type": "space", "title": "space", "font": "space", "width": "flex" },
|
||||||
|
"send": { "type": "return", "title": "send", "font": "send", "width": "sendWidth", "backgroundColor": "#B7BBC4" }
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"letters": {
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"letter:q", "letter:w", "letter:e", "letter:r", "letter:t",
|
||||||
|
"letter:y", "letter:u", "letter:i", "letter:o", "letter:p"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "center",
|
||||||
|
"insetLeft": 0,
|
||||||
|
"insetRight": 0,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"letter:a", "letter:s", "letter:d", "letter:f", "letter:g",
|
||||||
|
"letter:h", "letter:j", "letter:k", "letter:l"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{ "id": "shift", "width": "controlWidth" }
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
"letter:z", "letter:x", "letter:c", "letter:v", "letter:b", "letter:n", "letter:m"
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{ "id": "backspace", "width": "controlWidth" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"mode_123", "emoji", "space", "send"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"numbers": {
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"digit:1", "digit:2", "digit:3", "digit:4", "digit:5",
|
||||||
|
"digit:6", "digit:7", "digit:8", "digit:9", "digit:0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"sym:-", "sym:/", "sym::", "sym:;", "sym:(",
|
||||||
|
"sym:)", "sym:¥", "sym:&", "sym:@", "sym:“"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "center",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{ "id": "symbols_toggle_more", "width": "symbolsSideWidth" }
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
{ "id": "sym:.", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:,", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:?", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:!", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:‘", "width": "symbolsWideWidth" }
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{ "id": "backspace", "width": "symbolsSideWidth" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"mode_abc", "emoji", "space", "send"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"symbolsMore": {
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"sym:[", "sym:]", "sym:{", "sym:}", "sym:#",
|
||||||
|
"sym:%", "sym:^", "sym:*", "sym:+", "sym:="
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"sym:_", "sym:\\", "sym:|", "sym:~", "sym:<",
|
||||||
|
"sym:>", "sym:€", "sym:¥", "sym:$", "sym:·"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "center",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"segments": {
|
||||||
|
"left": [
|
||||||
|
{ "id": "symbols_toggle_123", "width": "symbolsSideWidth" }
|
||||||
|
],
|
||||||
|
"center": [
|
||||||
|
{ "id": "sym:.", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:,", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:?", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:!", "width": "symbolsWideWidth" },
|
||||||
|
{ "id": "sym:‘", "width": "symbolsWideWidth" }
|
||||||
|
],
|
||||||
|
"right": [
|
||||||
|
{ "id": "backspace", "width": "symbolsSideWidth" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"align": "left",
|
||||||
|
"insetLeft": 4,
|
||||||
|
"insetRight": 4,
|
||||||
|
"gap": 5,
|
||||||
|
"items": [
|
||||||
|
"mode_abc", "emoji", "space", "send"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
CustomKeyboard/Resource/normal_them.zip
Normal file
BIN
CustomKeyboard/Resource/normal_them.zip
Normal file
Binary file not shown.
@@ -15,6 +15,7 @@
|
|||||||
#import "Masonry.h"
|
#import "Masonry.h"
|
||||||
#import "KBSkinManager.h"
|
#import "KBSkinManager.h"
|
||||||
#import "KBBackspaceUndoManager.h"
|
#import "KBBackspaceUndoManager.h"
|
||||||
|
#import "KBKeyboardLayoutConfig.h"
|
||||||
|
|
||||||
@interface KBKeyBoardMainView ()<KBToolBarDelegate, KBKeyboardViewDelegate, KBEmojiPanelViewDelegate, KBSuggestionBarViewDelegate>
|
@interface KBKeyBoardMainView ()<KBToolBarDelegate, KBKeyboardViewDelegate, KBEmojiPanelViewDelegate, KBSuggestionBarViewDelegate>
|
||||||
@property (nonatomic, strong) KBToolBar *topBar;
|
@property (nonatomic, strong) KBToolBar *topBar;
|
||||||
@@ -45,6 +46,13 @@
|
|||||||
|
|
||||||
// 键盘区域(高度按照设计值做等比缩放,避免不同机型上按键被压缩/拉伸)
|
// 键盘区域(高度按照设计值做等比缩放,避免不同机型上按键被压缩/拉伸)
|
||||||
CGFloat keyboardAreaHeight = KBFit(200.0f);
|
CGFloat keyboardAreaHeight = KBFit(200.0f);
|
||||||
|
KBKeyboardLayoutConfig *layoutConfig = [KBKeyboardLayoutConfig sharedConfig];
|
||||||
|
if (layoutConfig) {
|
||||||
|
CGFloat configHeight = [layoutConfig keyboardAreaScaledHeight];
|
||||||
|
if (configHeight > 0.0) {
|
||||||
|
keyboardAreaHeight = configHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
CGFloat bottomInset = KBFit(4.0f);
|
CGFloat bottomInset = KBFit(4.0f);
|
||||||
// CGFloat topBarHeight = KBFit(40.0f);
|
// CGFloat topBarHeight = KBFit(40.0f);
|
||||||
CGFloat barSpacing = KBFit(6.0f);
|
CGFloat barSpacing = KBFit(6.0f);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
@property (nonatomic, strong) KBKey *key;
|
@property (nonatomic, strong) KBKey *key;
|
||||||
@property (nonatomic, strong) UIImageView *iconView;
|
@property (nonatomic, strong) UIImageView *iconView;
|
||||||
|
@property (nonatomic, strong, nullable) UIColor *customBackgroundColor;
|
||||||
|
|
||||||
/// 配置基础样式(背景、圆角等)。创建按钮时调用。
|
/// 配置基础样式(背景、圆角等)。创建按钮时调用。
|
||||||
- (void)applyDefaultStyle;
|
- (void)applyDefaultStyle;
|
||||||
|
|||||||
@@ -6,12 +6,14 @@
|
|||||||
#import "KBKeyButton.h"
|
#import "KBKeyButton.h"
|
||||||
#import "KBKey.h"
|
#import "KBKey.h"
|
||||||
#import "KBSkinManager.h"
|
#import "KBSkinManager.h"
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
@interface KBKeyButton ()
|
@interface KBKeyButton ()
|
||||||
// 内部缓存:便于从按钮查找到所属的 KBKeyboardView
|
// 内部缓存:便于从按钮查找到所属的 KBKeyboardView
|
||||||
@property (nonatomic, weak, readonly) UIView *kb_keyboardContainer;
|
@property (nonatomic, weak, readonly) UIView *kb_keyboardContainer;
|
||||||
@property (nonatomic, strong) UIImageView *normalImageView; /// 没有皮肤的时候展示
|
@property (nonatomic, strong) UIImageView *normalImageView; /// 没有皮肤的时候展示
|
||||||
@property (nonatomic, strong) UIColor *baseBackgroundColor; /// 无按下状态下,由皮肤/主题决定的底色(由 normalImageView 展示)
|
@property (nonatomic, strong) UIColor *baseBackgroundColor; /// 无按下状态下,由皮肤/主题决定的底色(由 normalImageView 展示)
|
||||||
|
@property (nonatomic, strong) CAGradientLayer *bottomShadowLayer;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -24,8 +26,10 @@
|
|||||||
[NSLayoutConstraint activateConstraints:@[
|
[NSLayoutConstraint activateConstraints:@[
|
||||||
[self.normalImageView.topAnchor constraintEqualToAnchor:self.topAnchor],
|
[self.normalImageView.topAnchor constraintEqualToAnchor:self.topAnchor],
|
||||||
[self.normalImageView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
[self.normalImageView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
||||||
[self.normalImageView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:2],
|
// [self.normalImageView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:2],
|
||||||
[self.normalImageView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-2],
|
// [self.normalImageView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-2],
|
||||||
|
[self.normalImageView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0],
|
||||||
|
[self.normalImageView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-0],
|
||||||
]];
|
]];
|
||||||
[self applyDefaultStyle];
|
[self applyDefaultStyle];
|
||||||
}
|
}
|
||||||
@@ -48,6 +52,7 @@
|
|||||||
|
|
||||||
// 初始状态下根据主题设置底色(给没有皮肤图的按键使用)
|
// 初始状态下根据主题设置底色(给没有皮肤图的按键使用)
|
||||||
[self refreshStateAppearance];
|
[self refreshStateAppearance];
|
||||||
|
[self kb_setupBottomShadowIfNeeded];
|
||||||
|
|
||||||
// 懒创建图标视图,用于后续皮肤按键小图标展示
|
// 懒创建图标视图,用于后续皮肤按键小图标展示
|
||||||
if (!self.iconView) {
|
if (!self.iconView) {
|
||||||
@@ -72,6 +77,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
[super layoutSubviews];
|
||||||
|
if (!self.bottomShadowLayer) { return; }
|
||||||
|
CGRect bounds = self.normalImageView.bounds;
|
||||||
|
CGFloat shadowHeight = 2;
|
||||||
|
if (CGRectGetHeight(bounds) <= 0 || CGRectGetWidth(bounds) <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.bottomShadowLayer.frame = CGRectMake(0,
|
||||||
|
CGRectGetHeight(bounds) - shadowHeight,
|
||||||
|
CGRectGetWidth(bounds),
|
||||||
|
shadowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setKey:(KBKey *)key {
|
- (void)setKey:(KBKey *)key {
|
||||||
_key = key;
|
_key = key;
|
||||||
}
|
}
|
||||||
@@ -121,14 +140,25 @@
|
|||||||
[self refreshStateAppearance];
|
[self refreshStateAppearance];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setCustomBackgroundColor:(UIColor *)customBackgroundColor {
|
||||||
|
_customBackgroundColor = customBackgroundColor;
|
||||||
|
[self refreshStateAppearance];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)refreshStateAppearance {
|
- (void)refreshStateAppearance {
|
||||||
// 选中态用于 Shift/CapsLock 等特殊按键的高亮显示
|
// 选中态用于 Shift/CapsLock 等特殊按键的高亮显示
|
||||||
KBSkinTheme *t = [KBSkinManager shared].current;
|
KBSkinTheme *t = [KBSkinManager shared].current;
|
||||||
UIColor *base = nil;
|
UIColor *base = nil;
|
||||||
if (self.isSelected) {
|
if (self.isSelected) {
|
||||||
base = t.keyHighlightBackground ?: t.keyBackground;
|
base = t.keyHighlightBackground ?: t.keyBackground;
|
||||||
|
if (self.customBackgroundColor) {
|
||||||
|
base = t.keyHighlightBackground ?: self.customBackgroundColor;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
base = t.keyBackground;
|
base = self.customBackgroundColor ?: t.keyBackground;
|
||||||
|
}
|
||||||
|
if (self.customBackgroundColor && self.key.type == KBKeyTypeShift) {
|
||||||
|
base = self.customBackgroundColor;
|
||||||
}
|
}
|
||||||
if (!base) {
|
if (!base) {
|
||||||
base = [UIColor whiteColor];
|
base = [UIColor whiteColor];
|
||||||
@@ -138,6 +168,13 @@
|
|||||||
// 按键背景统一由 normalImageView 控制,按钮本身透明
|
// 按键背景统一由 normalImageView 控制,按钮本身透明
|
||||||
self.backgroundColor = [UIColor clearColor];
|
self.backgroundColor = [UIColor clearColor];
|
||||||
|
|
||||||
|
if (self.key.type == KBKeyTypeShift) {
|
||||||
|
UIColor *textColor = self.isSelected ? [UIColor blackColor] : (t.keyTextColor ?: [UIColor blackColor]);
|
||||||
|
[self setTitleColor:textColor forState:UIControlStateNormal];
|
||||||
|
[self setTitleColor:textColor forState:UIControlStateHighlighted];
|
||||||
|
[self setTitleColor:textColor forState:UIControlStateSelected];
|
||||||
|
}
|
||||||
|
|
||||||
// 有皮肤图时仅展示 icon,不再显示普通背景色
|
// 有皮肤图时仅展示 icon,不再显示普通背景色
|
||||||
if (self.iconView.image != nil || self.normalImageView.hidden) {
|
if (self.iconView.image != nil || self.normalImageView.hidden) {
|
||||||
return;
|
return;
|
||||||
@@ -169,6 +206,7 @@
|
|||||||
|
|
||||||
BOOL hasIcon = (iconImg != nil);
|
BOOL hasIcon = (iconImg != nil);
|
||||||
self.normalImageView.hidden = hasIcon;
|
self.normalImageView.hidden = hasIcon;
|
||||||
|
self.bottomShadowLayer.hidden = hasIcon;
|
||||||
if (hasIcon) {
|
if (hasIcon) {
|
||||||
// 有图标:仅显示图片,完全隐藏文字
|
// 有图标:仅显示图片,完全隐藏文字
|
||||||
[self setTitle:@"" forState:UIControlStateNormal];
|
[self setTitle:@"" forState:UIControlStateNormal];
|
||||||
@@ -184,6 +222,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)kb_setupBottomShadowIfNeeded {
|
||||||
|
if (self.bottomShadowLayer) { return; }
|
||||||
|
CAGradientLayer *layer = [CAGradientLayer layer];
|
||||||
|
layer.startPoint = CGPointMake(0.5, 0.0);
|
||||||
|
layer.endPoint = CGPointMake(0.5, 1.0);
|
||||||
|
layer.colors = @[
|
||||||
|
(id)[UIColor colorWithWhite:0 alpha:0.5].CGColor,
|
||||||
|
(id)[UIColor colorWithWhite:0 alpha:0.7].CGColor
|
||||||
|
];
|
||||||
|
[self.normalImageView.layer addSublayer:layer];
|
||||||
|
// self.bottomShadowLayer = layer;
|
||||||
|
}
|
||||||
|
|
||||||
- (UIImageView *)normalImageView{
|
- (UIImageView *)normalImageView{
|
||||||
if (!_normalImageView) {
|
if (!_normalImageView) {
|
||||||
_normalImageView = [[UIImageView alloc] init];
|
_normalImageView = [[UIImageView alloc] init];
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#import "KBSkinManager.h"
|
#import "KBSkinManager.h"
|
||||||
#import "KBKeyPreviewView.h"
|
#import "KBKeyPreviewView.h"
|
||||||
#import "KBBackspaceLongPressHandler.h"
|
#import "KBBackspaceLongPressHandler.h"
|
||||||
|
#import "KBKeyboardLayoutConfig.h"
|
||||||
|
|
||||||
// UI 常量统一管理,方便后续调试样式(以 375 宽设计稿为基准,通过 KBFit 做等比缩放)
|
// UI 常量统一管理,方便后续调试样式(以 375 宽设计稿为基准,通过 KBFit 做等比缩放)
|
||||||
#define kKBRowVerticalSpacing KBFit(8.0f)
|
#define kKBRowVerticalSpacing KBFit(8.0f)
|
||||||
@@ -33,6 +34,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
|||||||
@property (nonatomic, strong) NSArray<NSArray<KBKey *> *> *keysForRows;
|
@property (nonatomic, strong) NSArray<NSArray<KBKey *> *> *keysForRows;
|
||||||
@property (nonatomic, strong) KBBackspaceLongPressHandler *backspaceHandler;
|
@property (nonatomic, strong) KBBackspaceLongPressHandler *backspaceHandler;
|
||||||
@property (nonatomic, strong) KBKeyPreviewView *previewView;
|
@property (nonatomic, strong) KBKeyPreviewView *previewView;
|
||||||
|
@property (nonatomic, strong) KBKeyboardLayoutConfig *layoutConfig;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation KBKeyboardView
|
@implementation KBKeyboardView
|
||||||
@@ -44,6 +46,7 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
|||||||
// 默认小写:与需求一致,初始不开启 Shift
|
// 默认小写:与需求一致,初始不开启 Shift
|
||||||
_shiftOn = NO;
|
_shiftOn = NO;
|
||||||
_symbolsMoreOn = NO; // 数字面板默认第一页(123)
|
_symbolsMoreOn = NO; // 数字面板默认第一页(123)
|
||||||
|
self.layoutConfig = [KBKeyboardLayoutConfig sharedConfig];
|
||||||
self.backspaceHandler = [[KBBackspaceLongPressHandler alloc] initWithContainerView:self];
|
self.backspaceHandler = [[KBBackspaceLongPressHandler alloc] initWithContainerView:self];
|
||||||
[self buildBase];
|
[self buildBase];
|
||||||
[self reloadKeys];
|
[self reloadKeys];
|
||||||
@@ -67,26 +70,39 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
|||||||
[self addSubview:self.row3];
|
[self addSubview:self.row3];
|
||||||
[self addSubview:self.row4];
|
[self addSubview:self.row4];
|
||||||
|
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
KBKeyboardLayout *layout = [self kb_layoutForName:@"letters"];
|
||||||
|
NSArray<KBKeyboardRowConfig *> *rows = layout.rows ?: @[];
|
||||||
|
|
||||||
|
CGFloat rowSpacing = [self kb_metricValue:config.metrics.rowSpacing fallback:nil defaultValue:8.0];
|
||||||
|
CGFloat topInset = [self kb_metricValue:config.metrics.topInset fallback:nil defaultValue:8.0];
|
||||||
|
CGFloat bottomInset = [self kb_metricValue:config.metrics.bottomInset fallback:nil defaultValue:6.0];
|
||||||
|
|
||||||
|
CGFloat row1Height = [self kb_rowHeightForRow:(rows.count > 0 ? rows[0] : nil)];
|
||||||
|
CGFloat row2Height = [self kb_rowHeightForRow:(rows.count > 1 ? rows[1] : nil)];
|
||||||
|
CGFloat row3Height = [self kb_rowHeightForRow:(rows.count > 2 ? rows[2] : nil)];
|
||||||
|
CGFloat row4Height = [self kb_rowHeightForRow:(rows.count > 3 ? rows[3] : nil)];
|
||||||
|
|
||||||
[self.row1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.row1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.top.equalTo(self.mas_top).offset(kKBRowVerticalSpacing);
|
make.top.equalTo(self.mas_top).offset(topInset);
|
||||||
make.left.right.equalTo(self);
|
make.left.right.equalTo(self);
|
||||||
make.height.mas_equalTo(kKBRowHeight);
|
make.height.mas_equalTo(row1Height);
|
||||||
}];
|
}];
|
||||||
[self.row2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.row2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.top.equalTo(self.row1.mas_bottom).offset(kKBRowVerticalSpacing);
|
make.top.equalTo(self.row1.mas_bottom).offset(rowSpacing);
|
||||||
make.left.right.equalTo(self);
|
make.left.right.equalTo(self);
|
||||||
make.height.equalTo(self.row1);
|
make.height.mas_equalTo(row2Height);
|
||||||
}];
|
}];
|
||||||
[self.row3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.row3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.top.equalTo(self.row2.mas_bottom).offset(kKBRowVerticalSpacing);
|
make.top.equalTo(self.row2.mas_bottom).offset(rowSpacing);
|
||||||
make.left.right.equalTo(self);
|
make.left.right.equalTo(self);
|
||||||
make.height.equalTo(self.row1);
|
make.height.mas_equalTo(row3Height);
|
||||||
}];
|
}];
|
||||||
[self.row4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
[self.row4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
make.top.equalTo(self.row3.mas_bottom).offset(kKBRowVerticalSpacing);
|
make.top.equalTo(self.row3.mas_bottom).offset(rowSpacing);
|
||||||
make.left.right.equalTo(self);
|
make.left.right.equalTo(self);
|
||||||
make.height.equalTo(self.row1);
|
make.height.mas_equalTo(row4Height);
|
||||||
make.bottom.equalTo(self.mas_bottom).offset(-6);
|
make.bottom.equalTo(self.mas_bottom).offset(-bottomInset);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,18 +115,17 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
|||||||
[row.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
[row.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.keysForRows = [self buildKeysForCurrentLayout];
|
KBKeyboardLayout *layout = [self kb_currentLayout];
|
||||||
if (self.keysForRows.count < 4) return;
|
NSArray<KBKeyboardRowConfig *> *rows = layout.rows ?: @[];
|
||||||
|
if (rows.count < 4) {
|
||||||
|
[self kb_buildLegacyLayout];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[self buildRow:self.row1 withKeys:self.keysForRows[0]];
|
[self buildRow:self.row1 withRowConfig:rows[0]];
|
||||||
|
[self buildRow:self.row2 withRowConfig:rows[1]];
|
||||||
// 第二行:字母布局时通过左右等宽占位让整行居中
|
[self buildRow:self.row3 withRowConfig:rows[2]];
|
||||||
CGFloat row2Spacer = (self.layoutStyle == KBKeyboardLayoutStyleLetters)
|
[self buildRow:self.row4 withRowConfig:rows[3]];
|
||||||
? kKBLettersRow2EdgeSpacerMultiplier : 0.0;
|
|
||||||
[self buildRow:self.row2 withKeys:self.keysForRows[1] edgeSpacerMultiplier:row2Spacer];
|
|
||||||
|
|
||||||
[self buildRow:self.row3 withKeys:self.keysForRows[2]];
|
|
||||||
[self buildRow:self.row4 withKeys:self.keysForRows[3]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Key Model Construction
|
#pragma mark - Key Model Construction
|
||||||
@@ -315,6 +330,152 @@ static const CGFloat kKBLettersRow2EdgeSpacerMultiplier = 0.5;
|
|||||||
|
|
||||||
#pragma mark - Row Building
|
#pragma mark - Row Building
|
||||||
|
|
||||||
|
- (void)buildRow:(UIView *)row withRowConfig:(KBKeyboardRowConfig *)rowConfig {
|
||||||
|
if (!row || !rowConfig) { return; }
|
||||||
|
CGFloat gap = [self kb_gapForRow:rowConfig];
|
||||||
|
CGFloat insetLeft = [self kb_insetLeftForRow:rowConfig];
|
||||||
|
CGFloat insetRight = [self kb_insetRightForRow:rowConfig];
|
||||||
|
|
||||||
|
if (rowConfig.segments) {
|
||||||
|
KBKeyboardRowSegments *segments = rowConfig.segments;
|
||||||
|
NSArray<KBKeyboardRowItem *> *leftItems = [segments leftItems];
|
||||||
|
NSArray<KBKeyboardRowItem *> *centerItems = [segments centerItems];
|
||||||
|
NSArray<KBKeyboardRowItem *> *rightItems = [segments rightItems];
|
||||||
|
UIView *leftContainer = [UIView new];
|
||||||
|
UIView *centerContainer = [UIView new];
|
||||||
|
UIView *rightContainer = [UIView new];
|
||||||
|
[row addSubview:leftContainer];
|
||||||
|
[row addSubview:centerContainer];
|
||||||
|
[row addSubview:rightContainer];
|
||||||
|
|
||||||
|
[leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(row.mas_left).offset(insetLeft);
|
||||||
|
make.top.bottom.equalTo(row);
|
||||||
|
}];
|
||||||
|
[rightContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.equalTo(row.mas_right).offset(-insetRight);
|
||||||
|
make.top.bottom.equalTo(row);
|
||||||
|
}];
|
||||||
|
[centerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.centerX.equalTo(row);
|
||||||
|
make.top.bottom.equalTo(row);
|
||||||
|
make.left.greaterThanOrEqualTo(leftContainer.mas_right).offset(gap);
|
||||||
|
make.right.lessThanOrEqualTo(rightContainer.mas_left).offset(-gap);
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (leftItems.count == 0) {
|
||||||
|
[leftContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_equalTo(0);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
if (centerItems.count == 0) {
|
||||||
|
[centerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_equalTo(0);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
if (rightItems.count == 0) {
|
||||||
|
[rightContainer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_equalTo(0);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self kb_buildButtonsInContainer:leftContainer
|
||||||
|
items:leftItems
|
||||||
|
gap:gap
|
||||||
|
insetLeft:0
|
||||||
|
insetRight:0
|
||||||
|
alignCenter:NO];
|
||||||
|
[self kb_buildButtonsInContainer:centerContainer
|
||||||
|
items:centerItems
|
||||||
|
gap:gap
|
||||||
|
insetLeft:0
|
||||||
|
insetRight:0
|
||||||
|
alignCenter:NO];
|
||||||
|
[self kb_buildButtonsInContainer:rightContainer
|
||||||
|
items:rightItems
|
||||||
|
gap:gap
|
||||||
|
insetLeft:0
|
||||||
|
insetRight:0
|
||||||
|
alignCenter:NO];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL alignCenter = [rowConfig.align.lowercaseString isEqualToString:@"center"];
|
||||||
|
[self kb_buildButtonsInContainer:row
|
||||||
|
items:[rowConfig resolvedItems]
|
||||||
|
gap:gap
|
||||||
|
insetLeft:insetLeft
|
||||||
|
insetRight:insetRight
|
||||||
|
alignCenter:alignCenter];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)kb_buildButtonsInContainer:(UIView *)container
|
||||||
|
items:(NSArray<KBKeyboardRowItem *> *)items
|
||||||
|
gap:(CGFloat)gap
|
||||||
|
insetLeft:(CGFloat)insetLeft
|
||||||
|
insetRight:(CGFloat)insetRight
|
||||||
|
alignCenter:(BOOL)alignCenter {
|
||||||
|
if (items.count == 0) { return; }
|
||||||
|
|
||||||
|
UIView *leftSpacer = nil;
|
||||||
|
UIView *rightSpacer = nil;
|
||||||
|
if (alignCenter) {
|
||||||
|
leftSpacer = [UIView new];
|
||||||
|
rightSpacer = [UIView new];
|
||||||
|
[container addSubview:leftSpacer];
|
||||||
|
[container addSubview:rightSpacer];
|
||||||
|
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.left.equalTo(container.mas_left).offset(insetLeft);
|
||||||
|
make.top.bottom.equalTo(container);
|
||||||
|
}];
|
||||||
|
[rightSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.right.equalTo(container.mas_right).offset(-insetRight);
|
||||||
|
make.top.bottom.equalTo(container);
|
||||||
|
}];
|
||||||
|
[leftSpacer mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.equalTo(rightSpacer);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
KBKeyButton *previous = nil;
|
||||||
|
for (KBKeyboardRowItem *item in items) {
|
||||||
|
KBKeyButton *btn = [self kb_buttonForItem:item];
|
||||||
|
if (!btn) { continue; }
|
||||||
|
[container addSubview:btn];
|
||||||
|
|
||||||
|
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.top.bottom.equalTo(container);
|
||||||
|
if (previous) {
|
||||||
|
make.left.equalTo(previous.mas_right).offset(gap);
|
||||||
|
} else {
|
||||||
|
if (leftSpacer) {
|
||||||
|
make.left.equalTo(leftSpacer.mas_right).offset(gap);
|
||||||
|
} else {
|
||||||
|
make.left.equalTo(container.mas_left).offset(insetLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
CGFloat width = [self kb_widthForItem:item key:btn.key];
|
||||||
|
if (width > 0.0) {
|
||||||
|
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
make.width.mas_equalTo(width);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!previous) { return; }
|
||||||
|
[previous mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||||
|
if (rightSpacer) {
|
||||||
|
make.right.equalTo(rightSpacer.mas_left).offset(-gap);
|
||||||
|
} else {
|
||||||
|
make.right.equalTo(container.mas_right).offset(-insetRight);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)buildRow:(UIView *)row withKeys:(NSArray<KBKey *> *)keys {
|
- (void)buildRow:(UIView *)row withKeys:(NSArray<KBKey *> *)keys {
|
||||||
[self buildRow:row withKeys:keys edgeSpacerMultiplier:0.0];
|
[self buildRow:row withKeys:keys edgeSpacerMultiplier:0.0];
|
||||||
}
|
}
|
||||||
@@ -581,6 +742,382 @@ edgeSpacerMultiplier:(CGFloat)edgeSpacerMultiplier {
|
|||||||
// Space 不设置宽度;通过此前已建立的左右约束自动占满剩余宽度。
|
// Space 不设置宽度;通过此前已建立的左右约束自动占满剩余宽度。
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Config Helpers
|
||||||
|
|
||||||
|
- (KBKeyboardLayoutConfig *)kb_layoutConfig {
|
||||||
|
if (!self.layoutConfig) {
|
||||||
|
self.layoutConfig = [KBKeyboardLayoutConfig sharedConfig];
|
||||||
|
}
|
||||||
|
return self.layoutConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyboardLayout *)kb_layoutForName:(NSString *)name {
|
||||||
|
return [[self kb_layoutConfig] layoutForName:name];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyboardLayout *)kb_currentLayout {
|
||||||
|
if (self.layoutStyle == KBKeyboardLayoutStyleNumbers) {
|
||||||
|
return [self kb_layoutForName:(self.symbolsMoreOn ? @"symbolsMore" : @"numbers")];
|
||||||
|
}
|
||||||
|
return [self kb_layoutForName:@"letters"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)kb_buildLegacyLayout {
|
||||||
|
self.keysForRows = [self buildKeysForCurrentLayout];
|
||||||
|
if (self.keysForRows.count < 4) { return; }
|
||||||
|
|
||||||
|
[self buildRow:self.row1 withKeys:self.keysForRows[0]];
|
||||||
|
|
||||||
|
CGFloat row2Spacer = (self.layoutStyle == KBKeyboardLayoutStyleLetters)
|
||||||
|
? kKBLettersRow2EdgeSpacerMultiplier : 0.0;
|
||||||
|
[self buildRow:self.row2 withKeys:self.keysForRows[1] edgeSpacerMultiplier:row2Spacer];
|
||||||
|
|
||||||
|
[self buildRow:self.row3 withKeys:self.keysForRows[2]];
|
||||||
|
[self buildRow:self.row4 withKeys:self.keysForRows[3]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_scaledValue:(CGFloat)designValue {
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
if (config) {
|
||||||
|
return [config scaledValue:designValue];
|
||||||
|
}
|
||||||
|
return KBFit(designValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_numberValue:(NSNumber *)value defaultValue:(CGFloat)defaultValue {
|
||||||
|
if ([value isKindOfClass:[NSNumber class]]) {
|
||||||
|
return value.doubleValue;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_metricValue:(NSNumber *)value fallback:(NSNumber *)fallback defaultValue:(CGFloat)defaultValue {
|
||||||
|
CGFloat v = [self kb_numberValue:value defaultValue:-1.0];
|
||||||
|
if (v < 0.0) {
|
||||||
|
v = [self kb_numberValue:fallback defaultValue:defaultValue];
|
||||||
|
}
|
||||||
|
if (v < 0.0) {
|
||||||
|
v = defaultValue;
|
||||||
|
}
|
||||||
|
return [self kb_scaledValue:v];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_rowHeightForRow:(KBKeyboardRowConfig *)row {
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
NSNumber *height = row.height ?: config.metrics.keyHeight;
|
||||||
|
CGFloat value = [self kb_numberValue:height defaultValue:40.0];
|
||||||
|
return [self kb_scaledValue:value];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_gapForRow:(KBKeyboardRowConfig *)row {
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
return [self kb_metricValue:row.gap fallback:config.metrics.gap defaultValue:5.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_insetLeftForRow:(KBKeyboardRowConfig *)row {
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
return [self kb_metricValue:row.insetLeft fallback:config.metrics.edgeInset defaultValue:0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_insetRightForRow:(KBKeyboardRowConfig *)row {
|
||||||
|
KBKeyboardLayoutConfig *config = [self kb_layoutConfig];
|
||||||
|
return [self kb_metricValue:row.insetRight fallback:config.metrics.edgeInset defaultValue:0.0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyButton *)kb_buttonForItem:(KBKeyboardRowItem *)item {
|
||||||
|
if (item.itemId.length == 0) { return nil; }
|
||||||
|
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:item.itemId];
|
||||||
|
KBKey *key = [self kb_keyForItemId:item.itemId];
|
||||||
|
if (!key) { return nil; }
|
||||||
|
|
||||||
|
KBKeyButton *btn = [[KBKeyButton alloc] init];
|
||||||
|
btn.key = key;
|
||||||
|
[btn setTitle:key.title forState:UIControlStateNormal];
|
||||||
|
|
||||||
|
UIColor *bgColor = [self kb_backgroundColorForItem:item keyDef:def];
|
||||||
|
if (bgColor) {
|
||||||
|
btn.customBackgroundColor = bgColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat fontSize = [self kb_fontSizeForItem:item key:key];
|
||||||
|
if (fontSize > 0.0) {
|
||||||
|
btn.titleLabel.font = [UIFont systemFontOfSize:fontSize weight:UIFontWeightSemibold];
|
||||||
|
}
|
||||||
|
|
||||||
|
[btn applyThemeForCurrentKey];
|
||||||
|
[self kb_applySymbolIfNeededForButton:btn keyDef:def fontSize:fontSize];
|
||||||
|
[btn addTarget:self action:@selector(onKeyTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
|
if (key.type == KBKeyTypeBackspace) {
|
||||||
|
[self.backspaceHandler bindDeleteButton:btn showClearLabel:YES];
|
||||||
|
}
|
||||||
|
if (key.type == KBKeyTypeShift) {
|
||||||
|
btn.selected = self.shiftOn;
|
||||||
|
}
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)kb_applySymbolIfNeededForButton:(KBKeyButton *)button
|
||||||
|
keyDef:(KBKeyboardKeyDef *)def
|
||||||
|
fontSize:(CGFloat)fontSize {
|
||||||
|
if (!button || !def) { return; }
|
||||||
|
if (button.iconView.image != nil) { return; }
|
||||||
|
NSString *symbolName = button.isSelected ? def.selectedSymbolName : def.symbolName;
|
||||||
|
if (symbolName.length == 0) { return; }
|
||||||
|
|
||||||
|
UIImage *image = [UIImage systemImageNamed:symbolName];
|
||||||
|
if (!image) { return; }
|
||||||
|
|
||||||
|
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:fontSize weight:UIFontWeightSemibold];
|
||||||
|
image = [image imageWithConfiguration:config];
|
||||||
|
|
||||||
|
button.iconView.image = image;
|
||||||
|
button.iconView.hidden = NO;
|
||||||
|
button.iconView.contentMode = UIViewContentModeCenter;
|
||||||
|
button.titleLabel.hidden = YES;
|
||||||
|
|
||||||
|
UIColor *textColor = [KBSkinManager shared].current.keyTextColor ?: [UIColor blackColor];
|
||||||
|
button.iconView.tintColor = button.isSelected ? [UIColor blackColor] : textColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (UIColor *)kb_backgroundColorForItem:(KBKeyboardRowItem *)item keyDef:(KBKeyboardKeyDef *)def {
|
||||||
|
NSString *hex = def.backgroundColor;
|
||||||
|
if (hex.length == 0) {
|
||||||
|
hex = [self kb_layoutConfig].defaultKeyBackground;
|
||||||
|
}
|
||||||
|
if (hex.length == 0) { return nil; }
|
||||||
|
return [KBSkinManager colorFromHexString:hex defaultColor:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_metricWidthForKey:(NSString *)key {
|
||||||
|
KBKeyboardLayoutMetrics *m = [self kb_layoutConfig].metrics;
|
||||||
|
if ([key isEqualToString:@"letterWidth"]) { return m.letterWidth.doubleValue; }
|
||||||
|
if ([key isEqualToString:@"controlWidth"]) { return m.controlWidth.doubleValue; }
|
||||||
|
if ([key isEqualToString:@"sendWidth"]) { return m.sendWidth.doubleValue; }
|
||||||
|
if ([key isEqualToString:@"symbolsWideWidth"]) { return m.symbolsWideWidth.doubleValue; }
|
||||||
|
if ([key isEqualToString:@"symbolsSideWidth"]) { return m.symbolsSideWidth.doubleValue; }
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_widthForItem:(KBKeyboardRowItem *)item key:(KBKey *)key {
|
||||||
|
CGFloat width = 0.0;
|
||||||
|
if (item.widthValue.doubleValue > 0.0) {
|
||||||
|
width = item.widthValue.doubleValue;
|
||||||
|
} else if (item.width.length > 0) {
|
||||||
|
if ([item.width.lowercaseString isEqualToString:@"flex"]) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
width = [self kb_metricWidthForKey:item.width];
|
||||||
|
if (width <= 0.0) {
|
||||||
|
width = item.width.doubleValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 0.0) {
|
||||||
|
KBKeyboardLayoutMetrics *m = [self kb_layoutConfig].metrics;
|
||||||
|
if ([item.itemId hasPrefix:@"letter:"] ||
|
||||||
|
[item.itemId hasPrefix:@"digit:"] ||
|
||||||
|
[item.itemId hasPrefix:@"sym:"]) {
|
||||||
|
width = m.letterWidth.doubleValue;
|
||||||
|
} else if (key.type == KBKeyTypeReturn) {
|
||||||
|
width = m.sendWidth.doubleValue;
|
||||||
|
} else if (key.type == KBKeyTypeSpace) {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
width = m.controlWidth.doubleValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 0.0) {
|
||||||
|
if ([item.itemId hasPrefix:@"letter:"] ||
|
||||||
|
[item.itemId hasPrefix:@"digit:"] ||
|
||||||
|
[item.itemId hasPrefix:@"sym:"]) {
|
||||||
|
width = 32.0;
|
||||||
|
} else if (key.type == KBKeyTypeReturn) {
|
||||||
|
width = 88.0;
|
||||||
|
} else if (key.type == KBKeyTypeSpace) {
|
||||||
|
return 0.0;
|
||||||
|
} else {
|
||||||
|
width = 41.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width > 0.0 ? [self kb_scaledValue:width] : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_fontSizeForItem:(KBKeyboardRowItem *)item key:(KBKey *)key {
|
||||||
|
NSString *fontKey = nil;
|
||||||
|
if ([item.itemId hasPrefix:@"letter:"]) {
|
||||||
|
fontKey = @"letter";
|
||||||
|
} else if ([item.itemId hasPrefix:@"digit:"]) {
|
||||||
|
fontKey = @"digit";
|
||||||
|
} else if ([item.itemId hasPrefix:@"sym:"]) {
|
||||||
|
fontKey = @"symbol";
|
||||||
|
} else {
|
||||||
|
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:item.itemId];
|
||||||
|
fontKey = def.font;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontKey.length == 0) {
|
||||||
|
switch (key.type) {
|
||||||
|
case KBKeyTypeModeChange:
|
||||||
|
case KBKeyTypeSymbolsToggle:
|
||||||
|
fontKey = @"mode";
|
||||||
|
break;
|
||||||
|
case KBKeyTypeSpace:
|
||||||
|
fontKey = @"space";
|
||||||
|
break;
|
||||||
|
case KBKeyTypeReturn:
|
||||||
|
fontKey = @"send";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fontKey = @"symbol";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self kb_fontSizeForFontKey:fontKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGFloat)kb_fontSizeForFontKey:(NSString *)fontKey {
|
||||||
|
KBKeyboardLayoutFonts *fonts = [self kb_layoutConfig].fonts;
|
||||||
|
CGFloat size = 0.0;
|
||||||
|
if ([fontKey isEqualToString:@"letter"]) { size = fonts.letter.doubleValue; }
|
||||||
|
else if ([fontKey isEqualToString:@"digit"]) { size = fonts.digit.doubleValue; }
|
||||||
|
else if ([fontKey isEqualToString:@"symbol"]) { size = fonts.symbol.doubleValue; }
|
||||||
|
else if ([fontKey isEqualToString:@"mode"]) { size = fonts.mode.doubleValue; }
|
||||||
|
else if ([fontKey isEqualToString:@"space"]) { size = fonts.space.doubleValue; }
|
||||||
|
else if ([fontKey isEqualToString:@"send"]) { size = fonts.send.doubleValue; }
|
||||||
|
if (size <= 0.0) { size = 18.0; }
|
||||||
|
return [self kb_scaledValue:size];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKey *)kb_keyForItemId:(NSString *)itemId {
|
||||||
|
if (itemId.length == 0) { return nil; }
|
||||||
|
KBKeyboardKeyDef *def = [[self kb_layoutConfig] keyDefForIdentifier:itemId];
|
||||||
|
if (def) {
|
||||||
|
return [self kb_keyFromDef:def identifier:itemId];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSRange range = [itemId rangeOfString:@":"];
|
||||||
|
if (range.location != NSNotFound) {
|
||||||
|
NSString *prefix = [itemId substringToIndex:range.location];
|
||||||
|
NSString *value = [itemId substringFromIndex:range.location + 1];
|
||||||
|
if ([prefix isEqualToString:@"letter"]) {
|
||||||
|
if (value.length == 1) {
|
||||||
|
return [self kb_letterKeyWithChar:value];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if ([prefix isEqualToString:@"digit"]) {
|
||||||
|
NSString *identifier = [NSString stringWithFormat:@"digit_%@", value];
|
||||||
|
KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter];
|
||||||
|
k.caseVariant = KBKeyCaseVariantNone;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
if ([prefix isEqualToString:@"sym"]) {
|
||||||
|
NSString *identifier = [self kb_identifierForSymbol:value];
|
||||||
|
KBKey *k = [KBKey keyWithIdentifier:identifier title:value output:value type:KBKeyTypeCharacter];
|
||||||
|
k.caseVariant = KBKeyCaseVariantNone;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKey *)kb_keyFromDef:(KBKeyboardKeyDef *)def identifier:(NSString *)identifier {
|
||||||
|
KBKeyType type = [self kb_keyTypeForDef:def];
|
||||||
|
NSString *title = def.title ?: @"";
|
||||||
|
if (type == KBKeyTypeShift && self.shiftOn && def.selectedTitle.length > 0) {
|
||||||
|
title = def.selectedTitle;
|
||||||
|
}
|
||||||
|
NSString *output = @"";
|
||||||
|
switch (type) {
|
||||||
|
case KBKeyTypeSpace:
|
||||||
|
output = @" ";
|
||||||
|
break;
|
||||||
|
case KBKeyTypeReturn:
|
||||||
|
output = @"\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
output = @"";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *finalId = identifier;
|
||||||
|
if ([identifier isEqualToString:@"emoji"]) {
|
||||||
|
finalId = KBKeyIdentifierEmojiPanel;
|
||||||
|
} else if ([identifier isEqualToString:@"send"]) {
|
||||||
|
finalId = @"return";
|
||||||
|
}
|
||||||
|
|
||||||
|
KBKey *k = [KBKey keyWithIdentifier:finalId title:title output:output type:type];
|
||||||
|
k.caseVariant = KBKeyCaseVariantNone;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (KBKeyType)kb_keyTypeForDef:(KBKeyboardKeyDef *)def {
|
||||||
|
NSString *type = def.type.lowercaseString;
|
||||||
|
if ([type isEqualToString:@"shift"]) return KBKeyTypeShift;
|
||||||
|
if ([type isEqualToString:@"backspace"]) return KBKeyTypeBackspace;
|
||||||
|
if ([type isEqualToString:@"mode"]) return KBKeyTypeModeChange;
|
||||||
|
if ([type isEqualToString:@"symbolstoggle"]) return KBKeyTypeSymbolsToggle;
|
||||||
|
if ([type isEqualToString:@"space"]) return KBKeyTypeSpace;
|
||||||
|
if ([type isEqualToString:@"return"]) return KBKeyTypeReturn;
|
||||||
|
if ([type isEqualToString:@"globe"]) return KBKeyTypeGlobe;
|
||||||
|
return KBKeyTypeCustom;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)kb_identifierForSymbol:(NSString *)symbol {
|
||||||
|
if (symbol.length == 0) { return nil; }
|
||||||
|
static NSDictionary<NSString *, NSString *> *map = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
map = @{
|
||||||
|
@"-": @"sym_minus",
|
||||||
|
@"/": @"sym_slash",
|
||||||
|
@":": @"sym_colon",
|
||||||
|
@";": @"sym_semicolon",
|
||||||
|
@"(": @"sym_paren_l",
|
||||||
|
@")": @"sym_paren_r",
|
||||||
|
@"¥": @"sym_money",
|
||||||
|
@"¥": @"sym_money",
|
||||||
|
@"&": @"sym_amp",
|
||||||
|
@"@": @"sym_at",
|
||||||
|
@"\"": @"sym_quote_double",
|
||||||
|
@"“": @"sym_quote_double",
|
||||||
|
@"”": @"sym_quote_double",
|
||||||
|
@".": @"sym_dot",
|
||||||
|
@",": @"sym_comma",
|
||||||
|
@"?": @"sym_question",
|
||||||
|
@"!": @"sym_exclam",
|
||||||
|
@"'": @"sym_quote_single",
|
||||||
|
@"‘": @"sym_quote_single",
|
||||||
|
@"’": @"sym_quote_single",
|
||||||
|
@"[": @"sym_bracket_l",
|
||||||
|
@"]": @"sym_bracket_r",
|
||||||
|
@"{": @"sym_brace_l",
|
||||||
|
@"}": @"sym_brace_r",
|
||||||
|
@"#": @"sym_hash",
|
||||||
|
@"%": @"sym_percent",
|
||||||
|
@"^": @"sym_caret",
|
||||||
|
@"*": @"sym_asterisk",
|
||||||
|
@"+": @"sym_plus",
|
||||||
|
@"=": @"sym_equal",
|
||||||
|
@"_": @"sym_underscore",
|
||||||
|
@"\\": @"sym_backslash",
|
||||||
|
@"|": @"sym_pipe",
|
||||||
|
@"~": @"sym_tilde",
|
||||||
|
@"<": @"sym_lt",
|
||||||
|
@">": @"sym_gt",
|
||||||
|
@"€": @"sym_euro",
|
||||||
|
@"$": @"sym_dollar",
|
||||||
|
@"·": @"sym_bullet"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return map[symbol];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
|
|
||||||
- (void)onKeyTapped:(KBKeyButton *)sender {
|
- (void)onKeyTapped:(KBKeyButton *)sender {
|
||||||
|
|||||||
@@ -129,10 +129,6 @@
|
|||||||
0498BD8C2EE69E15006CC1D5 /* KBTagItemModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8A2EE69E15006CC1D5 /* KBTagItemModel.m */; };
|
0498BD8C2EE69E15006CC1D5 /* KBTagItemModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8A2EE69E15006CC1D5 /* KBTagItemModel.m */; };
|
||||||
0498BD8F2EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
0498BD8F2EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
||||||
0498BD902EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
0498BD902EE6A3BD006CC1D5 /* KBMyMainModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */; };
|
||||||
A1F0C1D22FACAD0012345678 /* KBMaiPointReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */; };
|
|
||||||
A1F0C1D32FACAD0012345678 /* KBMaiPointReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */; };
|
|
||||||
A1F0C1C22FABCDEF12345678 /* KBInviteCodeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */; };
|
|
||||||
A1F0C1C32FABCDEF12345678 /* KBInviteCodeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */; };
|
|
||||||
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */; };
|
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */; };
|
||||||
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDDD2EE81508006CC1D5 /* KBShopVM.m */; };
|
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDDD2EE81508006CC1D5 /* KBShopVM.m */; };
|
||||||
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */; };
|
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BDE02EEA87C8006CC1D5 /* KBShopStyleModel.m */; };
|
||||||
@@ -176,6 +172,7 @@
|
|||||||
04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EADC2EAF8CEB0089C901 /* KBToolBar.m */; };
|
04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EADC2EAF8CEB0089C901 /* KBToolBar.m */; };
|
||||||
04D1F6B22EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
|
04D1F6B22EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
|
||||||
04D1F6B32EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
|
04D1F6B32EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
|
||||||
|
04E161782F0FA7BD0022C23B /* normal_them.zip in Resources */ = {isa = PBXBuildFile; fileRef = 04E161772F0FA7BD0022C23B /* normal_them.zip */; };
|
||||||
04FC95672EB0546C007BD342 /* KBKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95652EB0546C007BD342 /* KBKey.m */; };
|
04FC95672EB0546C007BD342 /* KBKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95652EB0546C007BD342 /* KBKey.m */; };
|
||||||
04FC956A2EB05497007BD342 /* KBKeyButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95692EB05497007BD342 /* KBKeyButton.m */; };
|
04FC956A2EB05497007BD342 /* KBKeyButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95692EB05497007BD342 /* KBKeyButton.m */; };
|
||||||
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC956C2EB054B7007BD342 /* KBKeyboardView.m */; };
|
04FC956D2EB054B7007BD342 /* KBKeyboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC956C2EB054B7007BD342 /* KBKeyboardView.m */; };
|
||||||
@@ -205,6 +202,7 @@
|
|||||||
04FEDB032EFE000000123456 /* KBEmojiBottomBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDB022EFE000000123456 /* KBEmojiBottomBarView.m */; };
|
04FEDB032EFE000000123456 /* KBEmojiBottomBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDB022EFE000000123456 /* KBEmojiBottomBarView.m */; };
|
||||||
04FEDC122F00010000999999 /* KBKeyboardSubscriptionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC112F00010000999999 /* KBKeyboardSubscriptionView.m */; };
|
04FEDC122F00010000999999 /* KBKeyboardSubscriptionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC112F00010000999999 /* KBKeyboardSubscriptionView.m */; };
|
||||||
04FEDC222F00020000999999 /* KBKeyboardSubscriptionProduct.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */; };
|
04FEDC222F00020000999999 /* KBKeyboardSubscriptionProduct.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */; };
|
||||||
|
04FEDC252F10000100000001 /* KBKeyboardLayoutConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC242F10000100000001 /* KBKeyboardLayoutConfig.m */; };
|
||||||
04FEDC322F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC312F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m */; };
|
04FEDC322F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC312F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m */; };
|
||||||
04FEDC422F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC412F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m */; };
|
04FEDC422F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FEDC412F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.m */; };
|
||||||
05A1B2D12F5B1A2B3C4D5E60 /* KBSearchVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A1B2C52F5B1A2B3C4D5E60 /* KBSearchVM.m */; };
|
05A1B2D12F5B1A2B3C4D5E60 /* KBSearchVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A1B2C52F5B1A2B3C4D5E60 /* KBSearchVM.m */; };
|
||||||
@@ -218,6 +216,7 @@
|
|||||||
A1B2C3EA2F20000000000001 /* KBSuggestionEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E72F20000000000001 /* KBSuggestionEngine.m */; };
|
A1B2C3EA2F20000000000001 /* KBSuggestionEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E72F20000000000001 /* KBSuggestionEngine.m */; };
|
||||||
A1B2C3EB2F20000000000001 /* KBSuggestionBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E92F20000000000001 /* KBSuggestionBarView.m */; };
|
A1B2C3EB2F20000000000001 /* KBSuggestionBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3E92F20000000000001 /* KBSuggestionBarView.m */; };
|
||||||
A1B2C3ED2F20000000000001 /* kb_words.txt in Resources */ = {isa = PBXBuildFile; fileRef = A1B2C3EC2F20000000000001 /* kb_words.txt */; };
|
A1B2C3ED2F20000000000001 /* kb_words.txt in Resources */ = {isa = PBXBuildFile; fileRef = A1B2C3EC2F20000000000001 /* kb_words.txt */; };
|
||||||
|
A1B2C3F12F20000000000002 /* kb_keyboard_layout_config.json in Resources */ = {isa = PBXBuildFile; fileRef = A1B2C3F02F20000000000002 /* kb_keyboard_layout_config.json */; };
|
||||||
A1B2C3F42EB35A9900000001 /* KBFullAccessGuideView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */; };
|
A1B2C3F42EB35A9900000001 /* KBFullAccessGuideView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */; };
|
||||||
A1B2C4002EB4A0A100000003 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
A1B2C4002EB4A0A100000003 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||||
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C4002EB4A0A100000002 /* KBAuthManager.m */; };
|
||||||
@@ -232,6 +231,10 @@
|
|||||||
A1F0C1B12F1234567890ABCD /* KBConsumptionRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A12F1234567890ABCD /* KBConsumptionRecord.m */; };
|
A1F0C1B12F1234567890ABCD /* KBConsumptionRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A12F1234567890ABCD /* KBConsumptionRecord.m */; };
|
||||||
A1F0C1B22F1234567890ABCD /* KBConsumptionRecordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A32F1234567890ABCD /* KBConsumptionRecordCell.m */; };
|
A1F0C1B22F1234567890ABCD /* KBConsumptionRecordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A32F1234567890ABCD /* KBConsumptionRecordCell.m */; };
|
||||||
A1F0C1B32F1234567890ABCD /* KBConsumptionRecordVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A52F1234567890ABCD /* KBConsumptionRecordVC.m */; };
|
A1F0C1B32F1234567890ABCD /* KBConsumptionRecordVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1A52F1234567890ABCD /* KBConsumptionRecordVC.m */; };
|
||||||
|
A1F0C1C22FABCDEF12345678 /* KBInviteCodeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */; };
|
||||||
|
A1F0C1C32FABCDEF12345678 /* KBInviteCodeModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */; };
|
||||||
|
A1F0C1D22FACAD0012345678 /* KBMaiPointReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */; };
|
||||||
|
A1F0C1D32FACAD0012345678 /* KBMaiPointReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */; };
|
||||||
EB72B60040437E3C0A4890FC /* KBShopThemeDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B9F60894E529C3EDAF6BAC3D /* KBShopThemeDetailModel.m */; };
|
EB72B60040437E3C0A4890FC /* KBShopThemeDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B9F60894E529C3EDAF6BAC3D /* KBShopThemeDetailModel.m */; };
|
||||||
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; };
|
ECC9EE02174D86E8D792472F /* Pods_keyBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967065BB5230E43F293B3AF9 /* Pods_keyBoard.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@@ -460,10 +463,6 @@
|
|||||||
0498BD8A2EE69E15006CC1D5 /* KBTagItemModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTagItemModel.m; sourceTree = "<group>"; };
|
0498BD8A2EE69E15006CC1D5 /* KBTagItemModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTagItemModel.m; sourceTree = "<group>"; };
|
||||||
0498BD8D2EE6A3BD006CC1D5 /* KBMyMainModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyMainModel.h; sourceTree = "<group>"; };
|
0498BD8D2EE6A3BD006CC1D5 /* KBMyMainModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyMainModel.h; sourceTree = "<group>"; };
|
||||||
0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyMainModel.m; sourceTree = "<group>"; };
|
0498BD8E2EE6A3BD006CC1D5 /* KBMyMainModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyMainModel.m; sourceTree = "<group>"; };
|
||||||
A1F0C1C02FABCDEF12345678 /* KBInviteCodeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBInviteCodeModel.h; sourceTree = "<group>"; };
|
|
||||||
A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBInviteCodeModel.m; sourceTree = "<group>"; };
|
|
||||||
A1F0C1D02FACAD0012345678 /* KBMaiPointReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMaiPointReporter.h; sourceTree = "<group>"; };
|
|
||||||
A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMaiPointReporter.m; sourceTree = "<group>"; };
|
|
||||||
0498BDD72EE7ECEA006CC1D5 /* WJXEventSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WJXEventSource.h; sourceTree = "<group>"; };
|
0498BDD72EE7ECEA006CC1D5 /* WJXEventSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WJXEventSource.h; sourceTree = "<group>"; };
|
||||||
0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WJXEventSource.m; sourceTree = "<group>"; };
|
0498BDD82EE7ECEA006CC1D5 /* WJXEventSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WJXEventSource.m; sourceTree = "<group>"; };
|
||||||
0498BDDC2EE81508006CC1D5 /* KBShopVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopVM.h; sourceTree = "<group>"; };
|
0498BDDC2EE81508006CC1D5 /* KBShopVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBShopVM.h; sourceTree = "<group>"; };
|
||||||
@@ -542,6 +541,7 @@
|
|||||||
04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPermissionViewController.m; sourceTree = "<group>"; };
|
04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPermissionViewController.m; sourceTree = "<group>"; };
|
||||||
04D1F6B02EDFF10A00B12345 /* KBSkinInstallBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinInstallBridge.h; sourceTree = "<group>"; };
|
04D1F6B02EDFF10A00B12345 /* KBSkinInstallBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinInstallBridge.h; sourceTree = "<group>"; };
|
||||||
04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinInstallBridge.m; sourceTree = "<group>"; };
|
04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinInstallBridge.m; sourceTree = "<group>"; };
|
||||||
|
04E161772F0FA7BD0022C23B /* normal_them.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = normal_them.zip; sourceTree = "<group>"; };
|
||||||
04FC953A2EAFAE56007BD342 /* KeyBoardPrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyBoardPrefixHeader.pch; sourceTree = "<group>"; };
|
04FC953A2EAFAE56007BD342 /* KeyBoardPrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyBoardPrefixHeader.pch; sourceTree = "<group>"; };
|
||||||
04FC95642EB0546C007BD342 /* KBKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKey.h; sourceTree = "<group>"; };
|
04FC95642EB0546C007BD342 /* KBKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKey.h; sourceTree = "<group>"; };
|
||||||
04FC95652EB0546C007BD342 /* KBKey.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKey.m; sourceTree = "<group>"; };
|
04FC95652EB0546C007BD342 /* KBKey.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKey.m; sourceTree = "<group>"; };
|
||||||
@@ -603,6 +603,8 @@
|
|||||||
04FEDC112F00010000999999 /* KBKeyboardSubscriptionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionView.m; sourceTree = "<group>"; };
|
04FEDC112F00010000999999 /* KBKeyboardSubscriptionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionView.m; sourceTree = "<group>"; };
|
||||||
04FEDC202F00020000999999 /* KBKeyboardSubscriptionProduct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionProduct.h; sourceTree = "<group>"; };
|
04FEDC202F00020000999999 /* KBKeyboardSubscriptionProduct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionProduct.h; sourceTree = "<group>"; };
|
||||||
04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionProduct.m; sourceTree = "<group>"; };
|
04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionProduct.m; sourceTree = "<group>"; };
|
||||||
|
04FEDC232F10000100000001 /* KBKeyboardLayoutConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardLayoutConfig.h; sourceTree = "<group>"; };
|
||||||
|
04FEDC242F10000100000001 /* KBKeyboardLayoutConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardLayoutConfig.m; sourceTree = "<group>"; };
|
||||||
04FEDC302F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionFeatureItemView.h; sourceTree = "<group>"; };
|
04FEDC302F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionFeatureItemView.h; sourceTree = "<group>"; };
|
||||||
04FEDC312F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionFeatureItemView.m; sourceTree = "<group>"; };
|
04FEDC312F00030000999999 /* KBKeyboardSubscriptionFeatureItemView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyboardSubscriptionFeatureItemView.m; sourceTree = "<group>"; };
|
||||||
04FEDC402F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionFeatureMarqueeView.h; sourceTree = "<group>"; };
|
04FEDC402F00040000999999 /* KBKeyboardSubscriptionFeatureMarqueeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyboardSubscriptionFeatureMarqueeView.h; sourceTree = "<group>"; };
|
||||||
@@ -630,6 +632,7 @@
|
|||||||
A1B2C3E82F20000000000001 /* KBSuggestionBarView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSuggestionBarView.h; sourceTree = "<group>"; };
|
A1B2C3E82F20000000000001 /* KBSuggestionBarView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSuggestionBarView.h; sourceTree = "<group>"; };
|
||||||
A1B2C3E92F20000000000001 /* KBSuggestionBarView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSuggestionBarView.m; sourceTree = "<group>"; };
|
A1B2C3E92F20000000000001 /* KBSuggestionBarView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSuggestionBarView.m; sourceTree = "<group>"; };
|
||||||
A1B2C3EC2F20000000000001 /* kb_words.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = kb_words.txt; sourceTree = "<group>"; };
|
A1B2C3EC2F20000000000001 /* kb_words.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = kb_words.txt; sourceTree = "<group>"; };
|
||||||
|
A1B2C3F02F20000000000002 /* kb_keyboard_layout_config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = kb_keyboard_layout_config.json; sourceTree = "<group>"; };
|
||||||
A1B2C3F12EB35A9900000001 /* KBFullAccessGuideView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessGuideView.h; sourceTree = "<group>"; };
|
A1B2C3F12EB35A9900000001 /* KBFullAccessGuideView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessGuideView.h; sourceTree = "<group>"; };
|
||||||
A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessGuideView.m; sourceTree = "<group>"; };
|
A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessGuideView.m; sourceTree = "<group>"; };
|
||||||
A1B2C4002EB4A0A100000001 /* KBAuthManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAuthManager.h; sourceTree = "<group>"; };
|
A1B2C4002EB4A0A100000001 /* KBAuthManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAuthManager.h; sourceTree = "<group>"; };
|
||||||
@@ -654,6 +657,10 @@
|
|||||||
A1F0C1A32F1234567890ABCD /* KBConsumptionRecordCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBConsumptionRecordCell.m; sourceTree = "<group>"; };
|
A1F0C1A32F1234567890ABCD /* KBConsumptionRecordCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBConsumptionRecordCell.m; sourceTree = "<group>"; };
|
||||||
A1F0C1A42F1234567890ABCD /* KBConsumptionRecordVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBConsumptionRecordVC.h; sourceTree = "<group>"; };
|
A1F0C1A42F1234567890ABCD /* KBConsumptionRecordVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBConsumptionRecordVC.h; sourceTree = "<group>"; };
|
||||||
A1F0C1A52F1234567890ABCD /* KBConsumptionRecordVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBConsumptionRecordVC.m; sourceTree = "<group>"; };
|
A1F0C1A52F1234567890ABCD /* KBConsumptionRecordVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBConsumptionRecordVC.m; sourceTree = "<group>"; };
|
||||||
|
A1F0C1C02FABCDEF12345678 /* KBInviteCodeModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBInviteCodeModel.h; sourceTree = "<group>"; };
|
||||||
|
A1F0C1C12FABCDEF12345678 /* KBInviteCodeModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBInviteCodeModel.m; sourceTree = "<group>"; };
|
||||||
|
A1F0C1D02FACAD0012345678 /* KBMaiPointReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMaiPointReporter.h; sourceTree = "<group>"; };
|
||||||
|
A1F0C1D12FACAD0012345678 /* KBMaiPointReporter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMaiPointReporter.m; sourceTree = "<group>"; };
|
||||||
B12EC429812407B9F0E67565 /* Pods-CustomKeyboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.release.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.release.xcconfig"; sourceTree = "<group>"; };
|
B12EC429812407B9F0E67565 /* Pods-CustomKeyboard.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.release.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
B8CA018AB878499327504AAD /* Pods-CustomKeyboard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.debug.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.debug.xcconfig"; sourceTree = "<group>"; };
|
B8CA018AB878499327504AAD /* Pods-CustomKeyboard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CustomKeyboard.debug.xcconfig"; path = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
B9F60894E529C3EDAF6BAC3D /* KBShopThemeDetailModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopThemeDetailModel.m; sourceTree = "<group>"; };
|
B9F60894E529C3EDAF6BAC3D /* KBShopThemeDetailModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBShopThemeDetailModel.m; sourceTree = "<group>"; };
|
||||||
@@ -685,7 +692,9 @@
|
|||||||
041007D02ECE010100D203BB /* Resource */ = {
|
041007D02ECE010100D203BB /* Resource */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
04E161772F0FA7BD0022C23B /* normal_them.zip */,
|
||||||
A1B2C3EC2F20000000000001 /* kb_words.txt */,
|
A1B2C3EC2F20000000000001 /* kb_words.txt */,
|
||||||
|
A1B2C3F02F20000000000002 /* kb_keyboard_layout_config.json */,
|
||||||
0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */,
|
0498BDF42EEC50EE006CC1D5 /* emoji_categories.json */,
|
||||||
041007D12ECE012000D203BB /* KBSkinIconMap.strings */,
|
041007D12ECE012000D203BB /* KBSkinIconMap.strings */,
|
||||||
041007D32ECE012500D203BB /* 002.zip */,
|
041007D32ECE012500D203BB /* 002.zip */,
|
||||||
@@ -1248,6 +1257,8 @@
|
|||||||
04FC95652EB0546C007BD342 /* KBKey.m */,
|
04FC95652EB0546C007BD342 /* KBKey.m */,
|
||||||
04FEDC202F00020000999999 /* KBKeyboardSubscriptionProduct.h */,
|
04FEDC202F00020000999999 /* KBKeyboardSubscriptionProduct.h */,
|
||||||
04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */,
|
04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */,
|
||||||
|
04FEDC232F10000100000001 /* KBKeyboardLayoutConfig.h */,
|
||||||
|
04FEDC242F10000100000001 /* KBKeyboardLayoutConfig.m */,
|
||||||
);
|
);
|
||||||
path = Model;
|
path = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1817,8 +1828,10 @@
|
|||||||
files = (
|
files = (
|
||||||
04A9FE202EB893F10020DB6D /* Localizable.strings in Resources */,
|
04A9FE202EB893F10020DB6D /* Localizable.strings in Resources */,
|
||||||
041007D42ECE012500D203BB /* 002.zip in Resources */,
|
041007D42ECE012500D203BB /* 002.zip in Resources */,
|
||||||
|
04E161782F0FA7BD0022C23B /* normal_them.zip in Resources */,
|
||||||
041007D22ECE012000D203BB /* KBSkinIconMap.strings in Resources */,
|
041007D22ECE012000D203BB /* KBSkinIconMap.strings in Resources */,
|
||||||
A1B2C3ED2F20000000000001 /* kb_words.txt in Resources */,
|
A1B2C3ED2F20000000000001 /* kb_words.txt in Resources */,
|
||||||
|
A1B2C3F12F20000000000002 /* kb_keyboard_layout_config.json in Resources */,
|
||||||
04791FFB2ED5EAB8004E8522 /* fense.zip in Resources */,
|
04791FFB2ED5EAB8004E8522 /* fense.zip in Resources */,
|
||||||
0498BDF52EEC50EE006CC1D5 /* emoji_categories.json in Resources */,
|
0498BDF52EEC50EE006CC1D5 /* emoji_categories.json in Resources */,
|
||||||
04791FF72ED5B985004E8522 /* Christmas.zip in Resources */,
|
04791FF72ED5B985004E8522 /* Christmas.zip in Resources */,
|
||||||
@@ -1962,6 +1975,7 @@
|
|||||||
A1F0C1C22FABCDEF12345678 /* KBInviteCodeModel.m in Sources */,
|
A1F0C1C22FABCDEF12345678 /* KBInviteCodeModel.m in Sources */,
|
||||||
A1F0C1D22FACAD0012345678 /* KBMaiPointReporter.m in Sources */,
|
A1F0C1D22FACAD0012345678 /* KBMaiPointReporter.m in Sources */,
|
||||||
04FEDC222F00020000999999 /* KBKeyboardSubscriptionProduct.m in Sources */,
|
04FEDC222F00020000999999 /* KBKeyboardSubscriptionProduct.m in Sources */,
|
||||||
|
04FEDC252F10000100000001 /* KBKeyboardLayoutConfig.m in Sources */,
|
||||||
0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */,
|
0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */,
|
||||||
550CB2630FA4A7B4B9782EFA /* KBMyTheme.m in Sources */,
|
550CB2630FA4A7B4B9782EFA /* KBMyTheme.m in Sources */,
|
||||||
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */,
|
0498BDDA2EE7ECEA006CC1D5 /* WJXEventSource.m in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user