3
@@ -20,13 +20,29 @@ typedef NS_ENUM(NSInteger, KBKeyType) {
|
||||
KBKeyTypeSymbolsToggle // 数字面板内的“#+=/123”切换
|
||||
};
|
||||
|
||||
/// 字母键的大小写变体标记(非字母键使用 KBKeyCaseVariantNone)
|
||||
typedef NS_ENUM(NSInteger, KBKeyCaseVariant) {
|
||||
KBKeyCaseVariantNone = 0,
|
||||
KBKeyCaseVariantLower = 1,
|
||||
KBKeyCaseVariantUpper = 2,
|
||||
};
|
||||
|
||||
@interface KBKey : NSObject
|
||||
|
||||
@property (nonatomic, assign) KBKeyType type;
|
||||
@property (nonatomic, copy) NSString *title; // 显示标题
|
||||
@property (nonatomic, copy) NSString *output; // 字符键插入的文本
|
||||
/// 逻辑按键标识,用于皮肤映射(如 @"letter_q" @"space" @"backspace")
|
||||
@property (nonatomic, copy, nullable) NSString *identifier;
|
||||
/// 字母键的大小写变体(便于皮肤为大小写准备不同图)
|
||||
@property (nonatomic, assign) KBKeyCaseVariant caseVariant;
|
||||
|
||||
+ (instancetype)keyWithTitle:(NSString *)title output:(NSString *)output;
|
||||
+ (instancetype)keyWithTitle:(NSString *)title type:(KBKeyType)type;
|
||||
/// 通用构造方法:用于指定 identifier,便于皮肤做精细控制
|
||||
+ (instancetype)keyWithIdentifier:(nullable NSString *)identifier
|
||||
title:(NSString *)title
|
||||
output:(NSString *)output
|
||||
type:(KBKeyType)type;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
k.type = KBKeyTypeCharacter;
|
||||
k.title = title ?: @"";
|
||||
k.output = output ?: title ?: @"";
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
|
||||
@@ -20,8 +21,21 @@
|
||||
k.type = type;
|
||||
k.title = title ?: @"";
|
||||
k.output = @"";
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
|
||||
+ (instancetype)keyWithIdentifier:(NSString *)identifier
|
||||
title:(NSString *)title
|
||||
output:(NSString *)output
|
||||
type:(KBKeyType)type {
|
||||
KBKey *k = [[KBKey alloc] init];
|
||||
k.type = type;
|
||||
k.identifier = identifier;
|
||||
k.title = title ?: @"";
|
||||
k.output = output ?: @"";
|
||||
k.caseVariant = KBKeyCaseVariantNone;
|
||||
return k;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
/// 根据选中/高亮等状态刷新外观
|
||||
- (void)refreshStateAppearance;
|
||||
|
||||
/// 根据当前皮肤与按键标识,应用图标和文字显隐等细节
|
||||
- (void)applyThemeForCurrentKey;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#import "KBKey.h"
|
||||
#import "KBSkinManager.h"
|
||||
|
||||
@interface KBKeyButton ()
|
||||
@property (nonatomic, strong) UIImageView *iconView;
|
||||
@end
|
||||
|
||||
@implementation KBKeyButton
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
@@ -29,6 +33,34 @@
|
||||
self.layer.shadowOffset = CGSizeMake(0, 1);
|
||||
self.layer.shadowRadius = 1.5;
|
||||
[self refreshStateAppearance];
|
||||
|
||||
// 懒创建图标视图,用于后续皮肤按键小图标展示
|
||||
if (!self.iconView) {
|
||||
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectZero];
|
||||
// 作为按键的整块皮肤背景,铺满整个按钮区域
|
||||
iv.contentMode = UIViewContentModeScaleAspectFill;
|
||||
iv.clipsToBounds = YES;
|
||||
iv.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:iv];
|
||||
// 让皮肤图片撑满整个按钮
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[iv.topAnchor constraintEqualToAnchor:self.topAnchor],
|
||||
[iv.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
|
||||
[iv.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
|
||||
[iv.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
|
||||
]];
|
||||
self.iconView = iv;
|
||||
|
||||
// 文字保持居中;若需要显示文字,则覆盖在皮肤图片之上
|
||||
self.titleEdgeInsets = UIEdgeInsetsZero;
|
||||
[self bringSubviewToFront:self.titleLabel];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setKey:(KBKey *)key {
|
||||
_key = key;
|
||||
// 每次切换按键模型时,根据皮肤刷新一次图标和文字显隐
|
||||
[self applyThemeForCurrentKey];
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)highlighted {
|
||||
@@ -56,4 +88,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applyThemeForCurrentKey {
|
||||
// 依据皮肤决定是否显示文字
|
||||
NSString *identifier = self.key.identifier;
|
||||
BOOL hideText = [[KBSkinManager shared] shouldHideKeyTextForIdentifier:identifier];
|
||||
self.titleLabel.hidden = hideText;
|
||||
|
||||
// 根据皮肤映射加载图标(若有),支持大小写变体:
|
||||
// - identifier: 逻辑按键标识(如 letter_q)
|
||||
// - caseVariant: 0/1/2 => 无变体/小写/大写
|
||||
NSInteger variant = (NSInteger)self.key.caseVariant;
|
||||
UIImage *iconImg = [[KBSkinManager shared] iconImageForKeyIdentifier:identifier caseVariant:variant];
|
||||
self.iconView.image = iconImg;
|
||||
self.iconView.hidden = (iconImg == nil);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -96,16 +96,41 @@
|
||||
|
||||
if (!self.symbolsMoreOn) {
|
||||
// 数字第一页(123)
|
||||
r1 = @[ [KBKey keyWithTitle:@"1" output:@"1"], [KBKey keyWithTitle:@"2" output:@"2"], [KBKey keyWithTitle:@"3" output:@"3"],
|
||||
[KBKey keyWithTitle:@"4" output:@"4"], [KBKey keyWithTitle:@"5" output:@"5"], [KBKey keyWithTitle:@"6" output:@"6"],
|
||||
[KBKey keyWithTitle:@"7" output:@"7"], [KBKey keyWithTitle:@"8" output:@"8"], [KBKey keyWithTitle:@"9" output:@"9"], [KBKey keyWithTitle:@"0" output:@"0"] ];
|
||||
r2 = @[ [KBKey keyWithTitle:@"-" output:@"-"], [KBKey keyWithTitle:@"/" output:@"/"], [KBKey keyWithTitle:@":" output:@":"],
|
||||
[KBKey keyWithTitle:@";" output:@";"], [KBKey keyWithTitle:@"(" output:@"("], [KBKey keyWithTitle:@")" output:@")"],
|
||||
[KBKey keyWithTitle:@"$" output:@"$"], [KBKey keyWithTitle:@"&" output:@"&"], [KBKey keyWithTitle:@"@" output:@"@"], [KBKey keyWithTitle:@"\"" output:@"\""] ];
|
||||
r3 = @[ [KBKey keyWithTitle:@"#+=" type:KBKeyTypeSymbolsToggle],
|
||||
[KBKey keyWithTitle:@"," output:@","], [KBKey keyWithTitle:@"." output:@"."], [KBKey keyWithTitle:@"?" output:@"?"],
|
||||
[KBKey keyWithTitle:@"!" output:@"!"], [KBKey keyWithTitle:@"'" output:@"'"],
|
||||
[KBKey keyWithTitle:@"⌫" type:KBKeyTypeBackspace] ];
|
||||
r1 = @[ [KBKey keyWithTitle:@"1" output:@"1"],
|
||||
[KBKey keyWithTitle:@"2" output:@"2"],
|
||||
[KBKey keyWithTitle:@"3" output:@"3"],
|
||||
[KBKey keyWithTitle:@"4" output:@"4"],
|
||||
[KBKey keyWithTitle:@"5" output:@"5"],
|
||||
[KBKey keyWithTitle:@"6" output:@"6"],
|
||||
[KBKey keyWithTitle:@"7" output:@"7"],
|
||||
[KBKey keyWithTitle:@"8" output:@"8"],
|
||||
[KBKey keyWithTitle:@"9" output:@"9"],
|
||||
[KBKey keyWithTitle:@"0" output:@"0"] ];
|
||||
r2 = @[ [KBKey keyWithTitle:@"-" output:@"-"],
|
||||
[KBKey keyWithTitle:@"/" output:@"/"],
|
||||
[KBKey keyWithTitle:@":" output:@":"],
|
||||
[KBKey keyWithTitle:@";" output:@";"],
|
||||
[KBKey keyWithTitle:@"(" output:@"("],
|
||||
[KBKey keyWithTitle:@")" output:@")"],
|
||||
[KBKey keyWithTitle:@"$" output:@"$"],
|
||||
[KBKey keyWithTitle:@"&" output:@"&"],
|
||||
[KBKey keyWithTitle:@"@" output:@"@"],
|
||||
[KBKey keyWithTitle:@"\"" output:@"\""] ];
|
||||
// 第三行:左下角是“#+=”切换键,右下角是退格键
|
||||
KBKey *toggle = [KBKey keyWithIdentifier:@"symbols_toggle_more"
|
||||
title:@"#+="
|
||||
output:@""
|
||||
type:KBKeyTypeSymbolsToggle];
|
||||
KBKey *comma = [KBKey keyWithTitle:@"," output:@","];
|
||||
KBKey *dot = [KBKey keyWithTitle:@"." output:@"."];
|
||||
KBKey *q = [KBKey keyWithTitle:@"?" output:@"?"];
|
||||
KBKey *ex = [KBKey keyWithTitle:@"!" output:@"!"];
|
||||
KBKey *quote = [KBKey keyWithTitle:@"'" output:@"'"];
|
||||
KBKey *back = [KBKey keyWithIdentifier:@"backspace"
|
||||
title:@"⌫"
|
||||
output:@""
|
||||
type:KBKeyTypeBackspace];
|
||||
r3 = @[ toggle, comma, dot, q, ex, quote, back ];
|
||||
} else {
|
||||
// 数字第二页(#+=):前两行替换为更多符号,左下角按钮文案改为“123”
|
||||
r1 = @[ [KBKey keyWithTitle:@"[" output:@"["], [KBKey keyWithTitle:@"]" output:@"]"], [KBKey keyWithTitle:@"{" output:@"{"],
|
||||
@@ -116,16 +141,40 @@
|
||||
[KBKey keyWithTitle:@"~" output:@"~"], [KBKey keyWithTitle:@"<" output:@"<"], [KBKey keyWithTitle:@">" output:@">"],
|
||||
[KBKey keyWithTitle:@"$" output:@"$"], [KBKey keyWithTitle:@"€" output:@"€"], [KBKey keyWithTitle:@"£" output:@"£"],
|
||||
[KBKey keyWithTitle:@"•" output:@"•"] ];
|
||||
r3 = @[ [KBKey keyWithTitle:@"123" type:KBKeyTypeSymbolsToggle],
|
||||
[KBKey keyWithTitle:@"," output:@","], [KBKey keyWithTitle:@"." output:@"."], [KBKey keyWithTitle:@"?" output:@"?"],
|
||||
[KBKey keyWithTitle:@"!" output:@"!"], [KBKey keyWithTitle:@"'" output:@"'"],
|
||||
[KBKey keyWithTitle:@"⌫" type:KBKeyTypeBackspace] ];
|
||||
KBKey *toggle = [KBKey keyWithIdentifier:@"symbols_toggle_123"
|
||||
title:@"123"
|
||||
output:@""
|
||||
type:KBKeyTypeSymbolsToggle];
|
||||
KBKey *comma = [KBKey keyWithTitle:@"," output:@","];
|
||||
KBKey *dot = [KBKey keyWithTitle:@"." output:@"."];
|
||||
KBKey *q = [KBKey keyWithTitle:@"?" output:@"?"];
|
||||
KBKey *ex = [KBKey keyWithTitle:@"!" output:@"!"];
|
||||
KBKey *quote = [KBKey keyWithTitle:@"'" output:@"'"];
|
||||
KBKey *back = [KBKey keyWithIdentifier:@"backspace"
|
||||
title:@"⌫"
|
||||
output:@""
|
||||
type:KBKeyTypeBackspace];
|
||||
r3 = @[ toggle, comma, dot, q, ex, quote, back ];
|
||||
}
|
||||
|
||||
NSArray *r4 = @[ [KBKey keyWithTitle:@"abc" type:KBKeyTypeModeChange],
|
||||
[KBKey keyWithTitle:@"AI" type:KBKeyTypeCustom],
|
||||
[KBKey keyWithTitle:@"space" type:KBKeyTypeSpace],
|
||||
[KBKey keyWithTitle:KBLocalized(@"Send") type:KBKeyTypeReturn] ];
|
||||
KBKey *modeABC = [KBKey keyWithIdentifier:@"mode_abc"
|
||||
title:@"abc"
|
||||
output:@""
|
||||
type:KBKeyTypeModeChange];
|
||||
KBKey *customAI = [KBKey keyWithIdentifier:@"ai"
|
||||
title:@"AI"
|
||||
output:@""
|
||||
type:KBKeyTypeCustom];
|
||||
KBKey *space = [KBKey keyWithIdentifier:@"space"
|
||||
title:@"space"
|
||||
output:@" "
|
||||
type:KBKeyTypeSpace];
|
||||
KBKey *ret = [KBKey keyWithIdentifier:@"return"
|
||||
title:KBLocalized(@"Send")
|
||||
output:@"\n"
|
||||
type:KBKeyTypeReturn];
|
||||
|
||||
NSArray *r4 = @[ modeABC, customAI, space, ret ];
|
||||
|
||||
return @[r1, r2, r3, r4];
|
||||
}
|
||||
@@ -139,27 +188,67 @@
|
||||
// 字母键标题与输出同时随 Shift 切换大小写,界面与输入保持一致
|
||||
for (NSString *s in r1) {
|
||||
NSString *shown = self.shiftOn ? s : s.lowercaseString;
|
||||
[row1 addObject:[KBKey keyWithTitle:shown output:shown]];
|
||||
NSString *identifier = [NSString stringWithFormat:@"letter_%@", s.lowercaseString];
|
||||
KBKey *k = [KBKey keyWithIdentifier:identifier
|
||||
title:shown
|
||||
output:shown
|
||||
type:KBKeyTypeCharacter];
|
||||
k.caseVariant = self.shiftOn ? KBKeyCaseVariantUpper : KBKeyCaseVariantLower;
|
||||
[row1 addObject:k];
|
||||
}
|
||||
|
||||
NSMutableArray *row2 = [NSMutableArray arrayWithCapacity:r2.count];
|
||||
for (NSString *s in r2) {
|
||||
NSString *shown = self.shiftOn ? s : s.lowercaseString;
|
||||
[row2 addObject:[KBKey keyWithTitle:shown output:shown]];
|
||||
NSString *identifier = [NSString stringWithFormat:@"letter_%@", s.lowercaseString];
|
||||
KBKey *k = [KBKey keyWithIdentifier:identifier
|
||||
title:shown
|
||||
output:shown
|
||||
type:KBKeyTypeCharacter];
|
||||
k.caseVariant = self.shiftOn ? KBKeyCaseVariantUpper : KBKeyCaseVariantLower;
|
||||
[row2 addObject:k];
|
||||
}
|
||||
|
||||
NSMutableArray *row3 = [NSMutableArray array];
|
||||
[row3 addObject:[KBKey keyWithTitle:@"⇧" type:KBKeyTypeShift]];
|
||||
KBKey *shift = [KBKey keyWithIdentifier:@"shift"
|
||||
title:@"⇧"
|
||||
output:@""
|
||||
type:KBKeyTypeShift];
|
||||
[row3 addObject:shift];
|
||||
for (NSString *s in r3chars) {
|
||||
NSString *shown = self.shiftOn ? s : s.lowercaseString;
|
||||
[row3 addObject:[KBKey keyWithTitle:shown output:shown]];
|
||||
NSString *identifier = [NSString stringWithFormat:@"letter_%@", s.lowercaseString];
|
||||
KBKey *k = [KBKey keyWithIdentifier:identifier
|
||||
title:shown
|
||||
output:shown
|
||||
type:KBKeyTypeCharacter];
|
||||
k.caseVariant = self.shiftOn ? KBKeyCaseVariantUpper : KBKeyCaseVariantLower;
|
||||
[row3 addObject:k];
|
||||
}
|
||||
[row3 addObject:[KBKey keyWithTitle:@"⌫" type:KBKeyTypeBackspace]];
|
||||
KBKey *backspace = [KBKey keyWithIdentifier:@"backspace"
|
||||
title:@"⌫"
|
||||
output:@""
|
||||
type:KBKeyTypeBackspace];
|
||||
[row3 addObject:backspace];
|
||||
|
||||
NSArray *row4 = @[ [KBKey keyWithTitle:@"123" type:KBKeyTypeModeChange],
|
||||
[KBKey keyWithTitle:@"AI" type:KBKeyTypeCustom],
|
||||
[KBKey keyWithTitle:@"space" type:KBKeyTypeSpace],
|
||||
[KBKey keyWithTitle:KBLocalized(@"Send") type:KBKeyTypeReturn] ];
|
||||
KBKey *mode123 = [KBKey keyWithIdentifier:@"mode_123"
|
||||
title:@"123"
|
||||
output:@""
|
||||
type:KBKeyTypeModeChange];
|
||||
KBKey *customAI = [KBKey keyWithIdentifier:@"ai"
|
||||
title:@"AI"
|
||||
output:@""
|
||||
type:KBKeyTypeCustom];
|
||||
KBKey *space = [KBKey keyWithIdentifier:@"space"
|
||||
title:@"space"
|
||||
output:@" "
|
||||
type:KBKeyTypeSpace];
|
||||
KBKey *ret = [KBKey keyWithIdentifier:@"return"
|
||||
title:KBLocalized(@"Send")
|
||||
output:@"\n"
|
||||
type:KBKeyTypeReturn];
|
||||
|
||||
NSArray *row4 = @[ mode123, customAI, space, ret ];
|
||||
|
||||
return @[row1.copy, row2.copy, row3.copy, row4];
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
/// APP Groups
|
||||
#define AppGroup @"group.com.loveKey.nyx"
|
||||
|
||||
/// 皮肤图标加载模式:
|
||||
/// 0 = 使用本地 Assets 图片名(key_icons 的 value 写成图片名,例如 "kb_q_melon")
|
||||
/// 1 = 使用远程 URL 下载到 App Group 目录,再由键盘扩展从文件系统加载
|
||||
#ifndef KB_SKIN_ICON_USE_REMOTE
|
||||
#define KB_SKIN_ICON_USE_REMOTE 0
|
||||
#endif
|
||||
|
||||
|
||||
// 基础baseUrl
|
||||
#ifndef KB_BASE_URL
|
||||
@@ -84,4 +91,3 @@ static inline CGFloat KBFit(CGFloat designValue) {
|
||||
#ifndef KBWeakSelf
|
||||
#define KBWeakSelf __weak __typeof(self) weakSelf = self;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ extern NSString * const KBDarwinSkinChanged; // cross-process
|
||||
@property (nonatomic, strong) UIColor *accentColor; // function view accents
|
||||
/// 可选:键盘背景图片的 PNG/JPEG 数据(若存在,优先显示图片)
|
||||
@property (nonatomic, strong, nullable) NSData *backgroundImageData;
|
||||
/// 可选:需要隐藏文字的按键标识集合(例如 @"letter_q" @"space" 等)
|
||||
@property (nonatomic, strong, nullable) NSArray<NSString *> *hiddenKeyTextIdentifiers;
|
||||
/// 可选:按键图标映射(按键标识 -> 图标名或路径),具体加载策略由上层决定
|
||||
@property (nonatomic, strong, nullable) NSDictionary<NSString *, NSString *> *keyIconMap;
|
||||
@end
|
||||
|
||||
/// Shared skin manager (Keychain Sharing based)
|
||||
@@ -50,6 +54,23 @@ extern NSString * const KBDarwinSkinChanged; // cross-process
|
||||
/// 当前背景图片(若存在)
|
||||
- (nullable UIImage *)currentBackgroundImage;
|
||||
|
||||
/// 当前主题下,指定按键标识的文字是否应被隐藏(例如图标里已包含字母)
|
||||
- (BOOL)shouldHideKeyTextForIdentifier:(nullable NSString *)identifier;
|
||||
|
||||
/// 当前主题下,指定按键标识对应的图标名(可作为 imageName 或文件相对路径),若未配置则为 nil
|
||||
- (nullable NSString *)iconNameForKeyIdentifier:(nullable NSString *)identifier;
|
||||
|
||||
/// 当前主题下,返回指定按键的图标图片。
|
||||
/// 若 keyIconMap 中的 value 不包含 "/",则按本地 Assets 名称加载;
|
||||
/// 若包含 "/",则视为相对 App Group 根目录的文件路径,从文件系统加载。
|
||||
- (nullable UIImage *)iconImageForKeyIdentifier:(nullable NSString *)identifier;
|
||||
|
||||
/// 带大小写变体的按键图标获取接口。
|
||||
/// @param identifier 逻辑按键标识(如 @"letter_q" @"space")
|
||||
/// @param caseVariant 0=无变体/非字母,1=小写,2=大写(与 KBKeyCaseVariant 对应)
|
||||
- (nullable UIImage *)iconImageForKeyIdentifier:(nullable NSString *)identifier
|
||||
caseVariant:(NSInteger)caseVariant;
|
||||
|
||||
/// Parse a hex color string like "#RRGGBB"/"#RRGGBBAA"
|
||||
+ (UIColor *)colorFromHexString:(NSString *)hex defaultColor:(UIColor *)fallback;
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ static NSString * const kKBSkinAccount = @"current"; // Keychain ac
|
||||
if (self.backgroundImageData) {
|
||||
[coder encodeObject:self.backgroundImageData forKey:@"backgroundImageData"];
|
||||
}
|
||||
if (self.hiddenKeyTextIdentifiers.count > 0) {
|
||||
[coder encodeObject:self.hiddenKeyTextIdentifiers forKey:@"hiddenKeyTextIdentifiers"];
|
||||
}
|
||||
if (self.keyIconMap.count > 0) {
|
||||
[coder encodeObject:self.keyIconMap forKey:@"keyIconMap"];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
@@ -39,6 +45,9 @@ static NSString * const kKBSkinAccount = @"current"; // Keychain ac
|
||||
_keyHighlightBackground = [coder decodeObjectOfClass:UIColor.class forKey:@"keyHighlightBackground"] ?: [UIColor colorWithWhite:0.85 alpha:1.0];
|
||||
_accentColor = [coder decodeObjectOfClass:UIColor.class forKey:@"accentColor"] ?: [UIColor colorWithRed:0.77 green:0.93 blue:0.82 alpha:1.0];
|
||||
_backgroundImageData = [coder decodeObjectOfClass:NSData.class forKey:@"backgroundImageData"];
|
||||
// 这两个字段是新增的,旧数据没有也没关系
|
||||
_hiddenKeyTextIdentifiers = [coder decodeObjectOfClass:NSArray.class forKey:@"hiddenKeyTextIdentifiers"];
|
||||
_keyIconMap = [coder decodeObjectOfClass:NSDictionary.class forKey:@"keyIconMap"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -91,6 +100,16 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
|
||||
t.keyTextColor = [self.class colorFromHexString:json[@"key_text"] defaultColor:[self.class defaultTheme].keyTextColor];
|
||||
t.keyHighlightBackground = [self.class colorFromHexString:json[@"key_highlight"] defaultColor:[self.class defaultTheme].keyHighlightBackground];
|
||||
t.accentColor = [self.class colorFromHexString:json[@"accent"] defaultColor:[self.class defaultTheme].accentColor];
|
||||
// 可选:hidden_keys 为需要隐藏文本的按键标识数组
|
||||
id hidden = json[@"hidden_keys"];
|
||||
if ([hidden isKindOfClass:NSArray.class]) {
|
||||
t.hiddenKeyTextIdentifiers = hidden;
|
||||
}
|
||||
// 可选:key_icons 为 按键标识 -> 图标名/文件名 的字典
|
||||
id icons = json[@"key_icons"];
|
||||
if ([icons isKindOfClass:NSDictionary.class]) {
|
||||
t.keyIconMap = icons;
|
||||
}
|
||||
return [self applyTheme:t];
|
||||
}
|
||||
|
||||
@@ -121,6 +140,9 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
|
||||
t.keyTextColor = base.keyTextColor ?: [self.class defaultTheme].keyTextColor;
|
||||
t.keyHighlightBackground = base.keyHighlightBackground ?: [self.class defaultTheme].keyHighlightBackground;
|
||||
t.accentColor = base.accentColor ?: [self.class defaultTheme].accentColor;
|
||||
// 继承按键文本隐藏配置和图标映射,避免仅切换背景时丢失这些设置
|
||||
t.hiddenKeyTextIdentifiers = base.hiddenKeyTextIdentifiers;
|
||||
t.keyIconMap = base.keyIconMap;
|
||||
t.backgroundImageData = imageData;
|
||||
return [self applyTheme:t];
|
||||
}
|
||||
@@ -131,6 +153,103 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer,
|
||||
return [UIImage imageWithData:d scale:[UIScreen mainScreen].scale] ?: nil;
|
||||
}
|
||||
|
||||
- (BOOL)shouldHideKeyTextForIdentifier:(NSString *)identifier {
|
||||
if (identifier.length == 0) return NO;
|
||||
NSArray<NSString *> *list = self.current.hiddenKeyTextIdentifiers;
|
||||
if (list.count == 0) return NO;
|
||||
// 简单线性查找,数量有限足够;如需可改为 NSSet 缓存。
|
||||
for (NSString *s in list) {
|
||||
if ([s isKindOfClass:NSString.class] && [s isEqualToString:identifier]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)iconNameForKeyIdentifier:(NSString *)identifier {
|
||||
if (identifier.length == 0) return nil;
|
||||
NSDictionary<NSString *, NSString *> *map = self.current.keyIconMap;
|
||||
if (map.count == 0) return nil;
|
||||
NSString *name = map[identifier];
|
||||
if (![name isKindOfClass:NSString.class] || name.length == 0) return nil;
|
||||
return name;
|
||||
}
|
||||
|
||||
- (UIImage *)iconImageForKeyIdentifier:(NSString *)identifier {
|
||||
return [self iconImageForKeyIdentifier:identifier caseVariant:0];
|
||||
}
|
||||
|
||||
- (UIImage *)iconImageForKeyIdentifier:(NSString *)identifier caseVariant:(NSInteger)caseVariant {
|
||||
NSDictionary<NSString *, NSString *> *map = self.current.keyIconMap;
|
||||
NSString *value = nil;
|
||||
|
||||
if (identifier.length > 0 && map.count > 0) {
|
||||
// 1) 大小写变体优先:letter_q_upper / letter_q_lower
|
||||
if (caseVariant == 2) { // upper
|
||||
NSString *keyUpper = [identifier stringByAppendingString:@"_upper"];
|
||||
NSString *candidate = map[keyUpper];
|
||||
if ([candidate isKindOfClass:NSString.class] && candidate.length > 0) {
|
||||
value = candidate;
|
||||
}
|
||||
} else if (caseVariant == 1) { // lower
|
||||
NSString *keyLower = [identifier stringByAppendingString:@"_lower"];
|
||||
NSString *candidate = map[keyLower];
|
||||
if ([candidate isKindOfClass:NSString.class] && candidate.length > 0) {
|
||||
value = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 若未配置大小写专用图标,则回退到基础 id(兼容旧数据:letter_q)
|
||||
if (value.length == 0) {
|
||||
NSString *candidate = map[identifier];
|
||||
if ([candidate isKindOfClass:NSString.class] && candidate.length > 0) {
|
||||
value = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 若在 keyIconMap 中找到了 value,按约定加载
|
||||
if (value.length > 0) {
|
||||
if ([value containsString:@"/"]) {
|
||||
// 视为相对 App Group 根目录的文件路径
|
||||
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:AppGroup];
|
||||
if (!containerURL) return nil;
|
||||
NSString *fullPath = [[containerURL.path stringByAppendingPathComponent:value] stringByStandardizingPath];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) return nil;
|
||||
return [UIImage imageWithContentsOfFile:fullPath];
|
||||
}
|
||||
// 否则按本地 Assets 名称加载(兼容旧实现)
|
||||
return [UIImage imageNamed:value];
|
||||
}
|
||||
|
||||
// 兜底:若 keyIconMap 中没有该键,则按照约定的命名规则直接从 App Group 读取:
|
||||
// Skins/<skinId>/icons/(identifier[_upper/_lower]).png
|
||||
NSString *skinId = self.current.skinId;
|
||||
if (skinId.length == 0 || identifier.length == 0) return nil;
|
||||
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:AppGroup];
|
||||
if (!containerURL) return nil;
|
||||
// 先尝试大小写后缀
|
||||
if (caseVariant == 2) {
|
||||
NSString *relativeUpper = [NSString stringWithFormat:@"Skins/%@/icons/%@_upper.png", skinId, identifier];
|
||||
NSString *fullUpper = [[containerURL.path stringByAppendingPathComponent:relativeUpper] stringByStandardizingPath];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fullUpper]) {
|
||||
return [UIImage imageWithContentsOfFile:fullUpper];
|
||||
}
|
||||
} else if (caseVariant == 1) {
|
||||
NSString *relativeLower = [NSString stringWithFormat:@"Skins/%@/icons/%@_lower.png", skinId, identifier];
|
||||
NSString *fullLower = [[containerURL.path stringByAppendingPathComponent:relativeLower] stringByStandardizingPath];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:fullLower]) {
|
||||
return [UIImage imageWithContentsOfFile:fullLower];
|
||||
}
|
||||
}
|
||||
|
||||
// 最后回退到基础 id:Skins/<skinId>/icons/<identifier>.png
|
||||
NSString *relative = [NSString stringWithFormat:@"Skins/%@/icons/%@.png", skinId, identifier];
|
||||
NSString *fullPath = [[containerURL.path stringByAppendingPathComponent:relative] stringByStandardizingPath];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:fullPath]) return nil;
|
||||
return [UIImage imageWithContentsOfFile:fullPath];
|
||||
}
|
||||
|
||||
+ (UIColor *)colorFromHexString:(NSString *)hex defaultColor:(UIColor *)fallback {
|
||||
if (![hex isKindOfClass:NSString.class] || hex.length == 0) return fallback;
|
||||
NSString *s = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString];
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */; };
|
||||
04286A002ECAEF2B00CE730C /* KBMoneyBtn.m in Sources */ = {isa = PBXBuildFile; fileRef = 042869FE2ECAEF2B00CE730C /* KBMoneyBtn.m */; };
|
||||
04286A032ECB0A1600CE730C /* KBSexSelVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04286A022ECB0A1600CE730C /* KBSexSelVC.m */; };
|
||||
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */ = {isa = PBXBuildFile; fileRef = 04286A052ECC81B200CE730C /* KBSkinService.m */; };
|
||||
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; };
|
||||
0459D1B42EBA284C00F2D189 /* KBSkinCenterVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */; };
|
||||
0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B62EBA287900F2D189 /* KBSkinManager.m */; };
|
||||
@@ -234,6 +235,8 @@
|
||||
042869FE2ECAEF2B00CE730C /* KBMoneyBtn.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMoneyBtn.m; sourceTree = "<group>"; };
|
||||
04286A012ECB0A1600CE730C /* KBSexSelVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSexSelVC.h; sourceTree = "<group>"; };
|
||||
04286A022ECB0A1600CE730C /* KBSexSelVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSexSelVC.m; sourceTree = "<group>"; };
|
||||
04286A042ECC81B200CE730C /* KBSkinService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinService.h; sourceTree = "<group>"; };
|
||||
04286A052ECC81B200CE730C /* KBSkinService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinService.m; sourceTree = "<group>"; };
|
||||
0459D1B22EBA284C00F2D189 /* KBSkinCenterVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinCenterVC.h; sourceTree = "<group>"; };
|
||||
0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinCenterVC.m; sourceTree = "<group>"; };
|
||||
0459D1B52EBA287900F2D189 /* KBSkinManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinManager.h; sourceTree = "<group>"; };
|
||||
@@ -1297,6 +1300,8 @@
|
||||
children = (
|
||||
04FC95F22EB339C1007BD342 /* AppleSignInManager.h */,
|
||||
04FC95F32EB339C1007BD342 /* AppleSignInManager.m */,
|
||||
04286A042ECC81B200CE730C /* KBSkinService.h */,
|
||||
04286A052ECC81B200CE730C /* KBSkinService.m */,
|
||||
);
|
||||
path = Manager;
|
||||
sourceTree = "<group>";
|
||||
@@ -1621,6 +1626,7 @@
|
||||
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */,
|
||||
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
|
||||
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
|
||||
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */,
|
||||
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,
|
||||
049FB31D2EC21BCD00FAB05D /* KBMyKeyboardCell.m in Sources */,
|
||||
048909F62EC0AAAA00FABA60 /* KBCategoryTitleCell.m in Sources */,
|
||||
|
||||
6
keyBoard/Assets.xcassets/Test/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
keyBoard/Assets.xcassets/Test/key_123.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_123@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_123@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_123.imageset/key_123@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_123.imageset/key_123@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
22
keyBoard/Assets.xcassets/Test/key_a.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_a@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_a@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_a.imageset/key_a@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_a.imageset/key_a@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 29 KiB |
22
keyBoard/Assets.xcassets/Test/key_ai.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_ai@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_ai@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_ai.imageset/key_ai@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_ai.imageset/key_ai@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 49 KiB |
22
keyBoard/Assets.xcassets/Test/key_b.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_b@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_b@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_b.imageset/key_b@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_b.imageset/key_b@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
22
keyBoard/Assets.xcassets/Test/key_c.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_c@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_c@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_c.imageset/key_c@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_c.imageset/key_c@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 24 KiB |
22
keyBoard/Assets.xcassets/Test/key_d.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_d@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_d@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_d.imageset/key_d@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_d.imageset/key_d@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
22
keyBoard/Assets.xcassets/Test/key_del.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_del@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_del@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_del.imageset/key_del@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_del.imageset/key_del@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 45 KiB |
22
keyBoard/Assets.xcassets/Test/key_e.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_e@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_e@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_e.imageset/key_e@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_e.imageset/key_e@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
22
keyBoard/Assets.xcassets/Test/key_f.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_f@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_f@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_f.imageset/key_f@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_f.imageset/key_f@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
22
keyBoard/Assets.xcassets/Test/key_g.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_g@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_g@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_g.imageset/key_g@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_g.imageset/key_g@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
22
keyBoard/Assets.xcassets/Test/key_h.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_h@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_h@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_h.imageset/key_h@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_h.imageset/key_h@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
22
keyBoard/Assets.xcassets/Test/key_i.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_i@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_i@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_i.imageset/key_i@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_i.imageset/key_i@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
22
keyBoard/Assets.xcassets/Test/key_j.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_j@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_j@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_j.imageset/key_j@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_j.imageset/key_j@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 34 KiB |
22
keyBoard/Assets.xcassets/Test/key_k.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_k@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_k@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_k.imageset/key_k@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_k.imageset/key_k@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 25 KiB |
22
keyBoard/Assets.xcassets/Test/key_l.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_l@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_l@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_l.imageset/key_l@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_l.imageset/key_l@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 29 KiB |
22
keyBoard/Assets.xcassets/Test/key_m.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_m@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_m@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_m.imageset/key_m@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_m.imageset/key_m@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
22
keyBoard/Assets.xcassets/Test/key_n.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_n@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_n@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_n.imageset/key_n@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_n.imageset/key_n@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
22
keyBoard/Assets.xcassets/Test/key_o.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_o@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_o@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_o.imageset/key_o@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_o.imageset/key_o@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 34 KiB |
22
keyBoard/Assets.xcassets/Test/key_p.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_p@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_p@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_p.imageset/key_p@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_p.imageset/key_p@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
22
keyBoard/Assets.xcassets/Test/key_q.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_q@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_q@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_q.imageset/key_q@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_q.imageset/key_q@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 26 KiB |
22
keyBoard/Assets.xcassets/Test/key_r.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_r@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_r@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_r.imageset/key_r@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_r.imageset/key_r@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 29 KiB |
22
keyBoard/Assets.xcassets/Test/key_s.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_s@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_s@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_s.imageset/key_s@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_s.imageset/key_s@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
22
keyBoard/Assets.xcassets/Test/key_send.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_send@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_send@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_send.imageset/key_send@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_send.imageset/key_send@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 78 KiB |
22
keyBoard/Assets.xcassets/Test/key_space.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_space@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_space@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_space.imageset/key_space@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_space.imageset/key_space@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 108 KiB |
22
keyBoard/Assets.xcassets/Test/key_t.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_t@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_t@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_t.imageset/key_t@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_t.imageset/key_t@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 34 KiB |
22
keyBoard/Assets.xcassets/Test/key_u.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_u@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_u@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_u.imageset/key_u@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_u.imageset/key_u@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
22
keyBoard/Assets.xcassets/Test/key_up.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_up@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_up@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_up.imageset/key_up@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_up.imageset/key_up@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 51 KiB |
22
keyBoard/Assets.xcassets/Test/key_v.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_v@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_v@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_v.imageset/key_v@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_v.imageset/key_v@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
22
keyBoard/Assets.xcassets/Test/key_w.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_w@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_w@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_w.imageset/key_w@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_w.imageset/key_w@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
22
keyBoard/Assets.xcassets/Test/key_x.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_x@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "key_x@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
keyBoard/Assets.xcassets/Test/key_x.imageset/key_x@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
keyBoard/Assets.xcassets/Test/key_x.imageset/key_x@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 31 KiB |