From 2aa5fa8d0981a2e97da2041eba30203b02d6308a Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Mon, 2 Mar 2026 21:47:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9C=A8=E8=A5=BF=E7=8F=AD?= =?UTF-8?q?=E7=89=99=E9=94=AE=E7=9B=98bar=E4=B8=8A=20=20ai=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CustomKeyboard/View/KBToolBar.m | 17 ++++- Shared/KBSkinInstallBridge.m | 70 +++++++++++++++++---- Shared/KBSkinManager.m | 8 +++ keyBoard.xcodeproj/project.pbxproj | 8 +-- keyBoard/Class/Resource/西班牙初始皮肤.zip | Bin 434852 -> 439663 bytes 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/CustomKeyboard/View/KBToolBar.m b/CustomKeyboard/View/KBToolBar.m index 44ddb27..56a6cf9 100644 --- a/CustomKeyboard/View/KBToolBar.m +++ b/CustomKeyboard/View/KBToolBar.m @@ -42,6 +42,10 @@ selector:@selector(kb_undoStateChanged) name:KBBackspaceUndoStateDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(kb_skinDidChange) + name:KBSkinDidChangeNotification + object:nil]; } return self; } @@ -183,9 +187,14 @@ KBSkinManager *skinManager = [KBSkinManager shared]; UIImage *icon = [skinManager iconImageForKeyIdentifier:kKBAIKeyIdentifier caseVariant:0]; NSString *skinId = skinManager.current.skinId ?: @""; - BOOL usingDefaultSkin = (skinId.length == 0 || [skinId isEqualToString:@"default"]); - if (!icon && usingDefaultSkin) { + + NSLog(@"[KBToolBar] kb_updateAIButtonAppearance: skinId=%@ icon=%@", + skinId, icon ? @"有" : @"nil"); + + // 如果当前皮肤没有 ai 图标,使用默认图标 + if (!icon) { icon = [UIImage imageNamed:@"ai_key_icon"]; + NSLog(@"[KBToolBar] fallback to bundled ai_key_icon: %@", icon ? @"有" : @"nil"); } if (icon) { @@ -472,6 +481,10 @@ [self kb_updateUndoVisibilityAnimated:YES]; } +- (void)kb_skinDidChange { + [self kb_applyTheme]; +} + - (void)kb_updateUndoVisibilityAnimated:(BOOL)animated { BOOL visible = [KBBackspaceUndoManager shared].hasUndo; if (self.kbUndoVisible == visible) { return; } diff --git a/Shared/KBSkinInstallBridge.m b/Shared/KBSkinInstallBridge.m index 4a300d0..39a7532 100644 --- a/Shared/KBSkinInstallBridge.m +++ b/Shared/KBSkinInstallBridge.m @@ -959,21 +959,67 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json"; NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: currentSkin=%@ targetSkin=%@ lang=%@", currentSkinId, targetSkinId, languageCode); - if ([targetSkinId isEqualToString:currentSkinId]) { - NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: already on target skin, just refresh icon map"); - } else { - BOOL hasTargetSkin = [KBSkinManager kb_hasAssetsForSkinId:targetSkinId]; - NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: hasTargetSkin=%d", hasTargetSkin); - - if (hasTargetSkin) { - NSError *applyError = nil; - BOOL applied = [self applyInstalledSkinWithId:targetSkinId error:&applyError]; - NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: switched to %@ applied=%d error=%@", - targetSkinId, applied, applyError); - return applied; + // 检查目标皮肤是否存在 + BOOL hasTargetSkin = [KBSkinManager kb_hasAssetsForSkinId:targetSkinId]; + NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: hasTargetSkin=%d", hasTargetSkin); + + if (hasTargetSkin) { + // 先获取目标皮肤的图标映射 + NSDictionary *iconShortNames = [self iconShortNamesForLanguageCode:languageCode]; + if (iconShortNames.count == 0) { + iconShortNames = @{}; } + + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *targetSkinRoot = [[self kb_skinsRootPath] stringByAppendingPathComponent:targetSkinId]; + NSString *targetIconsDir = [targetSkinRoot stringByAppendingPathComponent:@"icons"]; + + NSMutableDictionary *iconPathMap = [NSMutableDictionary dictionary]; + [iconShortNames enumerateKeysAndObjectsUsingBlock:^(NSString *identifier, NSString *shortName, BOOL *stop) { + if (![shortName isKindOfClass:NSString.class] || shortName.length == 0) return; + NSString *fileName = shortName; + if (fileName.pathExtension.length == 0) { + fileName = [fileName stringByAppendingPathExtension:@"png"]; + } + NSString *fullPath = [targetIconsDir stringByAppendingPathComponent:fileName]; + BOOL exists = [fm fileExistsAtPath:fullPath]; + if ([identifier isEqualToString:@"ai"] || [identifier isEqualToString:@"key_revoke"]) { + NSLog(@"[SkinBridge] Checking icon: id=%@ shortName=%@ fullPath=%@ exists=%d", + identifier, shortName, fullPath, exists); + } + if (exists) { + NSString *relative = [NSString stringWithFormat:@"Skins/%@/icons/%@", targetSkinId, fileName]; + iconPathMap[identifier] = relative; + } + }]; + + NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: targetSkin=%@ iconCount=%lu", + targetSkinId, (unsigned long)iconPathMap.count); + + // 构建主题 JSON + NSDictionary *meta = [self kb_metadataForSkinId:targetSkinId]; + NSMutableDictionary *themeJSON = [NSMutableDictionary dictionary]; + themeJSON[@"id"] = targetSkinId; + NSString *name = [meta[kKBSkinMetadataNameKey] isKindOfClass:NSString.class] ? meta[kKBSkinMetadataNameKey] : targetSkinId; + themeJSON[@"name"] = name; + if (iconPathMap.count > 0) { + themeJSON[@"key_icons"] = iconPathMap.copy; + } + + NSString *bgPath = [targetSkinRoot stringByAppendingPathComponent:@"background.png"]; + NSData *bgData = [NSData dataWithContentsOfFile:bgPath]; + + BOOL themeOK = [[KBSkinManager shared] applyThemeFromJSON:themeJSON]; + if (bgData.length > 0) { + [[KBSkinManager shared] applyImageSkinWithData:bgData skinId:targetSkinId name:name]; + } + + NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: switched to %@ applied=%d iconCount=%lu", + targetSkinId, themeOK, (unsigned long)iconPathMap.count); + return themeOK; } + // 如果目标皮肤不存在,尝试更新当前皮肤的图标映射 if (currentSkinId.length == 0 || [currentSkinId isEqualToString:@"default"]) { NSLog(@"[SkinBridge] reloadCurrentSkinIconMap: no custom skin applied, skip"); return NO; diff --git a/Shared/KBSkinManager.m b/Shared/KBSkinManager.m index 62ec0e7..c637f62 100644 --- a/Shared/KBSkinManager.m +++ b/Shared/KBSkinManager.m @@ -355,6 +355,7 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer, @"shift", @"backspace", @"mode_123", @"mode_abc", @"symbols_toggle_more", @"symbols_toggle_123", @"return", @"space", @"emoji_panel", @"letter_q", + @"ai", @"key_revoke", nil]; }); BOOL shouldLog = [kb_debugIconIds containsObject:identifier]; @@ -388,6 +389,13 @@ static void KBSkinDarwinCallback(CFNotificationCenterRef center, void *observer, } } +#if DEBUG + if (shouldLog) { + NSLog(@"[SkinManager] iconImageForKey: id='%@' skin='%@' mapCount=%lu value='%@'", + identifier, self.current.skinId ?: @"default", (unsigned long)map.count, value ?: @"nil"); + } +#endif + // 调试日志:打印未找到映射的按键 ID if (value.length == 0 && identifier.length > 0) { static NSMutableSet *kb_loggedMissingIds = nil; diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index b5d12c7..b98e9b1 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -45,7 +45,7 @@ 043213B12F556DF80065C888 /* KBSkinIconMap_es.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AB2F556DF80065C888 /* KBSkinIconMap_es.strings */; }; 043213B22F556DF80065C888 /* KBSkinIconMap_zh_hant.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */; }; 043213B62F5582710065C888 /* spanish_words.json in Resources */ = {isa = PBXBuildFile; fileRef = 043213B52F5582710065C888 /* spanish_words.json */; }; - 043213B82F558BC20065C888 /* 西班牙初始皮肤.zip in Resources */ = {isa = PBXBuildFile; fileRef = 043213B72F558BC20065C888 /* 西班牙初始皮肤.zip */; }; + 043213BA2F55C5790065C888 /* 西班牙初始皮肤.zip in Resources */ = {isa = PBXBuildFile; fileRef = 043213B92F55C5790065C888 /* 西班牙初始皮肤.zip */; }; 043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; }; 0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; }; 0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; }; @@ -403,7 +403,7 @@ 043213AD2F556DF80065C888 /* KBSkinIconMap_pt.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_pt.strings; sourceTree = ""; }; 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_zh_hant.strings; sourceTree = ""; }; 043213B52F5582710065C888 /* spanish_words.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = spanish_words.json; sourceTree = ""; }; - 043213B72F558BC20065C888 /* 西班牙初始皮肤.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "西班牙初始皮肤.zip"; sourceTree = ""; }; + 043213B92F55C5790065C888 /* 西班牙初始皮肤.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "西班牙初始皮肤.zip"; sourceTree = ""; }; 0450AA722EF013D000B6AF06 /* KBEmojiCollectionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBEmojiCollectionCell.h; sourceTree = ""; }; 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBEmojiCollectionCell.m; sourceTree = ""; }; 0450AAE02EF03D5100B6AF06 /* keyBoard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "keyBoard-Bridging-Header.h"; sourceTree = ""; }; @@ -1298,12 +1298,12 @@ 047C652C2EBCAAAC0035E841 /* Resource */ = { isa = PBXGroup; children = ( - 043213B72F558BC20065C888 /* 西班牙初始皮肤.zip */, 0479200A2ED87CEE004E8522 /* permiss_video.mp4 */, 047920102ED98E7D004E8522 /* permiss_video_2.mp4 */, 047920062ED86ABC004E8522 /* kb_guide_keyboard.gif */, 045ED5292F540FBE00131114 /* normal_hei_them.zip */, 045ED52A2F540FBE00131114 /* normal_them.zip */, + 043213B92F55C5790065C888 /* 西班牙初始皮肤.zip */, ); path = Resource; sourceTree = ""; @@ -2336,7 +2336,7 @@ 04C6EABC2EAF86530089C901 /* LaunchScreen.storyboard in Resources */, 04E0394F2F236E75002CA5A0 /* KBChatTableView_Usage.md in Resources */, 04286A132ECDEBF900CE730C /* KBSkinIconMap.strings in Resources */, - 043213B82F558BC20065C888 /* 西班牙初始皮肤.zip in Resources */, + 043213BA2F55C5790065C888 /* 西班牙初始皮肤.zip in Resources */, 04C6EABD2EAF86530089C901 /* Main.storyboard in Resources */, 046086CB2F1A092500757C95 /* comments_mock.json in Resources */, 04E038E32F20E500002CA5A0 /* deepgramAPI.md in Resources */, diff --git a/keyBoard/Class/Resource/西班牙初始皮肤.zip b/keyBoard/Class/Resource/西班牙初始皮肤.zip index 8a841f545a2f14554bb8fbf04e912f93160dfaaf..9fcda65a8d4f74eacd1750718f77f3ed3f46c5cf 100644 GIT binary patch delta 10685 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 U2=_adcPt9-EG%oSupb!uKW#D4T>t<8 delta 6446 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 S;NQ>i)AQ{H4f=QI$NvN5#&Zb(