675 lines
24 KiB
Objective-C
675 lines
24 KiB
Objective-C
//
|
||
// KeyboardViewController+Panels.m
|
||
// CustomKeyboard
|
||
//
|
||
// Created by Codex on 2026/02/22.
|
||
//
|
||
|
||
#import "KeyboardViewController+Private.h"
|
||
|
||
#import "KBAuthManager.h"
|
||
#import "KBBackspaceUndoManager.h"
|
||
#import "KBChatMessage.h"
|
||
#import "KBChatPanelView.h"
|
||
#import "KBFunctionView.h"
|
||
#import "KBFullAccessManager.h"
|
||
#import "../Utils/KBExtensionAppLauncher.h"
|
||
#import "KBInputBufferManager.h"
|
||
#import "KBKey.h"
|
||
#import "KBKeyBoardMainView.h"
|
||
#import "KBKeyboardSubscriptionView.h"
|
||
#import "KBSettingView.h"
|
||
#import "Masonry.h"
|
||
#import <SDWebImage/SDWebImage.h>
|
||
#import <AVFoundation/AVAudioPlayer.h>
|
||
|
||
@implementation KeyboardViewController (Panels)
|
||
|
||
#pragma mark - Panel Mode
|
||
|
||
- (void)kb_setPanelMode:(KBKeyboardPanelMode)mode animated:(BOOL)animated {
|
||
if (mode == self.kb_panelMode) {
|
||
return;
|
||
}
|
||
|
||
KBKeyboardPanelMode fromMode = self.kb_panelMode;
|
||
|
||
// AI 入口先判完全访问:未开启时仅展示引导,不再继续登录态判断。
|
||
if (mode == KBKeyboardPanelModeFunction &&
|
||
![[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self.view]) {
|
||
return;
|
||
}
|
||
|
||
// 未登录时,不要提前写入面板状态,避免 mode 被错误卡在 Function 导致后续点击无响应。
|
||
BOOL islogin = YES;
|
||
if (mode == KBKeyboardPanelModeFunction) {
|
||
[[KBAuthManager shared] reloadFromKeychain];
|
||
islogin = KBAuthManager.shared.isLoggedIn;
|
||
}
|
||
#if DEBUG
|
||
if (mode == KBKeyboardPanelModeFunction) {
|
||
NSString *token = [KBAuthManager shared].current.accessToken ?: @"";
|
||
NSLog(@"[AuthTrace][Ext] tapAI mode=%ld isLoggedIn=%d tokenLen=%lu",
|
||
(long)mode, islogin, (unsigned long)token.length);
|
||
}
|
||
#endif
|
||
if (mode == KBKeyboardPanelModeFunction && !islogin) {
|
||
[KBHUD showInfo:KBLocalized(@"请先登录后使用AI功能")];
|
||
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||
NSURL *scheme =
|
||
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||
__weak typeof(self) weakSelf = self;
|
||
[KBExtensionAppLauncher openPrimaryURL:ul
|
||
fallbackURL:scheme
|
||
usingInputController:self
|
||
source:(self.view ?: (UIResponder *)weakSelf)
|
||
completion:^(BOOL success) {
|
||
if (success) {
|
||
return;
|
||
}
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[KBHUD showInfo:KBLocalized(@"请回到桌面手动打开App登录")];
|
||
});
|
||
}];
|
||
return;
|
||
}
|
||
|
||
self.kb_panelMode = mode;
|
||
|
||
// 主键盘视图是基础承载:确保存在(键盘隐藏后会被释放)
|
||
[self kb_ensureKeyBoardMainViewIfNeeded];
|
||
|
||
// 1) 先收起所有面板(再展开目标面板),避免互相调用导致漏关/层级错乱
|
||
[self kb_setSubscriptionPanelVisible:NO animated:animated];
|
||
[self kb_setSettingViewVisible:NO animated:animated];
|
||
[self kb_setChatPanelVisible:NO animated:animated];
|
||
[self kb_setFunctionPanelVisible:NO];
|
||
|
||
// 2) 再展开目标面板
|
||
switch (mode) {
|
||
case KBKeyboardPanelModeFunction:
|
||
[self kb_setFunctionPanelVisible:YES];
|
||
break;
|
||
case KBKeyboardPanelModeChat:
|
||
[self kb_setChatPanelVisible:YES animated:animated];
|
||
break;
|
||
case KBKeyboardPanelModeSettings:
|
||
[self kb_setSettingViewVisible:YES animated:animated];
|
||
break;
|
||
case KBKeyboardPanelModeSubscription:
|
||
[self kb_setSubscriptionPanelVisible:YES animated:animated];
|
||
break;
|
||
case KBKeyboardPanelModeMain:
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// 3) 事件埋点:保持原逻辑(仅功能面板/主面板会互相曝光)
|
||
if (mode == KBKeyboardPanelModeFunction) {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportPageExposureWithEventName:@"enter_keyboard_function_panel"
|
||
pageId:@"keyboard_function_panel"
|
||
extra:nil
|
||
completion:nil];
|
||
} else if (mode == KBKeyboardPanelModeMain &&
|
||
fromMode == KBKeyboardPanelModeFunction) {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportPageExposureWithEventName:@"enter_keyboard_main_panel"
|
||
pageId:@"keyboard_main_panel"
|
||
extra:nil
|
||
completion:nil];
|
||
} else if (mode == KBKeyboardPanelModeSettings) {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportPageExposureWithEventName:@"enter_keyboard_settings"
|
||
pageId:@"keyboard_settings"
|
||
extra:nil
|
||
completion:nil];
|
||
} else if (mode == KBKeyboardPanelModeSubscription) {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportPageExposureWithEventName:@"enter_keyboard_subscription_panel"
|
||
pageId:@"keyboard_subscription_panel"
|
||
extra:nil
|
||
completion:nil];
|
||
}
|
||
|
||
// 4) 层级:保证当前面板在最上层
|
||
if (mode == KBKeyboardPanelModeSubscription) {
|
||
[self.contentView bringSubviewToFront:self.subscriptionView];
|
||
} else if (mode == KBKeyboardPanelModeSettings) {
|
||
[self.contentView bringSubviewToFront:self.settingView];
|
||
} else if (mode == KBKeyboardPanelModeChat) {
|
||
[self.contentView bringSubviewToFront:self.chatPanelView];
|
||
} else if (mode == KBKeyboardPanelModeFunction) {
|
||
[self.contentView bringSubviewToFront:self.functionView];
|
||
} else {
|
||
[self.contentView bringSubviewToFront:self.keyBoardMainView];
|
||
}
|
||
}
|
||
|
||
/// 对外兼容:切换显示功能面板/键盘主视图
|
||
- (void)showFunctionPanel:(BOOL)show {
|
||
if (show) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeFunction animated:NO];
|
||
return;
|
||
}
|
||
if (self.kb_panelMode == KBKeyboardPanelModeFunction) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:NO];
|
||
}
|
||
}
|
||
|
||
/// 对外兼容:显示/隐藏设置页(高度与 keyBoardMainView 一致),右侧滑入/滑出
|
||
- (void)showSettingView:(BOOL)show {
|
||
if (show) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeSettings animated:YES];
|
||
return;
|
||
}
|
||
if (self.kb_panelMode == KBKeyboardPanelModeSettings) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:YES];
|
||
}
|
||
}
|
||
|
||
/// 对外兼容:显示/隐藏聊天面板(覆盖整个键盘区域)
|
||
- (void)showChatPanel:(BOOL)show {
|
||
if (show) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeChat animated:YES];
|
||
return;
|
||
}
|
||
if (self.kb_panelMode == KBKeyboardPanelModeChat) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:YES];
|
||
}
|
||
}
|
||
|
||
- (void)kb_setFunctionPanelVisible:(BOOL)visible {
|
||
if (visible) {
|
||
[self kb_ensureFunctionViewIfNeeded];
|
||
}
|
||
if (_functionView) {
|
||
_functionView.hidden = !visible;
|
||
} else if (visible) {
|
||
// ensure 后按理已存在;这里兜底一次,避免异常情况下状态不一致
|
||
self.functionView.hidden = NO;
|
||
}
|
||
self.keyBoardMainView.hidden = visible;
|
||
}
|
||
|
||
- (void)kb_setChatPanelVisible:(BOOL)visible animated:(BOOL)animated {
|
||
if (visible == self.chatPanelVisible) {
|
||
return;
|
||
}
|
||
self.chatPanelVisible = visible;
|
||
|
||
if (visible) {
|
||
// 记录打开聊天面板时宿主输入框已有的文本,发送时只取新增部分
|
||
[[KBInputBufferManager shared]
|
||
refreshFromProxyIfPossible:self.textDocumentProxy];
|
||
self.chatPanelBaselineText = [KBInputBufferManager shared].liveText ?: @"";
|
||
[self kb_ensureChatPanelViewIfNeeded];
|
||
self.chatPanelView.hidden = NO;
|
||
self.chatPanelView.alpha = 0.0;
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.2
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseOut
|
||
animations:^{
|
||
self.chatPanelView.alpha = 1.0;
|
||
}
|
||
completion:nil];
|
||
} else {
|
||
self.chatPanelView.alpha = 1.0;
|
||
}
|
||
} else {
|
||
// 从未创建过聊天面板时,直接返回,避免 show/hide 触发额外内存分配
|
||
if (!_chatPanelView) {
|
||
[self kb_updateKeyboardLayoutIfNeeded];
|
||
return;
|
||
}
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.18
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseIn
|
||
animations:^{
|
||
self.chatPanelView.alpha = 0.0;
|
||
}
|
||
completion:^(BOOL finished) {
|
||
self.chatPanelView.hidden = YES;
|
||
}];
|
||
} else {
|
||
self.chatPanelView.alpha = 0.0;
|
||
self.chatPanelView.hidden = YES;
|
||
}
|
||
}
|
||
[self kb_updateKeyboardLayoutIfNeeded];
|
||
}
|
||
|
||
- (void)kb_setSettingViewVisible:(BOOL)visible animated:(BOOL)animated {
|
||
if (visible) {
|
||
KBSettingView *settingView = self.settingView;
|
||
if (!settingView.superview) {
|
||
settingView.hidden = YES;
|
||
[self.contentView addSubview:settingView];
|
||
[settingView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.equalTo(self.contentView);
|
||
}];
|
||
[settingView.backButton addTarget:self
|
||
action:@selector(onTapSettingsBack)
|
||
forControlEvents:UIControlEventTouchUpInside];
|
||
}
|
||
[self.contentView bringSubviewToFront: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];
|
||
}
|
||
settingView.transform = CGAffineTransformMakeTranslation(w, 0);
|
||
settingView.hidden = NO;
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.25
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseOut
|
||
animations:^{
|
||
settingView.transform = CGAffineTransformIdentity;
|
||
}
|
||
completion:nil];
|
||
} else {
|
||
settingView.transform = CGAffineTransformIdentity;
|
||
}
|
||
} else {
|
||
KBSettingView *settingView = _settingView;
|
||
if (!settingView) {
|
||
return;
|
||
}
|
||
if (!settingView.superview || settingView.hidden) {
|
||
return;
|
||
}
|
||
CGFloat w = CGRectGetWidth(self.keyBoardMainView.bounds);
|
||
if (w <= 0) {
|
||
w = CGRectGetWidth(self.contentView.bounds);
|
||
}
|
||
if (w <= 0) {
|
||
w = [self kb_portraitWidth];
|
||
}
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.22
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseIn
|
||
animations:^{
|
||
settingView.transform = CGAffineTransformMakeTranslation(w, 0);
|
||
}
|
||
completion:^(BOOL finished) {
|
||
settingView.hidden = YES;
|
||
}];
|
||
} else {
|
||
settingView.transform = CGAffineTransformMakeTranslation(w, 0);
|
||
settingView.hidden = YES;
|
||
}
|
||
}
|
||
}
|
||
|
||
- (void)kb_setSubscriptionPanelVisible:(BOOL)visible animated:(BOOL)animated {
|
||
if (visible) {
|
||
KBKeyboardSubscriptionView *panel = self.subscriptionView;
|
||
if (!panel.superview) {
|
||
panel.hidden = YES;
|
||
[self.contentView addSubview:panel];
|
||
[panel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.equalTo(self.contentView);
|
||
}];
|
||
}
|
||
[self.contentView bringSubviewToFront:panel];
|
||
panel.hidden = NO;
|
||
panel.alpha = 0.0;
|
||
CGFloat height = CGRectGetHeight(self.contentView.bounds);
|
||
if (height <= 0) {
|
||
height = 260;
|
||
}
|
||
panel.transform = CGAffineTransformMakeTranslation(0, height);
|
||
[panel refreshProductsIfNeeded];
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.25
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseOut
|
||
animations:^{
|
||
panel.alpha = 1.0;
|
||
panel.transform = CGAffineTransformIdentity;
|
||
}
|
||
completion:nil];
|
||
} else {
|
||
panel.alpha = 1.0;
|
||
panel.transform = CGAffineTransformIdentity;
|
||
}
|
||
return;
|
||
}
|
||
|
||
KBKeyboardSubscriptionView *panel = _subscriptionView;
|
||
if (!panel) {
|
||
return;
|
||
}
|
||
if (!panel.superview || panel.hidden) {
|
||
return;
|
||
}
|
||
CGFloat height = CGRectGetHeight(panel.bounds);
|
||
if (height <= 0) {
|
||
height = CGRectGetHeight(self.contentView.bounds);
|
||
}
|
||
if (animated) {
|
||
[UIView animateWithDuration:0.22
|
||
delay:0
|
||
options:UIViewAnimationOptionCurveEaseIn
|
||
animations:^{
|
||
panel.alpha = 0.0;
|
||
panel.transform = CGAffineTransformMakeTranslation(0, height);
|
||
}
|
||
completion:^(BOOL finished) {
|
||
panel.hidden = YES;
|
||
panel.alpha = 1.0;
|
||
panel.transform = CGAffineTransformIdentity;
|
||
}];
|
||
} else {
|
||
panel.hidden = YES;
|
||
panel.alpha = 1.0;
|
||
panel.transform = CGAffineTransformIdentity;
|
||
}
|
||
}
|
||
|
||
// 延迟创建:仅在用户真正打开功能面板时才创建/布局,降低默认内存占用。
|
||
- (void)kb_ensureFunctionViewIfNeeded {
|
||
if (_functionView && _functionView.superview) {
|
||
return;
|
||
}
|
||
KBFunctionView *v = self.functionView;
|
||
if (!v.superview) {
|
||
v.hidden = YES;
|
||
[self.contentView addSubview:v];
|
||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.edges.equalTo(self.contentView);
|
||
}];
|
||
}
|
||
}
|
||
|
||
// 延迟创建:仅在用户打开聊天面板时才创建/布局。
|
||
- (void)kb_ensureChatPanelViewIfNeeded {
|
||
if (_chatPanelView && _chatPanelView.superview) {
|
||
return;
|
||
}
|
||
CGFloat portraitWidth = [self kb_portraitWidth];
|
||
CGFloat chatPanelHeight = [self kb_chatPanelHeightForWidth:portraitWidth];
|
||
KBChatPanelView *v = self.chatPanelView;
|
||
if (!v.superview) {
|
||
[self.contentView addSubview:v];
|
||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.left.right.equalTo(self.contentView);
|
||
make.bottom.equalTo(self.keyBoardMainView.mas_top);
|
||
self.chatPanelHeightConstraint =
|
||
make.height.mas_equalTo(chatPanelHeight);
|
||
}];
|
||
v.hidden = YES;
|
||
}
|
||
}
|
||
|
||
// 延迟创建:键盘主面板(按键区)在隐藏时会被释放;再次显示时需要重建。
|
||
- (void)kb_ensureKeyBoardMainViewIfNeeded {
|
||
if (_keyBoardMainView && _keyBoardMainView.superview) {
|
||
return;
|
||
}
|
||
CGFloat portraitWidth = [self kb_portraitWidth];
|
||
CGFloat keyboardBaseHeight =
|
||
[self kb_keyboardBaseHeightForWidth:portraitWidth];
|
||
KBKeyBoardMainView *v = self.keyBoardMainView;
|
||
if (!v.superview) {
|
||
[self.contentView addSubview:v];
|
||
[v mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.left.right.equalTo(self.contentView);
|
||
make.bottom.equalTo(self.contentView);
|
||
self.keyBoardMainHeightConstraint =
|
||
make.height.mas_equalTo(keyboardBaseHeight);
|
||
}];
|
||
}
|
||
[self.contentView bringSubviewToFront:v];
|
||
}
|
||
|
||
// 键盘隐藏时释放可重建资源(背景图/缓存/非必需面板),降低扩展内存峰值。
|
||
- (void)kb_releaseMemoryWhenKeyboardHidden {
|
||
[KBHUD setContainerView:nil];
|
||
self.bgImageView.image = nil;
|
||
self.kb_cachedGradientImage = nil;
|
||
[self.kb_defaultGradientLayer removeFromSuperlayer];
|
||
self.kb_defaultGradientLayer = nil;
|
||
[[SDImageCache sharedImageCache] clearMemory];
|
||
|
||
// 聊天相关可能持有音频数据/临时文件,键盘隐藏时直接清空,避免累计占用。
|
||
if (self.chatAudioPlayer) {
|
||
[self.chatAudioPlayer stop];
|
||
self.chatAudioPlayer = nil;
|
||
}
|
||
if (_chatMessages.count > 0) {
|
||
NSString *tmpRoot = NSTemporaryDirectory();
|
||
for (KBChatMessage *msg in _chatMessages.copy) {
|
||
if (tmpRoot.length > 0 && msg.audioFilePath.length > 0 &&
|
||
[msg.audioFilePath hasPrefix:tmpRoot]) {
|
||
[[NSFileManager defaultManager] removeItemAtPath:msg.audioFilePath
|
||
error:nil];
|
||
}
|
||
}
|
||
[_chatMessages removeAllObjects];
|
||
}
|
||
|
||
if (_keyBoardMainView) {
|
||
[_keyBoardMainView removeFromSuperview];
|
||
_keyBoardMainView = nil;
|
||
}
|
||
self.keyBoardMainHeightConstraint = nil;
|
||
|
||
if (_functionView) {
|
||
[_functionView removeFromSuperview];
|
||
_functionView = nil;
|
||
}
|
||
if (_chatPanelView) {
|
||
[_chatPanelView removeFromSuperview];
|
||
_chatPanelView = nil;
|
||
}
|
||
self.chatPanelVisible = NO;
|
||
self.kb_panelMode = KBKeyboardPanelModeMain;
|
||
|
||
if (_subscriptionView) {
|
||
[_subscriptionView removeFromSuperview];
|
||
_subscriptionView = nil;
|
||
}
|
||
if (_settingView) {
|
||
[_settingView removeFromSuperview];
|
||
_settingView = nil;
|
||
}
|
||
}
|
||
|
||
// MARK: - KBKeyBoardMainViewDelegate
|
||
|
||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView
|
||
didTapKey:(KBKey *)key {
|
||
switch (key.type) {
|
||
case KBKeyTypeCharacter: {
|
||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||
NSString *text = key.output ?: key.title ?: @"";
|
||
[self.textDocumentProxy insertText:text];
|
||
[self kb_updateCurrentWordWithInsertedText:text];
|
||
[[KBInputBufferManager shared] appendText:text];
|
||
} break;
|
||
case KBKeyTypeBackspace:
|
||
[[KBInputBufferManager shared]
|
||
refreshFromProxyIfPossible: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;
|
||
case KBKeyTypeSpace:
|
||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||
[self.textDocumentProxy insertText:@" "];
|
||
[self kb_clearCurrentWord];
|
||
[[KBInputBufferManager shared] appendText:@" "];
|
||
break;
|
||
case KBKeyTypeReturn:
|
||
if (self.chatPanelVisible) {
|
||
[self kb_handleChatSendAction];
|
||
break;
|
||
}
|
||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||
[self.textDocumentProxy insertText:@"\n"];
|
||
[self kb_clearCurrentWord];
|
||
[[KBInputBufferManager shared] appendText:@"\n"];
|
||
break;
|
||
case KBKeyTypeGlobe:
|
||
[self advanceToNextInputMode];
|
||
break;
|
||
case KBKeyTypeCustom:
|
||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||
// 点击自定义键切换到功能面板
|
||
[self kb_setPanelMode:KBKeyboardPanelModeFunction animated:NO];
|
||
[self kb_clearCurrentWord];
|
||
break;
|
||
case KBKeyTypeModeChange:
|
||
case KBKeyTypeShift:
|
||
// 这些已在 KBKeyBoardMainView/KBKeyboardView 内部处理
|
||
break;
|
||
}
|
||
}
|
||
|
||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView
|
||
didTapToolActionAtIndex:(NSInteger)index {
|
||
NSDictionary *extra = @{@"index" : @(index)};
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportClickWithEventName:@"click_keyboard_toolbar_action"
|
||
pageId:@"keyboard_main_panel"
|
||
elementId:@"toolbar_action"
|
||
extra:extra
|
||
completion:nil];
|
||
if (index == 0) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeFunction animated:YES];
|
||
[self kb_clearCurrentWord];
|
||
return;
|
||
}
|
||
if (index == 1) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeChat animated:YES];
|
||
return;
|
||
}
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:YES];
|
||
}
|
||
|
||
- (void)keyBoardMainViewDidTapSettings:(KBKeyBoardMainView *)keyBoardMainView {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportClickWithEventName:@"click_keyboard_settings_btn"
|
||
pageId:@"keyboard_main_panel"
|
||
elementId:@"settings_btn"
|
||
extra:nil
|
||
completion:nil];
|
||
[self kb_setPanelMode:KBKeyboardPanelModeSettings animated:YES];
|
||
}
|
||
|
||
- (void)keyBoardMainView:(KBKeyBoardMainView *)keyBoardMainView
|
||
didSelectEmoji:(NSString *)emoji {
|
||
if (emoji.length == 0) {
|
||
return;
|
||
}
|
||
[[KBBackspaceUndoManager shared] registerNonClearAction];
|
||
[self.textDocumentProxy insertText:emoji];
|
||
[self kb_clearCurrentWord];
|
||
[[KBInputBufferManager shared] appendText:emoji];
|
||
}
|
||
|
||
- (void)keyBoardMainViewDidTapUndo:(KBKeyBoardMainView *)keyBoardMainView {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportClickWithEventName:@"click_keyboard_undo_btn"
|
||
pageId:@"keyboard_main_panel"
|
||
elementId:@"undo_btn"
|
||
extra:nil
|
||
completion:nil];
|
||
[[KBBackspaceUndoManager shared] performUndoFromResponder:self.view];
|
||
[self kb_scheduleContextRefreshResetSuppression:YES];
|
||
}
|
||
|
||
- (void)keyBoardMainViewDidTapEmojiSearch:
|
||
(KBKeyBoardMainView *)keyBoardMainView {
|
||
// [[KBMaiPointReporter sharedReporter]
|
||
// reportClickWithEventName:@"click_keyboard_emoji_search_btn"
|
||
// pageId:@"keyboard_main_panel"
|
||
// elementId:@"emoji_search_btn"
|
||
// extra:nil
|
||
// completion:nil];
|
||
[KBHUD showInfo:KBLocalized(@"Search coming soon")];
|
||
}
|
||
|
||
// MARK: - KBFunctionViewDelegate
|
||
|
||
- (void)functionView:(KBFunctionView *)functionView
|
||
didTapToolActionAtIndex:(NSInteger)index {
|
||
// 需求:当 index == 0 时,切回键盘主视图
|
||
if (index == 0) {
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:NO];
|
||
}
|
||
}
|
||
|
||
- (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) {
|
||
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_LOGIN]];
|
||
NSURL *scheme =
|
||
[NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=keyboard", KB_APP_SCHEME]];
|
||
__weak typeof(self) weakSelf = self;
|
||
[KBExtensionAppLauncher openPrimaryURL:ul
|
||
fallbackURL:scheme
|
||
usingInputController:self
|
||
source:(self.view ?: (UIResponder *)weakSelf)
|
||
completion:nil];
|
||
return;
|
||
}
|
||
NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=keyboard", KB_UL_RECHARGE]];
|
||
NSURL *scheme =
|
||
[NSURL URLWithString:[NSString stringWithFormat:@"%@://recharge?src=keyboard", KB_APP_SCHEME]];
|
||
__weak typeof(self) weakSelf = self;
|
||
[KBExtensionAppLauncher openPrimaryURL:ul
|
||
fallbackURL:scheme
|
||
usingInputController:self
|
||
source:(self.view ?: (UIResponder *)weakSelf)
|
||
completion:^(BOOL success) {
|
||
if (success) {
|
||
return;
|
||
}
|
||
dispatch_async(dispatch_get_main_queue(), ^{
|
||
[KBHUD showInfo:@"当前应用不允许键盘直接唤起App,请回到桌面手动打开App进行充值"];
|
||
});
|
||
}];
|
||
}
|
||
|
||
- (void)functionViewDidRequestSubscription:(KBFunctionView *)functionView {
|
||
[self showSubscriptionPanel];
|
||
}
|
||
|
||
#pragma mark - Actions
|
||
|
||
- (void)onTapSettingsBack {
|
||
[[KBMaiPointReporter sharedReporter]
|
||
reportClickWithEventName:@"click_keyboard_settings_back_btn"
|
||
pageId:@"keyboard_settings"
|
||
elementId:@"back_btn"
|
||
extra:nil
|
||
completion:nil];
|
||
[self kb_setPanelMode:KBKeyboardPanelModeMain animated:YES];
|
||
}
|
||
|
||
@end
|