@@ -8,23 +8,26 @@
# import "KeyboardViewController.h"
# import "KBKeyBoardMainView.h"
# import "KBKey.h"
# import "KBFunctionView.h"
# import "KBSettingView.h"
# import "Masonry.h"
# import "KBAuthManager.h"
# import "KBFullAccessManager.h"
# import "KBSkinManager.h"
# import "KBSkinInstallBridge.h"
# import "KBHostAppLauncher.h"
# import "KBKeyboardSubscriptionView.h"
# import "KBKeyboardSubscriptionProduct.h"
# import "KBBackspaceUndoManager.h"
# import "KBFullAccessManager.h"
# import "KBFunctionView.h"
# import "KBHostAppLauncher.h"
# import "KBInputBufferManager.h"
# import "KBKey.h"
# import "KBKeyboardSubscriptionProduct.h"
# import "KBKeyboardSubscriptionView.h"
# import "KBSettingView.h"
# import "KBSkinInstallBridge.h"
# import "KBSkinManager.h"
# import "KBSuggestionEngine.h"
# import "Masonry.h"
# import "UIImage+KBColor.h"
// # import "KBLog.h"
// 提 前 声 明 一 个 类 别 , 使 编 译 器 在 static 回 调 中 识 别 kb_consumePendingShopSkin 方 法 。
// 提 前 声 明 一 个 类 别 , 使 编 译 器 在 static 回 调 中 识 别 kb_consumePendingShopSkin
// 方 法 。
@ interface KeyboardViewController ( KBSkinShopBridge )
- ( void ) kb_consumePendingShopSkin ;
@ end
@@ -37,12 +40,14 @@ static NSString * const kKBDefaultSkinIdDark = @"normal_hei_them";
static NSString * const kKBDefaultSkinZipNameDark = @ "normal_hei_them" ;
static void KBSkinInstallNotificationCallback ( CFNotificationCenterRef center ,
void * observer ,
CFStringRef name ,
void * observer , CFStringRef name ,
const void * object ,
CFDictionaryRef userInfo ) {
KeyboardViewController * strongSelf = ( __bridge KeyboardViewController * ) observer ;
if ( ! strongSelf ) { return ; }
KeyboardViewController * strongSelf =
( __bridge KeyboardViewController * ) observer ;
if ( ! strongSelf ) {
return ;
}
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
if ( [ strongSelf respondsToSelector : @ selector ( kb_consumePendingShopSkin ) ] ) {
[ strongSelf kb_consumePendingShopSkin ] ;
@@ -50,11 +55,16 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
} ) ;
}
@ interface KeyboardViewController ( ) < KBKeyBoardMainViewDelegate , KBFunctionViewDelegate , KBKeyboardSubscriptionViewDelegate >
@ property ( nonatomic , strong ) UIButton * nextKeyboardButton ; // 系 统 “ 下 一 个 键 盘 ” 按 钮 ( 可 选 )
@ interface KeyboardViewController ( ) < KBKeyBoardMainViewDelegate ,
KBFunctionViewDelegate ,
KBKeyboardSubscriptionViewDelegate >
@ property ( nonatomic , strong )
UIButton * nextKeyboardButton ; // 系 统 “ 下 一 个 键 盘 ” 按 钮 ( 可 选 )
@ property ( nonatomic , strong ) UIView * contentView ;
@ property ( nonatomic , strong ) KBKeyBoardMainView * keyBoardMainView ; // 功 能 面 板 视 图 ( 点 击 工 具 栏 第 0 个 时 显 示 )
@ property ( nonatomic , strong ) KBFunctionView * functio nView; // 功 能 面 板 视 图 ( 点 击 工 具 栏 第 0 个 时 显 示 )
@ property ( nonatomic , strong ) KBKeyBoardMainView
* keyBoardMai nView; // 功 能 面 板 视 图 ( 点 击 工 具 栏 第 0 个 时 显 示 )
@ property ( nonatomic , strong )
KBFunctionView * functionView ; // 功 能 面 板 视 图 ( 点 击 工 具 栏 第 0 个 时 显 示 )
@ property ( nonatomic , strong ) KBSettingView * settingView ; // 设 置 页
@ property ( nonatomic , strong ) UIImageView * bgImageView ; // 背 景 图 ( 在 底 层 )
@ property ( nonatomic , strong ) KBKeyboardSubscriptionView * subscriptionView ;
@@ -86,24 +96,30 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ KBHUD setContainerView : self . view ] ;
// 绑 定 完 全 访 问 管 理 器 , 便 于 统 一 感 知 和 联 动 网 络 开 关
[ [ KBFullAccessManager shared ] bindInputController : self ] ;
__unused id token = [ [ NSNotificationCenter defaultCenter ] addObserverForName : KBFullAccessChangedNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( __unused NSNotification * _Nonnull note ) {
__unused id token = [ [ NSNotificationCenter defaultCenter ]
addObserverForName : KBFullAccessChangedNotification
object : nil
queue : [ NSOperationQueue mainQueue ]
usingBlock : ^ ( __unused NSNotification * _Nonnull note ) {
// 如 需 , 可 在 此 刷 新 与 完 全 访 问 相 关 的 UI
} ] ;
// 皮 肤 变 化 时 , 立 即 应 用
__unused id token2 = [ [ NSNotificationCenter defaultCenter ] addObserverForName : KBSkinDidChangeNotification object : nil queue : [ NSOperationQueue mainQueue ] usingBlock : ^ ( __unused NSNotification * _Nonnull note ) {
__unused id token2 = [ [ NSNotificationCenter defaultCenter ]
addObserverForName : KBSkinDidChangeNotification
object : nil
queue : [ NSOperationQueue mainQueue ]
usingBlock : ^ ( __unused NSNotification * _Nonnull note ) {
[ self kb_applyTheme ] ;
} ] ;
[ self kb_applyTheme ] ;
CFNotificationCenterAddObserver ( CFNotificationCenterGetDarwinNotifyCenter ( ) ,
( __bridge const void * ) ( self ) ,
KBSkinInstallNotificationCallback ,
( __bridge CFStringRef ) KBDarwinSkinInstallRequestNotification ,
NULL ,
CFNotificationCenterAddObserver (
CFNotificationCenterGetDarwinNotifyCenter ( ) ,
( __bridge const void * ) ( self ) , KBSkinInstallNotificationCallback ,
( __bridge CFStringRef ) KBDarwinSkinInstallRequestNotification , NULL ,
CFNotificationSuspensionBehaviorDeliverImmediately ) ;
[ self kb_consumePendingShopSkin ] ;
[ self kb_applyDefaultSkinIfNeeded ] ;
}
- ( void ) viewWillAppear : ( BOOL ) animated {
@@ -112,9 +128,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ [ KBBackspaceUndoManager shared ] registerNonClearAction ] ;
[ [ KBInputBufferManager shared ] resetWithText : @ "" ] ;
[ [ KBLocalizationManager shared ] reloadFromSharedStorageIfNeeded ] ;
// 注 意 : 微 信 / QQ 等 宿 主 的 documentContext 可 能 是 “ 截 断 窗 口 ” , 这 里 只 更 新 liveText , 不 要 把 它 当 作 全 文 manualSnapshot 。
[ [ KBInputBufferManager shared ] updateFromExternalContextBefore : self . textDocumentProxy . documentContextBeforeInput
after : self . textDocumentProxy . documentContextAfterInput ] ;
// 注 意 : 微 信 / QQ 等 宿 主 的 documentContext 可 能 是 “ 截 断 窗 口 ” , 这 里 只 更 新
// liveText , 不 要 把 它 当 作 全 文 manualSnapshot 。
[ [ KBInputBufferManager shared ]
updateFromExternalContextBefore : self . textDocumentProxy
. documentContextBeforeInput
after : self . textDocumentProxy
. documentContextAfterInput ] ;
}
- ( void ) viewWillDisappear : ( BOOL ) animated {
@@ -125,7 +145,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- ( void ) traitCollectionDidChange : ( UITraitCollection * ) previousTraitCollection {
[ super traitCollectionDidChange : previousTraitCollection ] ;
if ( @ available ( iOS 13.0 , * ) ) {
if ( previousTraitCollection . userInterfaceStyle ! = self . traitCollection . userInterfaceStyle ) {
if ( previousTraitCollection . userInterfaceStyle ! =
self . traitCollection . userInterfaceStyle ) {
[ self kb_applyDefaultSkinIfNeeded ] ;
}
}
@@ -133,11 +154,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- ( void ) textDidChange : ( id < UITextInput > ) textInput {
[ super textDidChange : textInput ] ;
[ [ KBInputBufferManager shared ] updateFromExternalContextBefore : self . textDocumentProxy . documentContextBeforeInput
after : self . textDocumentProxy . documentContextAfterInput ] ;
[ [ KBInputBufferManager shared ]
updateFromExternalContextBefore : self . textDocumentProxy
. documentContextBeforeInput
after : self . textDocumentProxy
. documentContextAfterInput ] ;
}
- ( void ) setupUI {
self . view . translatesAutoresizingMaskIntoConstraints = NO ;
@@ -147,8 +170,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
CGFloat screenWidth = CGRectGetWidth ( [ UIScreen mainScreen ] . bounds ) ;
CGFloat outerVerticalInset = KBFit ( 4.0 f ) ;
NSLayoutConstraint * h = [ self . view . heightAnchor constraintEqualToConstant : keyboardHeight ] ;
NSLayoutConstraint * w = [ self . view . width Anchor constraintEqualToConstant : screenWidth ] ;
NSLayoutConstraint * h =
[ self . view . height Anchor constraintEqualToConstant : keyboardHeight ] ;
NSLayoutConstraint * w =
[ self . view . widthAnchor constraintEqualToConstant : screenWidth ] ;
self . kb_heightConstraint = h ;
self . kb_widthConstraint = w ;
@@ -189,14 +214,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
} ] ;
}
# pragma mark - Private
// MARK : - Suggestions
- ( void ) kb_updateCurrentWordWithInsertedText : ( NSString * ) text {
if ( text . length = = 0 ) { return ; }
if ( text . length = = 0 ) {
return ;
}
if ( [ self kb_isAlphabeticString : text ] ) {
NSString * current = self . currentWord ? : @ "" ;
self . currentWord = [ current stringByAppendingString : text ] ;
@@ -215,11 +240,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- ( void ) kb_scheduleContextRefreshResetSuppression : ( BOOL ) resetSuppression {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self kb_refreshCurrentWordFromDocumentContextResetSuppression : resetSuppression ] ;
[ self kb_refreshCurrentWordFromDocumentContextResetSuppression :
resetSuppression ] ;
} ) ;
}
- ( void ) kb_refreshCurrentWordFromDocumentContextResetSuppression : ( BOOL ) resetSuppression {
- ( void ) kb_refreshCurrentWordFromDocumentContextResetSuppression :
( BOOL ) resetSuppression {
NSString * context = self . textDocumentProxy . documentContextBeforeInput ? : @ "" ;
NSString * word = [ self kb_extractTrailingWordFromContext : context ] ;
self . currentWord = word ? : @ "" ;
@@ -230,11 +257,15 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( NSString * ) kb_extractTrailingWordFromContext : ( NSString * ) context {
if ( context . length = = 0 ) { return @ "" ; }
if ( context . length = = 0 ) {
return @ "" ;
}
static NSCharacterSet * letters = nil ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
letters = [ NSCharacterSet characterSetWithCharactersInString : @ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ] ;
letters = [ NSCharacterSet
characterSetWithCharactersInString :
@ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ] ;
} ) ;
NSInteger idx = ( NSInteger ) context . length - 1 ;
@@ -246,16 +277,22 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
idx - = 1 ;
}
NSUInteger start = ( NSUInteger ) ( idx + 1 ) ;
if ( start >= context . length ) { return @ "" ; }
if ( start >= context . length ) {
return @ "" ;
}
return [ context substringFromIndex : start ] ;
}
- ( BOOL ) kb_isAlphabeticString : ( NSString * ) text {
if ( text . length = = 0 ) { return NO ; }
if ( text . length = = 0 ) {
return NO ;
}
static NSCharacterSet * letters = nil ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
letters = [ NSCharacterSet characterSetWithCharactersInString : @ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ] ;
letters = [ NSCharacterSet
characterSetWithCharactersInString :
@ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ] ;
} ) ;
for ( NSUInteger i = 0 ; i < text . length ; i + + ) {
if ( ! [ letters characterIsMember : [ text characterAtIndex : i ] ] ) {
@@ -275,19 +312,28 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self . keyBoardMainView kb_setSuggestions : @ [ ] ] ;
return ;
}
NSArray < NSString * > * items = [ self . suggestionEngine suggestionsForPrefix : prefix limit : 5 ] ;
NSArray < NSString * > * cased = [ self kb_applyCaseToSuggestions : items prefix : prefix ] ;
NSArray < NSString * > * items =
[ self . suggestionEngine suggestionsForPrefix : prefix limit : 5 ] ;
NSArray < NSString * > * cased = [ self kb_applyCaseToSuggestions : items
prefix : prefix ] ;
[ self . keyBoardMainView kb_setSuggestions : cased ] ;
}
- ( NSArray < NSString * > * ) kb_applyCaseToSuggestions : ( NSArray < NSString * > * ) items prefix : ( NSString * ) prefix {
if ( items . count = = 0 || prefix . length = = 0 ) { return items ; }
- ( NSArray < NSString * > * ) kb_applyCaseToSuggestions : ( NSArray < NSString * > * ) items
prefix : ( NSString * ) prefix {
if ( items . count = = 0 || prefix . length = = 0 ) {
return items ;
}
BOOL allUpper = [ prefix isEqualToString : prefix . uppercaseString ] ;
BOOL firstUpper = [ [ prefix substringToIndex : 1 ] isEqualToString : [ [ prefix substringToIndex : 1 ] uppercaseString ] ] ;
BOOL firstUpper = [ [ prefix substringToIndex : 1 ]
isEqualToString : [ [ prefix substringToIndex : 1 ] uppercaseString ] ] ;
if ( ! allUpper && ! firstUpper ) { return items ; }
if ( ! allUpper && ! firstUpper ) {
return items ;
}
NSMutableArray < NSString * > * result = [ NSMutableArray arrayWithCapacity : items . count ] ;
NSMutableArray < NSString * > * result =
[ NSMutableArray arrayWithCapacity : items . count ] ;
for ( NSString * word in items ) {
if ( allUpper ) {
[ result addObject : word . uppercaseString ] ;
@@ -307,13 +353,15 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
self . keyBoardMainView . hidden = show ;
if ( show ) {
[ [ KBMaiPointReporter sharedReporter ] reportPageExposureWithEventName : @ "enter_keyboard_function_panel"
[ [ KBMaiPointReporter sharedReporter ]
reportPageExposureWithEventName : @ "enter_keyboard_function_panel"
pageId : @ "keyboard_function_panel"
extra : nil
completion : nil ] ;
[ self hideSubscriptionPanel ] ;
} else {
[ [ KBMaiPointReporter sharedReporter ] reportPageExposureWithEventName : @ "enter_keyboard_main_panel"
[ [ KBMaiPointReporter sharedReporter ]
reportPageExposureWithEventName : @ "enter_keyboard_main_panel"
pageId : @ "keyboard_main_panel"
extra : nil
completion : nil ] ;
@@ -330,7 +378,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
// / 显 示 / 隐 藏 设 置 页 ( 高 度 与 keyBoardMainView 一 致 ) , 右 侧 滑 入 / 滑 出
- ( void ) showSettingView : ( BOOL ) show {
if ( show ) {
[ [ KBMaiPointReporter sharedReporter ] reportPageExposureWithEventName : @ "enter_keyboard_settings"
[ [ KBMaiPointReporter sharedReporter ]
reportPageExposureWithEventName : @ "enter_keyboard_settings"
pageId : @ "keyboard_settings"
extra : nil
completion : nil ] ;
@@ -342,27 +391,46 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
// 与 键 盘 主 视 图 完 全 等 同 的 区 域 , 保 证 高 度 、 宽 度 一 致
make . edges . equalTo ( self . contentView ) ;
} ] ;
[ self . settingView . backButton addTarget : self action : @ selector ( onTapSettingsBack ) forControlEvents : UIControlEventTouchUpInside ] ;
[ self . settingView . backButton addTarget : self
action : @ selector ( onTapSettingsBack )
forControlEvents : UIControlEventTouchUpInside ] ;
// }
[ self . contentView bringSubviewToFront : self . settingView ] ;
// 以 keyBoardMainView 的 实 际 宽 度 为 准 , 避 免 首 次 添 加 时 self . view 宽 度 尚 未 计 算
[ self . contentView layoutIfNeeded ] ;
CGFloat w = CGRectGetWidth ( self . keyBoardMainView . bounds ) ;
if ( w <= 0 ) { w = CGRectGetWidth ( self . contentView . bounds ) ; }
if ( w < = 0 ) { w = [ self kb_portraitWidth ] ; }
if ( w <= 0 ) {
w = CGRectGetWidth ( self . contentView . bounds ) ;
}
if ( w <= 0 ) {
w = [ self kb_portraitWidth ] ;
}
self . settingView . transform = CGAffineTransformMakeTranslation ( w , 0 ) ;
self . settingView . hidden = NO ;
[ UIView animateWithDuration : 0.25 delay : 0 options : UIViewAnimationOptionCurveEaseOut animations : ^ {
[ UIView animateWithDuration : 0.25
delay : 0
options : UIViewAnimationOptionCurveEaseOut
animations : ^ {
self . settingView . transform = CGAffineTransformIdentity ;
} completion : nil ] ;
}
completion : nil ] ;
} else {
if ( ! self . settingView || self . settingView . hidden ) return ;
if ( ! self . settingView || self . settingView . hidden )
return ;
CGFloat w = CGRectGetWidth ( self . keyBoardMainView . bounds ) ;
if ( w <= 0 ) { w = CGRectGetWidth ( self . contentView . bounds ) ; }
if ( w < = 0 ) { w = [ self kb_portraitWidth ] ; }
[ UIView animateWithDuration : 0.22 delay : 0 options : UIViewAnimationOptionCurveEaseIn animations : ^ {
if ( w <= 0 ) {
w = CGRectGetWidth ( self . contentView . bounds ) ;
}
if ( w <= 0 ) {
w = [ self kb_portraitWidth ] ;
}
[ UIView animateWithDuration : 0.22
delay : 0
options : UIViewAnimationOptionCurveEaseIn
animations : ^ {
self . settingView . transform = CGAffineTransformMakeTranslation ( w , 0 ) ;
} completion : ^ ( BOOL finished ) {
}
completion : ^ ( BOOL finished ) {
self . settingView . hidden = YES ;
} ] ;
}
@@ -377,15 +445,18 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
return ;
}
// 点 击 充 值 要 先 判 断 是 否 登 录
// 2 ) 权 限 没 问 题 , 再 判 断 是 否 登 录 : 未 登 录 -> 直 接 拉 起 主 App , 由 主 App 负 责 完 成 登 录
// 2 ) 权 限 没 问 题 , 再 判 断 是 否 登 录 : 未 登 录 -> 直 接 拉 起 主 App , 由 主 App
// 负 责 完 成 登 录
if ( ! KBAuthManager . shared . isLoggedIn ) {
NSString * schemeStr = [ NSString stringWithFormat : @ "%@://login?src=keyboard" , KB_APP _SCHEME ] ;
NSString * schemeStr =
[ NSString stringWithFormat : @ "%@://login?src=keyboard" , KB_APP _SCHEME ] ;
NSURL * scheme = [ NSURL URLWithString : schemeStr ] ;
// 从 当 前 视 图 作 为 起 点 , 通 过 响 应 链 找 到 UIApplication 再 调 起 主 App
BOOL ok = [ KBHostAppLauncher openHostAppURL : scheme fromResponder : self . view ] ;
return ;
}
[ [ KBMaiPointReporter sharedReporter ] reportPageExposureWithEventName : @ "enter_keyboard_subscription_panel"
[ [ KBMaiPointReporter sharedReporter ]
reportPageExposureWithEventName : @ "enter_keyboard_subscription_panel"
pageId : @ "keyboard_subscription_panel"
extra : nil
completion : nil ] ;
@@ -402,34 +473,47 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
panel . hidden = NO ;
panel . alpha = 0.0 ;
CGFloat height = CGRectGetHeight ( self . contentView . bounds ) ;
if ( height <= 0 ) { height = 260 ; }
if ( height <= 0 ) {
height = 260 ;
}
panel . transform = CGAffineTransformMakeTranslation ( 0 , height ) ;
[ panel refreshProductsIfNeeded ] ;
[ UIView animateWithDuration : 0.25 delay : 0 options : UIViewAnimationOptionCurveEaseOut animations : ^ {
[ UIView animateWithDuration : 0.25
delay : 0
options : UIViewAnimationOptionCurveEaseOut
animations : ^ {
panel . alpha = 1.0 ;
panel . transform = CGAffineTransformIdentity ;
} completion : nil ] ;
}
completion : nil ] ;
}
- ( void ) hideSubscriptionPanel {
if ( ! self . subscriptionView || self . subscriptionView . hidden ) { return ; }
if ( ! self . subscriptionView || self . subscriptionView . hidden ) {
return ;
}
CGFloat height = CGRectGetHeight ( self . subscriptionView . bounds ) ;
if ( height <= 0 ) { height = CGRectGetHeight ( self . contentView . bounds ) ; }
if ( height <= 0 ) {
height = CGRectGetHeight ( self . contentView . bounds ) ;
}
KBKeyboardSubscriptionView * panel = self . subscriptionView ;
[ UIView animateWithDuration : 0.22 delay : 0 options : UIViewAnimationOptionCurveEaseIn animations : ^ {
[ UIView animateWithDuration : 0.22
delay : 0
options : UIViewAnimationOptionCurveEaseIn
animations : ^ {
panel . alpha = 0.0 ;
panel . transform = CGAffineTransformMakeTranslation ( 0 , height ) ;
} completion : ^ ( BOOL finished ) {
}
completion : ^ ( BOOL finished ) {
panel . hidden = YES ;
panel . alpha = 1.0 ;
panel . transform = CGAffineTransformIdentity ;
} ] ;
}
// MARK : - KBKeyBoardMainViewDelegate
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView didTapKey : ( KBKey * ) key {
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView
didTapKey : ( KBKey * ) key {
switch ( key . type ) {
case KBKeyTypeCharacter : {
[ [ KBBackspaceUndoManager shared ] registerNonClearAction ] ;
@@ -439,10 +523,17 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ [ KBInputBufferManager shared ] appendText : text ] ;
} break ;
case KBKeyTypeBackspace :
[ [ KBInputBufferManager shared ] refreshFromProxyIfPossible : self . textDocumentProxy ] ;
[ [ KBInputBufferManager shared ] prepareSnapshotForDeleteWithContextBefor e : self . textDocumentProxy . documentContextBeforeInput
after : self . textDocumentProxy . documentContextAfterInput ] ;
[ [ KBBackspaceUndoManager shared ] captureAndDeleteBackwardFromProxy : self . textDocumentProxy count : 1 ] ;
[ [ KBInputBufferManager shared ]
refreshFromProxyIfPossibl e : self . textDocumentProxy ] ;
[ [ KBInputBufferManager shared ]
prepareSnapshotForDeleteWithContextBefore :
self . textDocumentProxy . documentContextBeforeInput
after :
self . textDocumentProxy
. documentContextAfterInput ] ;
[ [ KBBackspaceUndoManager shared ]
captureAndDeleteBackwardFromProxy : self . textDocumentProxy
count : 1 ] ;
[ self kb_scheduleContextRefreshResetSuppression : NO ] ;
[ [ KBInputBufferManager shared ] applyHoldDeleteCount : 1 ] ;
break ;
@@ -459,7 +550,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ [ KBInputBufferManager shared ] appendText : @ "\n" ] ;
break ;
case KBKeyTypeGlobe :
[ self advanceToNextInputMode ] ; break ;
[ self advanceToNextInputMode ] ;
break ;
case KBKeyTypeCustom :
[ [ KBBackspaceUndoManager shared ] registerNonClearAction ] ;
// 点 击 自 定 义 键 切 换 到 功 能 面 板
@@ -473,9 +565,11 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
}
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView didTapToolActionAtIndex : ( NSInteger ) index {
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView
didTapToolActionAtIndex : ( NSInteger ) index {
NSDictionary * extra = @ { @ "index" : @ ( index ) } ;
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_toolbar_action"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_toolbar_action"
pageId : @ "keyboard_main_panel"
elementId : @ "toolbar_action"
extra : extra
@@ -489,7 +583,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( void ) keyBoardMainViewDidTapSettings : ( KBKeyBoardMainView * ) keyBoardMainView {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_settings_btn"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_settings_btn"
pageId : @ "keyboard_main_panel"
elementId : @ "settings_btn"
extra : nil
@@ -497,8 +592,11 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self showSettingView : YES ] ;
}
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView didSelectEmoji : ( NSString * ) emoji {
if ( emoji . length = = 0 ) { return ; }
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView
didSelectEmoji : ( NSString * ) emoji {
if ( emoji . length = = 0 ) {
return ;
}
[ [ KBBackspaceUndoManager shared ] registerNonClearAction ] ;
[ self . textDocumentProxy insertText : emoji ] ;
[ self kb_clearCurrentWord ] ;
@@ -506,7 +604,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( void ) keyBoardMainViewDidTapUndo : ( KBKeyBoardMainView * ) keyBoardMainView {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_undo_btn"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_undo_btn"
pageId : @ "keyboard_main_panel"
elementId : @ "undo_btn"
extra : nil
@@ -515,8 +614,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self kb_scheduleContextRefreshResetSuppression : YES ] ;
}
- ( void ) keyBoardMainViewDidTapEmojiSearch : ( KBKeyBoardMainView * ) keyBoardMainView {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_ keyb oard_emoji_search_btn"
- ( void ) keyBoardMainViewDidTapEmojiSearch :
( KBKeyBoardMainView * ) keyB oardMainView {
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_emoji_search_btn"
pageId : @ "keyboard_main_panel"
elementId : @ "emoji_search_btn"
extra : nil
@@ -524,10 +625,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ KBHUD showInfo : KBLocalized ( @ "Search coming soon" ) ] ;
}
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView didSelectSuggestion : ( NSString * ) suggestion {
if ( suggestion . length = = 0 ) { return ; }
- ( void ) keyBoardMainView : ( KBKeyBoardMainView * ) keyBoardMainView
didSelectSuggestion : ( NSString * ) suggestion {
if ( suggestion . length = = 0 ) {
return ;
}
NSDictionary * extra = @ { @ "suggestion_len" : @ ( suggestion . length ) } ;
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_suggestion_item"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_suggestion_item"
pageId : @ "keyboard_main_panel"
elementId : @ "suggestion_item"
extra : extra
@@ -544,30 +649,36 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self . suggestionEngine recordSelection : suggestion ] ;
self . suppressSuggestions = YES ;
[ self . keyBoardMainView kb_setSuggestions : @ [ ] ] ;
[ [ KBInputBufferManager shared ] replaceTailWithText : suggestion deleteCount : current . length ] ;
[ [ KBInputBufferManager shared ] replaceTailWithText : suggestion
deleteCount : current . length ] ;
}
// MARK : - KBFunctionViewDelegate
- ( void ) functionView : ( KBFunctionView * ) functionView didTapToolActionAtIndex : ( NSInteger ) index {
- ( void ) functionView : ( KBFunctionView * ) functionView
didTapToolActionAtIndex : ( NSInteger ) index {
// 需 求 : 当 index = = 0 时 , 切 回 键 盘 主 视 图
if ( index = = 0 ) {
[ self showFunctionPanel : NO ] ;
}
}
- ( void ) functionView : ( KBFunctionView * _Nullable ) functionView didRightTapToolActionAtIndex : ( NSInteger ) index {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_function_right_action"
- ( void ) functionView : ( KBFunctionView * _Nullable ) functionView
didRightTapToolActionAtIndex : ( NSInteger ) index {
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_function_right_action"
pageId : @ "keyboard_function_panel"
elementId : @ "right_action"
extra : @ { @ "action" : @ "login_or_recharge" }
completion : nil ] ;
if ( ! KBAuthManager . shared . isLoggedIn ) {
NSString * schemeStr = [ NSString stringWithFormat : @ "%@://login?src=keyboard" , KB_APP _SCHEME ] ;
NSString * schemeStr =
[ NSString stringWithFormat : @ "%@://login?src=keyboard" , KB_APP _SCHEME ] ;
NSURL * scheme = [ NSURL URLWithString : schemeStr ] ;
// 从 当 前 视 图 作 为 起 点 , 通 过 响 应 链 找 到 UIApplication 再 调 起 主 App
BOOL ok = [ KBHostAppLauncher openHostAppURL : scheme fromResponder : self . view ] ;
return ;
}
NSString * schemeStr = [ NSString stringWithFormat : @ "%@://recharge?src=keyboard" , KB_APP _SCHEME ] ;
NSString * schemeStr =
[ NSString stringWithFormat : @ "%@://recharge?src=keyboard" , KB_APP _SCHEME ] ;
NSURL * scheme = [ NSURL URLWithString : schemeStr ] ;
//
// if ( ! ul && ! scheme ) { return ; }
@@ -589,7 +700,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
# pragma mark - KBKeyboardSubscriptionViewDelegate
- ( void ) subscriptionViewDidTapClose : ( KBKeyboardSubscriptionView * ) view {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_subscription_close_btn"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_subscription_close_btn"
pageId : @ "keyboard_subscription_panel"
elementId : @ "close_btn"
extra : nil
@@ -597,12 +709,15 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self hideSubscriptionPanel ] ;
}
- ( void ) subscriptionView : ( KBKeyboardSubscriptionView * ) view didTapPurchaseForProduct : ( KBKeyboardSubscriptionProduct * ) product {
- ( void ) subscriptionView : ( KBKeyboardSubscriptionView * ) view
didTapPurchaseForProduct : ( KBKeyboardSubscriptionProduct * ) product {
NSMutableDictionary * extra = [ NSMutableDictionary dictionary ] ;
if ( [ product . productId isKindOfClass : NSString . class ] && product . productId . length > 0 ) {
if ( [ product . productId isKindOfClass : NSString . class ] &&
product . productId . length > 0 ) {
extra [ @ "product_id" ] = product . productId ;
}
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_subscription_product_btn"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_subscription_product_btn"
pageId : @ "keyboard_subscription_panel"
elementId : @ "product_btn"
extra : extra . copy
@@ -645,43 +760,52 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
return _subscriptionView ;
}
# pragma mark - Actions
- ( void ) kb_openRechargeForProduct : ( KBKeyboardSubscriptionProduct * ) product {
if ( ! [ product isKindOfClass : KBKeyboardSubscriptionProduct . class ] || product . productId . length = = 0 ) {
if ( ! [ product isKindOfClass : KBKeyboardSubscriptionProduct . class ] ||
product . productId . length = = 0 ) {
[ KBHUD showInfo : KBLocalized ( @ "Product unavailable" ) ] ;
return ;
}
NSString * encodedId = [ self . class kb_urlEncodedString : product . productId ] ;
NSString * title = [ product displayTitle ] ;
NSString * encodedTitle = [ self . class kb_urlEncodedString : title ] ;
NSMutableArray < NSString * > * params = [ NSMutableArray arrayWithObjects : @ "autoPay=1" , @ "prefill=1" , nil ] ;
NSMutableArray < NSString * > * params =
[ NSMutableArray arrayWithObjects : @ "autoPay=1" , @ "prefill=1" , nil ] ;
if ( encodedId . length ) {
[ params addObject : [ NSString stringWithFormat : @ "productId=%@" , encodedId ] ] ;
}
if ( encodedTitle . length ) {
[ params addObject : [ NSString stringWithFormat : @ "productTitle=%@" , encodedTitle ] ] ;
[ params
addObject : [ NSString stringWithFormat : @ "productTitle=%@" , encodedTitle ] ] ;
}
NSString * query = [ params componentsJoinedByString : @ "&" ] ;
NSString * urlString = [ NSString stringWithFormat : @ "%@://recharge?src=keyboard&%@" , KB_APP _SCHEME , query ] ;
NSString * urlString = [ NSString
stringWithFormat : @ "%@://recharge?src=keyboard&%@" , KB_APP _SCHEME , query ] ;
NSURL * scheme = [ NSURL URLWithString : urlString ] ;
BOOL success = [ KBHostAppLauncher openHostAppURL : scheme fromResponder : self . view ] ;
BOOL success = [ KBHostAppLauncher openHostAppURL : scheme
fromResponder : self . view ] ;
if ( ! success ) {
[ KBHUD showInfo : KBLocalized ( @ "Please open the App to finish purchase" ) ] ;
}
}
+ ( NSString * ) kb_urlEncodedString : ( NSString * ) value {
if ( value . length = = 0 ) { return @ "" ; }
if ( value . length = = 0 ) {
return @ "" ;
}
NSString * reserved = @ "!*'();:@&=+$,/?%#[]" ;
NSMutableCharacterSet * allowed = [ [ NSCharacterSet URLQueryAllowedCharacterSet ] mutableCopy ] ;
NSMutableCharacterSet * allowed =
[ [ NSCharacterSet URLQueryAllowedCharacterSet ] mutableCopy ] ;
[ allowed removeCharactersInString : reserved ] ;
return [ value stringByAddingPercentEncodingWithAllowedCharacters : allowed ] ? : @ "" ;
return [ value stringByAddingPercentEncodingWithAllowedCharacters : allowed ]
? : @ "" ;
}
- ( void ) onTapSettingsBack {
[ [ KBMaiPointReporter sharedReporter ] reportClickWithEventName : @ "click_keyboard_settings_back_btn"
[ [ KBMaiPointReporter sharedReporter ]
reportClickWithEventName : @ "click_keyboard_settings_back_btn"
pageId : @ "keyboard_settings"
elementId : @ "back_btn"
extra : nil
@@ -690,14 +814,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( void ) dealloc {
CFNotificationCenterRemoveObserver ( CFNotificationCenterGetDarwinNotifyCenter ( ) ,
CFNotificationCenterRemoveObserver (
CFNotificationCenterGetDarwinNotifyCenter ( ) ,
( __bridge const void * ) ( self ) ,
( __bridge CFStringRef ) KBDarwinSkinInstallRequestNotification ,
NULL ) ;
( __bridge CFStringRef ) KBDarwinSkinInstallRequestNotification , NULL ) ;
}
// 当 键 盘 第 一 次 显 示 时 , 尝 试 唤 起 主 App 以 提 示 登 录 ( 由 主 App 决定 是 否 真 的 弹 登 录 ) 。
// 当 键 盘 第 一 次 显 示 时 , 尝 试 唤 起 主 App 以 提 示 登 录 ( 由 主 App
// 决 定 是 否 真 的 弹 登 录 ) 。
- ( void ) viewDidAppear : ( BOOL ) animated {
[ super viewDidAppear : animated ] ;
// if ( ! _kb _didTriggerLoginDeepLinkOnce ) {
@@ -714,22 +838,29 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[ self kb_updateKeyboardLayoutIfNeeded ] ;
}
- ( void ) viewWillTransitionToSize : ( CGSize ) size withTransitionCoordinator : ( id < UIViewControllerTransitionCoordinator > ) coordinator {
- ( void ) viewWillTransitionToSize : ( CGSize ) size
withTransitionCoordinator :
( id < UIViewControllerTransitionCoordinator > ) coordinator {
[ super viewWillTransitionToSize : size withTransitionCoordinator : coordinator ] ;
__weak typeof ( self ) weakSelf = self ;
[ coordinator animateAlongsideTransition : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
[ coordinator
animateAlongsideTransition : ^ (
id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
[ weakSelf kb_updateKeyboardLayoutIfNeeded ] ;
} completion : ^ ( __unused id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
}
completion : ^ (
__unused id <
UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
[ weakSelf kb_updateKeyboardLayoutIfNeeded ] ;
} ] ;
}
// - ( void ) kb_tryOpenContainerForLoginIfNeeded {
// // 使 用 与 主 App 一 致 的 自 定 义 Scheme
// NSURL * url = [ NSURL URLWithString : [ NSString stringWithFormat : @ "%@@//login?src=keyboard" , KB_APP _SCHEME ] ] ;
// if ( ! url ) return ;
// KBWeakSelf
// [ self . extensionContext openURL : url completionHandler : ^ ( __unused BOOL success ) {
// NSURL * url = [ NSURL URLWithString : [ NSString
// stringWithFormat : @ "%@@//login?src=keyboard" , KB_APP _SCHEME ] ] ; if ( ! url )
// return ; KBWeakSelf [ self . extensionContext openURL : url
// completionHandler : ^ ( __unused BOOL success ) {
// // 即 使 失 败 也 不 重 复 尝 试 ; 避 免 打 扰 。
// __unused typeof ( weakSelf ) selfStrong = weakSelf ;
// } ] ;
@@ -740,8 +871,48 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- ( void ) kb_applyTheme {
KBSkinTheme * t = [ KBSkinManager shared ] . current ;
UIImage * img = [ [ KBSkinManager shared ] currentBackgroundImage ] ;
if ( [ self kb_isDefaultKeyboardTheme : t ] ) {
BOOL isDefaultTheme = [ self kb_isDefaultKeyboardTheme : t ] ;
BOOL isDarkMode = [ self kb_isDarkModeActive ] ;
CGSize size = self . bgImageView . bounds . size ;
if ( isDefaultTheme ) {
if ( isDarkMode ) {
// 暗 黑 模 式 : 直 接 使 用 背 景 色 , 不 使 用 图 片 渲 染
// 这 样 可 以 避 免 图 片 渲 染 时 的 色 彩 空 间 转 换 导 致 颜 色 不 一 致
img = nil ;
self . bgImageView . image = nil ;
// 使 用 与 系 统 键 盘 底 部 完 全 相 同 的 颜 色
if ( @ available ( iOS 13.0 , * ) ) {
// iOS 系 统 键 盘 使 用 的 实 际 颜 色 ( RGB : 44 , 44 , 46 in sRGB , 或 #2 C2C2E )
// 但 为 了 完 美 匹 配 , 我 们 使 用 动 态 颜 色 并 直 接 设 置 为 背 景
UIColor * kbBgColor =
[ UIColor colorWithDynamicProvider : ^ UIColor * _Nonnull (
UITraitCollection * _Nonnull traitCollection ) {
if ( traitCollection . userInterfaceStyle = =
UIUserInterfaceStyleDark ) {
// 暗 黑 模 式 下 系 统 键 盘 实 际 背 景 色
return [ UIColor colorWithRed : 43.0 / 255.0
green : 43.0 / 255.0
blue : 43.0 / 255.0
alpha : 1.0 ] ;
} else {
return [ UIColor colorWithRed : 209.0 / 255.0
green : 211.0 / 255.0
blue : 219.0 / 255.0
alpha : 1.0 ] ;
}
} ] ;
self . contentView . backgroundColor = kbBgColor ;
self . bgImageView . backgroundColor = kbBgColor ;
} else {
UIColor * darkColor = [ UIColor colorWithRed : 43.0 / 255.0
green : 43.0 / 255.0
blue : 43.0 / 255.0
alpha : 1.0 ] ;
self . contentView . backgroundColor = darkColor ;
self . bgImageView . backgroundColor = darkColor ;
}
} else {
// 浅 色 模 式 : 使 用 渐 变 图 片
if ( size . width <= 0 || size . height <= 0 ) {
[ self . view layoutIfNeeded ] ;
size = self . bgImageView . bounds . size ;
@@ -752,15 +923,24 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if ( size . width <= 0 || size . height <= 0 ) {
size = [ UIScreen mainScreen ] . bounds . size ;
}
img = [ self kb_defaultGradientImageWithSize : size ] ;
UIColor * topColor = [ UIColor colorWithHex : 0 xDEDFE4 ] ;
UIColor * bottomColor = [ UIColor colorWithHex : 0 xD1D3DB ] ;
img = [ self kb_defaultGradientImageWithSize : size
topColor : topColor
bottomColor : bottomColor ] ;
self . contentView . backgroundColor = [ UIColor clearColor ] ;
self . bgImageView . backgroundColor = [ UIColor clearColor ] ;
}
NSLog ( @ "===" ) ;
} else {
// 自 定 义 皮 肤 : 清 除 背 景 色 , 使 用 皮 肤 图 片
self . contentView . backgroundColor = [ UIColor clearColor ] ;
self . bgImageView . backgroundColor = [ UIColor clearColor ] ;
}
NSLog ( @ "⌨️[Keyboard] apply theme id=%@ hasBg=%d" , t . skinId , ( img ! = nil ) ) ;
[ self kb_logSkinDiagnosticsWithTheme : t backgroundImage : img ] ;
self . bgImageView . image = img ;
BOOL hasImg = ( img ! = nil ) ;
self . view . backgroundColor = hasImg ? [ UIColor clearColor ] : t . keyboardBackground ;
self . contentView . backgroundColor = hasImg ? [ UIColor clearColor ] : t . keyboardBackground ;
self . keyBoardMainView . backgroundColor = hasImg ? [ UIColor clearColor ] : t . keyboardBackground ;
// 触 发 键 区 按 主 题 重 绘
if ( [ self . keyBoardMainView respondsToSelector : @ selector ( kb_applyTheme ) ] ) {
// method declared in KBKeyBoardMainView . h
@@ -796,23 +976,39 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( NSString * ) kb_defaultSkinIdForCurrentStyle {
return [ self kb_isDarkModeActive ] ? kKBDefaultSkinIdDark : kKBDefaultSkinIdLight ;
return [ self kb_isDarkModeActive ] ? kKBDefaultSkinIdDark
: kKBDefaultSkinIdLight ;
}
- ( NSString * ) kb_defaultSkinZipNameForCurrentStyle {
return [ self kb_isDarkModeActive ] ? kKBDefaultSkinZipNameDark : kKBDefaultSkinZipNameLight ;
return [ self kb_isDarkModeActive ] ? kKBDefaultSkinZipNameDark
: kKBDefaultSkinZipNameLight ;
}
- ( UIImage * ) kb_defaultGradientImageWithSize : ( CGSize ) size
topColor : ( UIColor * ) topColor
bottomColor : ( UIColor * ) bottomColor {
if ( size . width <= 0 || size . height <= 0 ) {
return nil ;
}
// 将 动 态 颜 色 解 析 为 当 前 trait collection 下 的 具 体 颜 色 值
// 否 则 在 UIGraphicsBeginImageContextWithOptions 中 渲 染 时 会 使 用 默 认 的 浅 色 模 式
UIColor * resolvedTopColor = topColor ;
UIColor * resolvedBottomColor = bottomColor ;
if ( @ available ( iOS 13.0 , * ) ) {
resolvedTopColor =
[ topColor resolvedColorWithTraitCollection : self . traitCollection ] ;
resolvedBottomColor =
[ bottomColor resolvedColorWithTraitCollection : self . traitCollection ] ;
}
- ( UIImage * ) kb_defaultGradientImageWithSize : ( CGSize ) size {
if ( size . width <= 0 || size . height <= 0 ) { return nil ; }
CAGradientLayer * layer = [ CAGradientLayer layer ] ;
layer . frame = CGRectMake ( 0 , 0 , size . width , size . height ) ;
layer . startPoint = CGPointMake ( 0.5 , 0.0 ) ;
layer . endPoint = CGPointMake ( 0.5 , 1.0 ) ;
layer . colors = @ [
( id ) [ UIColor colorWithHex : 0 xDEDFE4 ] . CGColor ,
( id ) [ UIColor colorWithHex : 0 xD1D3DB ] . CGColor
] ;
layer . colors =
@ [ ( id ) resolvedTopColor . CGColor , ( id ) resolvedBottomColor . CGColor ] ;
UIGraphicsBeginImageContextWithOptions ( size , YES , 0 ) ;
[ layer renderInContext : UIGraphicsGetCurrentContext ( ) ] ;
@@ -827,11 +1023,14 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
NSString * skinId = theme . skinId ? : @ "" ;
NSString * name = theme . name ? : @ "" ;
NSMutableArray < NSString * > * roots = [ NSMutableArray array ] ;
NSURL * containerURL = [ [ NSFileManager defaultManager ] containerURLForSecurityApplicationGroupIdentifier : AppGroup ] ;
NSURL * containerURL = [ [ NSFileManager defaultManager ]
containerURLForSecurityApplicationGroupIdentifier : AppGroup ] ;
if ( containerURL . path . length > 0 ) {
[ roots addObject : containerURL . path ] ;
}
NSString * cacheRoot = NSSearchPathForDirectoriesInDomains ( NSCachesDirectory , NSUserDomainMask , YES ) . firstObject ;
NSString * cacheRoot = NSSearchPathForDirectoriesInDomains (
NSCachesDirectory , NSUserDomainMask , YES )
. firstObject ;
if ( cacheRoot . length > 0 ) {
[ roots addObject : cacheRoot ] ;
}
@@ -844,36 +1043,58 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
iconsDir = [ iconsDir stringByAppendingPathComponent : @ "icons" ] ;
BOOL isDir = NO ;
BOOL exists = [ fm fileExistsAtPath : iconsDir isDirectory : & isDir ] && isDir ;
NSArray * contents = exists ? [ fm contentsOfDirectoryAtPath : iconsDir error : nil ] : nil ;
NSArray * contents =
exists ? [ fm contentsOfDirectoryAtPath : iconsDir error : nil ] : nil ;
NSUInteger count = contents . count ;
BOOL hasQ = exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent : @ "key_q.png" ] ] ;
BOOL hasQUp = exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent : @ "key_q_up.png" ] ] ;
BOOL hasDel = exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent : @ "key_del.png" ] ] ;
BOOL hasShift = exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent : @ "key_up .png" ] ] ;
BOOL hasShiftUpper = exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent : @ "key_up_upper.png" ] ] ;
NSString * line = [ NSString stringWithForm at: @ "root=%@ icons=%@ exist=%d count=%tu key_q=%d key_q_up=%d key_del=%d key_up=%d key_up_upper=%d" ,
root , iconsDir , exists , count , hasQ , hasQUp , hasDel , hasShift , hasShiftUpper ] ;
BOOL hasQ =
exists &&
[ fm fileExistsAtPath : [ iconsDir
stringByAppendingPathComponent : @ "key_q .png" ] ] ;
BOOL hasQUp =
exists && [ fm fileExistsAtP ath : [ iconsDir stringByAppendingPathComponent :
@ "key_q_up.png" ] ] ;
BOOL hasDel =
exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent :
@ "key_del.png" ] ] ;
BOOL hasShift =
exists &&
[ fm fileExistsAtPath : [ iconsDir
stringByAppendingPathComponent : @ "key_up.png" ] ] ;
BOOL hasShiftUpper =
exists && [ fm fileExistsAtPath : [ iconsDir stringByAppendingPathComponent :
@ "key_up_upper.png" ] ] ;
NSString * line = [ NSString
stringWithFormat : @ "root=%@ icons=%@ exist=%d count=%tu key_q=%d "
@ "key_q_up=%d key_del=%d key_up=%d key_up_upper=%d" ,
root , iconsDir , exists , count , hasQ , hasQUp , hasDel ,
hasShift , hasShiftUpper ] ;
[ lines addObject : line ] ;
}
NSLog ( @ "[Keyboard] theme id=%@ name=%@ hasBg=%d\n%@" ,
skinId , name , ( image ! = nil ) , [ lines componentsJoinedByString : @ "\n" ] ) ;
NSLog ( @ "[Keyboard] theme id=%@ name=%@ hasBg=%d\n%@" , skinId , name ,
( image ! = nil ) , [ lines componentsJoinedByString : @ "\n" ] ) ;
# endif
}
- ( void ) kb_consumePendingShopSkin {
KBWeakSelf
[ KBSkinInstallBridge consumePendingRequestFromBundle : NSBundle . mainBundle
completion : ^ ( BOOL success , NSError * _Nullable error ) {
KBWeakSelf [ KBSkinInstallBridge
consumePendingRequestFromBundle : NSBundle . mainBundle
completion : ^ ( BOOL success ,
NSError * _Nullable error ) {
if ( ! success ) {
if ( error ) {
NSLog ( @ "[Keyboard] skin request failed: %@" , error ) ;
[ KBHUD showInfo : KBLocalized ( @ "皮肤资源准备失败,请稍后再试" ) ] ;
NSLog ( @ "[Keyboard] skin request failed: %@" ,
error ) ;
[ KBHUD
showInfo :
KBLocalized (
@ "皮肤资源准备失败,请稍后再试" ) ] ;
}
return ;
}
[ weakSelf kb_applyTheme ] ;
[ KBHUD showInfo : KBLocalized ( @ "皮肤已更新,立即体验吧" ) ] ;
[ KBHUD showInfo : KBLocalized (
@ "皮肤已更新,立即体验吧" ) ] ;
} ] ;
}
@@ -886,7 +1107,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
NSString * currentId = [ KBSkinManager shared ] . current . skinId ? : @ "" ;
BOOL isDefault = ( currentId . length = = 0 || [ currentId isEqualToString : @ "default" ] ) ;
BOOL isDefault =
( currentId . length = = 0 || [ currentId isEqualToString : @ "default" ] ) ;
BOOL isLightDefault = [ currentId isEqualToString : kKBDefaultSkinIdLight ] ;
BOOL isDarkDefault = [ currentId isEqualToString : kKBDefaultSkinIdDark ] ;
if ( ! isDefault && ! isLightDefault && ! isDarkDefault ) {
@@ -895,10 +1117,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
NSString * targetId = [ self kb_defaultSkinIdForCurrentStyle ] ;
NSString * targetZip = [ self kb_defaultSkinZipNameForCurrentStyle ] ;
if ( currentId . length > 0 && [ currentId isEqualToString : targetId ] ) { return ; }
if ( currentId . length > 0 && [ currentId isEqualToString : targetId ] ) {
return ;
}
NSError * applyError = nil ;
if ( [ KBSkinInstallBridge applyInstalledSkinWithId : targetId error : & applyError ] ) {
if ( [ KBSkinInstallBridge applyInstalledSkinWithId : targetId
error : & applyError ] ) {
return ;
}
@@ -906,8 +1131,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
name : targetId
zipName : targetZip
iconShortNames : nil ] ;
[ KBSkinInstallBridge consumePendingRequestFromBundle : NSBundle . mainBundle
completion : ^ ( __unused BOOL success , __unused NSError * _Nullable error ) {
[ KBSkinInstallBridge
consumePendingRequestFromBundle : NSBundle . mainBundle
completion : ^ ( __unused BOOL success ,
__unused NSError * _Nullable error ) {
// 已 通 过 通 知 触 发 主 题 刷 新 , 这 里 无 需 额 外 处 理
} ] ;
}
@@ -920,7 +1147,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- ( CGFloat ) kb_keyboardHeightForWidth : ( CGFloat ) width {
if ( width <= 0 ) { width = KB_DESIGN _WIDTH ; }
if ( width <= 0 ) {
width = KB_DESIGN _WIDTH ;
}
return kKBKeyboardBaseHeight * ( width / KB_DESIGN _WIDTH ) ;
}
@@ -936,8 +1165,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
BOOL widthChanged = ( fabs ( self . kb_lastPortraitWidth - portraitWidth ) >= 0.5 ) ;
BOOL heightChanged = ( fabs ( self . kb_lastKeyboardHeight - keyboardHeight ) >= 0.5 ) ;
if ( ! widthChanged && ! heightChanged && containerWidth > 0 && self . kb_widthConstraint . constant = = containerWidth ) {
BOOL heightChanged =
( fabs ( self . kb_lastKeyboardHeight - keyboardHeight ) > = 0.5 ) ;
if ( ! widthChanged && ! heightChanged && containerWidth > 0 &&
self . kb_widthConstraint . constant = = containerWidth ) {
return ;
}
self . kb_lastPortraitWidth = portraitWidth ;