This commit is contained in:
2026-02-10 10:21:21 +08:00
parent cb2e8467a7
commit 4c57f16058
6 changed files with 269 additions and 178 deletions

View File

@@ -78,10 +78,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
KBFunctionView *functionView; // 0
@property(nonatomic, strong) KBSettingView *settingView; //
@property(nonatomic, strong) UIImageView *bgImageView; //
@property(nonatomic, strong) UIImageView *personaAvatarImageView; // persona
@property(nonatomic, strong) UIImageView *personaGrayImageView; // persona
@property(nonatomic, strong) UIVisualEffectView *personaBlurView; //
@property(nonatomic, strong) KBChatPanelView *chatPanelView;
@property(nonatomic, strong) KBKeyboardSubscriptionView *subscriptionView;
@property(nonatomic, strong) KBSuggestionEngine *suggestionEngine;
@@ -96,9 +92,13 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
@property(nonatomic, strong) NSLayoutConstraint *kb_widthConstraint;
@property(nonatomic, assign) CGFloat kb_lastPortraitWidth;
@property(nonatomic, assign) CGFloat kb_lastKeyboardHeight;
@property(nonatomic, strong) UIImage *kb_cachedGradientImage;
@property(nonatomic, assign) CGSize kb_cachedGradientSize;
@property(nonatomic, strong) NSMutableArray<KBChatMessage *> *chatMessages;
@property(nonatomic, strong) AVAudioPlayer *chatAudioPlayer;
@property(nonatomic, assign) BOOL chatPanelVisible;
@property(nonatomic, strong, nullable) id kb_fullAccessObserverToken;
@property(nonatomic, strong, nullable) id kb_skinObserverToken;
@end
@implementation KeyboardViewController
@@ -118,7 +118,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[KBHUD setContainerView:self.view];
// 访便
[[KBFullAccessManager shared] bindInputController:self];
__unused id token = [[NSNotificationCenter defaultCenter]
self.kb_fullAccessObserverToken = [[NSNotificationCenter defaultCenter]
addObserverForName:KBFullAccessChangedNotification
object:nil
queue:[NSOperationQueue mainQueue]
@@ -127,11 +127,16 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}];
//
__unused id token2 = [[NSNotificationCenter defaultCenter]
__weak typeof(self) weakSelf = self;
self.kb_skinObserverToken = [[NSNotificationCenter defaultCenter]
addObserverForName:KBSkinDidChangeNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(__unused NSNotification *_Nonnull note) {
__strong typeof(weakSelf) self = weakSelf;
if (!self) {
return;
}
[self kb_applyTheme];
}];
[self kb_applyTheme];
@@ -162,8 +167,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[KBBackspaceUndoManager shared] registerNonClearAction];
// persona
[self kb_hidePersonaAvatar];
}
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
@@ -171,6 +174,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if (@available(iOS 13.0, *)) {
if (previousTraitCollection.userInterfaceStyle !=
self.traitCollection.userInterfaceStyle) {
self.kb_cachedGradientImage = nil;
[self kb_applyDefaultSkinIfNeeded];
}
}
@@ -250,6 +254,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
make.height.mas_equalTo(chatPanelHeight);
}];
self.chatPanelView.hidden = YES;
//
self.contentView.hidden = YES;
}
#pragma mark - Private
@@ -425,19 +432,18 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
pageId:@"keyboard_settings"
extra:nil
completion:nil];
// if (!self.settingView) {
self.settingView = [[KBSettingView alloc] init];
self.settingView.hidden = YES;
[self.contentView addSubview:self.settingView];
[self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
//
make.edges.equalTo(self.contentView);
}];
[self.settingView.backButton addTarget:self
action:@selector(onTapSettingsBack)
forControlEvents:UIControlEventTouchUpInside];
// }
[self.contentView bringSubviewToFront:self.settingView];
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);
@@ -447,17 +453,18 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if (w <= 0) {
w = [self kb_portraitWidth];
}
self.settingView.transform = CGAffineTransformMakeTranslation(w, 0);
self.settingView.hidden = NO;
settingView.transform = CGAffineTransformMakeTranslation(w, 0);
settingView.hidden = NO;
[UIView animateWithDuration:0.25
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.settingView.transform = CGAffineTransformIdentity;
settingView.transform = CGAffineTransformIdentity;
}
completion:nil];
} else {
if (!self.settingView || self.settingView.hidden)
KBSettingView *settingView = self.settingView;
if (!settingView.superview || settingView.hidden)
return;
CGFloat w = CGRectGetWidth(self.keyBoardMainView.bounds);
if (w <= 0) {
@@ -470,10 +477,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.settingView.transform = CGAffineTransformMakeTranslation(w, 0);
settingView.transform = CGAffineTransformMakeTranslation(w, 0);
}
completion:^(BOOL finished) {
self.settingView.hidden = YES;
settingView.hidden = YES;
}];
}
}
@@ -663,8 +670,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if (index == 1) {
[self showFunctionPanel:NO];
[self showChatPanel:YES];
// persona
[self kb_showPersonaAvatarOnBgImageView];
return;
}
[self showFunctionPanel:NO];
@@ -832,8 +837,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
self.chatAudioPlayer = nil;
[self showChatPanel:NO];
// persona
[self kb_hidePersonaAvatar];
}
#pragma mark - Chat Helpers
@@ -1482,108 +1485,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
return _subscriptionView;
}
- (UIImageView *)personaAvatarImageView {
if (!_personaAvatarImageView) {
_personaAvatarImageView = [[UIImageView alloc] init];
_personaAvatarImageView.contentMode = UIViewContentModeScaleAspectFill;
_personaAvatarImageView.clipsToBounds = YES;
_personaAvatarImageView.hidden = YES;
[_personaAvatarImageView addSubview:self.personaBlurView];
[self.personaBlurView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(_personaAvatarImageView);
}];
}
return _personaAvatarImageView;
}
- (UIImageView *)personaGrayImageView{
if (!_personaGrayImageView) {
_personaGrayImageView = [[UIImageView alloc] init];
_personaAvatarImageView.contentMode = UIViewContentModeScaleAspectFill;
}
return _personaGrayImageView;
}
- (UIVisualEffectView *)personaBlurView {
if (!_personaBlurView) {
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
_personaBlurView = [[UIVisualEffectView alloc] initWithEffect:effect];
_personaBlurView.hidden = YES;
_personaBlurView.userInteractionEnabled = NO;
}
return _personaBlurView;
}
#pragma mark - Persona Avatar
/// AppGroup persona
- (NSDictionary *)kb_selectedPersonaFromAppGroup {
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
NSDictionary *personaDict = [ud objectForKey:@"AppGroup_SelectedPersona"];
if ([personaDict isKindOfClass:[NSDictionary class]]) {
return personaDict;
}
return nil;
}
/// bgImageView persona
- (void)kb_showPersonaAvatarOnBgImageView {
// 访
if (![[KBFullAccessManager shared] hasFullAccess]) {
NSLog(@"[Keyboard] 未开启完全访问,无法显示 persona 头像");
return;
}
// AppGroup
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:AppGroup];
if (!containerURL) {
NSLog(@"[Keyboard] 无法获取 AppGroup 容器目录");
return;
}
NSString *imagePath = [[containerURL path] stringByAppendingPathComponent:@"persona_cover.jpg"];
if (![[NSFileManager defaultManager] fileExistsAtPath:imagePath]) {
NSLog(@"[Keyboard] persona 封面图文件不存在: %@", imagePath);
return;
}
NSLog(@"[Keyboard] 准备从本地加载 persona 封面图: %@", imagePath);
// contentView bgImageView
if (!self.personaAvatarImageView.superview) {
[self.contentView insertSubview:self.personaAvatarImageView aboveSubview:self.bgImageView];
[self.personaAvatarImageView addSubview:self.personaGrayImageView];
[self.personaAvatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.bgImageView);
}];
[self.personaGrayImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.bottom.equalTo(self.personaAvatarImageView);
make.height.mas_equalTo(self.keyBoardMainView);
}];
}
//
self.personaAvatarImageView.image = nil;
//
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
if (image) {
self.personaAvatarImageView.image = image;
self.personaAvatarImageView.hidden = NO;
self.personaBlurView.hidden = NO;
NSLog(@"[Keyboard] persona 封面图加载成功");
} else {
NSLog(@"[Keyboard] persona 封面图加载失败");
}
}
/// persona
- (void)kb_hidePersonaAvatar {
self.personaAvatarImageView.hidden = YES;
self.personaAvatarImageView.image = nil;
self.personaBlurView.hidden = YES;
}
#pragma mark - Actions
- (void)kb_openRechargeForProduct:(KBKeyboardSubscriptionProduct *)product {
@@ -1638,10 +1539,22 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
- (void)dealloc {
if (self.kb_fullAccessObserverToken) {
[[NSNotificationCenter defaultCenter]
removeObserver:self.kb_fullAccessObserverToken];
self.kb_fullAccessObserverToken = nil;
}
if (self.kb_skinObserverToken) {
[[NSNotificationCenter defaultCenter] removeObserver:self.kb_skinObserverToken];
self.kb_skinObserverToken = nil;
}
CFNotificationCenterRemoveObserver(
CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
(__bridge CFStringRef)KBDarwinSkinInstallRequestNotification, NULL);
#if DEBUG
NSLog(@"[Keyboard] KeyboardViewController dealloc");
#endif
}
// App App
@@ -1659,7 +1572,12 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self kb_updateKeyboardLayoutIfNeeded];
// [self kb_updateKeyboardLayoutIfNeeded];
//
if (self.contentView.hidden) {
self.contentView.hidden = NO;
}
}
- (void)viewWillTransitionToSize:(CGSize)size
@@ -1749,9 +1667,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
UIColor *topColor = [UIColor colorWithHex:0xDEDFE4];
UIColor *bottomColor = [UIColor colorWithHex:0xD1D3DB];
img = [self kb_defaultGradientImageWithSize:size
topColor:topColor
bottomColor:bottomColor];
// img = [self kb_defaultGradientImageWithSize:size
// topColor:topColor
// bottomColor:bottomColor];
self.contentView.backgroundColor = [UIColor clearColor];
self.bgImageView.backgroundColor = [UIColor clearColor];
}
@@ -1764,7 +1682,6 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
NSLog(@"⌨️[Keyboard] apply theme id=%@ hasBg=%d", t.skinId, (img != nil));
[self kb_logSkinDiagnosticsWithTheme:t backgroundImage:img];
self.bgImageView.image = img;
self.personaGrayImageView.image = img;
// [self.chatPanelView kb_setBackgroundImage:img];
BOOL hasImg = (img != nil);
@@ -1819,8 +1736,12 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
return nil;
}
// trait collection
// UIGraphicsBeginImageContextWithOptions 使
//
if (self.kb_cachedGradientImage &&
CGSizeEqualToSize(self.kb_cachedGradientSize, size)) {
return self.kb_cachedGradientImage;
}
UIColor *resolvedTopColor = topColor;
UIColor *resolvedBottomColor = bottomColor;
if (@available(iOS 13.0, *)) {
@@ -1841,6 +1762,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.kb_cachedGradientImage = image;
self.kb_cachedGradientSize = size;
return image;
}