76 Commits

Author SHA1 Message Date
6f7bb4f960 键盘的背景图添加高斯模糊 2026-02-03 14:22:44 +08:00
fa9af5ff1b 处理聊天信息没回来 切刀下一个collectionviewcell ,信息不对的问题(禁用滚动) 2026-02-03 14:05:29 +08:00
08628bcd1d aihome里统一发布消息控件 2026-02-03 13:31:52 +08:00
19cb29616f 优化发送输入框 2026-02-02 21:25:28 +08:00
6e50cdcd2a 1 2026-02-02 20:36:38 +08:00
f1b52151be 添加音频动画 2026-02-02 19:49:56 +08:00
993ec623af 1 2026-02-02 19:07:00 +08:00
0416a64235 处理为识别到语音 2026-02-02 17:41:23 +08:00
2b75ad90fb 修改举报和UI 2026-02-02 17:07:46 +08:00
0ac9030f80 1 2026-02-02 15:28:00 +08:00
ea9c40f64f 处理语音在B界面删除历史记录有声音问题 2026-02-02 15:27:55 +08:00
48c90fa0be 1 2026-02-02 14:29:42 +08:00
fe59a0cb45 1 2026-02-02 13:26:38 +08:00
81bc50ce17 1 2026-01-31 23:17:58 +08:00
6ae504823b tableview倒置 2026-01-31 22:40:50 +08:00
d2f582b7f8 处理崩溃 2026-01-30 21:38:58 +08:00
cc82396195 基本ok 2026-01-30 21:24:17 +08:00
2ff8a7a4af 处理键盘bug 2026-01-30 13:46:08 +08:00
3c0b7e754c 1 2026-01-30 13:33:23 +08:00
3705db4aab 简单封装 2026-01-30 13:26:02 +08:00
36774a8a2c 处理键盘 2026-01-30 13:17:11 +08:00
36135313d8 处理语音 2026-01-29 20:56:24 +08:00
23c0d14128 处理键盘部分 2026-01-29 19:18:38 +08:00
d0c5cada35 发送文本处理ui和逻辑 2026-01-29 17:56:53 +08:00
b556e6841d 添加举报 2026-01-29 16:42:43 +08:00
26096abbcc 添加个人主页 2026-01-29 16:03:21 +08:00
766c62f3c0 1 2026-01-29 15:53:26 +08:00
07a77149fc 处理评论数 2026-01-29 14:51:42 +08:00
32ebc6fb65 处理滚动底部问题 2026-01-29 14:42:49 +08:00
25fbe9b64e 分类移动文件 2026-01-29 13:44:52 +08:00
4392296616 修复聊天最后一条跑到最上面的问题 2026-01-29 13:13:42 +08:00
ef52cd4872 1 2026-01-28 20:18:18 +08:00
70a8466d9f 1 2026-01-28 19:31:27 +08:00
66d85f78a0 1 2026-01-28 18:58:30 +08:00
93a20cd92a 2 2026-01-28 18:15:58 +08:00
9a54a2ae6c 1 2026-01-28 18:11:46 +08:00
1b9ce1622d 修改动画 2026-01-28 17:21:19 +08:00
b4db79eba8 2 2026-01-28 16:35:47 +08:00
22f77d56ea 隐藏无更多消息文案 2026-01-28 15:32:56 +08:00
d8d5bdc3ae 1 2026-01-28 13:55:11 +08:00
7d583ceb1d 1 2026-01-28 13:43:36 +08:00
51b744ecd7 1 2026-01-28 12:04:31 +08:00
3fd7d2af2e 1 2026-01-27 21:32:52 +08:00
db869552e4 1 2026-01-27 18:53:19 +08:00
b34de116a3 修改布局 2026-01-27 17:49:45 +08:00
e67bc37571 修改bug 2026-01-27 17:03:16 +08:00
2b749cd2b0 1 2026-01-27 16:28:17 +08:00
ce889e1ed0 1 2026-01-27 13:57:32 +08:00
e8b4b2c58a 2 2026-01-26 20:36:51 +08:00
3a5a6395af 1 2026-01-26 18:51:37 +08:00
a22599feda 1 2026-01-26 18:43:07 +08:00
6a177ceebc 新增聊天记录 2026-01-26 18:17:02 +08:00
f9d7579536 新增接口,界面 2026-01-26 16:53:41 +08:00
0fa31418f6 1 2026-01-26 13:51:38 +08:00
77fd46aa34 1 2026-01-23 21:51:37 +08:00
6ad9783bcb 1 2026-01-22 22:03:56 +08:00
edc25c159d 1 2026-01-22 13:47:34 +08:00
06a572c08a 1 2026-01-21 17:59:12 +08:00
36c0b0b210 1 2026-01-21 17:25:38 +08:00
d1d47336c2 处理tabbar 2026-01-19 19:14:20 +08:00
063ceae10f 添加渐变色 2026-01-16 21:37:18 +08:00
552387293c 修改BUG 2026-01-16 20:44:10 +08:00
93489b09d9 1 2026-01-16 20:31:42 +08:00
663cb8493b 处理发送评论 2026-01-16 19:36:41 +08:00
ac0d9584d8 添加二级评论多个的时候的逻辑,默认每次点击出现5条 2026-01-16 19:29:42 +08:00
7fa124d45f 处理一级评论cell头像闪的问题 2026-01-16 19:13:26 +08:00
3dfb8f31e2 处理好评论了 2026-01-16 19:09:54 +08:00
619c02f236 1 2026-01-16 17:41:03 +08:00
28852a8d4b 添加评论 2026-01-16 15:55:08 +08:00
b021fd308f 添加语音websocket等,还没测试 2026-01-16 13:38:03 +08:00
169a1929d7 修改UI 2026-01-15 20:30:03 +08:00
b5da9f35a5 4 2026-01-15 19:14:34 +08:00
8f4deaac4e 删除录音相关文件 2026-01-15 19:00:25 +08:00
d479d1903b 2 2026-01-15 18:49:31 +08:00
32c4138ae0 1 2026-01-15 18:16:56 +08:00
da62d4f411 添加发送ai文本埋点 2026-01-13 17:37:34 +08:00
263 changed files with 32301 additions and 443 deletions

View File

@@ -6,6 +6,8 @@
<array>
<string>kbkeyboardAppExtension</string>
</array>
<key>NSMicrophoneUsageDescription</key>
<string>需要使用麦克风进行语音输入</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "close_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "close_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -18,11 +18,17 @@
#import "KBKeyboardSubscriptionProduct.h"
#import "KBKeyboardSubscriptionView.h"
#import "KBSettingView.h"
#import "KBChatMessage.h"
#import "KBChatPanelView.h"
#import "KBSkinInstallBridge.h"
#import "KBSkinManager.h"
#import "KBSuggestionEngine.h"
#import "KBNetworkManager.h"
#import "KBVM.h"
#import "Masonry.h"
#import "UIImage+KBColor.h"
#import <AVFoundation/AVFoundation.h>
#import <SDWebImage/SDWebImage.h>
// #import "KBLog.h"
@@ -34,6 +40,8 @@
// 375 稿
static const CGFloat kKBKeyboardBaseHeight = 250.0f;
static const CGFloat kKBChatPanelHeight = 180;
static const NSUInteger kKBChatMessageLimit = 6;
static NSString *const kKBDefaultSkinIdLight = @"normal_them";
static NSString *const kKBDefaultSkinZipNameLight = @"normal_them";
static NSString *const kKBDefaultSkinIdDark = @"normal_hei_them";
@@ -57,7 +65,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
@interface KeyboardViewController () <KBKeyBoardMainViewDelegate,
KBFunctionViewDelegate,
KBKeyboardSubscriptionViewDelegate>
KBKeyboardSubscriptionViewDelegate,
KBChatPanelViewDelegate>
@property(nonatomic, strong)
UIButton *nextKeyboardButton; //
@property(nonatomic, strong) UIView *contentView;
@@ -67,16 +76,26 @@ 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;
@property(nonatomic, copy) NSString *currentWord;
@property(nonatomic, assign) BOOL suppressSuggestions;
@property(nonatomic, strong) MASConstraint *contentWidthConstraint;
@property(nonatomic, strong) MASConstraint *contentHeightConstraint;
@property(nonatomic, strong) MASConstraint *keyBoardMainHeightConstraint;
@property(nonatomic, strong) MASConstraint *chatPanelHeightConstraint;
@property(nonatomic, strong) NSLayoutConstraint *kb_heightConstraint;
@property(nonatomic, strong) NSLayoutConstraint *kb_widthConstraint;
@property(nonatomic, assign) CGFloat kb_lastPortraitWidth;
@property(nonatomic, assign) CGFloat kb_lastKeyboardHeight;
@property(nonatomic, strong) NSMutableArray<KBChatMessage *> *chatMessages;
@property(nonatomic, strong) AVAudioPlayer *chatAudioPlayer;
@property(nonatomic, assign) BOOL chatPanelVisible;
@end
@implementation KeyboardViewController
@@ -140,6 +159,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[KBBackspaceUndoManager shared] registerNonClearAction];
// persona
[self kb_hidePersonaAvatar];
}
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
@@ -167,6 +188,8 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
//
CGFloat portraitWidth = [self kb_portraitWidth];
CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth];
CGFloat keyboardBaseHeight = [self kb_keyboardBaseHeightForWidth:portraitWidth];
CGFloat chatPanelHeight = [self kb_chatPanelHeightForWidth:portraitWidth];
CGFloat screenWidth = CGRectGetWidth([UIScreen mainScreen].bounds);
CGFloat outerVerticalInset = KBFit(4.0f);
@@ -210,8 +233,20 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[self.contentView addSubview:self.keyBoardMainView];
[self.keyBoardMainView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.contentView);
make.left.right.equalTo(self.contentView);
make.bottom.equalTo(self.contentView);
self.keyBoardMainHeightConstraint =
make.height.mas_equalTo(keyboardBaseHeight);
}];
[self.contentView addSubview:self.chatPanelView];
[self.chatPanelView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.contentView);
make.bottom.equalTo(self.keyBoardMainView.mas_top);
self.chatPanelHeightConstraint =
make.height.mas_equalTo(chatPanelHeight);
}];
self.chatPanelView.hidden = YES;
}
#pragma mark - Private
@@ -349,6 +384,9 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
/// /
- (void)showFunctionPanel:(BOOL)show {
//
if (show) {
[self showChatPanel:NO];
}
self.functionView.hidden = !show;
self.keyBoardMainView.hidden = show;
@@ -378,6 +416,7 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
/// / keyBoardMainView /
- (void)showSettingView:(BOOL)show {
if (show) {
[self showChatPanel:NO];
[[KBMaiPointReporter sharedReporter]
reportPageExposureWithEventName:@"enter_keyboard_settings"
pageId:@"keyboard_settings"
@@ -436,6 +475,40 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
}
}
/// /
- (void)showChatPanel:(BOOL)show {
if (show == self.chatPanelVisible) {
return;
}
self.chatPanelVisible = show;
if (show) {
self.chatPanelView.hidden = NO;
self.chatPanelView.alpha = 0.0;
[self.contentView bringSubviewToFront:self.chatPanelView];
self.functionView.hidden = YES;
[self hideSubscriptionPanel];
[self showSettingView:NO];
[UIView animateWithDuration:0.2
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.chatPanelView.alpha = 1.0;
}
completion:nil];
} else {
[UIView animateWithDuration:0.18
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.chatPanelView.alpha = 0.0;
}
completion:^(BOOL finished) {
self.chatPanelView.hidden = YES;
}];
}
[self kb_updateKeyboardLayoutIfNeeded];
}
- (void)showSubscriptionPanel {
// 1) 访
if (![[KBFullAccessManager shared] hasFullAccess]) {
@@ -544,6 +617,10 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[[KBInputBufferManager shared] appendText:@" "];
break;
case KBKeyTypeReturn:
if (self.chatPanelVisible) {
[self kb_handleChatSendAction];
break;
}
[[KBBackspaceUndoManager shared] registerNonClearAction];
[self.textDocumentProxy insertText:@"\n"];
[self kb_clearCurrentWord];
@@ -575,11 +652,20 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
extra:extra
completion:nil];
if (index == 0) {
[self showChatPanel:NO];
[self showFunctionPanel:YES];
[self kb_clearCurrentWord];
return;
}
if (index == 1) {
[self showFunctionPanel:NO];
[self showChatPanel:YES];
// persona
[self kb_showPersonaAvatarOnBgImageView];
return;
}
[self showFunctionPanel:NO];
[self showChatPanel:NO];
}
- (void)keyBoardMainViewDidTapSettings:(KBKeyBoardMainView *)keyBoardMainView {
@@ -697,6 +783,546 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
[self showSubscriptionPanel];
}
#pragma mark - KBChatPanelViewDelegate
- (void)chatPanelView:(KBChatPanelView *)view didSendText:(NSString *)text {
NSString *trim =
[text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (trim.length == 0) {
return;
}
[self kb_sendChatText:trim];
}
- (void)chatPanelView:(KBChatPanelView *)view
didTapMessage:(KBChatMessage *)message {
if (message.audioFilePath.length == 0) {
return;
}
[self kb_playChatAudioAtPath:message.audioFilePath];
}
- (void)chatPanelView:(KBChatPanelView *)view didTapVoiceButtonForMessage:(KBChatMessage *)message {
if (!message) return;
// audioData
if (message.audioData && message.audioData.length > 0) {
[self kb_playChatAudioData:message.audioData];
return;
}
// audioFilePath
if (message.audioFilePath.length > 0) {
[self kb_playChatAudioAtPath:message.audioFilePath];
return;
}
NSLog(@"[Keyboard] 没有音频数据可播放");
}
- (void)chatPanelViewDidTapClose:(KBChatPanelView *)view {
// chatPanelView
[self.chatPanelView kb_reloadWithMessages:@[]];
if (self.chatAudioPlayer.isPlaying) {
[self.chatAudioPlayer stop];
}
self.chatAudioPlayer = nil;
[self showChatPanel:NO];
// persona
[self kb_hidePersonaAvatar];
}
#pragma mark - Chat Helpers
- (void)kb_handleChatSendAction {
if (!self.chatPanelVisible) {
return;
}
[[KBInputBufferManager shared] refreshFromProxyIfPossible:self.textDocumentProxy];
NSString *rawText = [KBInputBufferManager shared].liveText ?: @"";
NSString *trim =
[rawText stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (trim.length == 0) {
[KBHUD showInfo:KBLocalized(@"请输入内容")];
return;
}
[self kb_sendChatText:trim];
[self kb_clearHostInputForText:rawText];
}
- (void)kb_sendChatText:(NSString *)text {
if (text.length == 0) {
return;
}
NSLog(@"[KB] 发送消息: %@", text);
KBChatMessage *outgoing = [KBChatMessage userMessageWithText:text];
outgoing.avatarURL = [self kb_sharedUserAvatarURL];
[self.chatPanelView kb_addUserMessage:text];
[self kb_prefetchAvatarForMessage:outgoing];
if (![[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self.view]) {
[KBHUD showInfo:KBLocalized(@"请开启完全访问后使用")];
return;
}
// loading
[self.chatPanelView kb_addLoadingAssistantMessage];
//
[self kb_requestChatMessageWithContent:text];
}
- (void)kb_clearHostInputForText:(NSString *)text {
if (text.length == 0) {
return;
}
NSUInteger count = [self kb_composedCharacterCountForString:text];
for (NSUInteger i = 0; i < count; i++) {
[self.textDocumentProxy deleteBackward];
}
[[KBInputBufferManager shared] clearAllLiveText];
[self kb_clearCurrentWord];
}
- (NSUInteger)kb_composedCharacterCountForString:(NSString *)text {
if (text.length == 0) {
return 0;
}
__block NSUInteger count = 0;
[text enumerateSubstringsInRange:NSMakeRange(0, text.length)
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(__unused NSString *substring,
__unused NSRange substringRange,
__unused NSRange enclosingRange,
__unused BOOL *stop) {
count += 1;
}];
return count;
}
- (NSString *)kb_sharedUserAvatarURL {
NSUserDefaults *ud = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
NSString *url = [ud stringForKey:AppGroup_UserAvatarURL];
return url ?: @"";
}
- (void)kb_prefetchAvatarForMessage:(KBChatMessage *)message {
if (!message || message.avatarImage) {
return;
}
NSString *urlString = message.avatarURL ?: @"";
if (urlString.length == 0) {
return;
}
if (![[KBFullAccessManager shared] hasFullAccess]) {
return;
}
__weak typeof(self) weakSelf = self;
[[KBVM shared] downloadAvatarFromURL:urlString completion:^(UIImage *image, NSError *error) {
__strong typeof(weakSelf) self = weakSelf;
if (!self || !image) return;
message.avatarImage = image;
[self kb_reloadChatRowForMessage:message];
}];
}
- (void)kb_reloadChatRowForMessage:(KBChatMessage *)message {
//
//
//
}
- (void)kb_requestChatAudioForText:(NSString *)text {
NSString *mockPath = [self kb_mockChatAudioPath];
if (mockPath.length > 0) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.35 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
NSString *displayText = KBLocalized(@"语音回复");
KBChatMessage *incoming =
[KBChatMessage messageWithText:displayText
outgoing:NO
audioFilePath:mockPath];
incoming.displayName = KBLocalized(@"AI助手");
[self kb_appendChatMessage:incoming];
[self kb_playChatAudioAtPath:mockPath];
});
return;
}
NSDictionary *payload = @{@"message" : text ?: @""};
__weak typeof(self) weakSelf = self;
[[KBNetworkManager shared] POST:API_AI_TALK
jsonBody:payload
headers:nil
completion:^(NSDictionary *json, NSURLResponse *response,
NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) self = weakSelf;
if (!self) {
return;
}
if (error) {
NSString *tip = error.localizedDescription
?: KBLocalized(@"请求失败");
[KBHUD showInfo:tip];
return;
}
NSString *displayText =
[self kb_chatTextFromJSON:json];
NSString *audioURL =
[self kb_chatAudioURLFromJSON:json];
NSString *audioBase64 =
[self kb_chatAudioBase64FromJSON:json];
if (audioURL.length > 0) {
[self kb_downloadChatAudioFromURL:audioURL
displayText:displayText];
return;
}
if (audioBase64.length > 0) {
NSData *data = [[NSData alloc]
initWithBase64EncodedString:audioBase64
options:0];
if (data.length == 0) {
[KBHUD showInfo:KBLocalized(@"音频数据解析失败")];
return;
}
[self kb_handleChatAudioData:data
fileExtension:@"m4a"
displayText:displayText];
return;
}
[KBHUD showInfo:KBLocalized(@"未获取到音频文件")];
});
}];
}
#pragma mark - New Chat API (with typewriter effect and audio preload)
/// audioId
- (void)kb_requestChatMessageWithContent:(NSString *)content {
if (content.length == 0) {
[self.chatPanelView kb_removeLoadingAssistantMessage];
return;
}
NSInteger companionId = [[KBVM shared] selectedCompanionIdFromAppGroup];
NSLog(@"[KB] 请求聊天: companionId=%ld", (long)companionId);
__weak typeof(self) weakSelf = self;
[[KBVM shared] sendChatMessageWithContent:content
companionId:companionId
completion:^(KBChatResponse *response) {
__strong typeof(weakSelf) self = weakSelf;
if (!self) return;
if (!response.success) {
NSLog(@"[KB] ❌ 请求失败: %@", response.errorMessage);
[self.chatPanelView kb_removeLoadingAssistantMessage];
[KBHUD showInfo:response.errorMessage ?: KBLocalized(@"请求失败")];
return;
}
NSLog(@"[KB] ✅ 收到回复: %@", response.text);
if (response.text.length == 0) {
[self.chatPanelView kb_removeLoadingAssistantMessage];
[KBHUD showInfo:KBLocalized(@"未获取到回复内容")];
return;
}
// AI
NSLog(@"[KB] 准备添加 AI 消息");
[self.chatPanelView kb_addAssistantMessage:response.text audioId:response.audioId];
NSLog(@"[KB] AI 消息添加完成");
// audioId
if (response.audioId.length > 0) {
[self kb_preloadAudioWithAudioId:response.audioId];
}
}];
}
/// AppGroup persona companionId
- (NSInteger)kb_selectedCompanionId {
return [[KBVM shared] selectedCompanionIdFromAppGroup];
}
#pragma mark - Audio Preload
/// audioURL
- (void)kb_preloadAudioWithAudioId:(NSString *)audioId {
if (audioId.length == 0) return;
NSLog(@"[Keyboard] 开始预加载音频audioId: %@", audioId);
__weak typeof(self) weakSelf = self;
[[KBVM shared] pollAudioURLWithAudioId:audioId
maxRetries:10
interval:1.0
completion:^(KBAudioResponse *response) {
__strong typeof(weakSelf) self = weakSelf;
if (!self) return;
if (!response.success || response.audioURL.length == 0) {
NSLog(@"[Keyboard] ❌ 预加载音频 URL 获取失败: %@", response.errorMessage);
return;
}
NSLog(@"[Keyboard] ✅ 预加载音频 URL 获取成功");
//
[[KBVM shared] downloadAudioFromURL:response.audioURL
completion:^(KBAudioResponse *audioResponse) {
if (!audioResponse.success) {
NSLog(@"[Keyboard] ❌ 预加载音频下载失败: %@", audioResponse.errorMessage);
return;
}
// AI
[self.chatPanelView kb_updateLastAssistantMessageWithAudioData:audioResponse.audioData
duration:audioResponse.duration];
NSLog(@"[Keyboard] ✅ 预加载音频完成,音频时长: %.2f秒", audioResponse.duration);
}];
}];
}
- (void)kb_downloadChatAudioFromURL:(NSString *)audioURL
displayText:(NSString *)displayText {
__weak typeof(self) weakSelf = self;
[[KBVM shared] downloadAudioFromURL:audioURL completion:^(KBAudioResponse *response) {
__strong typeof(weakSelf) self = weakSelf;
if (!self) return;
if (!response.success) {
[KBHUD showInfo:response.errorMessage ?: KBLocalized(@"下载失败")];
return;
}
if (!response.audioData || response.audioData.length == 0) {
[KBHUD showInfo:KBLocalized(@"未获取到音频数据")];
return;
}
NSString *ext = @"m4a";
NSURL *url = [NSURL URLWithString:audioURL];
if (url.pathExtension.length > 0) {
ext = url.pathExtension;
}
[self kb_handleChatAudioData:response.audioData
fileExtension:ext
displayText:displayText];
}];
}
- (void)kb_handleChatAudioData:(NSData *)data
fileExtension:(NSString *)extension
displayText:(NSString *)displayText {
if (data.length == 0) {
[KBHUD showInfo:KBLocalized(@"音频数据为空")];
return;
}
NSString *ext = extension.length > 0 ? extension : @"m4a";
NSString *fileName = [NSString
stringWithFormat:@"kb_chat_%@.%@",
@((long long)([NSDate date].timeIntervalSince1970 *
1000)),
ext];
NSString *filePath =
[NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
if (![data writeToFile:filePath atomically:YES]) {
[KBHUD showInfo:KBLocalized(@"音频保存失败")];
return;
}
NSString *text = displayText.length > 0 ? displayText : KBLocalized(@"语音消息");
KBChatMessage *incoming =
[KBChatMessage messageWithText:text
outgoing:NO
audioFilePath:filePath];
incoming.displayName = KBLocalized(@"AI助手");
[self kb_appendChatMessage:incoming];
}
- (void)kb_appendChatMessage:(KBChatMessage *)message {
if (!message) {
return;
}
[self.chatMessages addObject:message];
if (self.chatMessages.count > kKBChatMessageLimit) {
NSUInteger overflow = self.chatMessages.count - kKBChatMessageLimit;
NSArray<KBChatMessage *> *removed =
[self.chatMessages subarrayWithRange:NSMakeRange(0, overflow)];
[self.chatMessages removeObjectsInRange:NSMakeRange(0, overflow)];
for (KBChatMessage *msg in removed) {
if (msg.audioFilePath.length > 0) {
NSString *tmpRoot = NSTemporaryDirectory();
if (tmpRoot.length > 0 &&
[msg.audioFilePath hasPrefix:tmpRoot]) {
[[NSFileManager defaultManager] removeItemAtPath:msg.audioFilePath
error:nil];
}
}
}
}
[self.chatPanelView kb_reloadWithMessages:self.chatMessages];
}
- (NSString *)kb_mockChatAudioPath {
NSString *path = [[NSBundle mainBundle] pathForResource:@"ai_test"
ofType:@"m4a"];
return path ?: @"";
}
- (NSString *)kb_chatTextFromJSON:(NSDictionary *)json {
NSDictionary *data = [self kb_chatDataDictionaryFromJSON:json];
NSString *text =
[self kb_stringValueInDict:data
keys:@[ @"text", @"message", @"content" ]];
if (text.length == 0) {
text = [self kb_stringValueInDict:json
keys:@[ @"text", @"message", @"content" ]];
}
return text ?: @"";
}
- (NSString *)kb_chatAudioURLFromJSON:(NSDictionary *)json {
NSDictionary *data = [self kb_chatDataDictionaryFromJSON:json];
NSArray<NSString *> *keys =
@[ @"audioUrl", @"audioURL", @"audio_url", @"url", @"fileUrl",
@"file_url", @"audioFileUrl", @"audio_file_url" ];
NSString *url = [self kb_stringValueInDict:data keys:keys];
if (url.length == 0) {
url = [self kb_stringValueInDict:json keys:keys];
}
return url ?: @"";
}
- (NSString *)kb_chatAudioBase64FromJSON:(NSDictionary *)json {
NSDictionary *data = [self kb_chatDataDictionaryFromJSON:json];
NSArray<NSString *> *keys =
@[ @"audioBase64", @"audio_base64", @"audioData", @"audio_data",
@"base64" ];
NSString *b64 = [self kb_stringValueInDict:data keys:keys];
if (b64.length == 0) {
b64 = [self kb_stringValueInDict:json keys:keys];
}
return b64 ?: @"";
}
- (NSDictionary *)kb_chatDataDictionaryFromJSON:(NSDictionary *)json {
if (![json isKindOfClass:[NSDictionary class]]) {
return @{};
}
id dataObj = json[@"data"] ?: json[@"result"] ?: json[@"response"];
if ([dataObj isKindOfClass:[NSDictionary class]]) {
return (NSDictionary *)dataObj;
}
return @{};
}
- (NSString *)kb_stringValueInDict:(NSDictionary *)dict
keys:(NSArray<NSString *> *)keys {
if (![dict isKindOfClass:[NSDictionary class]]) {
return @"";
}
for (NSString *key in keys) {
id value = dict[key];
if ([value isKindOfClass:[NSString class]] &&
((NSString *)value).length > 0) {
return (NSString *)value;
}
}
return @"";
}
- (void)kb_playChatAudioAtPath:(NSString *)path {
if (path.length == 0) {
return;
}
NSURL *url = [NSURL fileURLWithPath:path];
if (![NSFileManager.defaultManager fileExistsAtPath:path]) {
[KBHUD showInfo:KBLocalized(@"音频文件不存在")];
return;
}
if (self.chatAudioPlayer && self.chatAudioPlayer.isPlaying) {
NSURL *currentURL = self.chatAudioPlayer.url;
if ([currentURL isEqual:url]) {
[self.chatAudioPlayer stop];
self.chatAudioPlayer = nil;
return;
}
[self.chatAudioPlayer stop];
self.chatAudioPlayer = nil;
}
NSError *sessionError = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:@selector(setCategory:options:error:)]) {
[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionDuckOthers
error:&sessionError];
} else {
[session setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
}
[session setActive:YES error:nil];
NSError *playerError = nil;
AVAudioPlayer *player =
[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&playerError];
if (playerError || !player) {
[KBHUD showInfo:KBLocalized(@"音频播放失败")];
return;
}
self.chatAudioPlayer = player;
[player prepareToPlay];
[player play];
}
///
- (void)kb_playChatAudioData:(NSData *)audioData {
if (!audioData || audioData.length == 0) {
NSLog(@"[Keyboard] 音频数据为空");
return;
}
//
if (self.chatAudioPlayer && self.chatAudioPlayer.isPlaying) {
[self.chatAudioPlayer stop];
self.chatAudioPlayer = nil;
}
//
NSError *sessionError = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
if ([session respondsToSelector:@selector(setCategory:options:error:)]) {
[session setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionDuckOthers
error:&sessionError];
} else {
[session setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
}
[session setActive:YES error:nil];
//
NSError *playerError = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:audioData error:&playerError];
if (playerError || !player) {
NSLog(@"[Keyboard] 音频播放器初始化失败: %@", playerError.localizedDescription);
[KBHUD showInfo:KBLocalized(@"音频播放失败")];
return;
}
self.chatAudioPlayer = player;
player.volume = 1.0;
[player prepareToPlay];
[player play];
NSLog(@"[Keyboard] 开始播放音频,时长: %.2f秒", player.duration);
}
#pragma mark - KBKeyboardSubscriptionViewDelegate
- (void)subscriptionViewDidTapClose:(KBKeyboardSubscriptionView *)view {
@@ -750,6 +1376,22 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
return _settingView;
}
- (KBChatPanelView *)chatPanelView {
if (!_chatPanelView) {
NSLog(@"[Keyboard] ⚠️ chatPanelView 被创建!");
_chatPanelView = [[KBChatPanelView alloc] init];
_chatPanelView.delegate = self;
}
return _chatPanelView;
}
- (NSMutableArray<KBChatMessage *> *)chatMessages {
if (!_chatMessages) {
_chatMessages = [NSMutableArray array];
}
return _chatMessages;
}
- (KBKeyboardSubscriptionView *)subscriptionView {
if (!_subscriptionView) {
_subscriptionView = [[KBKeyboardSubscriptionView alloc] init];
@@ -760,6 +1402,108 @@ 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 {
@@ -940,6 +1684,9 @@ 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);
//
if ([self.keyBoardMainView respondsToSelector:@selector(kb_applyTheme)]) {
@@ -1150,12 +1897,36 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if (width <= 0) {
width = KB_DESIGN_WIDTH;
}
return kKBKeyboardBaseHeight * (width / KB_DESIGN_WIDTH);
CGFloat scale = width / KB_DESIGN_WIDTH;
CGFloat baseHeight = kKBKeyboardBaseHeight * scale;
CGFloat chatHeight = kKBChatPanelHeight * scale;
if (self.chatPanelVisible) {
return baseHeight + chatHeight;
}
return baseHeight;
}
- (CGFloat)kb_keyboardBaseHeightForWidth:(CGFloat)width {
if (width <= 0) {
width = KB_DESIGN_WIDTH;
}
CGFloat scale = width / KB_DESIGN_WIDTH;
return kKBKeyboardBaseHeight * scale;
}
- (CGFloat)kb_chatPanelHeightForWidth:(CGFloat)width {
if (width <= 0) {
width = KB_DESIGN_WIDTH;
}
CGFloat scale = width / KB_DESIGN_WIDTH;
return kKBChatPanelHeight * scale;
}
- (void)kb_updateKeyboardLayoutIfNeeded {
CGFloat portraitWidth = [self kb_portraitWidth];
CGFloat keyboardHeight = [self kb_keyboardHeightForWidth:portraitWidth];
CGFloat keyboardBaseHeight = [self kb_keyboardBaseHeightForWidth:portraitWidth];
CGFloat chatPanelHeight = [self kb_chatPanelHeightForWidth:portraitWidth];
CGFloat containerWidth = CGRectGetWidth(self.view.superview.bounds);
if (containerWidth <= 0) {
containerWidth = CGRectGetWidth(self.view.window.bounds);
@@ -1186,6 +1957,12 @@ static void KBSkinInstallNotificationCallback(CFNotificationCenterRef center,
if (self.contentHeightConstraint) {
[self.contentHeightConstraint setOffset:keyboardHeight];
}
if (self.keyBoardMainHeightConstraint) {
[self.keyBoardMainHeightConstraint setOffset:keyboardBaseHeight];
}
if (self.chatPanelHeightConstraint) {
[self.chatPanelHeightConstraint setOffset:chatPanelHeight];
}
[self.view layoutIfNeeded];
}

View File

@@ -0,0 +1,49 @@
//
// KBChatMessage.h
// CustomKeyboard
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBChatMessage : NSObject
@property (nonatomic, copy) NSString *text;
@property (nonatomic, assign) BOOL outgoing;
@property (nonatomic, copy, nullable) NSString *audioFilePath;
@property (nonatomic, copy, nullable) NSString *avatarURL;
@property (nonatomic, copy, nullable) NSString *displayName;
@property (nonatomic, strong, nullable) UIImage *avatarImage;
/// 是否处于加载状态
@property (nonatomic, assign) BOOL isLoading;
/// 是否完成(用于打字机效果)
@property (nonatomic, assign) BOOL isComplete;
/// 是否需要打字机效果
@property (nonatomic, assign) BOOL needsTypewriterEffect;
/// 音频 ID用于异步加载音频
@property (nonatomic, copy, nullable) NSString *audioId;
/// 音频数据(缓存)
@property (nonatomic, strong, nullable) NSData *audioData;
/// 音频时长(秒)
@property (nonatomic, assign) NSTimeInterval audioDuration;
+ (instancetype)messageWithText:(NSString *)text
outgoing:(BOOL)outgoing
audioFilePath:(nullable NSString *)audioFilePath;
/// 创建用户消息
+ (instancetype)userMessageWithText:(NSString *)text;
/// 创建 AI 消息(带 audioId
+ (instancetype)assistantMessageWithText:(NSString *)text
audioId:(nullable NSString *)audioId;
/// 创建加载中的 AI 消息
+ (instancetype)loadingAssistantMessage;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,55 @@
//
// KBChatMessage.m
// CustomKeyboard
//
#import "KBChatMessage.h"
@implementation KBChatMessage
+ (instancetype)messageWithText:(NSString *)text
outgoing:(BOOL)outgoing
audioFilePath:(NSString *)audioFilePath {
KBChatMessage *msg = [[KBChatMessage alloc] init];
msg.text = text ?: @"";
msg.outgoing = outgoing;
msg.audioFilePath = audioFilePath;
msg.isComplete = YES;
msg.isLoading = NO;
msg.needsTypewriterEffect = NO;
return msg;
}
+ (instancetype)userMessageWithText:(NSString *)text {
KBChatMessage *msg = [[KBChatMessage alloc] init];
msg.text = text ?: @"";
msg.outgoing = YES;
msg.isComplete = YES;
msg.isLoading = NO;
msg.needsTypewriterEffect = NO;
return msg;
}
+ (instancetype)assistantMessageWithText:(NSString *)text
audioId:(NSString *)audioId {
KBChatMessage *msg = [[KBChatMessage alloc] init];
msg.text = text ?: @"";
msg.outgoing = NO;
msg.audioId = audioId;
msg.isComplete = NO;
msg.isLoading = NO;
msg.needsTypewriterEffect = YES;
return msg;
}
+ (instancetype)loadingAssistantMessage {
KBChatMessage *msg = [[KBChatMessage alloc] init];
msg.text = @"";
msg.outgoing = NO;
msg.isComplete = NO;
msg.isLoading = YES;
msg.needsTypewriterEffect = NO;
return msg;
}
@end

View File

@@ -64,6 +64,15 @@ typedef void(^KBNetworkDataCompletion)(NSData *_Nullable data,
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
completion:(KBNetworkCompletion)completion;
/// POST multipart 上传文件(常用于语音/图片等文件)
- (nullable NSURLSessionDataTask *)uploadFile:(NSString *)path
fileURL:(NSURL *)fileURL
name:(NSString *)name
mimeType:(NSString *)mimeType
parameters:(nullable NSDictionary *)parameters
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
completion:(KBNetworkCompletion)completion;
@end
NS_ASSUME_NONNULL_END

View File

@@ -124,6 +124,84 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
return [self startAFJSONTaskWithRequest:req completion:completion];
}
- (NSURLSessionDataTask *)uploadFile:(NSString *)path
fileURL:(NSURL *)fileURL
name:(NSString *)name
mimeType:(NSString *)mimeType
parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *, NSString *> *)headers
completion:(KBNetworkCompletion)completion {
[self getSignWithParare:parameters];
if (![self ensureEnabled:completion]) return nil;
NSString *urlString = [self buildURLStringWithPath:path];
if (!urlString) { [self fail:KBNetworkErrorInvalidURL completion:completion]; return nil; }
if (!fileURL) {
if (completion) completion(nil, nil, [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorInvalidResponse userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid file")}]);
return nil;
}
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
serializer.timeoutInterval = self.timeout;
NSError *error = nil;
NSMutableURLRequest *req = [serializer multipartFormRequestWithMethod:@"POST"
URLString:urlString
parameters:parameters
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSString *safeName = (name.length > 0) ? name : @"file";
NSString *fileName = fileURL.lastPathComponent ?: @"upload.bin";
NSString *type = (mimeType.length > 0) ? mimeType : @"application/octet-stream";
[formData appendPartWithFileURL:fileURL name:safeName fileName:fileName mimeType:type error:nil];
} error:&error];
if (error || !req) {
if (completion) completion(nil, nil, error ?: [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid URL")}]);
return nil;
}
[self applyHeaders:headers toMutableRequest:req contentType:nil];
self.manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURLSessionUploadTask *task = [self.manager uploadTaskWithStreamedRequest:req progress:nil completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
if (completion) completion(nil, response, error);
return;
}
NSData *data = (NSData *)responseObject;
if (![data isKindOfClass:[NSData class]]) {
if (completion) completion(nil, response, [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorInvalidResponse userInfo:@{NSLocalizedDescriptionKey:KBLocalized(@"No data")}]);
return;
}
NSString *ct = nil;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
ct = ((NSHTTPURLResponse *)response).allHeaderFields[@"Content-Type"];
}
BOOL looksJSON = (ct && [[ct lowercaseString] containsString:@"json"]);
if (!looksJSON) {
const unsigned char *bytes = data.bytes;
NSUInteger len = data.length;
for (NSUInteger i = 0; !looksJSON && i < len; i++) {
unsigned char c = bytes[i];
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') continue;
looksJSON = (c == '{' || c == '[');
break;
}
}
if (looksJSON) {
NSError *jsonErr = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonErr];
if (jsonErr) {
if (completion) completion(nil, response, [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorDecodeFailed userInfo:@{NSLocalizedDescriptionKey:KBLocalized(@"Failed to parse JSON")}]);
return;
}
if (![json isKindOfClass:[NSDictionary class]]) {
if (completion) completion(nil, response, [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorInvalidResponse userInfo:@{NSLocalizedDescriptionKey:KBLocalized(@"Invalid response")}]);
return;
}
if (completion) completion((NSDictionary *)json, response, nil);
} else {
if (completion) completion(nil, response, [NSError errorWithDomain:KBNetworkErrorDomain code:KBNetworkErrorInvalidResponse userInfo:@{NSLocalizedDescriptionKey:KBLocalized(@"Invalid response")}]);
}
}];
[task resume];
return task;
}
- (NSURLSessionDataTask *)GETData:(NSString *)path
parameters:(NSDictionary *)parameters
headers:(NSDictionary<NSString *,NSString *> *)headers

Binary file not shown.

95
CustomKeyboard/VM/KBVM.h Normal file
View File

@@ -0,0 +1,95 @@
//
// KBVM.h
// CustomKeyboard
//
// 键盘扩展的 ViewModel封装网络请求逻辑
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 聊天响应模型
@interface KBChatResponse : NSObject
@property (nonatomic, copy, nullable) NSString *text;
@property (nonatomic, copy, nullable) NSString *audioId;
@property (nonatomic, copy, nullable) NSString *errorMessage;
@property (nonatomic, assign) BOOL success;
@end
/// 音频响应模型
@interface KBAudioResponse : NSObject
@property (nonatomic, copy, nullable) NSString *audioURL;
@property (nonatomic, strong, nullable) NSData *audioData;
@property (nonatomic, assign) NSTimeInterval duration;
@property (nonatomic, copy, nullable) NSString *errorMessage;
@property (nonatomic, assign) BOOL success;
@end
/// 聊天请求回调
typedef void(^KBChatCompletion)(KBChatResponse *response);
/// 音频 URL 回调
typedef void(^KBAudioURLCompletion)(KBAudioResponse *response);
/// 音频数据回调
typedef void(^KBAudioDataCompletion)(KBAudioResponse *response);
/// 头像回调
typedef void(^KBAvatarCompletion)(UIImage * _Nullable image, NSError * _Nullable error);
@interface KBVM : NSObject
+ (instancetype)shared;
#pragma mark - Chat API
/// 发送聊天消息
/// @param content 消息内容
/// @param companionId 人设 ID
/// @param completion 回调
- (void)sendChatMessageWithContent:(NSString *)content
companionId:(NSInteger)companionId
completion:(KBChatCompletion)completion;
#pragma mark - Audio API
/// 获取音频 URL单次请求
/// @param audioId 音频 ID
/// @param completion 回调
- (void)fetchAudioURLWithAudioId:(NSString *)audioId
completion:(KBAudioURLCompletion)completion;
/// 轮询获取音频 URL自动重试
/// @param audioId 音频 ID
/// @param maxRetries 最大重试次数
/// @param interval 重试间隔(秒)
/// @param completion 回调
- (void)pollAudioURLWithAudioId:(NSString *)audioId
maxRetries:(NSInteger)maxRetries
interval:(NSTimeInterval)interval
completion:(KBAudioURLCompletion)completion;
/// 下载音频数据
/// @param urlString 音频 URL
/// @param completion 回调
- (void)downloadAudioFromURL:(NSString *)urlString
completion:(KBAudioDataCompletion)completion;
#pragma mark - Avatar API
/// 下载头像图片
/// @param urlString 头像 URL
/// @param completion 回调
- (void)downloadAvatarFromURL:(NSString *)urlString
completion:(KBAvatarCompletion)completion;
#pragma mark - Helper
/// 从 AppGroup 获取选中的 persona companionId
- (NSInteger)selectedCompanionIdFromAppGroup;
/// 从 AppGroup 获取选中的 persona 信息
- (nullable NSDictionary *)selectedPersonaFromAppGroup;
@end
NS_ASSUME_NONNULL_END

334
CustomKeyboard/VM/KBVM.m Normal file
View File

@@ -0,0 +1,334 @@
//
// KBVM.m
// CustomKeyboard
//
#import "KBVM.h"
#import "KBNetworkManager.h"
#import "KBConfig.h"
#import <AVFoundation/AVFoundation.h>
@implementation KBChatResponse
@end
@implementation KBAudioResponse
@end
@interface KBVM ()
@property (nonatomic, strong) NSCache<NSString *, UIImage *> *avatarCache;
@end
@implementation KBVM
+ (instancetype)shared {
static KBVM *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[KBVM alloc] init];
});
return instance;
}
- (instancetype)init {
if (self = [super init]) {
_avatarCache = [[NSCache alloc] init];
_avatarCache.countLimit = 20;
}
return self;
}
#pragma mark - Chat API
- (void)sendChatMessageWithContent:(NSString *)content
companionId:(NSInteger)companionId
completion:(KBChatCompletion)completion {
if (content.length == 0) {
if (completion) {
KBChatResponse *response = [[KBChatResponse alloc] init];
response.success = NO;
response.errorMessage = @"内容为空";
completion(response);
}
return;
}
NSString *encodedContent = [content stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *path = [NSString stringWithFormat:@"%@?content=%@&companionId=%ld",
API_AI_CHAT_MESSAGE, encodedContent ?: @"", (long)companionId];
NSDictionary *params = @{
@"content": content ?: @"",
@"companionId": @(companionId)
};
[[KBNetworkManager shared] POST:path
jsonBody:params
headers:nil
completion:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
KBChatResponse *chatResponse = [[KBChatResponse alloc] init];
if (error) {
chatResponse.success = NO;
chatResponse.errorMessage = error.localizedDescription ?: @"请求失败";
if (completion) completion(chatResponse);
return;
}
//
chatResponse.text = [self p_parseTextFromJSON:json];
// audioId
chatResponse.audioId = [self p_parseAudioIdFromJSON:json];
chatResponse.success = (chatResponse.text.length > 0);
if (!chatResponse.success) {
chatResponse.errorMessage = @"未获取到回复内容";
}
if (completion) completion(chatResponse);
});
}];
}
#pragma mark - Audio API
- (void)fetchAudioURLWithAudioId:(NSString *)audioId
completion:(KBAudioURLCompletion)completion {
if (audioId.length == 0) {
if (completion) {
KBAudioResponse *response = [[KBAudioResponse alloc] init];
response.success = NO;
response.errorMessage = @"audioId 为空";
completion(response);
}
return;
}
NSString *path = [NSString stringWithFormat:@"/chat/audio/%@", audioId];
[[KBNetworkManager shared] GET:path
parameters:nil
headers:nil
completion:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
KBAudioResponse *audioResponse = [[KBAudioResponse alloc] init];
if (error) {
audioResponse.success = NO;
audioResponse.errorMessage = error.localizedDescription;
if (completion) completion(audioResponse);
return;
}
// audioURL
NSString *audioURL = [self p_parseAudioURLFromJSON:json];
audioResponse.audioURL = audioURL;
audioResponse.success = (audioURL.length > 0);
if (completion) completion(audioResponse);
});
}];
}
- (void)pollAudioURLWithAudioId:(NSString *)audioId
maxRetries:(NSInteger)maxRetries
interval:(NSTimeInterval)interval
completion:(KBAudioURLCompletion)completion {
[self p_pollAudioURLWithAudioId:audioId
retryCount:0
maxRetries:maxRetries
interval:interval
completion:completion];
}
- (void)p_pollAudioURLWithAudioId:(NSString *)audioId
retryCount:(NSInteger)retryCount
maxRetries:(NSInteger)maxRetries
interval:(NSTimeInterval)interval
completion:(KBAudioURLCompletion)completion {
[self fetchAudioURLWithAudioId:audioId completion:^(KBAudioResponse *response) {
if (response.success && response.audioURL.length > 0) {
// URL
if (completion) completion(response);
return;
}
//
if (retryCount < maxRetries - 1) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[self p_pollAudioURLWithAudioId:audioId
retryCount:retryCount + 1
maxRetries:maxRetries
interval:interval
completion:completion];
});
} else {
//
KBAudioResponse *failResponse = [[KBAudioResponse alloc] init];
failResponse.success = NO;
failResponse.errorMessage = [NSString stringWithFormat:@"轮询失败,已重试 %ld 次", (long)maxRetries];
if (completion) completion(failResponse);
}
}];
}
- (void)downloadAudioFromURL:(NSString *)urlString
completion:(KBAudioDataCompletion)completion {
if (urlString.length == 0) {
if (completion) {
KBAudioResponse *response = [[KBAudioResponse alloc] init];
response.success = NO;
response.errorMessage = @"URL 为空";
completion(response);
}
return;
}
[[KBNetworkManager shared] GETData:urlString
parameters:nil
headers:nil
completion:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
KBAudioResponse *audioResponse = [[KBAudioResponse alloc] init];
if (error || !data || data.length == 0) {
audioResponse.success = NO;
audioResponse.errorMessage = error.localizedDescription ?: @"下载失败";
if (completion) completion(audioResponse);
return;
}
audioResponse.audioData = data;
//
NSError *playerError = nil;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:data error:&playerError];
if (!playerError && player) {
audioResponse.duration = player.duration;
}
audioResponse.success = YES;
if (completion) completion(audioResponse);
});
}];
}
#pragma mark - Avatar API
- (void)downloadAvatarFromURL:(NSString *)urlString
completion:(KBAvatarCompletion)completion {
if (urlString.length == 0) {
if (completion) completion(nil, nil);
return;
}
//
UIImage *cached = [self.avatarCache objectForKey:urlString];
if (cached) {
if (completion) completion(cached, nil);
return;
}
[[KBNetworkManager shared] GETData:urlString
parameters:nil
headers:nil
completion:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error || data.length == 0) {
if (completion) completion(nil, error);
return;
}
UIImage *image = [UIImage imageWithData:data];
if (image) {
[self.avatarCache setObject:image forKey:urlString];
}
if (completion) completion(image, nil);
});
}];
}
#pragma mark - Helper
- (NSInteger)selectedCompanionIdFromAppGroup {
NSDictionary *persona = [self selectedPersonaFromAppGroup];
if (persona) {
id companionIdObj = persona[@"personaId"] ?: persona[@"companionId"] ?: persona[@"id"];
if ([companionIdObj respondsToSelector:@selector(integerValue)]) {
return [companionIdObj integerValue];
}
}
return 0;
}
- (nullable NSDictionary *)selectedPersonaFromAppGroup {
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
return [shared objectForKey:@"AppGroup_SelectedPersona"];
}
#pragma mark - Private Parse Methods
///
- (NSString *)p_parseTextFromJSON:(NSDictionary *)json {
if (![json isKindOfClass:[NSDictionary class]]) return @"";
id dataObj = json[@"data"];
if ([dataObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *data = (NSDictionary *)dataObj;
// aiResponse
NSArray *keys = @[@"aiResponse", @"content", @"text", @"message"];
for (NSString *key in keys) {
id value = data[key];
if ([value isKindOfClass:[NSString class]] && ((NSString *)value).length > 0) {
return (NSString *)value;
}
}
} else if ([dataObj isKindOfClass:[NSString class]]) {
return (NSString *)dataObj;
}
return @"";
}
/// audioId
- (NSString *)p_parseAudioIdFromJSON:(NSDictionary *)json {
if (![json isKindOfClass:[NSDictionary class]]) return nil;
id dataObj = json[@"data"];
if ([dataObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *data = (NSDictionary *)dataObj;
NSString *audioId = data[@"audioId"];
if ([audioId isKindOfClass:[NSString class]] && audioId.length > 0) {
return audioId;
}
}
//
NSArray *keys = @[@"audioId", @"audio_id"];
for (NSString *key in keys) {
id value = json[key];
if ([value isKindOfClass:[NSString class]] && ((NSString *)value).length > 0) {
return (NSString *)value;
}
}
return nil;
}
/// audioURL
- (NSString *)p_parseAudioURLFromJSON:(NSDictionary *)json {
if (![json isKindOfClass:[NSDictionary class]]) return nil;
id dataObj = json[@"data"];
if ([dataObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *data = (NSDictionary *)dataObj;
id audioUrlObj = data[@"audioUrl"] ?: data[@"url"];
if (audioUrlObj && ![audioUrlObj isKindOfClass:[NSNull class]] && [audioUrlObj isKindOfClass:[NSString class]]) {
return (NSString *)audioUrlObj;
}
}
return nil;
}
@end

View File

@@ -0,0 +1,40 @@
//
// KBChatAssistantCell.h
// CustomKeyboard
//
// AI 消息 Cell左侧显示带语音按钮和打字机效果
//
#import <UIKit/UIKit.h>
@class KBChatMessage;
@class KBChatAssistantCell;
NS_ASSUME_NONNULL_BEGIN
@protocol KBChatAssistantCellDelegate <NSObject>
@optional
/// 点击语音播放按钮
- (void)assistantCell:(KBChatAssistantCell *)cell didTapVoiceButtonForMessage:(KBChatMessage *)message;
@end
@interface KBChatAssistantCell : UITableViewCell
@property (nonatomic, weak) id<KBChatAssistantCellDelegate> delegate;
- (void)configureWithMessage:(KBChatMessage *)message;
/// 更新语音播放状态
- (void)updateVoicePlayingState:(BOOL)isPlaying;
/// 显示语音加载动画
- (void)showVoiceLoadingAnimation;
/// 隐藏语音加载动画
- (void)hideVoiceLoadingAnimation;
/// 停止打字机效果
- (void)stopTypewriterEffect;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,346 @@
//
// KBChatAssistantCell.m
// CustomKeyboard
//
// AI Cell
//
#import "KBChatAssistantCell.h"
#import "KBChatMessage.h"
#import "Masonry.h"
@interface KBChatAssistantCell ()
@property (nonatomic, strong) UIButton *voiceButton;
@property (nonatomic, strong) UILabel *durationLabel;
@property (nonatomic, strong) UIView *bubbleView;
@property (nonatomic, strong) UILabel *messageLabel;
@property (nonatomic, strong) UIActivityIndicatorView *voiceLoadingIndicator;
@property (nonatomic, strong) UIActivityIndicatorView *messageLoadingIndicator;
@property (nonatomic, strong) KBChatMessage *currentMessage;
///
@property (nonatomic, strong) NSTimer *typewriterTimer;
@property (nonatomic, copy) NSString *fullText;
@property (nonatomic, assign) NSInteger currentCharIndex;
@end
@implementation KBChatAssistantCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.contentView.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self setupUI];
}
return self;
}
- (void)setupUI {
[self.contentView addSubview:self.voiceButton];
[self.contentView addSubview:self.durationLabel];
[self.contentView addSubview:self.voiceLoadingIndicator];
[self.contentView addSubview:self.messageLoadingIndicator];
[self.contentView addSubview:self.bubbleView];
[self.bubbleView addSubview:self.messageLabel];
//
[self.voiceButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(12);
make.top.equalTo(self.contentView).offset(6);
make.width.height.mas_equalTo(20);
}];
//
[self.durationLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.voiceButton.mas_right).offset(4);
make.centerY.equalTo(self.voiceButton);
}];
//
[self.voiceLoadingIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.voiceButton);
}];
//
[self.messageLoadingIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(12);
make.top.equalTo(self.voiceButton);
}];
//
[self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.voiceButton.mas_bottom).offset(4);
make.bottom.equalTo(self.contentView).offset(-4);
make.left.equalTo(self.contentView).offset(12);
make.width.lessThanOrEqualTo(self.contentView).multipliedBy(0.7);
}];
//
[self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.bubbleView).offset(8);
make.bottom.equalTo(self.bubbleView).offset(-8);
make.left.equalTo(self.bubbleView).offset(12);
make.right.equalTo(self.bubbleView).offset(-12);
make.height.greaterThanOrEqualTo(@18);
}];
}
- (void)configureWithMessage:(KBChatMessage *)message {
NSLog(@"[KBChatAssistantCell] ========== configureWithMessage ==========");
NSLog(@"[KBChatAssistantCell] text: %@", message.text);
NSLog(@"[KBChatAssistantCell] outgoing: %d, isLoading: %d, isComplete: %d, needsTypewriter: %d",
message.outgoing, message.isLoading, message.isComplete, message.needsTypewriterEffect);
//
[self stopTypewriterEffect];
self.currentMessage = message;
// loading
if (message.isLoading) {
NSLog(@"[KBChatAssistantCell] 显示 loading 状态");
self.messageLabel.attributedText = nil;
self.messageLabel.text = @"";
self.bubbleView.hidden = YES;
self.voiceButton.hidden = YES;
self.durationLabel.hidden = YES;
[self.messageLoadingIndicator startAnimating];
return;
}
// loading
[self.messageLoadingIndicator stopAnimating];
self.bubbleView.hidden = NO;
//
BOOL hasAudio = (message.audioId.length > 0) || (message.audioData.length > 0);
self.voiceButton.hidden = !hasAudio;
self.durationLabel.hidden = !hasAudio;
NSLog(@"[KBChatAssistantCell] hasAudio: %d, audioId: %@", hasAudio, message.audioId);
//
if (message.audioDuration > 0) {
NSInteger seconds = (NSInteger)ceil(message.audioDuration);
self.durationLabel.text = [NSString stringWithFormat:@"%ld\"", (long)seconds];
} else {
self.durationLabel.text = @"";
}
//
if (message.needsTypewriterEffect && !message.isComplete && message.text.length > 0) {
NSLog(@"[KBChatAssistantCell] ✅ 启动打字机效果");
[self startTypewriterEffectWithText:message.text];
} else {
NSLog(@"[KBChatAssistantCell] 直接显示文本(不使用打字机)");
self.messageLabel.attributedText = nil;
self.messageLabel.text = message.text ?: @"";
}
}
#pragma mark - Typewriter Effect
- (void)startTypewriterEffectWithText:(NSString *)text {
if (text.length == 0) return;
self.fullText = text;
self.currentCharIndex = 0;
//
self.messageLabel.text = text;
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
//
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
self.typewriterTimer = [NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:@selector(typewriterTick)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.typewriterTimer forMode:NSRunLoopCommonModes];
[self typewriterTick];
});
}
- (void)typewriterTick {
NSString *text = self.fullText;
if (!text || text.length == 0) {
[self stopTypewriterEffect];
return;
}
if (self.currentCharIndex < text.length) {
self.currentCharIndex++;
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
UIColor *textColor = [UIColor whiteColor];
if (self.currentCharIndex > 0) {
[attributedText addAttribute:NSForegroundColorAttributeName
value:textColor
range:NSMakeRange(0, self.currentCharIndex)];
}
if (self.currentCharIndex < text.length) {
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(self.currentCharIndex, text.length - self.currentCharIndex)];
}
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
} else {
[self stopTypewriterEffect];
//
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor whiteColor]
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
//
if (self.currentMessage) {
self.currentMessage.isComplete = YES;
self.currentMessage.needsTypewriterEffect = NO;
}
}
}
- (void)stopTypewriterEffect {
if (self.typewriterTimer && self.typewriterTimer.isValid) {
[self.typewriterTimer invalidate];
}
self.typewriterTimer = nil;
self.currentCharIndex = 0;
self.fullText = nil;
}
#pragma mark - Voice Button
- (void)updateVoicePlayingState:(BOOL)isPlaying {
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = isPlaying ? [UIImage systemImageNamed:@"pause.circle.fill"] : [UIImage systemImageNamed:@"play.circle.fill"];
}
[self.voiceButton setImage:icon forState:UIControlStateNormal];
}
- (void)showVoiceLoadingAnimation {
[self.voiceButton setImage:nil forState:UIControlStateNormal];
[self.voiceLoadingIndicator startAnimating];
}
- (void)hideVoiceLoadingAnimation {
[self.voiceLoadingIndicator stopAnimating];
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = [UIImage systemImageNamed:@"play.circle.fill"];
}
[self.voiceButton setImage:icon forState:UIControlStateNormal];
}
- (void)voiceButtonTapped {
if ([self.delegate respondsToSelector:@selector(assistantCell:didTapVoiceButtonForMessage:)]) {
[self.delegate assistantCell:self didTapVoiceButtonForMessage:self.currentMessage];
}
}
#pragma mark - Reuse
- (void)prepareForReuse {
[super prepareForReuse];
[self stopTypewriterEffect];
self.messageLabel.text = @"";
self.messageLabel.attributedText = nil;
[self.messageLoadingIndicator stopAnimating];
[self.voiceLoadingIndicator stopAnimating];
}
- (void)dealloc {
[self stopTypewriterEffect];
}
#pragma mark - Lazy
- (UIButton *)voiceButton {
if (!_voiceButton) {
_voiceButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = [UIImage systemImageNamed:@"play.circle.fill"];
}
[_voiceButton setImage:icon forState:UIControlStateNormal];
_voiceButton.tintColor = [UIColor whiteColor];
[_voiceButton addTarget:self action:@selector(voiceButtonTapped) forControlEvents:UIControlEventTouchUpInside];
}
return _voiceButton;
}
- (UILabel *)durationLabel {
if (!_durationLabel) {
_durationLabel = [[UILabel alloc] init];
_durationLabel.font = [UIFont systemFontOfSize:11];
_durationLabel.textColor = [UIColor whiteColor];
}
return _durationLabel;
}
- (UIActivityIndicatorView *)voiceLoadingIndicator {
if (!_voiceLoadingIndicator) {
_voiceLoadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
_voiceLoadingIndicator.color = [UIColor whiteColor];
_voiceLoadingIndicator.hidesWhenStopped = YES;
}
return _voiceLoadingIndicator;
}
- (UIActivityIndicatorView *)messageLoadingIndicator {
if (!_messageLoadingIndicator) {
_messageLoadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
_messageLoadingIndicator.color = [UIColor whiteColor];
_messageLoadingIndicator.hidesWhenStopped = YES;
}
return _messageLoadingIndicator;
}
- (UIView *)bubbleView {
if (!_bubbleView) {
_bubbleView = [[UIView alloc] init];
_bubbleView.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.7];
_bubbleView.layer.cornerRadius = 12;
_bubbleView.layer.masksToBounds = YES;
}
return _bubbleView;
}
- (UILabel *)messageLabel {
if (!_messageLabel) {
_messageLabel = [[UILabel alloc] init];
_messageLabel.numberOfLines = 0;
_messageLabel.font = [UIFont systemFontOfSize:14];
_messageLabel.textColor = [UIColor whiteColor];
_messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
return _messageLabel;
}
@end

View File

@@ -0,0 +1,49 @@
//
// KBChatPanelView.h
// CustomKeyboard
//
#import <UIKit/UIKit.h>
@class KBChatPanelView, KBChatMessage;
NS_ASSUME_NONNULL_BEGIN
@protocol KBChatPanelViewDelegate <NSObject>
@optional
- (void)chatPanelView:(KBChatPanelView *)view didSendText:(NSString *)text;
- (void)chatPanelView:(KBChatPanelView *)view didTapMessage:(KBChatMessage *)message;
- (void)chatPanelViewDidTapClose:(KBChatPanelView *)view;
/// 点击语音播放按钮
- (void)chatPanelView:(KBChatPanelView *)view didTapVoiceButtonForMessage:(KBChatMessage *)message;
@end
@interface KBChatPanelView : UIView
@property (nonatomic, weak) id<KBChatPanelViewDelegate> delegate;
@property (nonatomic, strong, readonly) UITableView *tableView;
//- (void)kb_setBackgroundImage:(nullable UIImage *)image;
- (void)kb_reloadWithMessages:(NSArray<KBChatMessage *> *)messages;
/// 添加用户消息
- (void)kb_addUserMessage:(NSString *)text;
/// 添加 loading 状态的 AI 消息
- (void)kb_addLoadingAssistantMessage;
/// 移除 loading 状态的 AI 消息
- (void)kb_removeLoadingAssistantMessage;
/// 添加 AI 消息(带打字机效果)
- (void)kb_addAssistantMessage:(NSString *)text audioId:(nullable NSString *)audioId;
/// 更新最后一条 AI 消息的音频数据
- (void)kb_updateLastAssistantMessageWithAudioData:(NSData *)audioData duration:(NSTimeInterval)duration;
/// 滚动到底部
- (void)kb_scrollToBottom;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,347 @@
//
// KBChatPanelView.m
// CustomKeyboard
//
#import "KBChatPanelView.h"
#import "KBChatMessage.h"
#import "KBChatUserCell.h"
#import "KBChatAssistantCell.h"
#import "Masonry.h"
static NSString * const kUserCellIdentifier = @"KBChatUserCell";
static NSString * const kAssistantCellIdentifier = @"KBChatAssistantCell";
static const NSUInteger kKBChatMessageLimit = 10;
@interface KBChatPanelView () <UITableViewDataSource, UITableViewDelegate, KBChatAssistantCellDelegate>
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *closeButton;
@property (nonatomic, strong) UITableView *tableViewInternal;
@property (nonatomic, strong) NSMutableArray<KBChatMessage *> *messages;
@end
@implementation KBChatPanelView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
self.messages = [NSMutableArray array];
[self addSubview:self.headerView];
[self addSubview:self.tableViewInternal];
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(self.mas_top);
make.height.mas_equalTo(KBFit(36.0f));
}];
[self.tableViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.top.equalTo(self.headerView.mas_bottom).offset(4);
make.bottom.equalTo(self.mas_bottom).offset(-8);
}];
}
return self;
}
#pragma mark - Public
- (void)kb_reloadWithMessages:(NSArray<KBChatMessage *> *)messages {
NSLog(@"[Panel] ⚠️ kb_reloadWithMessages 被调用,传入 %lu 条消息", (unsigned long)messages.count);
[self.messages removeAllObjects];
if (messages.count > 0) {
[self.messages addObjectsFromArray:messages];
}
[self.tableViewInternal reloadData];
[self kb_scrollToBottom];
}
- (void)kb_addUserMessage:(NSString *)text {
if (text.length == 0) return;
NSLog(@"[Panel] 添加用户消息: %@,当前消息数: %lu", text, (unsigned long)self.messages.count);
KBChatMessage *msg = [KBChatMessage userMessageWithText:text];
[self kb_appendMessage:msg];
NSLog(@"[Panel] 添加后消息数: %lu", (unsigned long)self.messages.count);
}
- (void)kb_addLoadingAssistantMessage {
NSLog(@"[Panel] 添加 loading 消息,当前消息数: %lu", (unsigned long)self.messages.count);
KBChatMessage *msg = [KBChatMessage loadingAssistantMessage];
[self kb_appendMessage:msg];
NSLog(@"[Panel] 添加后消息数: %lu", (unsigned long)self.messages.count);
}
- (void)kb_removeLoadingAssistantMessage {
NSLog(@"[Panel] 移除 loading 消息,当前消息数: %lu", (unsigned long)self.messages.count);
for (NSInteger i = self.messages.count - 1; i >= 0; i--) {
KBChatMessage *msg = self.messages[i];
// AI outgoing == NO loading
if (!msg.outgoing && msg.isLoading) {
NSLog(@"[Panel] ✅ 找到 loading 消息,移除索引: %ld", (long)i);
[self.messages removeObjectAtIndex:i];
// 使 beginUpdates/endUpdates
[self.tableViewInternal beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
[self.tableViewInternal deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableViewInternal endUpdates];
NSLog(@"[Panel] 移除后消息数: %lu", (unsigned long)self.messages.count);
break;
}
}
}
- (void)kb_addAssistantMessage:(NSString *)text audioId:(NSString *)audioId {
NSLog(@"[Panel] ========== kb_addAssistantMessage ==========");
NSLog(@"[Panel] 当前消息数: %lu", (unsigned long)self.messages.count);
// loading
NSInteger loadingIndex = -1;
for (NSInteger i = self.messages.count - 1; i >= 0; i--) {
KBChatMessage *msg = self.messages[i];
if (!msg.outgoing && msg.isLoading) {
loadingIndex = i;
break;
}
}
// AI
KBChatMessage *msg = [KBChatMessage assistantMessageWithText:text audioId:audioId];
msg.displayName = KBLocalized(@"AI助手");
NSLog(@"[Panel] 创建 AI 消息needsTypewriter: %d", msg.needsTypewriterEffect);
// 使
[self.tableViewInternal beginUpdates];
if (loadingIndex >= 0) {
// loading
NSLog(@"[Panel] 移除 loading 索引: %ld", (long)loadingIndex);
[self.messages removeObjectAtIndex:loadingIndex];
NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForRow:loadingIndex inSection:0];
[self.tableViewInternal deleteRowsAtIndexPaths:@[deleteIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
// AI
NSInteger insertIndex = self.messages.count;
[self.messages addObject:msg];
NSLog(@"[Panel] 插入 AI 消息索引: %ld", (long)insertIndex);
NSIndexPath *insertIndexPath = [NSIndexPath indexPathForRow:insertIndex inSection:0];
[self.tableViewInternal insertRowsAtIndexPaths:@[insertIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableViewInternal endUpdates];
//
[self kb_scrollToBottom];
NSLog(@"[Panel] 添加后消息数: %lu", (unsigned long)self.messages.count);
}
- (void)kb_updateLastAssistantMessageWithAudioData:(NSData *)audioData duration:(NSTimeInterval)duration {
NSLog(@"[Panel] 更新音频数据duration: %.2f", duration);
for (NSInteger i = self.messages.count - 1; i >= 0; i--) {
KBChatMessage *msg = self.messages[i];
// AI outgoing == NO loading
if (!msg.outgoing && !msg.isLoading) {
msg.audioData = audioData;
msg.audioDuration = duration;
// Cell
if (duration > 0) {
msg.needsTypewriterEffect = NO;
msg.isComplete = YES;
}
NSLog(@"[Panel] ✅ 音频数据已更新");
break;
}
}
}
- (void)kb_scrollToBottom {
if (self.messages.count == 0) return;
NSLog(@"[Panel] 滚动到底部,消息数: %lu", (unsigned long)self.messages.count);
[self.tableViewInternal layoutIfNeeded];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.messages.count - 1 inSection:0];
[self.tableViewInternal scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom
animated:NO]; // NO
}
#pragma mark - Private
- (void)kb_appendMessage:(KBChatMessage *)message {
if (!message) return;
NSInteger oldCount = self.messages.count;
[self.messages addObject:message];
NSLog(@"[Panel] kb_appendMessage: oldCount=%ld, newCount=%lu", (long)oldCount, (unsigned long)self.messages.count);
//
if (self.messages.count > kKBChatMessageLimit) {
NSUInteger overflow = self.messages.count - kKBChatMessageLimit;
[self.messages removeObjectsInRange:NSMakeRange(0, overflow)];
NSLog(@"[Panel] 消息超限reloadData");
[self.tableViewInternal reloadData];
} else {
NSLog(@"[Panel] 插入新行: %ld", (long)oldCount);
[self.tableViewInternal beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:oldCount inSection:0];
[self.tableViewInternal insertRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableViewInternal endUpdates];
}
// dispatch_async
[self kb_scrollToBottom];
}
#pragma mark - Actions
- (void)kb_onTapClose {
if ([self.delegate respondsToSelector:@selector(chatPanelViewDidTapClose:)]) {
[self.delegate chatPanelViewDidTapClose:self];
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.messages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= self.messages.count) {
NSLog(@"[Panel] ❌ cellForRow 索引越界: %ld >= %lu", (long)indexPath.row, (unsigned long)self.messages.count);
return [[UITableViewCell alloc] init];
}
KBChatMessage *msg = self.messages[indexPath.row];
NSLog(@"[Panel] cellForRow[%ld]: outgoing=%d, isLoading=%d", (long)indexPath.row, msg.outgoing, msg.isLoading);
if (msg.outgoing) {
//
KBChatUserCell *cell = [tableView dequeueReusableCellWithIdentifier:kUserCellIdentifier forIndexPath:indexPath];
[cell configureWithMessage:msg];
return cell;
} else {
// AI
KBChatAssistantCell *cell = [tableView dequeueReusableCellWithIdentifier:kAssistantCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
[cell configureWithMessage:msg];
return cell;
}
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 60.0;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row >= self.messages.count) { return; }
KBChatMessage *msg = self.messages[indexPath.row];
if ([self.delegate respondsToSelector:@selector(chatPanelView:didTapMessage:)]) {
[self.delegate chatPanelView:self didTapMessage:msg];
}
}
#pragma mark - KBChatAssistantCellDelegate
- (void)assistantCell:(KBChatAssistantCell *)cell didTapVoiceButtonForMessage:(KBChatMessage *)message {
if ([self.delegate respondsToSelector:@selector(chatPanelView:didTapVoiceButtonForMessage:)]) {
[self.delegate chatPanelView:self didTapVoiceButtonForMessage:message];
}
}
#pragma mark - Lazy
- (UITableView *)tableViewInternal {
if (!_tableViewInternal) {
_tableViewInternal = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableViewInternal.backgroundColor = [UIColor clearColor];
_tableViewInternal.backgroundView = nil;
_tableViewInternal.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableViewInternal.dataSource = self;
_tableViewInternal.delegate = self;
_tableViewInternal.estimatedRowHeight = 60.0;
_tableViewInternal.rowHeight = UITableViewAutomaticDimension;
// Cell
[_tableViewInternal registerClass:KBChatUserCell.class forCellReuseIdentifier:kUserCellIdentifier];
[_tableViewInternal registerClass:KBChatAssistantCell.class forCellReuseIdentifier:kAssistantCellIdentifier];
if (@available(iOS 11.0, *)) {
_tableViewInternal.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
}
return _tableViewInternal;
}
- (UIView *)headerView {
if (!_headerView) {
_headerView = [[UIView alloc] init];
_headerView.backgroundColor = [UIColor clearColor];
[_headerView addSubview:self.titleLabel];
[_headerView addSubview:self.closeButton];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_headerView.mas_left).offset(12);
make.centerY.equalTo(_headerView);
}];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_headerView.mas_right).offset(-12);
make.centerY.equalTo(_headerView);
make.width.height.mas_equalTo(KBFit(24.0f));
}];
}
return _headerView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [[UILabel alloc] init];
_titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium];
_titleLabel.textColor =
[UIColor kb_dynamicColorWithLightColor:[UIColor colorWithHex:0x1B1F1A]
darkColor:[UIColor whiteColor]];
_titleLabel.text = KBLocalized(@"AI对话");
}
return _titleLabel;
}
- (UIButton *)closeButton {
if (!_closeButton) {
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *icon = [UIImage imageNamed:@"close_icon"];
[_closeButton setImage:icon forState:UIControlStateNormal];
_closeButton.backgroundColor = [UIColor clearColor];
[_closeButton addTarget:self
action:@selector(kb_onTapClose)
forControlEvents:UIControlEventTouchUpInside];
}
return _closeButton;
}
#pragma mark - Expose
- (UITableView *)tableView { return self.tableViewInternal; }
@end

View File

@@ -0,0 +1,19 @@
//
// KBChatUserCell.h
// CustomKeyboard
//
// 用户消息 Cell右侧显示
//
#import <UIKit/UIKit.h>
@class KBChatMessage;
NS_ASSUME_NONNULL_BEGIN
@interface KBChatUserCell : UITableViewCell
- (void)configureWithMessage:(KBChatMessage *)message;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,85 @@
//
// KBChatUserCell.m
// CustomKeyboard
//
// Cell
//
#import "KBChatUserCell.h"
#import "KBChatMessage.h"
#import "Masonry.h"
@interface KBChatUserCell ()
@property (nonatomic, strong) UIView *bubbleView;
@property (nonatomic, strong) UILabel *messageLabel;
@end
@implementation KBChatUserCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.contentView.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self setupUI];
}
return self;
}
- (void)setupUI {
[self.contentView addSubview:self.bubbleView];
[self.bubbleView addSubview:self.messageLabel];
[self.bubbleView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView).offset(4);
make.bottom.equalTo(self.contentView).offset(-4);
make.right.equalTo(self.contentView).offset(-12);
make.width.lessThanOrEqualTo(self.contentView).multipliedBy(0.7);
make.height.greaterThanOrEqualTo(@36);
}];
[self.messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.bubbleView).offset(8);
make.bottom.equalTo(self.bubbleView).offset(-8);
make.left.equalTo(self.bubbleView).offset(12);
make.right.equalTo(self.bubbleView).offset(-12);
}];
}
- (void)configureWithMessage:(KBChatMessage *)message {
self.messageLabel.text = message.text ?: @"";
}
- (void)prepareForReuse {
[super prepareForReuse];
self.messageLabel.text = @"";
}
#pragma mark - Lazy
- (UIView *)bubbleView {
if (!_bubbleView) {
_bubbleView = [[UIView alloc] init];
_bubbleView.backgroundColor = [UIColor colorWithHex:0x02BEAC];
_bubbleView.layer.cornerRadius = 12;
_bubbleView.layer.masksToBounds = YES;
}
return _bubbleView;
}
- (UILabel *)messageLabel {
if (!_messageLabel) {
_messageLabel = [[UILabel alloc] init];
_messageLabel.numberOfLines = 0;
_messageLabel.font = [UIFont systemFontOfSize:14];
_messageLabel.textColor = [UIColor whiteColor];
_messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
}
return _messageLabel;
}
@end

View File

@@ -0,0 +1,38 @@
//
// KBChatMessageCell.h
// CustomKeyboard
//
#import <UIKit/UIKit.h>
@class KBChatMessage;
@class KBChatMessageCell;
NS_ASSUME_NONNULL_BEGIN
@protocol KBChatMessageCellDelegate <NSObject>
@optional
/// 点击语音播放按钮
- (void)chatMessageCell:(KBChatMessageCell *)cell didTapVoiceButtonForMessage:(KBChatMessage *)message;
@end
@interface KBChatMessageCell : UITableViewCell
@property (nonatomic, weak) id<KBChatMessageCellDelegate> delegate;
- (void)kb_configureWithMessage:(KBChatMessage *)message;
/// 更新语音播放状态
- (void)kb_updateVoicePlayingState:(BOOL)isPlaying;
/// 显示语音加载动画
- (void)kb_showVoiceLoadingAnimation;
/// 隐藏语音加载动画
- (void)kb_hideVoiceLoadingAnimation;
/// 停止打字机效果
- (void)kb_stopTypewriterEffect;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,495 @@
//
// KBChatMessageCell.m
// CustomKeyboard
//
#import "KBChatMessageCell.h"
#import "KBChatMessage.h"
#import "Masonry.h"
@interface KBChatMessageCell ()
@property (nonatomic, strong) UIImageView *avatarView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UIView *bubbleView;
@property (nonatomic, strong) UILabel *messageLabel;
@property (nonatomic, strong) UIImageView *audioIconView;
@property (nonatomic, strong) UILabel *audioLabel;
///
@property (nonatomic, strong) UIButton *voiceButton;
///
@property (nonatomic, strong) UILabel *durationLabel;
///
@property (nonatomic, strong) UIActivityIndicatorView *voiceLoadingIndicator;
/// AI loading
@property (nonatomic, strong) UIActivityIndicatorView *messageLoadingIndicator;
///
@property (nonatomic, strong) KBChatMessage *currentMessage;
///
@property (nonatomic, strong) NSTimer *typewriterTimer;
@property (nonatomic, copy) NSString *fullText;
@property (nonatomic, assign) NSInteger currentCharIndex;
@end
@implementation KBChatMessageCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.backgroundColor = [UIColor clearColor];
self.contentView.backgroundColor = [UIColor clearColor];
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self.contentView addSubview:self.avatarView];
[self.contentView addSubview:self.nameLabel];
[self.contentView addSubview:self.voiceButton];
[self.contentView addSubview:self.durationLabel];
[self.contentView addSubview:self.voiceLoadingIndicator];
[self.contentView addSubview:self.messageLoadingIndicator];
[self.contentView addSubview:self.bubbleView];
[self.bubbleView addSubview:self.messageLabel];
[self.bubbleView addSubview:self.audioIconView];
[self.bubbleView addSubview:self.audioLabel];
}
return self;
}
- (void)kb_configureWithMessage:(KBChatMessage *)message {
//
[self kb_stopTypewriterEffect];
self.currentMessage = message;
BOOL outgoing = message.outgoing;
BOOL audioMessage = (!outgoing && message.audioFilePath.length > 0);
UIColor *bubbleColor = outgoing ? [UIColor colorWithHex:0x02BEAC] : [UIColor colorWithWhite:1 alpha:0.95];
UIColor *incomingTextColor =
[UIColor kb_dynamicColorWithLightColor:[UIColor colorWithHex:0x1B1F1A]
darkColor:[UIColor whiteColor]];
UIColor *textColor = outgoing ? [UIColor whiteColor] : incomingTextColor;
UIColor *nameColor =
[UIColor kb_dynamicColorWithLightColor:[UIColor colorWithHex:0x6B6F7A]
darkColor:[UIColor colorWithHex:0xC7CBD4]];
self.bubbleView.backgroundColor = bubbleColor;
self.messageLabel.textColor = textColor;
self.audioLabel.textColor = textColor;
self.audioIconView.tintColor = textColor;
self.audioLabel.text =
(message.text.length > 0) ? message.text : KBLocalized(@"语音回复");
self.messageLabel.hidden = audioMessage;
self.audioIconView.hidden = !audioMessage;
self.audioLabel.hidden = !audioMessage;
UIImage *avatarImage = message.avatarImage;
if (!avatarImage) {
avatarImage = [self kb_defaultAvatarImage];
}
self.avatarView.image = avatarImage;
self.avatarView.backgroundColor =
avatarImage ? [UIColor clearColor] : [UIColor colorWithWhite:0.9 alpha:1.0];
self.nameLabel.hidden = outgoing;
self.nameLabel.textColor = nameColor;
self.nameLabel.text =
(message.displayName.length > 0) ? message.displayName : KBLocalized(@"AI助手");
// loading
if (message.isLoading && !outgoing) {
self.bubbleView.hidden = YES;
self.voiceButton.hidden = YES;
self.durationLabel.hidden = YES;
[self.messageLoadingIndicator startAnimating];
[self kb_layoutForOutgoing:outgoing audioMessage:NO];
return;
}
// loading
[self.messageLoadingIndicator stopAnimating];
self.bubbleView.hidden = NO;
// AI audioId audioData
BOOL hasAudio = (!outgoing) && (message.audioId.length > 0 || message.audioData.length > 0);
self.voiceButton.hidden = !hasAudio;
self.durationLabel.hidden = !hasAudio;
if (hasAudio && message.audioDuration > 0) {
NSInteger seconds = (NSInteger)ceil(message.audioDuration);
self.durationLabel.text = [NSString stringWithFormat:@"%ld\"", (long)seconds];
} else {
self.durationLabel.text = @"";
}
//
if (!outgoing && message.needsTypewriterEffect && !message.isComplete && message.text.length > 0) {
[self kb_startTypewriterEffectWithText:message.text];
} else {
self.messageLabel.attributedText = nil;
self.messageLabel.text = message.text ?: @"";
}
[self kb_layoutForOutgoing:outgoing audioMessage:audioMessage];
}
- (void)kb_layoutForOutgoing:(BOOL)outgoing audioMessage:(BOOL)audioMessage {
CGFloat avatarSize = 28.0;
[self.avatarView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(avatarSize);
make.top.equalTo(self.contentView.mas_top).offset(6);
if (outgoing) {
make.right.equalTo(self.contentView.mas_right).offset(-8);
} else {
make.left.equalTo(self.contentView.mas_left).offset(8);
}
}];
if (outgoing) {
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentView.mas_top).offset(0);
make.left.equalTo(self.contentView.mas_left);
}];
//
[self.voiceButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(0);
make.left.top.equalTo(self.contentView);
}];
[self.durationLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(0);
make.left.top.equalTo(self.contentView);
}];
} else {
[self.nameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.avatarView.mas_right).offset(6);
make.top.equalTo(self.contentView.mas_top).offset(2);
make.right.lessThanOrEqualTo(self.contentView.mas_right).offset(-12);
}];
// AI
[self.voiceButton mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.avatarView.mas_right).offset(6);
make.top.equalTo(self.nameLabel.mas_bottom).offset(4);
make.width.height.mas_equalTo(20);
}];
[self.durationLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.voiceButton.mas_right).offset(4);
make.centerY.equalTo(self.voiceButton);
}];
[self.voiceLoadingIndicator mas_remakeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.voiceButton);
}];
}
//
[self.messageLoadingIndicator mas_remakeConstraints:^(MASConstraintMaker *make) {
if (outgoing) {
make.right.equalTo(self.avatarView.mas_left).offset(-10);
} else {
make.left.equalTo(self.avatarView.mas_right).offset(10);
}
make.top.equalTo(self.nameLabel.mas_bottom).offset(8);
}];
[self.bubbleView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.lessThanOrEqualTo(self.contentView.mas_width).multipliedBy(0.65);
if (outgoing) {
make.top.equalTo(self.contentView.mas_top).offset(6);
make.bottom.equalTo(self.contentView.mas_bottom).offset(-6);
make.right.equalTo(self.avatarView.mas_left).offset(-6);
} else {
// AI
make.top.equalTo(self.voiceButton.mas_bottom).offset(4);
make.bottom.equalTo(self.contentView.mas_bottom).offset(-6);
make.left.equalTo(self.avatarView.mas_right).offset(6);
make.right.lessThanOrEqualTo(self.contentView.mas_right).offset(-12);
}
}];
if (audioMessage) {
[self.messageLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(0);
make.left.equalTo(self.bubbleView.mas_left);
make.top.equalTo(self.bubbleView.mas_top);
}];
[self.audioIconView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.bubbleView.mas_left).offset(10);
make.centerY.equalTo(self.bubbleView);
make.width.height.mas_equalTo(16);
}];
[self.audioLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.audioIconView.mas_right).offset(6);
make.centerY.equalTo(self.bubbleView);
make.right.equalTo(self.bubbleView.mas_right).offset(-10);
make.top.greaterThanOrEqualTo(self.bubbleView.mas_top).offset(8);
make.bottom.lessThanOrEqualTo(self.bubbleView.mas_bottom).offset(-8);
}];
} else {
[self.audioIconView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(0);
make.left.equalTo(self.bubbleView.mas_left);
make.top.equalTo(self.bubbleView.mas_top);
}];
[self.audioLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.width.height.mas_equalTo(0);
make.left.equalTo(self.audioIconView.mas_right);
make.top.equalTo(self.bubbleView.mas_top);
}];
[self.messageLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.bubbleView).insets(UIEdgeInsetsMake(8, 10, 8, 10));
}];
}
}
#pragma mark - Typewriter Effect
- (void)kb_startTypewriterEffectWithText:(NSString *)text {
if (text.length == 0) return;
self.fullText = text;
self.currentCharIndex = 0;
//
self.messageLabel.text = text;
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
//
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
self.typewriterTimer = [NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:@selector(kb_typewriterTick)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.typewriterTimer forMode:NSRunLoopCommonModes];
[self kb_typewriterTick];
});
}
- (void)kb_typewriterTick {
NSString *text = self.fullText;
if (!text || text.length == 0) {
[self kb_stopTypewriterEffect];
return;
}
if (self.currentCharIndex < text.length) {
self.currentCharIndex++;
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
UIColor *textColor = self.messageLabel.textColor ?: [UIColor blackColor];
if (self.currentCharIndex > 0) {
[attributedText addAttribute:NSForegroundColorAttributeName
value:textColor
range:NSMakeRange(0, self.currentCharIndex)];
}
if (self.currentCharIndex < text.length) {
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor clearColor]
range:NSMakeRange(self.currentCharIndex, text.length - self.currentCharIndex)];
}
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
} else {
[self kb_stopTypewriterEffect];
//
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
UIColor *textColor = self.messageLabel.textColor ?: [UIColor blackColor];
[attributedText addAttribute:NSForegroundColorAttributeName
value:textColor
range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName
value:self.messageLabel.font
range:NSMakeRange(0, text.length)];
self.messageLabel.attributedText = attributedText;
//
if (self.currentMessage) {
self.currentMessage.isComplete = YES;
self.currentMessage.needsTypewriterEffect = NO;
}
}
}
- (void)kb_stopTypewriterEffect {
if (self.typewriterTimer && self.typewriterTimer.isValid) {
[self.typewriterTimer invalidate];
}
self.typewriterTimer = nil;
self.currentCharIndex = 0;
self.fullText = nil;
}
#pragma mark - Voice Button
- (void)kb_updateVoicePlayingState:(BOOL)isPlaying {
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = isPlaying ? [UIImage systemImageNamed:@"pause.circle.fill"] : [UIImage systemImageNamed:@"play.circle.fill"];
}
[self.voiceButton setImage:icon forState:UIControlStateNormal];
}
- (void)kb_showVoiceLoadingAnimation {
[self.voiceButton setImage:nil forState:UIControlStateNormal];
[self.voiceLoadingIndicator startAnimating];
}
- (void)kb_hideVoiceLoadingAnimation {
[self.voiceLoadingIndicator stopAnimating];
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = [UIImage systemImageNamed:@"play.circle.fill"];
}
[self.voiceButton setImage:icon forState:UIControlStateNormal];
}
- (void)kb_onVoiceButtonTapped {
if ([self.delegate respondsToSelector:@selector(chatMessageCell:didTapVoiceButtonForMessage:)]) {
[self.delegate chatMessageCell:self didTapVoiceButtonForMessage:self.currentMessage];
}
}
#pragma mark - Reuse
- (void)prepareForReuse {
[super prepareForReuse];
[self kb_stopTypewriterEffect];
self.messageLabel.text = @"";
self.messageLabel.attributedText = nil;
[self.messageLoadingIndicator stopAnimating];
[self.voiceLoadingIndicator stopAnimating];
}
- (void)dealloc {
[self kb_stopTypewriterEffect];
}
#pragma mark - Lazy
- (UIImageView *)avatarView {
if (!_avatarView) {
_avatarView = [[UIImageView alloc] init];
_avatarView.contentMode = UIViewContentModeScaleAspectFill;
_avatarView.layer.cornerRadius = 14;
_avatarView.layer.masksToBounds = YES;
_avatarView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
_avatarView.tintColor =
[UIColor kb_dynamicColorWithLightColor:[UIColor colorWithHex:0xB9BDC8]
darkColor:[UIColor colorWithHex:0x6B6F7A]];
}
return _avatarView;
}
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
_nameLabel.font = [UIFont systemFontOfSize:11];
_nameLabel.textColor = [UIColor colorWithHex:0x6B6F7A];
_nameLabel.numberOfLines = 1;
}
return _nameLabel;
}
- (UIView *)bubbleView {
if (!_bubbleView) {
_bubbleView = [[UIView alloc] init];
_bubbleView.layer.cornerRadius = 12;
_bubbleView.layer.masksToBounds = YES;
}
return _bubbleView;
}
- (UILabel *)messageLabel {
if (!_messageLabel) {
_messageLabel = [[UILabel alloc] init];
_messageLabel.font = [UIFont systemFontOfSize:14];
_messageLabel.numberOfLines = 0;
}
return _messageLabel;
}
- (UIImageView *)audioIconView {
if (!_audioIconView) {
_audioIconView = [[UIImageView alloc] init];
_audioIconView.contentMode = UIViewContentModeScaleAspectFit;
_audioIconView.tintColor = [UIColor colorWithHex:0x1B1F1A];
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = [UIImage systemImageNamed:@"waveform"];
}
_audioIconView.image = icon;
}
return _audioIconView;
}
- (UILabel *)audioLabel {
if (!_audioLabel) {
_audioLabel = [[UILabel alloc] init];
_audioLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
_audioLabel.numberOfLines = 1;
}
return _audioLabel;
}
- (UIButton *)voiceButton {
if (!_voiceButton) {
_voiceButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *icon = nil;
if (@available(iOS 13.0, *)) {
icon = [UIImage systemImageNamed:@"play.circle.fill"];
}
[_voiceButton setImage:icon forState:UIControlStateNormal];
_voiceButton.tintColor = [UIColor whiteColor];
[_voiceButton addTarget:self action:@selector(kb_onVoiceButtonTapped) forControlEvents:UIControlEventTouchUpInside];
}
return _voiceButton;
}
- (UILabel *)durationLabel {
if (!_durationLabel) {
_durationLabel = [[UILabel alloc] init];
_durationLabel.font = [UIFont systemFontOfSize:11];
_durationLabel.textColor = [UIColor whiteColor];
}
return _durationLabel;
}
- (UIActivityIndicatorView *)voiceLoadingIndicator {
if (!_voiceLoadingIndicator) {
_voiceLoadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
_voiceLoadingIndicator.color = [UIColor whiteColor];
_voiceLoadingIndicator.hidesWhenStopped = YES;
}
return _voiceLoadingIndicator;
}
- (UIActivityIndicatorView *)messageLoadingIndicator {
if (!_messageLoadingIndicator) {
_messageLoadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
_messageLoadingIndicator.color = [UIColor whiteColor];
_messageLoadingIndicator.hidesWhenStopped = YES;
}
return _messageLoadingIndicator;
}
- (UIImage *)kb_defaultAvatarImage {
if (@available(iOS 13.0, *)) {
return [UIImage systemImageNamed:@"person.circle.fill"];
}
return nil;
}
@end

View File

@@ -360,7 +360,6 @@ static inline NSString *KBTrimRight(NSString *s) {
contextAfter = proxy.documentContextAfterInput ?: @"";
}
}
NSString *contextBefore = proxy.documentContextBeforeInput ?: @"";
while (contextBefore.length > 0) {
for (NSUInteger i = 0; i < contextBefore.length; i++) {
@@ -372,6 +371,16 @@ static inline NSString *KBTrimRight(NSString *s) {
if (rawText.length > 0) {
[proxy insertText:rawText];
}
NSMutableDictionary *extra = [NSMutableDictionary dictionary];
extra[@"send_text"] = rawText ? rawText : @"";
extra[@"index"] = index ? rawText : 0;
[[KBMaiPointReporter sharedReporter]
reportClickWithEventName:@"send_stream_text_action"
pageId:@"keyboard_StreamTextView"
elementId:@"handle_label"
extra:extra.copy
completion:nil];
[[KBInputBufferManager shared] resetWithText:rawText ?: @""];
}
}

View File

@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, weak, nullable) id<KBToolBarDelegate> delegate;
/// 左侧按钮的标题(数量由数组决定)。默认值:@[@"AI"]。
/// 左侧按钮的标题(数量由数组决定)。默认值:@[@"AI", @"语音"]。
@property (nonatomic, copy) NSArray<NSString *> *leftButtonTitles;
/// 暴露按钮以便外部定制(只读;首次访问时懒加载创建)

View File

@@ -26,11 +26,12 @@ static NSString * const kKBAIKeyIdentifier = @"ai";
static NSString * const kKBUndoKeyIdentifier = @"key_revoke";
static const CGFloat kKBAIButtonWidth = 40;
static const CGFloat kKBAIButtonHeight = 40;
static const NSInteger kKBVoiceButtonIndex = 1;
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
_leftButtonTitles = @[@"AI"]; //
_leftButtonTitles = @[@"AI", KBLocalized(@"语音")]; //
[self setupUI];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(kb_undoStateChanged)
@@ -68,6 +69,7 @@ static const CGFloat kKBAIButtonHeight = 40;
}
}];
[self kb_updateAIButtonAppearance];
[self kb_updateVoiceButtonAppearance];
}
#pragma mark -
@@ -171,6 +173,7 @@ static const CGFloat kKBAIButtonHeight = 40;
- (void)kb_applyTheme {
[self kb_updateAIButtonAppearance];
[self kb_updateVoiceButtonAppearance];
[self kb_updateUndoButtonAppearance];
}
@@ -208,6 +211,16 @@ static const CGFloat kKBAIButtonHeight = 40;
}
}
- (void)kb_updateVoiceButtonAppearance {
UIButton *voiceButton = [self kb_voiceButton];
if (!voiceButton) { return; }
voiceButton.backgroundColor = [UIColor colorWithHex:0xE53935];
[voiceButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
voiceButton.layer.cornerRadius = 16;
voiceButton.layer.masksToBounds = YES;
}
- (void)kb_updateUndoButtonAppearance {
if (!self.undoButtonInternal) { return; }
@@ -306,6 +319,11 @@ static const CGFloat kKBAIButtonHeight = 40;
return self.leftButtonsInternal[0];
}
- (UIButton *)kb_voiceButton {
if (self.leftButtonsInternal.count <= kKBVoiceButtonIndex) { return nil; }
return self.leftButtonsInternal[kKBVoiceButtonIndex];
}
#pragma mark - Globe (Input Mode Switch)
// 宿

View File

@@ -29,6 +29,7 @@ target 'CustomKeyboard' do
use_frameworks!
pod 'AFNetworking','4.0.1'
pod 'SDWebImage', '5.21.1'
pod 'Masonry', '1.1.0'
pod 'MBProgressHUD', '1.2.0'

View File

@@ -96,6 +96,6 @@ SPEC CHECKSUMS:
SDWebImage: f29024626962457f3470184232766516dee8dfea
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
PODFILE CHECKSUM: 3b9d37a9d2c323afb33b6389f3c70184f53ea313
PODFILE CHECKSUM: 890d1710715c017d7364a19c871e9bdf0d685fbf
COCOAPODS: 1.16.2

2
Pods/Manifest.lock generated
View File

@@ -96,6 +96,6 @@ SPEC CHECKSUMS:
SDWebImage: f29024626962457f3470184232766516dee8dfea
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
PODFILE CHECKSUM: 3b9d37a9d2c323afb33b6389f3c70184f53ea313
PODFILE CHECKSUM: 890d1710715c017d7364a19c871e9bdf0d685fbf
COCOAPODS: 1.16.2

View File

@@ -83,6 +83,7 @@
1CA85ECC202E5CF62530BAD7C0DCDAF2 /* LookinHierarchyInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = C792FA3E4D3612659DA4500FE9D4A687 /* LookinHierarchyInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
1D18A1A5D485D57192B021A8765C0AF5 /* LookinTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = A6D1CC45A7943BAD96C97D9225C9021D /* LookinTuple.h */; settings = {ATTRIBUTES = (Public, ); }; };
1D3DCD05B685A7CAF291C25D922B1831 /* HWPanModalPresentationController.m in Sources */ = {isa = PBXBuildFile; fileRef = F1FAB9A951323777D4A48D49725B9802 /* HWPanModalPresentationController.m */; };
1D7A626B22937B65716BDF135E5566C2 /* Pods-CustomKeyboard-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DDD0462C32F55EF5E9CB1056459809F /* Pods-CustomKeyboard-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
1DB724891F1F6468BDB333369F667F39 /* HWPanModalPresentableHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A518E59A590CAA7BC0D3ADD4113D0AC /* HWPanModalPresentableHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
1DC161351EBD409CC622E826340E4FD8 /* JXCategoryTitleVerticalZoomCell.h in Headers */ = {isa = PBXBuildFile; fileRef = ECE929CFE87E3E6402751CE58A6B7439 /* JXCategoryTitleVerticalZoomCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
1EA011B45EC780B434507AFB3D9647ED /* NSObject+MJCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 0157E81AF7D3A5016170216831D8914B /* NSObject+MJCoding.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -102,7 +103,6 @@
2175B894008D948C762468307BA677B8 /* RTLManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9FC9F1DFCA104E54D6E4547D96356D /* RTLManager.m */; };
2210A1E405AB21104E7AF86D05C8AD39 /* LYEmptyView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7C6325AEC2E86B0B251C3EB931247DD /* LYEmptyView.m */; };
22516EA77E7120000632C30BD9A03927 /* UIScrollView+MJExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ED944F2FDEEB1DA10261DC24BC5A158 /* UIScrollView+MJExtension.h */; settings = {ATTRIBUTES = (Public, ); }; };
22A4B2F6485F38FC998C238B899ED0DE /* Pods-CustomKeyboard-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CB13D51E717D347023EEB57263E3072 /* Pods-CustomKeyboard-dummy.m */; };
22C38AE7AB145224FF646303AFED11D2 /* JXCategoryDotCellModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 44F2EA17CF495B3C7801177736C26647 /* JXCategoryDotCellModel.h */; settings = {ATTRIBUTES = (Public, ); }; };
22F19B23471EE7840581A348EB735BD1 /* UIViewController+LayoutHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 44FDE6E0FD25622CBD1C32FE4FDD3698 /* UIViewController+LayoutHelper.m */; };
231A40F14D020AE2F61AA5C3289E6CF9 /* UITextView+LookinServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 81D1208390281107018E2EF73BCE3B61 /* UITextView+LookinServer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -216,6 +216,7 @@
4DD9F4BAA95C3527A660D3AAD055CF1E /* HWPanModalContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = BF92FB29A700B0634F55358F1FC1D8BE /* HWPanModalContentView.h */; settings = {ATTRIBUTES = (Public, ); }; };
4E56BA148170B3A6E7FA6D312B06C784 /* mz_zip_rw.h in Headers */ = {isa = PBXBuildFile; fileRef = B313FB2E02E6138E1628A481AF03A970 /* mz_zip_rw.h */; settings = {ATTRIBUTES = (Project, ); }; };
4E964FFE29CFF8613C0029C913F39A05 /* LKS_InbuiltAttrModificationHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = A0041C94BD88F8B62868FB3EF9609FB8 /* LKS_InbuiltAttrModificationHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
4EBF759D0963EB4E343C5B0A9CF3EA7F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8490F2CF00DB93F5FEEDE1C788BBE73 /* Foundation.framework */; };
4EC8DBADA7BB954276351A639EB4398D /* UIBlurEffect+LookinServer.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A301C66E696681FADD2B5F1A72E77F /* UIBlurEffect+LookinServer.h */; settings = {ATTRIBUTES = (Public, ); }; };
4ECE7F80A917130DE4045E25D741EAF9 /* JXCategoryTitleCellModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 677A9795E43833ACFE4BEFACEB9C9E50 /* JXCategoryTitleCellModel.m */; };
4ED05DB3E43FF6AE1FA22130B2B50F05 /* UIImage+MemoryCacheCost.h in Headers */ = {isa = PBXBuildFile; fileRef = FEF0A8FDB47640450B4AD235DDCCFFE1 /* UIImage+MemoryCacheCost.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -356,7 +357,6 @@
7EB365BD2FC75CE205A638DD725B0555 /* LSTTimer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B60A9EA622DCF45E87F4BCA20F525D85 /* LSTTimer-dummy.m */; };
7ED6C3C05EA6EE83780A3600C7088B46 /* mz_crypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 43F7DFAD54A39AC067B93B7F37CEACC4 /* mz_crypt.h */; settings = {ATTRIBUTES = (Project, ); }; };
7F10C0D094C74F2FA4CD38C7FD77B0A8 /* WKWebView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = E7430A9EA4CB87590757C1508062129E /* WKWebView+AFNetworking.m */; };
7F2995EC78B2E2AA4D1A778EF6965729 /* Pods-CustomKeyboard-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DDD0462C32F55EF5E9CB1056459809F /* Pods-CustomKeyboard-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
7F886FC2763F0BF1625A24EE4F94C04D /* UIRefreshControl+AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = A496809B712DE9F509171A8B6356A099 /* UIRefreshControl+AFNetworking.h */; settings = {ATTRIBUTES = (Public, ); }; };
7FA48BF8B9F73775654E75CEB5363FF4 /* UIViewController+PanModalPresenter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FDD439886220AA95FF6B36A5C000873 /* UIViewController+PanModalPresenter.h */; settings = {ATTRIBUTES = (Public, ); }; };
7FA8C78DB021A7731D30D80C102DE042 /* NSObject+MJKeyValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 36F771A08989CA5134B23D5F5E970ACA /* NSObject+MJKeyValue.m */; };
@@ -395,7 +395,6 @@
8B47B7F220A2B9E121EFF5A28B477972 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8490F2CF00DB93F5FEEDE1C788BBE73 /* Foundation.framework */; };
8B990235A0006E1F9C1E6F68AD81F77C /* JXCategoryView-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F727D55D6275E422C78261D496AAC93 /* JXCategoryView-dummy.m */; };
8C6C7E25C5A24C936F81823978190E96 /* ViewController+MASAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 03CF13D7504F201F21E62DE0C23B49F7 /* ViewController+MASAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
8C910EBFEAB32D47BA166C7A2BDA4833 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8490F2CF00DB93F5FEEDE1C788BBE73 /* Foundation.framework */; };
8D2CBEBF5F1DA6766A833CCD0BF02B5B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B039DC77C7D8D33CEAB56314AAFE04CB /* CoreGraphics.framework */; };
8D8AD606ECD8E1F247965CD43956D412 /* UIImage+Transform.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD20E21FF7A2BAB6FAAB004A82D3143 /* UIImage+Transform.h */; settings = {ATTRIBUTES = (Public, ); }; };
8F43694404EAFF6D73EE58928154C0F2 /* mz_strm_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 263454233B5B0DBB14C5D80582B2B2AD /* mz_strm_buf.h */; settings = {ATTRIBUTES = (Project, ); }; };
@@ -624,6 +623,7 @@
E1BF615DD0422B06C97542F03C879D41 /* AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = 06A64D211ADC6AF2DF1D9E7D4F7F2788 /* AFNetworking.h */; settings = {ATTRIBUTES = (Public, ); }; };
E1DE69F6BB6235A6EDB6C99A184BEDB4 /* UIScrollView+MJExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 85E0616DFCFEB6E1346B75E425451AFD /* UIScrollView+MJExtension.m */; };
E283D8FF283E09D9CF863A27B55886EF /* mz_crypt_apple.c in Sources */ = {isa = PBXBuildFile; fileRef = 59AF9F3690B04B3F352C8CAC3F871AB8 /* mz_crypt_apple.c */; };
E2BFC7E0926543D2958A027FF90ADB7D /* Pods-CustomKeyboard-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CB13D51E717D347023EEB57263E3072 /* Pods-CustomKeyboard-dummy.m */; };
E2DF1B379D9444D40D78320E90B1DC07 /* JXCategoryIndicatorLineView.h in Headers */ = {isa = PBXBuildFile; fileRef = 67CB215173B14FC72227F43EE74EF96E /* JXCategoryIndicatorLineView.h */; settings = {ATTRIBUTES = (Public, ); }; };
E3FC6BEE41652C0500F57E0CB83B347F /* UIButton+AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = 9187109C444449118A500CD6A1F2D532 /* UIButton+AFNetworking.h */; settings = {ATTRIBUTES = (Public, ); }; };
E42D6EF120A5C17DA2F6FD6473CE7E7A /* JXCategoryTitleVerticalZoomCellModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E9252395065AF703DEC1F4DB7906407 /* JXCategoryTitleVerticalZoomCellModel.m */; };
@@ -720,6 +720,13 @@
remoteGlobalIDString = B32AF3F43989CBA171BB1FB3957A4509;
remoteInfo = "MJExtension-MJExtension";
};
0BA199CC20B25ECBF52240507FDC08C4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 55AF53E6C77A10ED4985E04D74A8878E;
remoteInfo = Masonry;
};
0F9E615457E5337681A14D3D3D4458A5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -734,12 +741,12 @@
remoteGlobalIDString = 8BEAFAA726C1965864B79B4B441AA513;
remoteInfo = JXCategoryView;
};
27B965B2A5BF3AAB32C259DCFA82E713 /* PBXContainerItemProxy */ = {
251D3BEB8BCF4207A404D692AE545BC0 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 82B0A41D3031FF27D78E17B0A9A46FB0;
remoteInfo = MBProgressHUD;
remoteGlobalIDString = 0130B3724283586C0E9D2A112D4F2AA1;
remoteInfo = AFNetworking;
};
2FE163B88A520FE9B2F4EF7346158A53 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@@ -755,20 +762,6 @@
remoteGlobalIDString = 5A2609DB0612F95A3450D2E02CA850A0;
remoteInfo = LSTTimer;
};
35DB38B21DD3BB8CCFFEBEA22F70E3EC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 4D3BA58D0583DF37575CACAB3DDADC85;
remoteInfo = MJExtension;
};
4087212A2E57778E1FAE4448329729FC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0130B3724283586C0E9D2A112D4F2AA1;
remoteInfo = AFNetworking;
};
43E0BC7F6C06EB0590226928F1AA1BA3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -825,6 +818,13 @@
remoteGlobalIDString = 4A68CFD979D413A619DF631BB121D98F;
remoteInfo = Bugly;
};
7008466503D9ECD9A228719ABE80A8B8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3847153A6E5EEFB86565BA840768F429;
remoteInfo = SDWebImage;
};
73A9CA6BDE2B4D18F9677452E6992CBE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -839,6 +839,20 @@
remoteGlobalIDString = 638FEAAFC575BB76BC6AC055CDDA3506;
remoteInfo = LookinServer;
};
8E4A89375470440DB2A9D7DE942EA358 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F1BCD9702276377FB5B3BDB6EAF709D7;
remoteInfo = DZNEmptyDataSet;
};
8FA5A660DC27E9C3CA22FAEBEAFD4EAE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 82B0A41D3031FF27D78E17B0A9A46FB0;
remoteInfo = MBProgressHUD;
};
9E12D5E078E322AEAC001666EEE5AA65 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -846,6 +860,13 @@
remoteGlobalIDString = 94CFBA7D633ECA58DF85C327B035E6A3;
remoteInfo = "SDWebImage-SDWebImage";
};
A54DB880113009E6DC0A1C72BF95FEBC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F60E38364AFF5E1349FF07415B944396;
remoteInfo = SSZipArchive;
};
A671E8D796937C62D30391BE1F16A0AD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -888,13 +909,6 @@
remoteGlobalIDString = C4E1020AF425614337737213AA26DBD5;
remoteInfo = JXPagingView;
};
C64183E6A8A311BA11445309E5971A39 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F60E38364AFF5E1349FF07415B944396;
remoteInfo = SSZipArchive;
};
D264D8BA205995C828877A13415E636F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
@@ -902,19 +916,12 @@
remoteGlobalIDString = 8B7D23DD98E41BAE91418E9E85F191D6;
remoteInfo = LSTPopView;
};
E84BA8741985D658E053DCDE9D54DC93 /* PBXContainerItemProxy */ = {
FF3D3DA5C34F21FD0969B09D751C9FE4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 55AF53E6C77A10ED4985E04D74A8878E;
remoteInfo = Masonry;
};
E9AF0D0B9313853D3F5E9187EFFEFD3E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
proxyType = 1;
remoteGlobalIDString = F1BCD9702276377FB5B3BDB6EAF709D7;
remoteInfo = DZNEmptyDataSet;
remoteGlobalIDString = 4D3BA58D0583DF37575CACAB3DDADC85;
remoteInfo = MJExtension;
};
/* End PBXContainerItemProxy section */
@@ -1734,14 +1741,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
2B2A05DA621D2C41C33F96F10A8D14CA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8C910EBFEAB32D47BA166C7A2BDA4833 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
37145BAEB1B97BA7ADD7D6C3E86E99BD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1759,6 +1758,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
3EC76FC6C791E7FE69C7759A8887094C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4EBF759D0963EB4E343C5B0A9CF3EA7F /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
481273BD538BE69936DB3D2C8EB1E61B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -3281,6 +3288,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
25CC84E8B8C20837CF92C21B1D12D6A5 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
1D7A626B22937B65716BDF135E5566C2 /* Pods-CustomKeyboard-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
33783D69751B087D045FCF1FCA02E724 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -3554,14 +3569,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
9410C6DE72A0330546B884B956D00AE3 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
7F2995EC78B2E2AA4D1A778EF6965729 /* Pods-CustomKeyboard-umbrella.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
9AD51F59D2F73C167710F5A0609DC491 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -4019,22 +4026,23 @@
};
D9B2DB11933DB55A80A118934E6680AB /* Pods-CustomKeyboard */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9D98282E352578D31FFA72EC2EA10205 /* Build configuration list for PBXNativeTarget "Pods-CustomKeyboard" */;
buildConfigurationList = C91382D1639D3BC69FAE164863007F33 /* Build configuration list for PBXNativeTarget "Pods-CustomKeyboard" */;
buildPhases = (
9410C6DE72A0330546B884B956D00AE3 /* Headers */,
8699DF800B987868E64537798BF35D21 /* Sources */,
2B2A05DA621D2C41C33F96F10A8D14CA /* Frameworks */,
58D6818319C1893F5DD838DA2E524465 /* Resources */,
25CC84E8B8C20837CF92C21B1D12D6A5 /* Headers */,
544B1A3A7751D86ED8D64727A731F538 /* Sources */,
3EC76FC6C791E7FE69C7759A8887094C /* Frameworks */,
2B96AF27C134A995F5218E67CF3B6DFC /* Resources */,
);
buildRules = (
);
dependencies = (
29EEEFA492E836FF504DC738E40616C1 /* PBXTargetDependency */,
563A5BA80B0E2469A5B175F42B4CDCB3 /* PBXTargetDependency */,
DBDC4DC1910238D9E4AFB348253087E0 /* PBXTargetDependency */,
D81C399F78E00E0C0F046839ECAECED8 /* PBXTargetDependency */,
A0F93D6E706C7F4A596E07F119D77189 /* PBXTargetDependency */,
1D4616B2C078FD73573BFBC623E9C978 /* PBXTargetDependency */,
7793C47E78D668D8DF962F887006EBBA /* PBXTargetDependency */,
D9CDEC212B78FBACD23CCBFBB4AEF183 /* PBXTargetDependency */,
96BBA4F53A10C9797B36082CF698D670 /* PBXTargetDependency */,
3461C912C0C986DEA384D3845A39EBDE /* PBXTargetDependency */,
1CAF7447041685C03E13BF8B2B8AC1B2 /* PBXTargetDependency */,
2E0AB221F45B2386A80E75669D7FD229 /* PBXTargetDependency */,
BB80D6BB502E21A84C54851E8BB7233D /* PBXTargetDependency */,
);
name = "Pods-CustomKeyboard";
productName = Pods_CustomKeyboard;
@@ -4177,6 +4185,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
2B96AF27C134A995F5218E67CF3B6DFC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
311EF2CB460B544059B769919A899ECA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4209,13 +4224,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
58D6818319C1893F5DD838DA2E524465 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
5C89912961D7B3B99680563233DBEA04 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4505,6 +4513,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
544B1A3A7751D86ED8D64727A731F538 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2BFC7E0926543D2958A027FF90ADB7D /* Pods-CustomKeyboard-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
6027CC4F7393762F72827585E71DFAB2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4520,14 +4536,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8699DF800B987868E64537798BF35D21 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
22A4B2F6485F38FC998C238B899ED0DE /* Pods-CustomKeyboard-dummy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8AF957863B2E92075C7B36542829939B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4806,11 +4814,11 @@
target = 638FEAAFC575BB76BC6AC055CDDA3506 /* LookinServer */;
targetProxy = 8B4AF11BA988C8F1F93788F8C486B793 /* PBXContainerItemProxy */;
};
1D4616B2C078FD73573BFBC623E9C978 /* PBXTargetDependency */ = {
1CAF7447041685C03E13BF8B2B8AC1B2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = SSZipArchive;
target = F60E38364AFF5E1349FF07415B944396 /* SSZipArchive */;
targetProxy = C64183E6A8A311BA11445309E5971A39 /* PBXContainerItemProxy */;
name = Masonry;
target = 55AF53E6C77A10ED4985E04D74A8878E /* Masonry */;
targetProxy = 0BA199CC20B25ECBF52240507FDC08C4 /* PBXContainerItemProxy */;
};
248F793A182F289B47E8B7AC0E143C15 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
@@ -4818,24 +4826,30 @@
target = 8B7D23DD98E41BAE91418E9E85F191D6 /* LSTPopView */;
targetProxy = D264D8BA205995C828877A13415E636F /* PBXContainerItemProxy */;
};
29EEEFA492E836FF504DC738E40616C1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = AFNetworking;
target = 0130B3724283586C0E9D2A112D4F2AA1 /* AFNetworking */;
targetProxy = 4087212A2E57778E1FAE4448329729FC /* PBXContainerItemProxy */;
};
2A8FD4D63439C4E1939EBDE48A029628 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = AFNetworking;
target = 0130B3724283586C0E9D2A112D4F2AA1 /* AFNetworking */;
targetProxy = 5E2F9C1908DE8387A6F9BF93EF451351 /* PBXContainerItemProxy */;
};
2E0AB221F45B2386A80E75669D7FD229 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = SDWebImage;
target = 3847153A6E5EEFB86565BA840768F429 /* SDWebImage */;
targetProxy = 7008466503D9ECD9A228719ABE80A8B8 /* PBXContainerItemProxy */;
};
318E148AD8C551E2DEAB4E4705F3E9A3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = LSTTimer;
target = 5A2609DB0612F95A3450D2E02CA850A0 /* LSTTimer */;
targetProxy = B4B05B8E8A2B8CDA0C66D6BAD76B2853 /* PBXContainerItemProxy */;
};
3461C912C0C986DEA384D3845A39EBDE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MJExtension;
target = 4D3BA58D0583DF37575CACAB3DDADC85 /* MJExtension */;
targetProxy = FF3D3DA5C34F21FD0969B09D751C9FE4 /* PBXContainerItemProxy */;
};
3C59938CEAB0C654F6E6F4BDA7461510 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = SDWebImage;
@@ -4848,12 +4862,6 @@
target = 55AF53E6C77A10ED4985E04D74A8878E /* Masonry */;
targetProxy = C4958E3B26588834E71F94361C112780 /* PBXContainerItemProxy */;
};
563A5BA80B0E2469A5B175F42B4CDCB3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = DZNEmptyDataSet;
target = F1BCD9702276377FB5B3BDB6EAF709D7 /* DZNEmptyDataSet */;
targetProxy = E9AF0D0B9313853D3F5E9187EFFEFD3E /* PBXContainerItemProxy */;
};
639EDB1EF0277187CB2CFA270FDAF6FB /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Bugly;
@@ -4878,6 +4886,12 @@
target = F60E38364AFF5E1349FF07415B944396 /* SSZipArchive */;
targetProxy = 0F9E615457E5337681A14D3D3D4458A5 /* PBXContainerItemProxy */;
};
7793C47E78D668D8DF962F887006EBBA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = AFNetworking;
target = 0130B3724283586C0E9D2A112D4F2AA1 /* AFNetworking */;
targetProxy = 251D3BEB8BCF4207A404D692AE545BC0 /* PBXContainerItemProxy */;
};
8FDFA4D41ED37BC3CC62156D15AAAD81 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "MJRefresh-MJRefresh.Privacy";
@@ -4896,24 +4910,30 @@
target = E79E29F55A2453370D27112480FCF6A2 /* JXCategoryView-JXCategoryView */;
targetProxy = AB4EC7D2E9FDF608986EDAF1E480CFD7 /* PBXContainerItemProxy */;
};
96BBA4F53A10C9797B36082CF698D670 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MBProgressHUD;
target = 82B0A41D3031FF27D78E17B0A9A46FB0 /* MBProgressHUD */;
targetProxy = 8FA5A660DC27E9C3CA22FAEBEAFD4EAE /* PBXContainerItemProxy */;
};
9E31237C8A36AF7A7A0B110E3EB735D6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MJExtension;
target = 4D3BA58D0583DF37575CACAB3DDADC85 /* MJExtension */;
targetProxy = A671E8D796937C62D30391BE1F16A0AD /* PBXContainerItemProxy */;
};
A0F93D6E706C7F4A596E07F119D77189 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Masonry;
target = 55AF53E6C77A10ED4985E04D74A8878E /* Masonry */;
targetProxy = E84BA8741985D658E053DCDE9D54DC93 /* PBXContainerItemProxy */;
};
B44D94075E090726E517F9003F07D314 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MJRefresh;
target = 6868056D761E163D10FDAF8CF1C4D9B8 /* MJRefresh */;
targetProxy = 43E0BC7F6C06EB0590226928F1AA1BA3 /* PBXContainerItemProxy */;
};
BB80D6BB502E21A84C54851E8BB7233D /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = SSZipArchive;
target = F60E38364AFF5E1349FF07415B944396 /* SSZipArchive */;
targetProxy = A54DB880113009E6DC0A1C72BF95FEBC /* PBXContainerItemProxy */;
};
BDAE500408DCC4FE45DED4761241917F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = LYEmptyView;
@@ -4932,17 +4952,11 @@
target = 16704C6B67439DA959DB043702C75A7A /* JXPagingView-JXPagerView */;
targetProxy = 682B4482FB905997BF77F5EE588BD3E4 /* PBXContainerItemProxy */;
};
D81C399F78E00E0C0F046839ECAECED8 /* PBXTargetDependency */ = {
D9CDEC212B78FBACD23CCBFBB4AEF183 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MJExtension;
target = 4D3BA58D0583DF37575CACAB3DDADC85 /* MJExtension */;
targetProxy = 35DB38B21DD3BB8CCFFEBEA22F70E3EC /* PBXContainerItemProxy */;
};
DBDC4DC1910238D9E4AFB348253087E0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = MBProgressHUD;
target = 82B0A41D3031FF27D78E17B0A9A46FB0 /* MBProgressHUD */;
targetProxy = 27B965B2A5BF3AAB32C259DCFA82E713 /* PBXContainerItemProxy */;
name = DZNEmptyDataSet;
target = F1BCD9702276377FB5B3BDB6EAF709D7 /* DZNEmptyDataSet */;
targetProxy = 8E4A89375470440DB2A9D7DE942EA358 /* PBXContainerItemProxy */;
};
E4C8B75060752222288EE781ED53D28B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
@@ -5217,6 +5231,46 @@
};
name = Debug;
};
24665D97781934C3B37DE62A9BDDAC61 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1D774D8146EBC82B4A77204A273761B8 /* Pods-CustomKeyboard.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
26CEDC3022E1F92C78B66EF88DA3E538 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 35BFA337F4E1FDE67C773A82CCDFD6DA /* Pods-keyBoard.debug.xcconfig */;
@@ -5256,6 +5310,45 @@
};
name = Debug;
};
275B39FBA2E7104CEE81B3D399E7C7D3 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0D6215D1BCCE125B8DF73E38013CBBDC /* Pods-CustomKeyboard.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
319C3324D522C12DEC60436B1B3B2CE7 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 01771F71A5835C346537272402AFB9A6 /* LSTTimer.debug.xcconfig */;
@@ -5350,45 +5443,6 @@
};
name = Debug;
};
4B175742078B8D3442EF645D38AE40CC /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0D6215D1BCCE125B8DF73E38013CBBDC /* Pods-CustomKeyboard.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
4C8CF8906202B413F352B558474547DF /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BEB9455CE0A06FE1E60E43D8A39479DA /* JXCategoryView.debug.xcconfig */;
@@ -6147,46 +6201,6 @@
};
name = Debug;
};
AF99EB3786A8B2C9346426EAB1BB2239 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1D774D8146EBC82B4A77204A273761B8 /* Pods-CustomKeyboard.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
CLANG_ENABLE_OBJC_WEAK = NO;
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard-Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MACH_O_TYPE = staticlib;
MODULEMAP_FILE = "Target Support Files/Pods-CustomKeyboard/Pods-CustomKeyboard.modulemap";
OTHER_LDFLAGS = "";
OTHER_LIBTOOLFLAGS = "";
PODS_ROOT = "$(SRCROOT)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
B26FBB655ABB114E4C0D589843814D6C /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 73625BF0D8F9A3389059227F5BE246B9 /* Bugly.release.xcconfig */;
@@ -6850,15 +6864,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
9D98282E352578D31FFA72EC2EA10205 /* Build configuration list for PBXNativeTarget "Pods-CustomKeyboard" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4B175742078B8D3442EF645D38AE40CC /* Debug */,
AF99EB3786A8B2C9346426EAB1BB2239 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A0F23D46D133F936F0565C0D3363B200 /* Build configuration list for PBXNativeTarget "LSTTimer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -6877,6 +6882,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C91382D1639D3BC69FAE164863007F33 /* Build configuration list for PBXNativeTarget "Pods-CustomKeyboard" */ = {
isa = XCConfigurationList;
buildConfigurations = (
275B39FBA2E7104CEE81B3D399E7C7D3 /* Debug */,
24665D97781934C3B37DE62A9BDDAC61 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D47A0ADD8E3841C9330561C3E1664BB3 /* Build configuration list for PBXNativeTarget "HWPanModal" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -104,6 +104,30 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## SDWebImage
Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## SSZipArchive
Copyright (c) 2013-2021, ZipArchive, https://github.com/ZipArchive

View File

@@ -145,6 +145,36 @@ THE SOFTWARE.</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2009-2020 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>SDWebImage</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2013-2021, ZipArchive, https://github.com/ZipArchive

View File

@@ -1,10 +1,10 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive/SSZipArchive.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive/SSZipArchive.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks'
OTHER_LDFLAGS = $(inherited) -l"iconv" -l"z" -framework "AFNetworking" -framework "CoreGraphics" -framework "DZNEmptyDataSet" -framework "Foundation" -framework "MBProgressHUD" -framework "MJExtension" -framework "Masonry" -framework "QuartzCore" -framework "SSZipArchive" -framework "Security" -framework "UIKit"
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "-F${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
OTHER_LDFLAGS = $(inherited) -l"iconv" -l"z" -framework "AFNetworking" -framework "CoreGraphics" -framework "DZNEmptyDataSet" -framework "Foundation" -framework "ImageIO" -framework "MBProgressHUD" -framework "MJExtension" -framework "Masonry" -framework "QuartzCore" -framework "SDWebImage" -framework "SSZipArchive" -framework "Security" -framework "UIKit"
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "-F${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@@ -1,10 +1,10 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive/SSZipArchive.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet/DZNEmptyDataSet.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive/SSZipArchive.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' '@executable_path/../../Frameworks'
OTHER_LDFLAGS = $(inherited) -l"iconv" -l"z" -framework "AFNetworking" -framework "CoreGraphics" -framework "DZNEmptyDataSet" -framework "Foundation" -framework "MBProgressHUD" -framework "MJExtension" -framework "Masonry" -framework "QuartzCore" -framework "SSZipArchive" -framework "Security" -framework "UIKit"
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "-F${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
OTHER_LDFLAGS = $(inherited) -l"iconv" -l"z" -framework "AFNetworking" -framework "CoreGraphics" -framework "DZNEmptyDataSet" -framework "Foundation" -framework "ImageIO" -framework "MBProgressHUD" -framework "MJExtension" -framework "Masonry" -framework "QuartzCore" -framework "SDWebImage" -framework "SSZipArchive" -framework "Security" -framework "UIKit"
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "-F${PODS_CONFIGURATION_BUILD_DIR}/DZNEmptyDataSet" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@@ -1,3 +1,4 @@
APPLICATION_EXTENSION_API_ONLY = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = NO

View File

@@ -1,3 +1,4 @@
APPLICATION_EXTENSION_API_ONLY = YES
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = NO

View File

@@ -69,6 +69,11 @@
/// AI
#define API_AI_TALK @"/chat/talk"
#define API_AI_VOICE_TALK @"/chat/voice" // 语音对话(替换为后端真实路径)
#define API_AI_CHAT_SYNC @"/chat/sync" // 同步对话
#define API_AI_CHAT_MESSAGE @"/chat/message" // 文本润色
#define API_AI_AUDIO_UPLOAD @"/chat/audio/upload" // 语音上传(替换为后端真实路径)
#define API_AI_SPEECH_TRANSCRIBE @"/speech/transcribe" // 语音转文字

View File

@@ -27,6 +27,9 @@
/// 键盘 -> 主 App 订阅页预填充数据(用于免二次请求)
#define AppGroup_SubscriptionPrefillPayload @"AppGroup_SubscriptionPrefillPayload"
/// 用户头像 URL主 App 写入,键盘扩展读取)
#define AppGroup_UserAvatarURL @"AppGroup_UserAvatarURL"
/// 皮肤图标加载模式:
/// 0 = 使用本地 Assets 图片名key_icons 的 value 写成图片名,例如 "kb_q_melon"
/// 1 = 使用远程 Zip 皮肤包skinJSON 中提供 zip_urlkey_icons 的 value 写成 Zip 内图标文件名,例如 "key_a"
@@ -38,7 +41,7 @@
// 基础baseUrl
#ifndef KB_BASE_URL
//#define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/"
//#define KB_BASE_URL @"http://192.168.2.21:7529/api"
//#define KB_BASE_URL @"http://192.168.2.22:7529/api"
#define KB_BASE_URL @"https://devcallback.loveamorkey.com/api"
#endif

View File

@@ -0,0 +1,469 @@
1f8dcd4726717a4b724e5408ca24829bdef67a49 not-for-merge branch 'action-xcode-versions' of https://github.com/apple/swift-collections
7ae9880f0fb622992a8a5328fd4af78af5b6b26f not-for-merge branch 'dn/remove-retain-release-during-find' of https://github.com/apple/swift-collections
ddff9004d745c4b2d13e35ebdd1a3d0b67e14717 not-for-merge branch 'doc-basic-span-index-mutation' of https://github.com/apple/swift-collections
ebd51171f0e45788e2cdb3cc6d54233e11d7443c not-for-merge branch 'future' of https://github.com/apple/swift-collections
534c0cbbfef9d2f6e7a6519930967d75f7c60336 not-for-merge branch 'main' of https://github.com/apple/swift-collections
68c32ed80b138d1f8a6ec5dcf1b105f32fcaaf12 not-for-merge branch 'maxd/run-wasm-tests' of https://github.com/apple/swift-collections
762bc5757de4bcf86cc3b3266e3df93f76469089 not-for-merge branch 'nate/zip_dispatch_benchmarking' of https://github.com/apple/swift-collections
d029d9d39c87bed85b1c50adee7c41795261a192 not-for-merge branch 'release/1.0' of https://github.com/apple/swift-collections
c11818f3cae0780656baa430b49e7f163f08dffd not-for-merge branch 'release/1.1' of https://github.com/apple/swift-collections
2d1f4172091ca272b461397748fd2c32847036dd not-for-merge branch 'release/1.2' of https://github.com/apple/swift-collections
c55cbe540366c704c279298ca6ad4c09a067ebe0 not-for-merge branch 'release/1.3' of https://github.com/apple/swift-collections
a26fc8e7e4c6e0d63b08951f5b7268044fb95c83 not-for-merge branch 'span-prototype' of https://github.com/apple/swift-collections
434d30dae30fbb57699370260c69c2108c1abf8f not-for-merge branch 'wasm-tests' of https://github.com/apple/swift-collections
c65cd649fb91f64636f2f1ef5da4991987139f68 not-for-merge 'refs/pull/10/head' of https://github.com/apple/swift-collections
6a9703c3f13061291eff1baf8af4fce1e6ce35af not-for-merge 'refs/pull/100/head' of https://github.com/apple/swift-collections
8303a77bc2915be76777d6fc17b702146b6fb192 not-for-merge 'refs/pull/102/head' of https://github.com/apple/swift-collections
6cd03922372c85e2dca476f665527976911e7397 not-for-merge 'refs/pull/105/head' of https://github.com/apple/swift-collections
96100d4b6ad61bbfbf549ee42dc73239325b353f not-for-merge 'refs/pull/106/head' of https://github.com/apple/swift-collections
f69104b5071ef9a44112e3c4fef8904b5e8b6d73 not-for-merge 'refs/pull/107/head' of https://github.com/apple/swift-collections
5f255a887e51093f058e7ee9ea0b959051be38d4 not-for-merge 'refs/pull/108/head' of https://github.com/apple/swift-collections
c46c77f7f85f9efe83cc5cb8d54b32c538b06450 not-for-merge 'refs/pull/109/head' of https://github.com/apple/swift-collections
cfca1038b53eecd4fc50da15cc715f966904012e not-for-merge 'refs/pull/11/head' of https://github.com/apple/swift-collections
103008aca495f3b80a50713086d451b08cef9f50 not-for-merge 'refs/pull/110/head' of https://github.com/apple/swift-collections
39a16a15cc8c7e11486015d2deb78468b4a64c85 not-for-merge 'refs/pull/111/head' of https://github.com/apple/swift-collections
7f57a0ed1c8b1d44eacab95d3cfd57d87482b25a not-for-merge 'refs/pull/112/head' of https://github.com/apple/swift-collections
efefae56531b30d75553f234134e3c83bd26c6a6 not-for-merge 'refs/pull/113/head' of https://github.com/apple/swift-collections
565b1ab20bef052f52fad4ebe112803facb325e3 not-for-merge 'refs/pull/114/head' of https://github.com/apple/swift-collections
8b3af12ece11ea7b0e748749c39a59c59269ca25 not-for-merge 'refs/pull/115/head' of https://github.com/apple/swift-collections
8be0f192e8f120969427cb2645aabe6f5fdf15a1 not-for-merge 'refs/pull/116/head' of https://github.com/apple/swift-collections
771bca404c0ee603bb6cc2ea3a19cfc4ebc3d001 not-for-merge 'refs/pull/117/head' of https://github.com/apple/swift-collections
95be379a3ac1e4278d114a22501267065062b39a not-for-merge 'refs/pull/118/head' of https://github.com/apple/swift-collections
f41f2cae69dc6ffcc178227a0a46607561fa925c not-for-merge 'refs/pull/119/head' of https://github.com/apple/swift-collections
276ddee5df4ea0f44c5edea0dbe726cb74682498 not-for-merge 'refs/pull/121/head' of https://github.com/apple/swift-collections
1c1e6206fa1a4b0a6bf97ac979f841c1d1821ad7 not-for-merge 'refs/pull/122/head' of https://github.com/apple/swift-collections
074b0ad21387e767b5b3ff1cb014a118a3b80bde not-for-merge 'refs/pull/123/head' of https://github.com/apple/swift-collections
ddc8b9c66d07cb0af38e98ca160f1f7cc85c88d3 not-for-merge 'refs/pull/126/head' of https://github.com/apple/swift-collections
9dde4b560323d43ec2ca8225a6c5c79a9bc0735d not-for-merge 'refs/pull/128/head' of https://github.com/apple/swift-collections
453adb695f615886cd7a897d62676713aeb25bf9 not-for-merge 'refs/pull/13/head' of https://github.com/apple/swift-collections
286fedb1e8f6b2567cd214cf1127a9322dea1400 not-for-merge 'refs/pull/130/head' of https://github.com/apple/swift-collections
e77d82c71271b7848e3ac9e007a52f36f04a1c7e not-for-merge 'refs/pull/132/head' of https://github.com/apple/swift-collections
1bde9674f42e41bfb62deb96d8b247a537171ba7 not-for-merge 'refs/pull/132/merge' of https://github.com/apple/swift-collections
cee04e96ed96fefa5527e33a4a055482e4ea14e9 not-for-merge 'refs/pull/14/head' of https://github.com/apple/swift-collections
50e6a1ac71df96e5cd257c565e9a3299f491ba3e not-for-merge 'refs/pull/140/head' of https://github.com/apple/swift-collections
29120ea6406a856c36496b4f5d3b13ca381436a6 not-for-merge 'refs/pull/141/head' of https://github.com/apple/swift-collections
867231031ac792328eff9133a289ce9e693a03c3 not-for-merge 'refs/pull/15/head' of https://github.com/apple/swift-collections
6cb037037d45f78622fd7cab3f62e3c6a4ff5ddb not-for-merge 'refs/pull/153/head' of https://github.com/apple/swift-collections
7016a13f0e8d0d0a36f3566a6dc6acaf5b83fbf4 not-for-merge 'refs/pull/155/head' of https://github.com/apple/swift-collections
00a99aa77c4982a6e7343982220e44b15e4d5974 not-for-merge 'refs/pull/156/head' of https://github.com/apple/swift-collections
74a800ac534877875d5d1187ac04f35b31a0b98c not-for-merge 'refs/pull/159/head' of https://github.com/apple/swift-collections
b9d73a5bab8d71e121687f79ed4aabfbd73d016b not-for-merge 'refs/pull/16/head' of https://github.com/apple/swift-collections
ddb6d141b3e4e8726a15e3e9e916ee697bd310db not-for-merge 'refs/pull/160/head' of https://github.com/apple/swift-collections
3437abecc49cfbbb91893e3a0d0f124db163637f not-for-merge 'refs/pull/161/head' of https://github.com/apple/swift-collections
1071b372942289dbd3209ede40f613d339cca8e1 not-for-merge 'refs/pull/162/head' of https://github.com/apple/swift-collections
b9d91f4a9aa3cfd6c8589aee997c4399e6d7d83d not-for-merge 'refs/pull/163/head' of https://github.com/apple/swift-collections
ee1b2de06edf18545084d99a5c99995e9c1ff8d4 not-for-merge 'refs/pull/165/head' of https://github.com/apple/swift-collections
b379fa7aee604738bd0b4076984c934e242bb7a5 not-for-merge 'refs/pull/168/head' of https://github.com/apple/swift-collections
71aa4a39ae59addf40e9dd40e79a4968f1c857cc not-for-merge 'refs/pull/169/head' of https://github.com/apple/swift-collections
feca3b6f4c7bf7adf9fa4a0fd200f96cf1b5a4b5 not-for-merge 'refs/pull/170/head' of https://github.com/apple/swift-collections
9a9d7d87d844b2a14ec602792d9ae216ea57ea53 not-for-merge 'refs/pull/172/head' of https://github.com/apple/swift-collections
8cc0b1d43975a9d547053cf0e943498c0d6d7992 not-for-merge 'refs/pull/173/head' of https://github.com/apple/swift-collections
aa428d0489be5888c72de4a4327f0f316a586632 not-for-merge 'refs/pull/174/head' of https://github.com/apple/swift-collections
14f90620c89e311a067a1fa49813d8bbcd539950 not-for-merge 'refs/pull/175/head' of https://github.com/apple/swift-collections
77edbef16d24e657fc3d7b0bc9adb57e6b0567d9 not-for-merge 'refs/pull/176/head' of https://github.com/apple/swift-collections
9d9659a079644d300d3571fb64ac7bb14322e506 not-for-merge 'refs/pull/177/head' of https://github.com/apple/swift-collections
9f38e7424baa3497e4d481790fc6ec2950725de8 not-for-merge 'refs/pull/178/head' of https://github.com/apple/swift-collections
d45f264ef0dc625a37801ee6e05b764ccbef30b4 not-for-merge 'refs/pull/179/head' of https://github.com/apple/swift-collections
58579394fc929c1b89b762c3ef68a1657442ca7d not-for-merge 'refs/pull/18/head' of https://github.com/apple/swift-collections
39fc818e0efaa148e038e3d89cd78be64567849a not-for-merge 'refs/pull/180/head' of https://github.com/apple/swift-collections
4c4154ca2350d981cd6abeadbdcad18071fe3b95 not-for-merge 'refs/pull/181/head' of https://github.com/apple/swift-collections
59858a77210f506e622a68e5b92e36bae6fc9215 not-for-merge 'refs/pull/182/head' of https://github.com/apple/swift-collections
ba303dca1d72860f0b253778f193010af20f9b79 not-for-merge 'refs/pull/184/head' of https://github.com/apple/swift-collections
778b8ae977c420dfe323b27ed3a1cf3f747f936b not-for-merge 'refs/pull/185/head' of https://github.com/apple/swift-collections
0f92943ba349d0337d254789bc49e9a5c45ff74e not-for-merge 'refs/pull/187/head' of https://github.com/apple/swift-collections
f71ebd9494b3b0b8c1450017f8c30fb61e4dcc37 not-for-merge 'refs/pull/188/head' of https://github.com/apple/swift-collections
66651795d89e760188908bb65b3398aa30b84897 not-for-merge 'refs/pull/189/head' of https://github.com/apple/swift-collections
832e58027cdb86e618089ebdf2e3474da915c357 not-for-merge 'refs/pull/190/head' of https://github.com/apple/swift-collections
9b7c6ecb10599568876b1108005b189de54d9ce9 not-for-merge 'refs/pull/191/head' of https://github.com/apple/swift-collections
4604c1bc381c4d164a030d11830701b2897a0002 not-for-merge 'refs/pull/192/head' of https://github.com/apple/swift-collections
0b86bb11d24e187ab6ab930f582f75ae00bcabf9 not-for-merge 'refs/pull/193/head' of https://github.com/apple/swift-collections
c7c0a094f91bd5cce90b1dc1f3feeb9d2508e7f5 not-for-merge 'refs/pull/194/head' of https://github.com/apple/swift-collections
1b71d2cd942459049b870264b7db649ba7509046 not-for-merge 'refs/pull/195/head' of https://github.com/apple/swift-collections
7cec5d1ed71d0c29fc7515725401c8a711a01074 not-for-merge 'refs/pull/196/head' of https://github.com/apple/swift-collections
b83d06b43337cc2855c1b55ba1cdba854724110b not-for-merge 'refs/pull/197/head' of https://github.com/apple/swift-collections
6286cd0b99741db984e5c1115a4c748bc42efec1 not-for-merge 'refs/pull/198/head' of https://github.com/apple/swift-collections
8b06c61c7e4ecb6777895a8fba275a44ec8c5e01 not-for-merge 'refs/pull/199/head' of https://github.com/apple/swift-collections
5aed92655d73228211985c933e0d5141d8203a09 not-for-merge 'refs/pull/200/head' of https://github.com/apple/swift-collections
51604cd196265a1e4444cef0a7ac749e34f5e64e not-for-merge 'refs/pull/201/head' of https://github.com/apple/swift-collections
2a81cb1186ac3483183df32ba8c3e2fe7360cbcb not-for-merge 'refs/pull/202/head' of https://github.com/apple/swift-collections
6dbc8b8c4f36ff470060464d69066e2e094a194f not-for-merge 'refs/pull/203/head' of https://github.com/apple/swift-collections
6b428b5a7fadfae0120db4fc96a3d5b14f7b7c36 not-for-merge 'refs/pull/204/head' of https://github.com/apple/swift-collections
b1506b62250f074d23cddc6d0318277dda5d21dc not-for-merge 'refs/pull/205/head' of https://github.com/apple/swift-collections
2e872739d3a6201e2b888c73f08ef54ae4125d6d not-for-merge 'refs/pull/206/head' of https://github.com/apple/swift-collections
4c842df1b8cfc9611762bdf5fbd9023ab2d3d333 not-for-merge 'refs/pull/207/head' of https://github.com/apple/swift-collections
1228e9c1628925843575a11c1de8342e402c7c30 not-for-merge 'refs/pull/208/head' of https://github.com/apple/swift-collections
b6184b667bd8f636558522f18cc2fe993a825679 not-for-merge 'refs/pull/21/head' of https://github.com/apple/swift-collections
fc8092d0441e0073831d6b170c74b6cca0da9bf5 not-for-merge 'refs/pull/210/head' of https://github.com/apple/swift-collections
cfc3d4a5179e61c36d77babd9fd3029a0f85cff4 not-for-merge 'refs/pull/211/head' of https://github.com/apple/swift-collections
02ea4e849230bc2326c83c5560822a228d83afab not-for-merge 'refs/pull/212/head' of https://github.com/apple/swift-collections
1490835b289653b145b91a16fe5522d928509efb not-for-merge 'refs/pull/213/head' of https://github.com/apple/swift-collections
2b4ec22949acbfa99f9e22c390d850a650f3d298 not-for-merge 'refs/pull/214/head' of https://github.com/apple/swift-collections
5e0a0149a4c9b2ab407f65b257b5b36bc589307d not-for-merge 'refs/pull/215/head' of https://github.com/apple/swift-collections
734730d72460e7bd536e8021d4aa711cb3aa75b2 not-for-merge 'refs/pull/216/head' of https://github.com/apple/swift-collections
381cf5d17e46f2d3266bd1be7295118647443313 not-for-merge 'refs/pull/217/head' of https://github.com/apple/swift-collections
3c6cb8cd56d04392bf9f79a2d5020fc2abf1958d not-for-merge 'refs/pull/218/head' of https://github.com/apple/swift-collections
67fdff5a25539a51ce2a8bf574a7e4a6b72ebfb8 not-for-merge 'refs/pull/219/head' of https://github.com/apple/swift-collections
fbdf73e1b787a0ac113e930dff73382f612698d4 not-for-merge 'refs/pull/22/head' of https://github.com/apple/swift-collections
d3987c79a1214e279a49a09304c13322560c8a1b not-for-merge 'refs/pull/220/head' of https://github.com/apple/swift-collections
5783b82d72e620f37545924d46bdbfb429f03cbb not-for-merge 'refs/pull/221/head' of https://github.com/apple/swift-collections
2df7f6d3a8fe5f9bb12b5034da2e095424694d44 not-for-merge 'refs/pull/222/head' of https://github.com/apple/swift-collections
72e2df59e3ea600f4d5e67a324bd6df1a7acbd41 not-for-merge 'refs/pull/223/head' of https://github.com/apple/swift-collections
98d62d236bef8c30af5b7015ccbb7db66f43399e not-for-merge 'refs/pull/224/head' of https://github.com/apple/swift-collections
ba7e3927e76ff55b0579770fb036ffce6ea07b3c not-for-merge 'refs/pull/225/head' of https://github.com/apple/swift-collections
207029a613dca008e708370c09fc69010cf6a11d not-for-merge 'refs/pull/226/head' of https://github.com/apple/swift-collections
68bc6567be4c1ae96cfea1217b9e5cee63421c6a not-for-merge 'refs/pull/227/head' of https://github.com/apple/swift-collections
1c147e3b06edbe0b00217e38e94d2d3bc4b4c6a7 not-for-merge 'refs/pull/228/head' of https://github.com/apple/swift-collections
5aa603edfe8c13e0256141cb45f70ec427fe94c1 not-for-merge 'refs/pull/23/head' of https://github.com/apple/swift-collections
d19fb14c46266a20cba9c5362923c6a076e74407 not-for-merge 'refs/pull/230/head' of https://github.com/apple/swift-collections
a32048d44ee028b915565c3093ec5305e41aa6f1 not-for-merge 'refs/pull/231/head' of https://github.com/apple/swift-collections
4448454fbc79b8052acc6b6e7eb6c75c70d1ee2f not-for-merge 'refs/pull/232/head' of https://github.com/apple/swift-collections
14e86daeebe18bd32466a1f2bd2d8da936aa6508 not-for-merge 'refs/pull/233/head' of https://github.com/apple/swift-collections
581490a7351be07e465100628ded472aaa137a99 not-for-merge 'refs/pull/234/head' of https://github.com/apple/swift-collections
ff2d526c1baa53df478db47156bbdd68fcaed4df not-for-merge 'refs/pull/235/head' of https://github.com/apple/swift-collections
98d519ec12ec6bc209ad61fed2e7e2101e312566 not-for-merge 'refs/pull/237/head' of https://github.com/apple/swift-collections
339f1677450d7a8f43518d61cfd93be85fa080c3 not-for-merge 'refs/pull/238/head' of https://github.com/apple/swift-collections
ff85ea9e4f1cf6fd50fb758cde3dedf01a742f52 not-for-merge 'refs/pull/240/head' of https://github.com/apple/swift-collections
18c4f6dc5a771cd3f90ef3e7ae02a99e09e89115 not-for-merge 'refs/pull/241/head' of https://github.com/apple/swift-collections
3d66da5f5baa3585aa4b5fe8f9d9eaaee5e5a6ef not-for-merge 'refs/pull/242/head' of https://github.com/apple/swift-collections
2c33149e4e2cb9a5b2616cdbad9eabb5f51f0e0c not-for-merge 'refs/pull/243/head' of https://github.com/apple/swift-collections
a2f4b18ae02cd14a8488c357c75fef3f2c2a9013 not-for-merge 'refs/pull/244/head' of https://github.com/apple/swift-collections
69768b6eacd442681bc8424cc76516e7e24fdacc not-for-merge 'refs/pull/245/head' of https://github.com/apple/swift-collections
f8252436e5e4384eaa1a68560db380d83b7c71eb not-for-merge 'refs/pull/246/head' of https://github.com/apple/swift-collections
07032a92671dea282cbc935383dd3d5a0a598682 not-for-merge 'refs/pull/246/merge' of https://github.com/apple/swift-collections
b8ed4950368d4d54cefd2b8bfe14c329e057172c not-for-merge 'refs/pull/247/head' of https://github.com/apple/swift-collections
10a01bd9fb383668a987ec8f512da627dbe55f9e not-for-merge 'refs/pull/248/head' of https://github.com/apple/swift-collections
470bf29d014757caae7222f3a41aea0b86b6ee1c not-for-merge 'refs/pull/249/head' of https://github.com/apple/swift-collections
b43076ca7b46b8216590766fd446ae538ab91c5a not-for-merge 'refs/pull/25/head' of https://github.com/apple/swift-collections
c0853ebef8dad7eddb6a44b76dac0f42f699b96a not-for-merge 'refs/pull/251/head' of https://github.com/apple/swift-collections
089666b32ba82c06a166e072ebcdf988108b66b7 not-for-merge 'refs/pull/252/head' of https://github.com/apple/swift-collections
fef38395004569688a967b88c70d8774c63f5fc5 not-for-merge 'refs/pull/254/head' of https://github.com/apple/swift-collections
972578a44da6463eb8f88552cc7d30cf0b6de9a4 not-for-merge 'refs/pull/259/head' of https://github.com/apple/swift-collections
0c2071ecda7a50dcdc8ec435a45b3b830b3e5bcf not-for-merge 'refs/pull/259/merge' of https://github.com/apple/swift-collections
4e2f86b6cd24a124d69bf9257d2ffa751d11da8f not-for-merge 'refs/pull/26/head' of https://github.com/apple/swift-collections
580beb4c121a85f60aaf6f10403e7f457c81ccb9 not-for-merge 'refs/pull/260/head' of https://github.com/apple/swift-collections
5b4e4e032fc56ca77b888ca36b7a342e9932e5fa not-for-merge 'refs/pull/260/merge' of https://github.com/apple/swift-collections
3e6df33472d54ed83dffe3bca7a3c8f65bab4c43 not-for-merge 'refs/pull/263/head' of https://github.com/apple/swift-collections
fcd6800b9d1171fbe0a00f51a72afac32b0a1987 not-for-merge 'refs/pull/264/head' of https://github.com/apple/swift-collections
5dc7a8970eabcf6aaa49529b5ef6401f5128637e not-for-merge 'refs/pull/265/head' of https://github.com/apple/swift-collections
1666222de2200b2a614a0d5184751b8b6f7309b0 not-for-merge 'refs/pull/266/head' of https://github.com/apple/swift-collections
e6ecdac581c3f03f442111b87655702e0664df67 not-for-merge 'refs/pull/267/head' of https://github.com/apple/swift-collections
26de4aa094c87a9efd793f3ec37ec7facea24184 not-for-merge 'refs/pull/268/head' of https://github.com/apple/swift-collections
73936bba69bd49e025aa8113fa81caa7f76ed571 not-for-merge 'refs/pull/269/head' of https://github.com/apple/swift-collections
454c84b5e4253e462dac5472b853ee222ca93368 not-for-merge 'refs/pull/270/head' of https://github.com/apple/swift-collections
9c3328e235e5f17c06328f021a5d11e7221690f5 not-for-merge 'refs/pull/271/head' of https://github.com/apple/swift-collections
96d71628887275fc3010a0979cdebef15edde911 not-for-merge 'refs/pull/272/head' of https://github.com/apple/swift-collections
4b6978bf8b220c9c7d03d1f8124d537fbbddc32a not-for-merge 'refs/pull/273/head' of https://github.com/apple/swift-collections
7f63914a7161923e9af6889ed0f954de1ed4c7f0 not-for-merge 'refs/pull/275/head' of https://github.com/apple/swift-collections
ac0c075ccc0fe2754a41dd777bb39507e73efe5b not-for-merge 'refs/pull/276/head' of https://github.com/apple/swift-collections
a8dad62bc9c76f1f455a372c91759e7bb1e92e63 not-for-merge 'refs/pull/277/head' of https://github.com/apple/swift-collections
99adbe97af48017fb51d884936f6bb87c27166c2 not-for-merge 'refs/pull/278/head' of https://github.com/apple/swift-collections
b0fe7ca8bad02599faa6a308b561f71d4d5e3b4b not-for-merge 'refs/pull/279/head' of https://github.com/apple/swift-collections
dce7b156e7276d44c3641f05bf675d90fea16523 not-for-merge 'refs/pull/280/head' of https://github.com/apple/swift-collections
c4ad48826105dd299f45473784d22bf395b56863 not-for-merge 'refs/pull/281/head' of https://github.com/apple/swift-collections
1f204555aa1678c0aa01cfba5836920acb8c5537 not-for-merge 'refs/pull/282/head' of https://github.com/apple/swift-collections
992e0f3446b4f608f5ead9dd6edc92f6bbc0b0a0 not-for-merge 'refs/pull/283/head' of https://github.com/apple/swift-collections
3f4d8f9912c9c3f5bacef6e6543b3f5b93168f65 not-for-merge 'refs/pull/284/head' of https://github.com/apple/swift-collections
9befd06185369d287deee36f3d0de65f41edabb1 not-for-merge 'refs/pull/285/head' of https://github.com/apple/swift-collections
0c002200bbee27acc8a663075da69120f666b4e5 not-for-merge 'refs/pull/286/head' of https://github.com/apple/swift-collections
de0f59418503fc0c4866395751d930be3abbf17c not-for-merge 'refs/pull/287/head' of https://github.com/apple/swift-collections
a5fda7c368e06561fba87dd33c47443e879dd6da not-for-merge 'refs/pull/288/head' of https://github.com/apple/swift-collections
989bd7f2db6d9e7aa91881389359e369d621e3d9 not-for-merge 'refs/pull/29/head' of https://github.com/apple/swift-collections
03c9ef743ad9de4eea816225afa2fc52490339cc not-for-merge 'refs/pull/290/head' of https://github.com/apple/swift-collections
03e7f0c401e771f4a4c529eae4d3fde91f5bd355 not-for-merge 'refs/pull/291/head' of https://github.com/apple/swift-collections
9c88dce30d213e1844ce60476e7d3eba2b1f1e60 not-for-merge 'refs/pull/292/head' of https://github.com/apple/swift-collections
671cff0b3e579cbdad3a0818031063588d866ad2 not-for-merge 'refs/pull/296/head' of https://github.com/apple/swift-collections
b3d089e37d0d4adc07bdbf1ecd14e9be3786bf25 not-for-merge 'refs/pull/297/head' of https://github.com/apple/swift-collections
2f6606401781d32f3ffe3e245f2ba946acefe97e not-for-merge 'refs/pull/298/head' of https://github.com/apple/swift-collections
8fbc1d318cf4c48931ffc6d204123284087fad0c not-for-merge 'refs/pull/299/head' of https://github.com/apple/swift-collections
cf2cbd6ce39cbbdf7c60b76a8dca8e38b80486fc not-for-merge 'refs/pull/300/head' of https://github.com/apple/swift-collections
09c09f0f734c006186df57595dc823159e0d49ef not-for-merge 'refs/pull/302/head' of https://github.com/apple/swift-collections
a58628449c5e398433472b1bfd7e67e0acbe09fc not-for-merge 'refs/pull/303/head' of https://github.com/apple/swift-collections
a82138e714dcd28ef5b7bacc4b708acc118e87ac not-for-merge 'refs/pull/304/head' of https://github.com/apple/swift-collections
f15c276542595cb0f55368f8abf9f277e8eb51c9 not-for-merge 'refs/pull/304/merge' of https://github.com/apple/swift-collections
1cf3b88cb3d237183cacd6482e4adaec48b17bb5 not-for-merge 'refs/pull/307/head' of https://github.com/apple/swift-collections
ccd11e55dd4991055b260bb39d7e20ceb09046e9 not-for-merge 'refs/pull/31/head' of https://github.com/apple/swift-collections
9efa05c583441159bd505dfde340cf774d6144e0 not-for-merge 'refs/pull/314/head' of https://github.com/apple/swift-collections
bf742617f30870372ed235c6ccf4515ea0a204d3 not-for-merge 'refs/pull/315/head' of https://github.com/apple/swift-collections
b6e227b9d779fe7405dc410812cb3aba6d2b529a not-for-merge 'refs/pull/316/head' of https://github.com/apple/swift-collections
5c9ee680d20c4a758b0ffe06876fdca823f8068a not-for-merge 'refs/pull/316/merge' of https://github.com/apple/swift-collections
de2c8a90865dcdbd97defe3c2c7396a2400e455a not-for-merge 'refs/pull/318/head' of https://github.com/apple/swift-collections
bd1a62273592d5ad6ef388a70f53a61e33ffcba4 not-for-merge 'refs/pull/319/head' of https://github.com/apple/swift-collections
171edb86e347f70d85ac593c139d26d6b4d3bbea not-for-merge 'refs/pull/32/head' of https://github.com/apple/swift-collections
33f23b6a06f4a9f6b013fdef108cc1c82153afe4 not-for-merge 'refs/pull/320/head' of https://github.com/apple/swift-collections
b67553e0c27857bbc5310f40cd6e68daa2d585de not-for-merge 'refs/pull/321/head' of https://github.com/apple/swift-collections
b72a6cfd9384bc3ace8ea2412e79d5ec34c24934 not-for-merge 'refs/pull/322/head' of https://github.com/apple/swift-collections
90b67c44eae7277d57e79e3c25c5dc72939a3b93 not-for-merge 'refs/pull/323/head' of https://github.com/apple/swift-collections
19ec155f6089f6de453f8835aad46c09f5fd0b4d not-for-merge 'refs/pull/326/head' of https://github.com/apple/swift-collections
069dd4e5df442e813eb30e3216aafa1cc1696a5f not-for-merge 'refs/pull/327/head' of https://github.com/apple/swift-collections
53831b3a2264e24ca6c7ffcfe33c8653a72d51e1 not-for-merge 'refs/pull/328/head' of https://github.com/apple/swift-collections
0b7ebf49775a8e5177eeaea6513083363a20e08c not-for-merge 'refs/pull/330/head' of https://github.com/apple/swift-collections
3bd3d3ba28c6e72515e56b535b8a638144c12413 not-for-merge 'refs/pull/331/head' of https://github.com/apple/swift-collections
cd03e5b471755b00aa948f7de950932c2c5a5d79 not-for-merge 'refs/pull/332/head' of https://github.com/apple/swift-collections
e732790fde08a5e3d4f2347ac4a3e74399a5b457 not-for-merge 'refs/pull/333/head' of https://github.com/apple/swift-collections
d2662892cd218eec7b56e505e4a343e5c676f02c not-for-merge 'refs/pull/335/head' of https://github.com/apple/swift-collections
2bc657fad1def9519f88d851ef9e91bc01dc0e47 not-for-merge 'refs/pull/336/head' of https://github.com/apple/swift-collections
6e91291cb24b777f0db29a6d50a728a2183ab660 not-for-merge 'refs/pull/337/head' of https://github.com/apple/swift-collections
f9c400fb1c9bb8f2f76484b1a398135175d87a7f not-for-merge 'refs/pull/338/head' of https://github.com/apple/swift-collections
071a1011d1f02ac96f92164b0313c429a159ad80 not-for-merge 'refs/pull/339/head' of https://github.com/apple/swift-collections
85b00faba7071b5d7babb426bc06aa401ac8814d not-for-merge 'refs/pull/34/head' of https://github.com/apple/swift-collections
525bb545c4c1f7dfe3ca461136c072af11cb6e4f not-for-merge 'refs/pull/340/head' of https://github.com/apple/swift-collections
2122327782b71345cce48f23b688deebf582adc3 not-for-merge 'refs/pull/341/head' of https://github.com/apple/swift-collections
40e737cdaf9341d821cba518ee990406fdcfd7e3 not-for-merge 'refs/pull/342/head' of https://github.com/apple/swift-collections
8bfcaddd5fadea396620871451ca9ffc43b0985d not-for-merge 'refs/pull/343/head' of https://github.com/apple/swift-collections
9d4a1e5ad279e6bc1c4230f90208b0886608a387 not-for-merge 'refs/pull/346/head' of https://github.com/apple/swift-collections
cdcf9e606a12221e123a642353fbcfdc5d48bcf6 not-for-merge 'refs/pull/347/head' of https://github.com/apple/swift-collections
1a0ac8c06c5a27f330a55a61464eaebc840d89d1 not-for-merge 'refs/pull/348/head' of https://github.com/apple/swift-collections
258df0792818d6c331ccee923736ea234c24cf07 not-for-merge 'refs/pull/349/head' of https://github.com/apple/swift-collections
3c9df19f7da674295f58f07f6dffa5d9e114fbc8 not-for-merge 'refs/pull/351/head' of https://github.com/apple/swift-collections
c61e5e23c89b99d26aaaec6ec6c58bda1b502ebc not-for-merge 'refs/pull/352/head' of https://github.com/apple/swift-collections
8dd4e591b3789ea14e8bd8cfde3ed81aa6edfefe not-for-merge 'refs/pull/353/head' of https://github.com/apple/swift-collections
50f6307501712d87110f3f4d2e4959e84ace3bc8 not-for-merge 'refs/pull/354/head' of https://github.com/apple/swift-collections
8e64f064f562a918993b147a3872e92c157e8e01 not-for-merge 'refs/pull/355/head' of https://github.com/apple/swift-collections
ab744afc39dcd099948bfeb7fa4ac14f3f53dd36 not-for-merge 'refs/pull/356/head' of https://github.com/apple/swift-collections
75395832459d3e7a05ec51ca2ea081fe99be5e8e not-for-merge 'refs/pull/357/head' of https://github.com/apple/swift-collections
e004cd36fa3900c67d97f9944320a213e0d62c42 not-for-merge 'refs/pull/358/head' of https://github.com/apple/swift-collections
f6380bb6608eb7d43c199b3d0ab2f932d300a338 not-for-merge 'refs/pull/36/head' of https://github.com/apple/swift-collections
e424b487611d755ee5fe94271dd69677cc7688f0 not-for-merge 'refs/pull/360/head' of https://github.com/apple/swift-collections
a45e90653a50d7cd8813775cbf3d4ae546db1479 not-for-merge 'refs/pull/361/head' of https://github.com/apple/swift-collections
1e132acbb4f4aceea67ac8cdd5a4afdb1053e13d not-for-merge 'refs/pull/362/head' of https://github.com/apple/swift-collections
09566acb3a06bcb80147555395ae564402a4013f not-for-merge 'refs/pull/367/head' of https://github.com/apple/swift-collections
7425af3a9e29913aeb7cae881f9583f204ca5310 not-for-merge 'refs/pull/368/head' of https://github.com/apple/swift-collections
e9112f40dd90d800c46adf88c7ad58653276bb5b not-for-merge 'refs/pull/370/head' of https://github.com/apple/swift-collections
f46333d4a7c3a3f408131e268589203a68b84a09 not-for-merge 'refs/pull/371/head' of https://github.com/apple/swift-collections
37feda1bb815269044e98991edf011dd713eda6a not-for-merge 'refs/pull/372/head' of https://github.com/apple/swift-collections
ba5154b934dde320698eb31623e6c61eb63675e8 not-for-merge 'refs/pull/373/head' of https://github.com/apple/swift-collections
e3954cdae4f9e97fbd7fd3ec1e80f01abbd6c06c not-for-merge 'refs/pull/375/head' of https://github.com/apple/swift-collections
89b3ca0146f7371dd1008b0f6dd1d1452840deb2 not-for-merge 'refs/pull/377/head' of https://github.com/apple/swift-collections
8d9e1e32484fa7fbbfe49df058fee41304c47213 not-for-merge 'refs/pull/378/head' of https://github.com/apple/swift-collections
5d891350f44eecd7767b85259b1fd3068afe3c16 not-for-merge 'refs/pull/379/head' of https://github.com/apple/swift-collections
d46a563351a5785e7ece59366fb80d1ffc21885c not-for-merge 'refs/pull/38/head' of https://github.com/apple/swift-collections
ead6314a1cb17c2ecce50c80876f1998dcff6286 not-for-merge 'refs/pull/381/head' of https://github.com/apple/swift-collections
35d5746117b42a556f81cff9fe016fdff8a6ddaa not-for-merge 'refs/pull/382/head' of https://github.com/apple/swift-collections
a0b839d7de3278c5003836ad27d8ab75b994cbf5 not-for-merge 'refs/pull/384/head' of https://github.com/apple/swift-collections
d10a328f79966ada76c0f5e1f13922363e1d7da9 not-for-merge 'refs/pull/385/head' of https://github.com/apple/swift-collections
21264913c5162a74f58ef8af8d675417b188b8b9 not-for-merge 'refs/pull/386/head' of https://github.com/apple/swift-collections
dbf90bd36bcfdd3659670e26259e1a1cf40b053a not-for-merge 'refs/pull/388/head' of https://github.com/apple/swift-collections
5c2623b1a8d01d670455c739d07d94ba4f731f72 not-for-merge 'refs/pull/389/head' of https://github.com/apple/swift-collections
7d18b37a95732fa58da3863efb4f8f142524abdb not-for-merge 'refs/pull/390/head' of https://github.com/apple/swift-collections
094bf7ff2c87c735eb7ef41e1eeaedb41c8c0625 not-for-merge 'refs/pull/391/head' of https://github.com/apple/swift-collections
16fcea238788bd5d298d96a199ffbbeea9f0845a not-for-merge 'refs/pull/392/head' of https://github.com/apple/swift-collections
b7ccc7206cefa77e0139cd01af053895a5021fce not-for-merge 'refs/pull/393/head' of https://github.com/apple/swift-collections
79e3fee891cf132262e66a192424cc5a5892c732 not-for-merge 'refs/pull/394/head' of https://github.com/apple/swift-collections
7afbd7686e3ed22f4fff4f12721e944fb94c3476 not-for-merge 'refs/pull/394/merge' of https://github.com/apple/swift-collections
36d53620b57f2c90b897525049d50d327f174edf not-for-merge 'refs/pull/395/head' of https://github.com/apple/swift-collections
ce574378f856d15eec794157225005947534a6ca not-for-merge 'refs/pull/396/head' of https://github.com/apple/swift-collections
99b025049e3fd4f1a791349716d7e3a6e6742ea7 not-for-merge 'refs/pull/397/head' of https://github.com/apple/swift-collections
09f9340dcec6744e7238c0d966cad57e302a7419 not-for-merge 'refs/pull/398/head' of https://github.com/apple/swift-collections
f049c7ae66996b3be81be9688aecc313fb62d2bd not-for-merge 'refs/pull/399/head' of https://github.com/apple/swift-collections
3595ca05808ce018fb0fe6ca985a94d162cee300 not-for-merge 'refs/pull/4/head' of https://github.com/apple/swift-collections
ec1893ac2372b7f596f4bdcff9b3fdbf1017dddc not-for-merge 'refs/pull/40/head' of https://github.com/apple/swift-collections
105afd86fbc2a40752f4d522f7168c4f5c68f551 not-for-merge 'refs/pull/400/head' of https://github.com/apple/swift-collections
3dd72d1c289e56fac76e5a5416c397da4946e98d not-for-merge 'refs/pull/401/head' of https://github.com/apple/swift-collections
edb00bd980448f956a07b3d513f27fca32a1bb08 not-for-merge 'refs/pull/402/head' of https://github.com/apple/swift-collections
cf241c3b6c32196768d825f961fc9b00e7e6b53f not-for-merge 'refs/pull/402/merge' of https://github.com/apple/swift-collections
6b8276e2521d63ae1adc2cfd41d9e5a03e099ebe not-for-merge 'refs/pull/403/head' of https://github.com/apple/swift-collections
6f4d9d856088be4b13c96717e45e94f902bb3fbd not-for-merge 'refs/pull/404/head' of https://github.com/apple/swift-collections
5e1fe6e8f04e609273ee4fafe2fb77922ac2012f not-for-merge 'refs/pull/405/head' of https://github.com/apple/swift-collections
93efdb9e4e967a0ad0cb735721b0a67447cd12b2 not-for-merge 'refs/pull/406/head' of https://github.com/apple/swift-collections
effb33569a926c12dc8e7bae979ac2075c219189 not-for-merge 'refs/pull/408/head' of https://github.com/apple/swift-collections
e14970493019b12d03046f2fdd01b76fd4f9fa3c not-for-merge 'refs/pull/409/head' of https://github.com/apple/swift-collections
897b7c1a387e7afc2c95b4022c3b303137631c62 not-for-merge 'refs/pull/41/head' of https://github.com/apple/swift-collections
5dd817c33df1a62776320437413ad7afbeaab414 not-for-merge 'refs/pull/410/head' of https://github.com/apple/swift-collections
75aa5b075534ab11b77bc694f4c6d7cc29eab26f not-for-merge 'refs/pull/411/head' of https://github.com/apple/swift-collections
0f138be4021524c1b9b8fa2dcd343876695b8101 not-for-merge 'refs/pull/414/head' of https://github.com/apple/swift-collections
ca0c7a28b9b94243cac476dc4275db29f5d0be46 not-for-merge 'refs/pull/415/head' of https://github.com/apple/swift-collections
0030b455f42d9a8588cb9791fdf9e62a4d0e401c not-for-merge 'refs/pull/417/head' of https://github.com/apple/swift-collections
0030b455f42d9a8588cb9791fdf9e62a4d0e401c not-for-merge 'refs/pull/418/head' of https://github.com/apple/swift-collections
7f49fa5164ce43bd1bfcdfe2b43b56cdf6845bd6 not-for-merge 'refs/pull/419/head' of https://github.com/apple/swift-collections
ea4ab58dbc0a886c8a50752068de817ba1e49e81 not-for-merge 'refs/pull/42/head' of https://github.com/apple/swift-collections
fec5a5a6302e3bd30b71cbb8a22706d417eb5e72 not-for-merge 'refs/pull/421/head' of https://github.com/apple/swift-collections
a49afbe1be5e5d26f74b32d77057bf01ecee83bf not-for-merge 'refs/pull/422/head' of https://github.com/apple/swift-collections
ccff1fbf71b315e0eee2ba2b46b82dda44fac55d not-for-merge 'refs/pull/423/head' of https://github.com/apple/swift-collections
3f6522fef12acbebec4e425fec2a0d63a4bbac60 not-for-merge 'refs/pull/424/head' of https://github.com/apple/swift-collections
b33922ed298ce150cd04d0ee330d0c85b3cee104 not-for-merge 'refs/pull/426/head' of https://github.com/apple/swift-collections
84087c786e25744e47affbaae0b44415a973bdc9 not-for-merge 'refs/pull/427/head' of https://github.com/apple/swift-collections
ebe01ea88769ec788cdcd91bdd9d24ae5ceb4f55 not-for-merge 'refs/pull/43/head' of https://github.com/apple/swift-collections
2709b9694779797954b7bebb18764c2a85876e7e not-for-merge 'refs/pull/433/head' of https://github.com/apple/swift-collections
98d345bd66496d36a1d62506d405e6d7b07e8cde not-for-merge 'refs/pull/436/head' of https://github.com/apple/swift-collections
2d4df7d85dea6c6e81edb7a51de92c413318b6c9 not-for-merge 'refs/pull/438/head' of https://github.com/apple/swift-collections
8d73c7cced4d9a8403e2353f02359844bd33b5b9 not-for-merge 'refs/pull/438/merge' of https://github.com/apple/swift-collections
117c81053b70de031bac51b53288c001662c9305 not-for-merge 'refs/pull/44/head' of https://github.com/apple/swift-collections
4450b7c62274bc08f21b94269e0316e2799afe90 not-for-merge 'refs/pull/445/head' of https://github.com/apple/swift-collections
99db3179fcfab1add1a2418ed5f5392f25156aa0 not-for-merge 'refs/pull/446/head' of https://github.com/apple/swift-collections
40adeb7fd7e86a3d84779a2c43c2211ae805b804 not-for-merge 'refs/pull/447/head' of https://github.com/apple/swift-collections
1cb3ca50a63e8eac9dc503b3fba69ef56a99bce2 not-for-merge 'refs/pull/449/head' of https://github.com/apple/swift-collections
0f73f0ace74ea44f39ab10f23a3d2c03afd54a8f not-for-merge 'refs/pull/450/head' of https://github.com/apple/swift-collections
7ae9880f0fb622992a8a5328fd4af78af5b6b26f not-for-merge 'refs/pull/451/head' of https://github.com/apple/swift-collections
c5ac12e2bc1ad8df1df0ee9d1236ab6366a2c32d not-for-merge 'refs/pull/452/head' of https://github.com/apple/swift-collections
cfbebf4c80d0bc18609e7d603366f384dbdc8ef3 not-for-merge 'refs/pull/453/head' of https://github.com/apple/swift-collections
dbc2866bb5f564d3be3fa5efdda769f2946ee968 not-for-merge 'refs/pull/454/head' of https://github.com/apple/swift-collections
225159599d37106d63795d2df1bcbe0ccf7b3479 not-for-merge 'refs/pull/455/head' of https://github.com/apple/swift-collections
25509c0b883738629b6a13c013b6274538112fbe not-for-merge 'refs/pull/456/head' of https://github.com/apple/swift-collections
c42b4d1ebc5d198401f3efbcda36874b987e29d4 not-for-merge 'refs/pull/457/head' of https://github.com/apple/swift-collections
fd9ee69e0ba4e389a5ecdd85822a0932b0496e3c not-for-merge 'refs/pull/458/head' of https://github.com/apple/swift-collections
769bc7b07c3b986d928540d74d53bdd3d73f4374 not-for-merge 'refs/pull/459/head' of https://github.com/apple/swift-collections
ca939f84e132eb64a44db49c8092c8ec261b3092 not-for-merge 'refs/pull/46/head' of https://github.com/apple/swift-collections
75837a77174c0dd3243a599fae8c1675c64860d1 not-for-merge 'refs/pull/460/head' of https://github.com/apple/swift-collections
3fffe2ad2062eabe93dddb4d2e37bffe9bf278dc not-for-merge 'refs/pull/461/head' of https://github.com/apple/swift-collections
fea1d24e7be3284646858ef7bc9950f685adaa61 not-for-merge 'refs/pull/462/head' of https://github.com/apple/swift-collections
b765db28be0063341ef9048a8c4f6efb8b0e4cbd not-for-merge 'refs/pull/463/head' of https://github.com/apple/swift-collections
6385ebbe4d5fd7235dca833a4b041b14f06d46cf not-for-merge 'refs/pull/464/head' of https://github.com/apple/swift-collections
7ec497fb53a8d0a680576f1e0b0781fb71c99429 not-for-merge 'refs/pull/47/head' of https://github.com/apple/swift-collections
a7fec81fc4c4af5e49d2ce19f3b39ef51202fd22 not-for-merge 'refs/pull/470/head' of https://github.com/apple/swift-collections
117a1aad2d8194b8632bb46483573bb0b7aa50f1 not-for-merge 'refs/pull/471/head' of https://github.com/apple/swift-collections
0bd8dec08b8bb484f4a39e8d241a40c8e0c8a051 not-for-merge 'refs/pull/472/head' of https://github.com/apple/swift-collections
d5f3b81e690242c750deb4ede721539250297bd6 not-for-merge 'refs/pull/473/head' of https://github.com/apple/swift-collections
c25a388c1375c634d42a6f5608a863a4b6aace2c not-for-merge 'refs/pull/474/head' of https://github.com/apple/swift-collections
a09d7cdf458769f6f9586a2782b03d624d710428 not-for-merge 'refs/pull/475/head' of https://github.com/apple/swift-collections
e1be57c0f55f90d9489773dec69449bd86fce692 not-for-merge 'refs/pull/476/head' of https://github.com/apple/swift-collections
1812091001b264fc9b0db6a4b847ef9b330f5fd4 not-for-merge 'refs/pull/478/head' of https://github.com/apple/swift-collections
e337c2b936320f538fc8b9e8b66d51bff56646e4 not-for-merge 'refs/pull/479/head' of https://github.com/apple/swift-collections
137bd464c14792cadc721d90afd412c2e7735424 not-for-merge 'refs/pull/48/head' of https://github.com/apple/swift-collections
6819c6d1491caf6819649a0635d35956700cd165 not-for-merge 'refs/pull/480/head' of https://github.com/apple/swift-collections
c50c57f52eaae3f241dd3a4338d05f199d0bd94d not-for-merge 'refs/pull/481/head' of https://github.com/apple/swift-collections
83457e19c8b17548bf30f43bdfe7563cc6621633 not-for-merge 'refs/pull/482/head' of https://github.com/apple/swift-collections
d5568ee899f3b9487cf752cb28027910f84aad46 not-for-merge 'refs/pull/483/head' of https://github.com/apple/swift-collections
65f99e3eff346e5033d9ac9310021a4ff55a9a64 not-for-merge 'refs/pull/485/head' of https://github.com/apple/swift-collections
fc411858ee8c2d1ca4113555c185752f5d8212f5 not-for-merge 'refs/pull/486/head' of https://github.com/apple/swift-collections
05ad8633a8d6e407bd9dfce36da47b3fe36b3da2 not-for-merge 'refs/pull/487/head' of https://github.com/apple/swift-collections
a1f8f33a5b5ae60c6bdad045176e3fc96427a0a5 not-for-merge 'refs/pull/488/head' of https://github.com/apple/swift-collections
3fe754c0804d97b446a8ca70b3e4aa8d9c17c831 not-for-merge 'refs/pull/49/head' of https://github.com/apple/swift-collections
2d5ed365ff0a9d7c7bf9a84e8ac0692b80caed92 not-for-merge 'refs/pull/490/head' of https://github.com/apple/swift-collections
9f68408a70172d6c4ce3ba4e3a7528f489629e43 not-for-merge 'refs/pull/491/head' of https://github.com/apple/swift-collections
2fe5c4a31d9e599dfb55d21a02b8f9b74c5b3165 not-for-merge 'refs/pull/492/head' of https://github.com/apple/swift-collections
1f8dcd4726717a4b724e5408ca24829bdef67a49 not-for-merge 'refs/pull/493/head' of https://github.com/apple/swift-collections
c883a1729ac36de8cfc30729dd9650a98ce5c5a3 not-for-merge 'refs/pull/494/head' of https://github.com/apple/swift-collections
f44eabc30ee11beb77577f4c059bc6cf1643885b not-for-merge 'refs/pull/495/head' of https://github.com/apple/swift-collections
ab46d6415275a4f1c66923aad5d9759394b9999f not-for-merge 'refs/pull/496/head' of https://github.com/apple/swift-collections
31183bf059d3d1698d2b5e10a17bfb892a57876b not-for-merge 'refs/pull/497/head' of https://github.com/apple/swift-collections
b33592ebce263de67a30234f5952833e58f519f8 not-for-merge 'refs/pull/498/head' of https://github.com/apple/swift-collections
efac873c1357fd397b246e601021930c2a1561b9 not-for-merge 'refs/pull/499/head' of https://github.com/apple/swift-collections
efac873c1357fd397b246e601021930c2a1561b9 not-for-merge 'refs/pull/500/head' of https://github.com/apple/swift-collections
f6256df2628c6dc9b8637a81c9ce3bd9354b4df5 not-for-merge 'refs/pull/501/head' of https://github.com/apple/swift-collections
a98fbaba8b4236b1f98a9a4ee8269f5beb054425 not-for-merge 'refs/pull/502/head' of https://github.com/apple/swift-collections
8db0c6eb7539e9e73dce1a74be02093f531c8c60 not-for-merge 'refs/pull/503/head' of https://github.com/apple/swift-collections
890f33b56a7c03f5d8c680b5b566b07669adf6fb not-for-merge 'refs/pull/504/head' of https://github.com/apple/swift-collections
16f8d5b6bf91315e87e3922d2acae52d38c6bfe1 not-for-merge 'refs/pull/505/head' of https://github.com/apple/swift-collections
4ea19dd03e4c9632ee09a94f32f18a12df02da9e not-for-merge 'refs/pull/506/head' of https://github.com/apple/swift-collections
21757b6add20f67be68cad7c3b36e3ef3ec6875a not-for-merge 'refs/pull/507/head' of https://github.com/apple/swift-collections
5cd51978a44752b0432329904e72fe3ffbe22523 not-for-merge 'refs/pull/508/head' of https://github.com/apple/swift-collections
5f92d48d0d590f68340a9a6acdf0c7ae9638bb7e not-for-merge 'refs/pull/509/head' of https://github.com/apple/swift-collections
dff2b1783badd696c3135abd8e26c3b7ad2e67fd not-for-merge 'refs/pull/51/head' of https://github.com/apple/swift-collections
434d30dae30fbb57699370260c69c2108c1abf8f not-for-merge 'refs/pull/512/head' of https://github.com/apple/swift-collections
fb75c41e703f7ddaf22edfce3488c888cbb3136e not-for-merge 'refs/pull/512/merge' of https://github.com/apple/swift-collections
43367db377713ef76db6e16df128a96a7db5a805 not-for-merge 'refs/pull/513/head' of https://github.com/apple/swift-collections
50a9c6c655766bcbabac0453a5dce8cddd3e8cf7 not-for-merge 'refs/pull/514/head' of https://github.com/apple/swift-collections
101bac2d30cce81a24eb2b223aa64d928ca6598d not-for-merge 'refs/pull/515/head' of https://github.com/apple/swift-collections
6340fa0e9b818a19be3982951106ec6071075843 not-for-merge 'refs/pull/516/head' of https://github.com/apple/swift-collections
90934a152b26db2cacafaf26c0f85261815f2344 not-for-merge 'refs/pull/517/head' of https://github.com/apple/swift-collections
3fe1bb8561a92c45a56afb6dc3af95755cc2273c not-for-merge 'refs/pull/519/head' of https://github.com/apple/swift-collections
42e6045ca1307cdd5b13a69aef57336abb7ea486 not-for-merge 'refs/pull/519/merge' of https://github.com/apple/swift-collections
5e6b95649be69c3e9d6c326f2a7c2ba88c25f460 not-for-merge 'refs/pull/52/head' of https://github.com/apple/swift-collections
377d2a55a8b9506d56d4eedefe26565240b208f0 not-for-merge 'refs/pull/520/head' of https://github.com/apple/swift-collections
4cc6cad50849690b2c551f306265509d7168730b not-for-merge 'refs/pull/521/head' of https://github.com/apple/swift-collections
b88e7d0b00bcd6721cc0b11ac2b948a32a9c444d not-for-merge 'refs/pull/522/head' of https://github.com/apple/swift-collections
f4d851a739f6f1cfd0364b1c1ceb9aadd1b07f2f not-for-merge 'refs/pull/523/head' of https://github.com/apple/swift-collections
68eca941248011fdc278bd752f39fbd3f62e46c7 not-for-merge 'refs/pull/524/head' of https://github.com/apple/swift-collections
ccb60599696d69e9744224367ca927e6ba3f74b3 not-for-merge 'refs/pull/525/head' of https://github.com/apple/swift-collections
bb8d56683375160bdcc35d0ca7dcf06bb875bece not-for-merge 'refs/pull/526/head' of https://github.com/apple/swift-collections
ab7ca1353732f13ba1b24f4b95efe3dc148a0a73 not-for-merge 'refs/pull/527/head' of https://github.com/apple/swift-collections
f9669dc4186220345d8a856550386492aae74e5c not-for-merge 'refs/pull/528/head' of https://github.com/apple/swift-collections
b0f915ac6981dc529e3aa27bfe13b93c067da83e not-for-merge 'refs/pull/529/head' of https://github.com/apple/swift-collections
cf2685d6213f8966f3e453d66aa51c5f993cb514 not-for-merge 'refs/pull/529/merge' of https://github.com/apple/swift-collections
4432aa8d79607328e6e96ae2a89f878ea58b27fe not-for-merge 'refs/pull/53/head' of https://github.com/apple/swift-collections
fa45e0e0cc63150df8ff27c49a8385f1f989d2fb not-for-merge 'refs/pull/530/head' of https://github.com/apple/swift-collections
a2a4bbd3dcd04b7ec7fc84258c1732298fb95d60 not-for-merge 'refs/pull/530/merge' of https://github.com/apple/swift-collections
ea71bf2ce9a4420dc5716b94c0e02032ef3b0486 not-for-merge 'refs/pull/531/head' of https://github.com/apple/swift-collections
347825dd43e9c7f3b346aff777ae4a0cffe93ea0 not-for-merge 'refs/pull/532/head' of https://github.com/apple/swift-collections
ab649ca5fc756ed6b3b290662fb273460c4a038b not-for-merge 'refs/pull/533/head' of https://github.com/apple/swift-collections
a7e40d20551cab8bdf753c9ea809f80443903290 not-for-merge 'refs/pull/534/head' of https://github.com/apple/swift-collections
55130cecb0b8eb39da9c281e9124168d1068079e not-for-merge 'refs/pull/535/head' of https://github.com/apple/swift-collections
e5e653088cb61fae41189623b208cb100624b0d8 not-for-merge 'refs/pull/535/merge' of https://github.com/apple/swift-collections
fa408c9e853e04971c32351bab2e2200c4e07349 not-for-merge 'refs/pull/536/head' of https://github.com/apple/swift-collections
f2b51f49978351bc6225aec3cb18a916b0c4245a not-for-merge 'refs/pull/536/merge' of https://github.com/apple/swift-collections
65d174cc77577c972ed34fa03efa8c982c72f0ac not-for-merge 'refs/pull/537/head' of https://github.com/apple/swift-collections
e2e2d0088182c22f26a007d3ea4fdb3497cc830a not-for-merge 'refs/pull/538/head' of https://github.com/apple/swift-collections
0cf0071c1db25a01454339aa1dac6f8c984f8244 not-for-merge 'refs/pull/538/merge' of https://github.com/apple/swift-collections
691855a60fca67d1176bbca0871ce9beb9170bbb not-for-merge 'refs/pull/539/head' of https://github.com/apple/swift-collections
788c17c16b5bc88466d1a0a96f0bf7eaef8b9352 not-for-merge 'refs/pull/54/head' of https://github.com/apple/swift-collections
8b3d2878dea8451badb5b66094e7b4d0e4d1c658 not-for-merge 'refs/pull/540/head' of https://github.com/apple/swift-collections
ddff9004d745c4b2d13e35ebdd1a3d0b67e14717 not-for-merge 'refs/pull/541/head' of https://github.com/apple/swift-collections
5e091e541bc88b91fc750bb908aab665a4f13334 not-for-merge 'refs/pull/541/merge' of https://github.com/apple/swift-collections
1d63cdd629a5fc9e2b15a25b667f804d872f9e47 not-for-merge 'refs/pull/542/head' of https://github.com/apple/swift-collections
a617f5e2b1e7bee60846a2033645f28015990d2b not-for-merge 'refs/pull/543/head' of https://github.com/apple/swift-collections
92baa3289dee72e28b5add8cfd88c3a909d68f17 not-for-merge 'refs/pull/545/head' of https://github.com/apple/swift-collections
cf642a237ea2c2c0e345fdb856e203d418aedc81 not-for-merge 'refs/pull/545/merge' of https://github.com/apple/swift-collections
347825dd43e9c7f3b346aff777ae4a0cffe93ea0 not-for-merge 'refs/pull/547/head' of https://github.com/apple/swift-collections
2b5cbd54cf8d59e4780dad338b31cf31c3ea4aa8 not-for-merge 'refs/pull/547/merge' of https://github.com/apple/swift-collections
68c32ed80b138d1f8a6ec5dcf1b105f32fcaaf12 not-for-merge 'refs/pull/548/head' of https://github.com/apple/swift-collections
c35ca292f71bd0c2d7eb37e1dbac9318fae5bb68 not-for-merge 'refs/pull/548/merge' of https://github.com/apple/swift-collections
ad176827391e97cc1a919f38f3f6af655184facb not-for-merge 'refs/pull/549/head' of https://github.com/apple/swift-collections
ff76bbdc775050687a8495f75122faa8fef37d84 not-for-merge 'refs/pull/55/head' of https://github.com/apple/swift-collections
353496019475df6047027998d1cf69505fef172f not-for-merge 'refs/pull/550/head' of https://github.com/apple/swift-collections
7f8a32c5a9c9b07f57ebef314a5a289c7eb51021 not-for-merge 'refs/pull/551/head' of https://github.com/apple/swift-collections
a0e7df98638abbdaa452dc08b929538bda94ae18 not-for-merge 'refs/pull/552/head' of https://github.com/apple/swift-collections
174b3135c3a20094b65edb2e2c4e3e1c13693d58 not-for-merge 'refs/pull/553/head' of https://github.com/apple/swift-collections
c5d5d97c43f38162bb49fef37149ea6c4a136c50 not-for-merge 'refs/pull/554/head' of https://github.com/apple/swift-collections
7c926083822b8eea2c51cf6c6f425b9101b5d2bf not-for-merge 'refs/pull/556/head' of https://github.com/apple/swift-collections
b36804e15608a070213059cf803cc353ef88263a not-for-merge 'refs/pull/556/merge' of https://github.com/apple/swift-collections
80b8a6fb80ebb1ce7f5e918027b77a99fc57759c not-for-merge 'refs/pull/557/head' of https://github.com/apple/swift-collections
6274c2a3b1ed55f5227f54b37c1437b74a060b3c not-for-merge 'refs/pull/558/head' of https://github.com/apple/swift-collections
81514112d770a2ceeddcbba2207204661f40c650 not-for-merge 'refs/pull/558/merge' of https://github.com/apple/swift-collections
fdaf3fe24c72ac54998e4d2361aaa5d9fedd12b5 not-for-merge 'refs/pull/560/head' of https://github.com/apple/swift-collections
59bb505b1a18e05342fd58d873a967b484f2f268 not-for-merge 'refs/pull/562/head' of https://github.com/apple/swift-collections
de54709ca9dffef94ee4f1b04f6a6483d620d1a3 not-for-merge 'refs/pull/563/head' of https://github.com/apple/swift-collections
d1efcb19db72befae31841116b43586350a60a72 not-for-merge 'refs/pull/565/head' of https://github.com/apple/swift-collections
b7d2cf8908b42f35b5a3929e18ab63d3a321a3a1 not-for-merge 'refs/pull/58/head' of https://github.com/apple/swift-collections
956ea437dfdfcc6b431315fe54a9388271f5b512 not-for-merge 'refs/pull/6/head' of https://github.com/apple/swift-collections
175e1eb6b3395e3808218e72910235658819bdc5 not-for-merge 'refs/pull/60/head' of https://github.com/apple/swift-collections
083102e1e2bad3bfc869f3072f134fc48a401550 not-for-merge 'refs/pull/61/head' of https://github.com/apple/swift-collections
0b963fe790c694a35c34b2b31caa84a681f74945 not-for-merge 'refs/pull/62/head' of https://github.com/apple/swift-collections
cfe64fa1f270ff99ae4c5bf36502656d5c77596f not-for-merge 'refs/pull/63/head' of https://github.com/apple/swift-collections
787c4fac1492d4d877127ccf086195b5051b5c01 not-for-merge 'refs/pull/64/head' of https://github.com/apple/swift-collections
478d3cc73fe173775883d35a2b0a073567da3b4b not-for-merge 'refs/pull/65/head' of https://github.com/apple/swift-collections
2a60245369a3e88485ed4f8c92ca5c378ce77c06 not-for-merge 'refs/pull/76/head' of https://github.com/apple/swift-collections
b70b6fec29949244914e7501725deb52370da0b0 not-for-merge 'refs/pull/77/head' of https://github.com/apple/swift-collections
303e1990d6317fc39c5c072483d18e4f0235db60 not-for-merge 'refs/pull/78/head' of https://github.com/apple/swift-collections
cfaab9a73140595755a5bcc138c45ad817dc4f44 not-for-merge 'refs/pull/79/head' of https://github.com/apple/swift-collections
8de85365808b3d984148d0adb5dc36125a71c36f not-for-merge 'refs/pull/8/head' of https://github.com/apple/swift-collections
976a8c276338a00a436f620f9cb8d3c0f74f6d81 not-for-merge 'refs/pull/80/head' of https://github.com/apple/swift-collections
1146f2644c44ff629c5dfc8f5588d6d4cc734a22 not-for-merge 'refs/pull/80/merge' of https://github.com/apple/swift-collections
07134a5bce472917a2fc2f2a19401861a688530b not-for-merge 'refs/pull/81/head' of https://github.com/apple/swift-collections
3d4aca47308287244f2dd7b9c2085dea63c27b60 not-for-merge 'refs/pull/82/head' of https://github.com/apple/swift-collections
140a1752fdfa9788db9e5b23ee32d8bdbed4c9f7 not-for-merge 'refs/pull/83/head' of https://github.com/apple/swift-collections
40ab3405b25719a490abea591d80b7ce27ab8803 not-for-merge 'refs/pull/84/head' of https://github.com/apple/swift-collections
52f77c4486ea96a3c5ed373932ee0220d5a7ebee not-for-merge 'refs/pull/85/head' of https://github.com/apple/swift-collections
029dd258a1d19cbcd8e22523b0811c7dcb6d450a not-for-merge 'refs/pull/86/head' of https://github.com/apple/swift-collections
8ef7b779cd17e95baeef138a612c48b063036aca not-for-merge 'refs/pull/87/head' of https://github.com/apple/swift-collections
ace0073826e3e2bdc1b08d78e6fe6f1efc700aab not-for-merge 'refs/pull/9/head' of https://github.com/apple/swift-collections
e78605942c7fb08c3e8812a166e85bcae2ddd15e not-for-merge 'refs/pull/91/head' of https://github.com/apple/swift-collections
7c68b05ed94391100c1933770cd18e95533bd53d not-for-merge 'refs/pull/92/head' of https://github.com/apple/swift-collections
d6774be62f7f857f0b30dae49a3a6f02b58e5679 not-for-merge 'refs/pull/93/head' of https://github.com/apple/swift-collections
6192ad1fc8795b647f8fb9eec20257ae2cb4716d not-for-merge 'refs/pull/95/head' of https://github.com/apple/swift-collections
dcdd7ebabbdcac6442e45db68f6e3d10b96f0c88 not-for-merge 'refs/pull/96/head' of https://github.com/apple/swift-collections
41bfaaae0af3809b808405df0fab4a5e02ddd206 not-for-merge 'refs/pull/97/head' of https://github.com/apple/swift-collections
462fb1d3fc318f4e1f81d6945b87f1dc32dd8079 not-for-merge 'refs/pull/98/head' of https://github.com/apple/swift-collections
c1c9541a3b91ec076076ad8e9a4e28a00b80cb6b not-for-merge 'refs/pull/99/head' of https://github.com/apple/swift-collections
bd924007a25488900d2e3f3437a0388a97636020 not-for-merge tag '0.0.1' of https://github.com/apple/swift-collections
2d719d75a2065f213e58a5164384a3d2fcf9b59a not-for-merge tag '0.0.2' of https://github.com/apple/swift-collections
d45e63421d3dff834949ac69d3c37691e994bd69 not-for-merge tag '0.0.3' of https://github.com/apple/swift-collections
3426dba9ee5c9f8e4981b0fc9d39a818d36eec28 not-for-merge tag '0.0.4' of https://github.com/apple/swift-collections
0959ba76a1d4a98fd11163aa83fd49c25b93bfae not-for-merge tag '0.0.5' of https://github.com/apple/swift-collections
9d8719c8bebdc79740b6969c912ac706eb721d7a not-for-merge tag '0.0.7' of https://github.com/apple/swift-collections
07e47b1e93e5a1e0ef0c50fcb2d6739fb6be4003 not-for-merge tag '1.0.0' of https://github.com/apple/swift-collections
2d33a0ea89c961dcb2b3da2157963d9c0370347e not-for-merge tag '1.0.1' of https://github.com/apple/swift-collections
48254824bb4248676bf7ce56014ff57b142b77eb not-for-merge tag '1.0.2' of https://github.com/apple/swift-collections
f504716c27d2e5d4144fa4794b12129301d17729 not-for-merge tag '1.0.3' of https://github.com/apple/swift-collections
937e904258d22af6e447a0b72c0bc67583ef64a2 not-for-merge tag '1.0.4' of https://github.com/apple/swift-collections
a902f1823a7ff3c9ab2fba0f992396b948eda307 not-for-merge tag '1.0.5' of https://github.com/apple/swift-collections
d029d9d39c87bed85b1c50adee7c41795261a192 not-for-merge tag '1.0.6' of https://github.com/apple/swift-collections
94cf62b3ba8d4bed62680a282d4c25f9c63c2efb not-for-merge tag '1.1.0' of https://github.com/apple/swift-collections
ee97538f5b81ae89698fd95938896dec5217b148 not-for-merge tag '1.1.1' of https://github.com/apple/swift-collections
3d2dc41a01f9e49d84f0a3925fb858bed64f702d not-for-merge tag '1.1.2' of https://github.com/apple/swift-collections
9bf03ff58ce34478e66aaee630e491823326fd06 not-for-merge tag '1.1.3' of https://github.com/apple/swift-collections
671108c96644956dddcd89dd59c203dcdb36cec7 not-for-merge tag '1.1.4' of https://github.com/apple/swift-collections
ad9f6723fd29591e6c0a19a9c4982cae51d65b1d not-for-merge tag '1.1.5' of https://github.com/apple/swift-collections
c11818f3cae0780656baa430b49e7f163f08dffd not-for-merge tag '1.1.6' of https://github.com/apple/swift-collections
c1805596154bb3a265fd91b8ac0c4433b4348fb0 not-for-merge tag '1.2.0' of https://github.com/apple/swift-collections
8c0c0a8b49e080e54e5e328cc552821ff07cd341 not-for-merge tag '1.2.1' of https://github.com/apple/swift-collections
7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e not-for-merge tag '1.3.0' of https://github.com/apple/swift-collections

View File

@@ -0,0 +1 @@
ref: refs/heads/main

View File

@@ -0,0 +1,10 @@
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = https://github.com/apple/swift-collections.git
fetch = +refs/*:refs/*
mirror = true

View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@@ -0,0 +1,174 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
my $last_update_line = "";
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
$last_update_line = qq[\n"since": $last_update_token,];
}
my $query = <<" END";
["query", "$git_work_tree", {$last_update_line
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}

View File

@@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git update-server-info

View File

@@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
precommit="$(git rev-parse --git-path hooks/pre-commit)"
test -x "$precommit" && exec "$precommit" ${1+"$@"}
:

View File

@@ -0,0 +1,49 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --type=bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

View File

@@ -0,0 +1,13 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git merge" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message to
# stderr if it wants to stop the merge commit.
#
# To enable this hook, rename this file to "pre-merge-commit".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:

View File

@@ -0,0 +1,53 @@
#!/bin/sh
# An example hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local oid> <remote ref> <remote oid>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
while read local_ref local_oid remote_ref remote_oid
do
if test "$local_oid" = "$zero"
then
# Handle delete
:
else
if test "$remote_oid" = "$zero"
then
# New branch, examine all commits
range="$local_oid"
else
# Update to existing branch, examine new commits
range="$remote_oid..$local_oid"
fi
# Check for WIP commit
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
if test -n "$commit"
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
fi
fi
done
exit 0

View File

@@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up to date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
/usr/bin/perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
<<\DOC_END
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git rev-list ^master ^topic next
git rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git rev-list master..topic
if this is empty, it is fully merged to "master".
DOC_END

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to make use of push options.
# The example simply echoes all push options that start with 'echoback='
# and rejects all pushes when the "reject" push option is used.
#
# To enable this hook, rename this file to "pre-receive".
if test -n "$GIT_PUSH_OPTION_COUNT"
then
i=0
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
do
eval "value=\$GIT_PUSH_OPTION_$i"
case "$value" in
echoback=*)
echo "echo from the pre-receive-hook: ${value#*=}" >&2
;;
reject)
exit 1
esac
i=$((i + 1))
done
fi

View File

@@ -0,0 +1,42 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first one removes the
# "# Please enter the commit message..." help message.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
# case "$COMMIT_SOURCE,$SHA1" in
# ,|template,)
# /usr/bin/perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
# *) ;;
# esac
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
# if test -z "$COMMIT_SOURCE"
# then
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
# fi

View File

@@ -0,0 +1,78 @@
#!/bin/sh
# An example hook script to update a checked-out tree on a git push.
#
# This hook is invoked by git-receive-pack(1) when it reacts to git
# push and updates reference(s) in its repository, and when the push
# tries to update the branch that is currently checked out and the
# receive.denyCurrentBranch configuration variable is set to
# updateInstead.
#
# By default, such a push is refused if the working tree and the index
# of the remote repository has any difference from the currently
# checked out commit; when both the working tree and the index match
# the current commit, they are updated to match the newly pushed tip
# of the branch. This hook is to be used to override the default
# behaviour; however the code below reimplements the default behaviour
# as a starting point for convenient modification.
#
# The hook receives the commit with which the tip of the current
# branch is going to be updated:
commit=$1
# It can exit with a non-zero status to refuse the push (when it does
# so, it must not modify the index or the working tree).
die () {
echo >&2 "$*"
exit 1
}
# Or it can make any necessary changes to the working tree and to the
# index to bring them to the desired state when the tip of the current
# branch is updated to the new commit, and exit with a zero status.
#
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
# in order to emulate git fetch that is run in the reverse direction
# with git push, as the two-tree form of git read-tree -u -m is
# essentially the same as git switch or git checkout that switches
# branches while keeping the local changes in the working tree that do
# not interfere with the difference between the branches.
# The below is a more-or-less exact translation to shell of the C code
# for the default behaviour for git's push-to-checkout hook defined in
# the push_to_deploy() function in builtin/receive-pack.c.
#
# Note that the hook will be executed from the repository directory,
# not from the working tree, so if you want to perform operations on
# the working tree, you will have to adapt your code accordingly, e.g.
# by adding "cd .." or using relative paths.
if ! git update-index -q --ignore-submodules --refresh
then
die "Up-to-date check failed"
fi
if ! git diff-files --quiet --ignore-submodules --
then
die "Working directory has unstaged changes"
fi
# This is a rough translation of:
#
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
if git cat-file -e HEAD 2>/dev/null
then
head=HEAD
else
head=$(git hash-object -t tree --stdin </dev/null)
fi
if ! git diff-index --quiet --cached --ignore-submodules $head --
then
die "Working directory has staged changes"
fi
if ! git read-tree -u -m "$commit"
then
die "Could not update working tree to new HEAD"
fi

View File

@@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --type=bool hooks.allowunannotated)
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

View File

@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

View File

@@ -0,0 +1,466 @@
# pack-refs with: peeled fully-peeled sorted
1f8dcd4726717a4b724e5408ca24829bdef67a49 refs/heads/action-xcode-versions
7ae9880f0fb622992a8a5328fd4af78af5b6b26f refs/heads/dn/remove-retain-release-during-find
ddff9004d745c4b2d13e35ebdd1a3d0b67e14717 refs/heads/doc-basic-span-index-mutation
ebd51171f0e45788e2cdb3cc6d54233e11d7443c refs/heads/future
39b83a1f44289d67e422b6030c498b8a2c6ff7ce refs/heads/main
68c32ed80b138d1f8a6ec5dcf1b105f32fcaaf12 refs/heads/maxd/run-wasm-tests
762bc5757de4bcf86cc3b3266e3df93f76469089 refs/heads/nate/zip_dispatch_benchmarking
d029d9d39c87bed85b1c50adee7c41795261a192 refs/heads/release/1.0
c11818f3cae0780656baa430b49e7f163f08dffd refs/heads/release/1.1
2d1f4172091ca272b461397748fd2c32847036dd refs/heads/release/1.2
c55cbe540366c704c279298ca6ad4c09a067ebe0 refs/heads/release/1.3
a26fc8e7e4c6e0d63b08951f5b7268044fb95c83 refs/heads/span-prototype
434d30dae30fbb57699370260c69c2108c1abf8f refs/heads/wasm-tests
c65cd649fb91f64636f2f1ef5da4991987139f68 refs/pull/10/head
6a9703c3f13061291eff1baf8af4fce1e6ce35af refs/pull/100/head
8303a77bc2915be76777d6fc17b702146b6fb192 refs/pull/102/head
6cd03922372c85e2dca476f665527976911e7397 refs/pull/105/head
96100d4b6ad61bbfbf549ee42dc73239325b353f refs/pull/106/head
f69104b5071ef9a44112e3c4fef8904b5e8b6d73 refs/pull/107/head
5f255a887e51093f058e7ee9ea0b959051be38d4 refs/pull/108/head
c46c77f7f85f9efe83cc5cb8d54b32c538b06450 refs/pull/109/head
cfca1038b53eecd4fc50da15cc715f966904012e refs/pull/11/head
103008aca495f3b80a50713086d451b08cef9f50 refs/pull/110/head
39a16a15cc8c7e11486015d2deb78468b4a64c85 refs/pull/111/head
7f57a0ed1c8b1d44eacab95d3cfd57d87482b25a refs/pull/112/head
efefae56531b30d75553f234134e3c83bd26c6a6 refs/pull/113/head
565b1ab20bef052f52fad4ebe112803facb325e3 refs/pull/114/head
8b3af12ece11ea7b0e748749c39a59c59269ca25 refs/pull/115/head
8be0f192e8f120969427cb2645aabe6f5fdf15a1 refs/pull/116/head
771bca404c0ee603bb6cc2ea3a19cfc4ebc3d001 refs/pull/117/head
95be379a3ac1e4278d114a22501267065062b39a refs/pull/118/head
f41f2cae69dc6ffcc178227a0a46607561fa925c refs/pull/119/head
276ddee5df4ea0f44c5edea0dbe726cb74682498 refs/pull/121/head
1c1e6206fa1a4b0a6bf97ac979f841c1d1821ad7 refs/pull/122/head
074b0ad21387e767b5b3ff1cb014a118a3b80bde refs/pull/123/head
ddc8b9c66d07cb0af38e98ca160f1f7cc85c88d3 refs/pull/126/head
9dde4b560323d43ec2ca8225a6c5c79a9bc0735d refs/pull/128/head
453adb695f615886cd7a897d62676713aeb25bf9 refs/pull/13/head
286fedb1e8f6b2567cd214cf1127a9322dea1400 refs/pull/130/head
e77d82c71271b7848e3ac9e007a52f36f04a1c7e refs/pull/132/head
1bde9674f42e41bfb62deb96d8b247a537171ba7 refs/pull/132/merge
cee04e96ed96fefa5527e33a4a055482e4ea14e9 refs/pull/14/head
50e6a1ac71df96e5cd257c565e9a3299f491ba3e refs/pull/140/head
29120ea6406a856c36496b4f5d3b13ca381436a6 refs/pull/141/head
867231031ac792328eff9133a289ce9e693a03c3 refs/pull/15/head
6cb037037d45f78622fd7cab3f62e3c6a4ff5ddb refs/pull/153/head
7016a13f0e8d0d0a36f3566a6dc6acaf5b83fbf4 refs/pull/155/head
00a99aa77c4982a6e7343982220e44b15e4d5974 refs/pull/156/head
74a800ac534877875d5d1187ac04f35b31a0b98c refs/pull/159/head
b9d73a5bab8d71e121687f79ed4aabfbd73d016b refs/pull/16/head
ddb6d141b3e4e8726a15e3e9e916ee697bd310db refs/pull/160/head
3437abecc49cfbbb91893e3a0d0f124db163637f refs/pull/161/head
1071b372942289dbd3209ede40f613d339cca8e1 refs/pull/162/head
b9d91f4a9aa3cfd6c8589aee997c4399e6d7d83d refs/pull/163/head
ee1b2de06edf18545084d99a5c99995e9c1ff8d4 refs/pull/165/head
b379fa7aee604738bd0b4076984c934e242bb7a5 refs/pull/168/head
71aa4a39ae59addf40e9dd40e79a4968f1c857cc refs/pull/169/head
feca3b6f4c7bf7adf9fa4a0fd200f96cf1b5a4b5 refs/pull/170/head
9a9d7d87d844b2a14ec602792d9ae216ea57ea53 refs/pull/172/head
8cc0b1d43975a9d547053cf0e943498c0d6d7992 refs/pull/173/head
aa428d0489be5888c72de4a4327f0f316a586632 refs/pull/174/head
14f90620c89e311a067a1fa49813d8bbcd539950 refs/pull/175/head
77edbef16d24e657fc3d7b0bc9adb57e6b0567d9 refs/pull/176/head
9d9659a079644d300d3571fb64ac7bb14322e506 refs/pull/177/head
9f38e7424baa3497e4d481790fc6ec2950725de8 refs/pull/178/head
d45f264ef0dc625a37801ee6e05b764ccbef30b4 refs/pull/179/head
58579394fc929c1b89b762c3ef68a1657442ca7d refs/pull/18/head
39fc818e0efaa148e038e3d89cd78be64567849a refs/pull/180/head
4c4154ca2350d981cd6abeadbdcad18071fe3b95 refs/pull/181/head
59858a77210f506e622a68e5b92e36bae6fc9215 refs/pull/182/head
ba303dca1d72860f0b253778f193010af20f9b79 refs/pull/184/head
778b8ae977c420dfe323b27ed3a1cf3f747f936b refs/pull/185/head
0f92943ba349d0337d254789bc49e9a5c45ff74e refs/pull/187/head
f71ebd9494b3b0b8c1450017f8c30fb61e4dcc37 refs/pull/188/head
66651795d89e760188908bb65b3398aa30b84897 refs/pull/189/head
832e58027cdb86e618089ebdf2e3474da915c357 refs/pull/190/head
9b7c6ecb10599568876b1108005b189de54d9ce9 refs/pull/191/head
4604c1bc381c4d164a030d11830701b2897a0002 refs/pull/192/head
0b86bb11d24e187ab6ab930f582f75ae00bcabf9 refs/pull/193/head
c7c0a094f91bd5cce90b1dc1f3feeb9d2508e7f5 refs/pull/194/head
1b71d2cd942459049b870264b7db649ba7509046 refs/pull/195/head
7cec5d1ed71d0c29fc7515725401c8a711a01074 refs/pull/196/head
b83d06b43337cc2855c1b55ba1cdba854724110b refs/pull/197/head
6286cd0b99741db984e5c1115a4c748bc42efec1 refs/pull/198/head
8b06c61c7e4ecb6777895a8fba275a44ec8c5e01 refs/pull/199/head
5aed92655d73228211985c933e0d5141d8203a09 refs/pull/200/head
51604cd196265a1e4444cef0a7ac749e34f5e64e refs/pull/201/head
2a81cb1186ac3483183df32ba8c3e2fe7360cbcb refs/pull/202/head
6dbc8b8c4f36ff470060464d69066e2e094a194f refs/pull/203/head
6b428b5a7fadfae0120db4fc96a3d5b14f7b7c36 refs/pull/204/head
b1506b62250f074d23cddc6d0318277dda5d21dc refs/pull/205/head
2e872739d3a6201e2b888c73f08ef54ae4125d6d refs/pull/206/head
4c842df1b8cfc9611762bdf5fbd9023ab2d3d333 refs/pull/207/head
1228e9c1628925843575a11c1de8342e402c7c30 refs/pull/208/head
b6184b667bd8f636558522f18cc2fe993a825679 refs/pull/21/head
fc8092d0441e0073831d6b170c74b6cca0da9bf5 refs/pull/210/head
cfc3d4a5179e61c36d77babd9fd3029a0f85cff4 refs/pull/211/head
02ea4e849230bc2326c83c5560822a228d83afab refs/pull/212/head
1490835b289653b145b91a16fe5522d928509efb refs/pull/213/head
2b4ec22949acbfa99f9e22c390d850a650f3d298 refs/pull/214/head
5e0a0149a4c9b2ab407f65b257b5b36bc589307d refs/pull/215/head
734730d72460e7bd536e8021d4aa711cb3aa75b2 refs/pull/216/head
381cf5d17e46f2d3266bd1be7295118647443313 refs/pull/217/head
3c6cb8cd56d04392bf9f79a2d5020fc2abf1958d refs/pull/218/head
67fdff5a25539a51ce2a8bf574a7e4a6b72ebfb8 refs/pull/219/head
fbdf73e1b787a0ac113e930dff73382f612698d4 refs/pull/22/head
d3987c79a1214e279a49a09304c13322560c8a1b refs/pull/220/head
5783b82d72e620f37545924d46bdbfb429f03cbb refs/pull/221/head
2df7f6d3a8fe5f9bb12b5034da2e095424694d44 refs/pull/222/head
72e2df59e3ea600f4d5e67a324bd6df1a7acbd41 refs/pull/223/head
98d62d236bef8c30af5b7015ccbb7db66f43399e refs/pull/224/head
ba7e3927e76ff55b0579770fb036ffce6ea07b3c refs/pull/225/head
207029a613dca008e708370c09fc69010cf6a11d refs/pull/226/head
68bc6567be4c1ae96cfea1217b9e5cee63421c6a refs/pull/227/head
1c147e3b06edbe0b00217e38e94d2d3bc4b4c6a7 refs/pull/228/head
5aa603edfe8c13e0256141cb45f70ec427fe94c1 refs/pull/23/head
d19fb14c46266a20cba9c5362923c6a076e74407 refs/pull/230/head
a32048d44ee028b915565c3093ec5305e41aa6f1 refs/pull/231/head
4448454fbc79b8052acc6b6e7eb6c75c70d1ee2f refs/pull/232/head
14e86daeebe18bd32466a1f2bd2d8da936aa6508 refs/pull/233/head
581490a7351be07e465100628ded472aaa137a99 refs/pull/234/head
ff2d526c1baa53df478db47156bbdd68fcaed4df refs/pull/235/head
98d519ec12ec6bc209ad61fed2e7e2101e312566 refs/pull/237/head
339f1677450d7a8f43518d61cfd93be85fa080c3 refs/pull/238/head
ff85ea9e4f1cf6fd50fb758cde3dedf01a742f52 refs/pull/240/head
18c4f6dc5a771cd3f90ef3e7ae02a99e09e89115 refs/pull/241/head
3d66da5f5baa3585aa4b5fe8f9d9eaaee5e5a6ef refs/pull/242/head
2c33149e4e2cb9a5b2616cdbad9eabb5f51f0e0c refs/pull/243/head
a2f4b18ae02cd14a8488c357c75fef3f2c2a9013 refs/pull/244/head
69768b6eacd442681bc8424cc76516e7e24fdacc refs/pull/245/head
f8252436e5e4384eaa1a68560db380d83b7c71eb refs/pull/246/head
07032a92671dea282cbc935383dd3d5a0a598682 refs/pull/246/merge
b8ed4950368d4d54cefd2b8bfe14c329e057172c refs/pull/247/head
10a01bd9fb383668a987ec8f512da627dbe55f9e refs/pull/248/head
470bf29d014757caae7222f3a41aea0b86b6ee1c refs/pull/249/head
b43076ca7b46b8216590766fd446ae538ab91c5a refs/pull/25/head
c0853ebef8dad7eddb6a44b76dac0f42f699b96a refs/pull/251/head
089666b32ba82c06a166e072ebcdf988108b66b7 refs/pull/252/head
fef38395004569688a967b88c70d8774c63f5fc5 refs/pull/254/head
972578a44da6463eb8f88552cc7d30cf0b6de9a4 refs/pull/259/head
0c2071ecda7a50dcdc8ec435a45b3b830b3e5bcf refs/pull/259/merge
4e2f86b6cd24a124d69bf9257d2ffa751d11da8f refs/pull/26/head
580beb4c121a85f60aaf6f10403e7f457c81ccb9 refs/pull/260/head
5b4e4e032fc56ca77b888ca36b7a342e9932e5fa refs/pull/260/merge
3e6df33472d54ed83dffe3bca7a3c8f65bab4c43 refs/pull/263/head
fcd6800b9d1171fbe0a00f51a72afac32b0a1987 refs/pull/264/head
5dc7a8970eabcf6aaa49529b5ef6401f5128637e refs/pull/265/head
1666222de2200b2a614a0d5184751b8b6f7309b0 refs/pull/266/head
e6ecdac581c3f03f442111b87655702e0664df67 refs/pull/267/head
26de4aa094c87a9efd793f3ec37ec7facea24184 refs/pull/268/head
73936bba69bd49e025aa8113fa81caa7f76ed571 refs/pull/269/head
454c84b5e4253e462dac5472b853ee222ca93368 refs/pull/270/head
9c3328e235e5f17c06328f021a5d11e7221690f5 refs/pull/271/head
96d71628887275fc3010a0979cdebef15edde911 refs/pull/272/head
4b6978bf8b220c9c7d03d1f8124d537fbbddc32a refs/pull/273/head
7f63914a7161923e9af6889ed0f954de1ed4c7f0 refs/pull/275/head
ac0c075ccc0fe2754a41dd777bb39507e73efe5b refs/pull/276/head
a8dad62bc9c76f1f455a372c91759e7bb1e92e63 refs/pull/277/head
99adbe97af48017fb51d884936f6bb87c27166c2 refs/pull/278/head
b0fe7ca8bad02599faa6a308b561f71d4d5e3b4b refs/pull/279/head
dce7b156e7276d44c3641f05bf675d90fea16523 refs/pull/280/head
c4ad48826105dd299f45473784d22bf395b56863 refs/pull/281/head
1f204555aa1678c0aa01cfba5836920acb8c5537 refs/pull/282/head
992e0f3446b4f608f5ead9dd6edc92f6bbc0b0a0 refs/pull/283/head
3f4d8f9912c9c3f5bacef6e6543b3f5b93168f65 refs/pull/284/head
9befd06185369d287deee36f3d0de65f41edabb1 refs/pull/285/head
0c002200bbee27acc8a663075da69120f666b4e5 refs/pull/286/head
de0f59418503fc0c4866395751d930be3abbf17c refs/pull/287/head
a5fda7c368e06561fba87dd33c47443e879dd6da refs/pull/288/head
989bd7f2db6d9e7aa91881389359e369d621e3d9 refs/pull/29/head
03c9ef743ad9de4eea816225afa2fc52490339cc refs/pull/290/head
03e7f0c401e771f4a4c529eae4d3fde91f5bd355 refs/pull/291/head
9c88dce30d213e1844ce60476e7d3eba2b1f1e60 refs/pull/292/head
671cff0b3e579cbdad3a0818031063588d866ad2 refs/pull/296/head
b3d089e37d0d4adc07bdbf1ecd14e9be3786bf25 refs/pull/297/head
2f6606401781d32f3ffe3e245f2ba946acefe97e refs/pull/298/head
8fbc1d318cf4c48931ffc6d204123284087fad0c refs/pull/299/head
cf2cbd6ce39cbbdf7c60b76a8dca8e38b80486fc refs/pull/300/head
09c09f0f734c006186df57595dc823159e0d49ef refs/pull/302/head
a58628449c5e398433472b1bfd7e67e0acbe09fc refs/pull/303/head
a82138e714dcd28ef5b7bacc4b708acc118e87ac refs/pull/304/head
f15c276542595cb0f55368f8abf9f277e8eb51c9 refs/pull/304/merge
1cf3b88cb3d237183cacd6482e4adaec48b17bb5 refs/pull/307/head
ccd11e55dd4991055b260bb39d7e20ceb09046e9 refs/pull/31/head
9efa05c583441159bd505dfde340cf774d6144e0 refs/pull/314/head
bf742617f30870372ed235c6ccf4515ea0a204d3 refs/pull/315/head
b6e227b9d779fe7405dc410812cb3aba6d2b529a refs/pull/316/head
5c9ee680d20c4a758b0ffe06876fdca823f8068a refs/pull/316/merge
de2c8a90865dcdbd97defe3c2c7396a2400e455a refs/pull/318/head
bd1a62273592d5ad6ef388a70f53a61e33ffcba4 refs/pull/319/head
171edb86e347f70d85ac593c139d26d6b4d3bbea refs/pull/32/head
33f23b6a06f4a9f6b013fdef108cc1c82153afe4 refs/pull/320/head
b67553e0c27857bbc5310f40cd6e68daa2d585de refs/pull/321/head
b72a6cfd9384bc3ace8ea2412e79d5ec34c24934 refs/pull/322/head
90b67c44eae7277d57e79e3c25c5dc72939a3b93 refs/pull/323/head
19ec155f6089f6de453f8835aad46c09f5fd0b4d refs/pull/326/head
069dd4e5df442e813eb30e3216aafa1cc1696a5f refs/pull/327/head
53831b3a2264e24ca6c7ffcfe33c8653a72d51e1 refs/pull/328/head
0b7ebf49775a8e5177eeaea6513083363a20e08c refs/pull/330/head
3bd3d3ba28c6e72515e56b535b8a638144c12413 refs/pull/331/head
cd03e5b471755b00aa948f7de950932c2c5a5d79 refs/pull/332/head
e732790fde08a5e3d4f2347ac4a3e74399a5b457 refs/pull/333/head
d2662892cd218eec7b56e505e4a343e5c676f02c refs/pull/335/head
2bc657fad1def9519f88d851ef9e91bc01dc0e47 refs/pull/336/head
6e91291cb24b777f0db29a6d50a728a2183ab660 refs/pull/337/head
f9c400fb1c9bb8f2f76484b1a398135175d87a7f refs/pull/338/head
071a1011d1f02ac96f92164b0313c429a159ad80 refs/pull/339/head
85b00faba7071b5d7babb426bc06aa401ac8814d refs/pull/34/head
525bb545c4c1f7dfe3ca461136c072af11cb6e4f refs/pull/340/head
2122327782b71345cce48f23b688deebf582adc3 refs/pull/341/head
40e737cdaf9341d821cba518ee990406fdcfd7e3 refs/pull/342/head
8bfcaddd5fadea396620871451ca9ffc43b0985d refs/pull/343/head
9d4a1e5ad279e6bc1c4230f90208b0886608a387 refs/pull/346/head
cdcf9e606a12221e123a642353fbcfdc5d48bcf6 refs/pull/347/head
1a0ac8c06c5a27f330a55a61464eaebc840d89d1 refs/pull/348/head
258df0792818d6c331ccee923736ea234c24cf07 refs/pull/349/head
3c9df19f7da674295f58f07f6dffa5d9e114fbc8 refs/pull/351/head
c61e5e23c89b99d26aaaec6ec6c58bda1b502ebc refs/pull/352/head
8dd4e591b3789ea14e8bd8cfde3ed81aa6edfefe refs/pull/353/head
50f6307501712d87110f3f4d2e4959e84ace3bc8 refs/pull/354/head
8e64f064f562a918993b147a3872e92c157e8e01 refs/pull/355/head
ab744afc39dcd099948bfeb7fa4ac14f3f53dd36 refs/pull/356/head
75395832459d3e7a05ec51ca2ea081fe99be5e8e refs/pull/357/head
e004cd36fa3900c67d97f9944320a213e0d62c42 refs/pull/358/head
f6380bb6608eb7d43c199b3d0ab2f932d300a338 refs/pull/36/head
e424b487611d755ee5fe94271dd69677cc7688f0 refs/pull/360/head
a45e90653a50d7cd8813775cbf3d4ae546db1479 refs/pull/361/head
1e132acbb4f4aceea67ac8cdd5a4afdb1053e13d refs/pull/362/head
09566acb3a06bcb80147555395ae564402a4013f refs/pull/367/head
7425af3a9e29913aeb7cae881f9583f204ca5310 refs/pull/368/head
e9112f40dd90d800c46adf88c7ad58653276bb5b refs/pull/370/head
f46333d4a7c3a3f408131e268589203a68b84a09 refs/pull/371/head
37feda1bb815269044e98991edf011dd713eda6a refs/pull/372/head
ba5154b934dde320698eb31623e6c61eb63675e8 refs/pull/373/head
e3954cdae4f9e97fbd7fd3ec1e80f01abbd6c06c refs/pull/375/head
89b3ca0146f7371dd1008b0f6dd1d1452840deb2 refs/pull/377/head
8d9e1e32484fa7fbbfe49df058fee41304c47213 refs/pull/378/head
5d891350f44eecd7767b85259b1fd3068afe3c16 refs/pull/379/head
d46a563351a5785e7ece59366fb80d1ffc21885c refs/pull/38/head
ead6314a1cb17c2ecce50c80876f1998dcff6286 refs/pull/381/head
35d5746117b42a556f81cff9fe016fdff8a6ddaa refs/pull/382/head
a0b839d7de3278c5003836ad27d8ab75b994cbf5 refs/pull/384/head
d10a328f79966ada76c0f5e1f13922363e1d7da9 refs/pull/385/head
21264913c5162a74f58ef8af8d675417b188b8b9 refs/pull/386/head
dbf90bd36bcfdd3659670e26259e1a1cf40b053a refs/pull/388/head
5c2623b1a8d01d670455c739d07d94ba4f731f72 refs/pull/389/head
7d18b37a95732fa58da3863efb4f8f142524abdb refs/pull/390/head
094bf7ff2c87c735eb7ef41e1eeaedb41c8c0625 refs/pull/391/head
16fcea238788bd5d298d96a199ffbbeea9f0845a refs/pull/392/head
b7ccc7206cefa77e0139cd01af053895a5021fce refs/pull/393/head
79e3fee891cf132262e66a192424cc5a5892c732 refs/pull/394/head
7afbd7686e3ed22f4fff4f12721e944fb94c3476 refs/pull/394/merge
36d53620b57f2c90b897525049d50d327f174edf refs/pull/395/head
ce574378f856d15eec794157225005947534a6ca refs/pull/396/head
99b025049e3fd4f1a791349716d7e3a6e6742ea7 refs/pull/397/head
09f9340dcec6744e7238c0d966cad57e302a7419 refs/pull/398/head
f049c7ae66996b3be81be9688aecc313fb62d2bd refs/pull/399/head
3595ca05808ce018fb0fe6ca985a94d162cee300 refs/pull/4/head
ec1893ac2372b7f596f4bdcff9b3fdbf1017dddc refs/pull/40/head
105afd86fbc2a40752f4d522f7168c4f5c68f551 refs/pull/400/head
3dd72d1c289e56fac76e5a5416c397da4946e98d refs/pull/401/head
edb00bd980448f956a07b3d513f27fca32a1bb08 refs/pull/402/head
cf241c3b6c32196768d825f961fc9b00e7e6b53f refs/pull/402/merge
6b8276e2521d63ae1adc2cfd41d9e5a03e099ebe refs/pull/403/head
6f4d9d856088be4b13c96717e45e94f902bb3fbd refs/pull/404/head
5e1fe6e8f04e609273ee4fafe2fb77922ac2012f refs/pull/405/head
93efdb9e4e967a0ad0cb735721b0a67447cd12b2 refs/pull/406/head
effb33569a926c12dc8e7bae979ac2075c219189 refs/pull/408/head
e14970493019b12d03046f2fdd01b76fd4f9fa3c refs/pull/409/head
897b7c1a387e7afc2c95b4022c3b303137631c62 refs/pull/41/head
5dd817c33df1a62776320437413ad7afbeaab414 refs/pull/410/head
75aa5b075534ab11b77bc694f4c6d7cc29eab26f refs/pull/411/head
0f138be4021524c1b9b8fa2dcd343876695b8101 refs/pull/414/head
ca0c7a28b9b94243cac476dc4275db29f5d0be46 refs/pull/415/head
0030b455f42d9a8588cb9791fdf9e62a4d0e401c refs/pull/417/head
0030b455f42d9a8588cb9791fdf9e62a4d0e401c refs/pull/418/head
7f49fa5164ce43bd1bfcdfe2b43b56cdf6845bd6 refs/pull/419/head
ea4ab58dbc0a886c8a50752068de817ba1e49e81 refs/pull/42/head
fec5a5a6302e3bd30b71cbb8a22706d417eb5e72 refs/pull/421/head
a49afbe1be5e5d26f74b32d77057bf01ecee83bf refs/pull/422/head
ccff1fbf71b315e0eee2ba2b46b82dda44fac55d refs/pull/423/head
3f6522fef12acbebec4e425fec2a0d63a4bbac60 refs/pull/424/head
b33922ed298ce150cd04d0ee330d0c85b3cee104 refs/pull/426/head
84087c786e25744e47affbaae0b44415a973bdc9 refs/pull/427/head
ebe01ea88769ec788cdcd91bdd9d24ae5ceb4f55 refs/pull/43/head
2709b9694779797954b7bebb18764c2a85876e7e refs/pull/433/head
98d345bd66496d36a1d62506d405e6d7b07e8cde refs/pull/436/head
2d4df7d85dea6c6e81edb7a51de92c413318b6c9 refs/pull/438/head
8d73c7cced4d9a8403e2353f02359844bd33b5b9 refs/pull/438/merge
117c81053b70de031bac51b53288c001662c9305 refs/pull/44/head
4450b7c62274bc08f21b94269e0316e2799afe90 refs/pull/445/head
99db3179fcfab1add1a2418ed5f5392f25156aa0 refs/pull/446/head
40adeb7fd7e86a3d84779a2c43c2211ae805b804 refs/pull/447/head
1cb3ca50a63e8eac9dc503b3fba69ef56a99bce2 refs/pull/449/head
0f73f0ace74ea44f39ab10f23a3d2c03afd54a8f refs/pull/450/head
7ae9880f0fb622992a8a5328fd4af78af5b6b26f refs/pull/451/head
c5ac12e2bc1ad8df1df0ee9d1236ab6366a2c32d refs/pull/452/head
cfbebf4c80d0bc18609e7d603366f384dbdc8ef3 refs/pull/453/head
dbc2866bb5f564d3be3fa5efdda769f2946ee968 refs/pull/454/head
225159599d37106d63795d2df1bcbe0ccf7b3479 refs/pull/455/head
25509c0b883738629b6a13c013b6274538112fbe refs/pull/456/head
c42b4d1ebc5d198401f3efbcda36874b987e29d4 refs/pull/457/head
fd9ee69e0ba4e389a5ecdd85822a0932b0496e3c refs/pull/458/head
769bc7b07c3b986d928540d74d53bdd3d73f4374 refs/pull/459/head
ca939f84e132eb64a44db49c8092c8ec261b3092 refs/pull/46/head
75837a77174c0dd3243a599fae8c1675c64860d1 refs/pull/460/head
3fffe2ad2062eabe93dddb4d2e37bffe9bf278dc refs/pull/461/head
fea1d24e7be3284646858ef7bc9950f685adaa61 refs/pull/462/head
b765db28be0063341ef9048a8c4f6efb8b0e4cbd refs/pull/463/head
6385ebbe4d5fd7235dca833a4b041b14f06d46cf refs/pull/464/head
7ec497fb53a8d0a680576f1e0b0781fb71c99429 refs/pull/47/head
a7fec81fc4c4af5e49d2ce19f3b39ef51202fd22 refs/pull/470/head
117a1aad2d8194b8632bb46483573bb0b7aa50f1 refs/pull/471/head
0bd8dec08b8bb484f4a39e8d241a40c8e0c8a051 refs/pull/472/head
d5f3b81e690242c750deb4ede721539250297bd6 refs/pull/473/head
c25a388c1375c634d42a6f5608a863a4b6aace2c refs/pull/474/head
a09d7cdf458769f6f9586a2782b03d624d710428 refs/pull/475/head
e1be57c0f55f90d9489773dec69449bd86fce692 refs/pull/476/head
1812091001b264fc9b0db6a4b847ef9b330f5fd4 refs/pull/478/head
e337c2b936320f538fc8b9e8b66d51bff56646e4 refs/pull/479/head
137bd464c14792cadc721d90afd412c2e7735424 refs/pull/48/head
6819c6d1491caf6819649a0635d35956700cd165 refs/pull/480/head
c50c57f52eaae3f241dd3a4338d05f199d0bd94d refs/pull/481/head
83457e19c8b17548bf30f43bdfe7563cc6621633 refs/pull/482/head
d5568ee899f3b9487cf752cb28027910f84aad46 refs/pull/483/head
65f99e3eff346e5033d9ac9310021a4ff55a9a64 refs/pull/485/head
fc411858ee8c2d1ca4113555c185752f5d8212f5 refs/pull/486/head
05ad8633a8d6e407bd9dfce36da47b3fe36b3da2 refs/pull/487/head
a1f8f33a5b5ae60c6bdad045176e3fc96427a0a5 refs/pull/488/head
3fe754c0804d97b446a8ca70b3e4aa8d9c17c831 refs/pull/49/head
2d5ed365ff0a9d7c7bf9a84e8ac0692b80caed92 refs/pull/490/head
9f68408a70172d6c4ce3ba4e3a7528f489629e43 refs/pull/491/head
2fe5c4a31d9e599dfb55d21a02b8f9b74c5b3165 refs/pull/492/head
1f8dcd4726717a4b724e5408ca24829bdef67a49 refs/pull/493/head
c883a1729ac36de8cfc30729dd9650a98ce5c5a3 refs/pull/494/head
f44eabc30ee11beb77577f4c059bc6cf1643885b refs/pull/495/head
ab46d6415275a4f1c66923aad5d9759394b9999f refs/pull/496/head
31183bf059d3d1698d2b5e10a17bfb892a57876b refs/pull/497/head
b33592ebce263de67a30234f5952833e58f519f8 refs/pull/498/head
efac873c1357fd397b246e601021930c2a1561b9 refs/pull/499/head
efac873c1357fd397b246e601021930c2a1561b9 refs/pull/500/head
f6256df2628c6dc9b8637a81c9ce3bd9354b4df5 refs/pull/501/head
a98fbaba8b4236b1f98a9a4ee8269f5beb054425 refs/pull/502/head
8db0c6eb7539e9e73dce1a74be02093f531c8c60 refs/pull/503/head
890f33b56a7c03f5d8c680b5b566b07669adf6fb refs/pull/504/head
16f8d5b6bf91315e87e3922d2acae52d38c6bfe1 refs/pull/505/head
4ea19dd03e4c9632ee09a94f32f18a12df02da9e refs/pull/506/head
21757b6add20f67be68cad7c3b36e3ef3ec6875a refs/pull/507/head
5cd51978a44752b0432329904e72fe3ffbe22523 refs/pull/508/head
5f92d48d0d590f68340a9a6acdf0c7ae9638bb7e refs/pull/509/head
dff2b1783badd696c3135abd8e26c3b7ad2e67fd refs/pull/51/head
434d30dae30fbb57699370260c69c2108c1abf8f refs/pull/512/head
fb75c41e703f7ddaf22edfce3488c888cbb3136e refs/pull/512/merge
43367db377713ef76db6e16df128a96a7db5a805 refs/pull/513/head
50a9c6c655766bcbabac0453a5dce8cddd3e8cf7 refs/pull/514/head
101bac2d30cce81a24eb2b223aa64d928ca6598d refs/pull/515/head
6340fa0e9b818a19be3982951106ec6071075843 refs/pull/516/head
90934a152b26db2cacafaf26c0f85261815f2344 refs/pull/517/head
3fe1bb8561a92c45a56afb6dc3af95755cc2273c refs/pull/519/head
42e6045ca1307cdd5b13a69aef57336abb7ea486 refs/pull/519/merge
5e6b95649be69c3e9d6c326f2a7c2ba88c25f460 refs/pull/52/head
377d2a55a8b9506d56d4eedefe26565240b208f0 refs/pull/520/head
4cc6cad50849690b2c551f306265509d7168730b refs/pull/521/head
b88e7d0b00bcd6721cc0b11ac2b948a32a9c444d refs/pull/522/head
f4d851a739f6f1cfd0364b1c1ceb9aadd1b07f2f refs/pull/523/head
68eca941248011fdc278bd752f39fbd3f62e46c7 refs/pull/524/head
ccb60599696d69e9744224367ca927e6ba3f74b3 refs/pull/525/head
bb8d56683375160bdcc35d0ca7dcf06bb875bece refs/pull/526/head
ab7ca1353732f13ba1b24f4b95efe3dc148a0a73 refs/pull/527/head
f9669dc4186220345d8a856550386492aae74e5c refs/pull/528/head
b0f915ac6981dc529e3aa27bfe13b93c067da83e refs/pull/529/head
cf2685d6213f8966f3e453d66aa51c5f993cb514 refs/pull/529/merge
4432aa8d79607328e6e96ae2a89f878ea58b27fe refs/pull/53/head
fa45e0e0cc63150df8ff27c49a8385f1f989d2fb refs/pull/530/head
a2a4bbd3dcd04b7ec7fc84258c1732298fb95d60 refs/pull/530/merge
ea71bf2ce9a4420dc5716b94c0e02032ef3b0486 refs/pull/531/head
347825dd43e9c7f3b346aff777ae4a0cffe93ea0 refs/pull/532/head
ab649ca5fc756ed6b3b290662fb273460c4a038b refs/pull/533/head
a7e40d20551cab8bdf753c9ea809f80443903290 refs/pull/534/head
55130cecb0b8eb39da9c281e9124168d1068079e refs/pull/535/head
e5e653088cb61fae41189623b208cb100624b0d8 refs/pull/535/merge
fa408c9e853e04971c32351bab2e2200c4e07349 refs/pull/536/head
f2b51f49978351bc6225aec3cb18a916b0c4245a refs/pull/536/merge
65d174cc77577c972ed34fa03efa8c982c72f0ac refs/pull/537/head
e2e2d0088182c22f26a007d3ea4fdb3497cc830a refs/pull/538/head
0cf0071c1db25a01454339aa1dac6f8c984f8244 refs/pull/538/merge
691855a60fca67d1176bbca0871ce9beb9170bbb refs/pull/539/head
788c17c16b5bc88466d1a0a96f0bf7eaef8b9352 refs/pull/54/head
8b3d2878dea8451badb5b66094e7b4d0e4d1c658 refs/pull/540/head
ddff9004d745c4b2d13e35ebdd1a3d0b67e14717 refs/pull/541/head
5e091e541bc88b91fc750bb908aab665a4f13334 refs/pull/541/merge
1d63cdd629a5fc9e2b15a25b667f804d872f9e47 refs/pull/542/head
a617f5e2b1e7bee60846a2033645f28015990d2b refs/pull/543/head
92baa3289dee72e28b5add8cfd88c3a909d68f17 refs/pull/545/head
cf642a237ea2c2c0e345fdb856e203d418aedc81 refs/pull/545/merge
347825dd43e9c7f3b346aff777ae4a0cffe93ea0 refs/pull/547/head
2b5cbd54cf8d59e4780dad338b31cf31c3ea4aa8 refs/pull/547/merge
68c32ed80b138d1f8a6ec5dcf1b105f32fcaaf12 refs/pull/548/head
218066a6698047a111ce5fe6c77999db3cfb11ad refs/pull/548/merge
ad176827391e97cc1a919f38f3f6af655184facb refs/pull/549/head
ff76bbdc775050687a8495f75122faa8fef37d84 refs/pull/55/head
353496019475df6047027998d1cf69505fef172f refs/pull/550/head
7f8a32c5a9c9b07f57ebef314a5a289c7eb51021 refs/pull/551/head
a0e7df98638abbdaa452dc08b929538bda94ae18 refs/pull/552/head
174b3135c3a20094b65edb2e2c4e3e1c13693d58 refs/pull/553/head
c5d5d97c43f38162bb49fef37149ea6c4a136c50 refs/pull/554/head
7c926083822b8eea2c51cf6c6f425b9101b5d2bf refs/pull/556/head
5c119d9eb367474bd9cbca0e37481af4913d2db6 refs/pull/556/merge
29b31e5e0d3ca3d85bc1c546aeb16ad2f510c6f3 refs/pull/557/head
6274c2a3b1ed55f5227f54b37c1437b74a060b3c refs/pull/558/head
81514112d770a2ceeddcbba2207204661f40c650 refs/pull/558/merge
b7d2cf8908b42f35b5a3929e18ab63d3a321a3a1 refs/pull/58/head
956ea437dfdfcc6b431315fe54a9388271f5b512 refs/pull/6/head
175e1eb6b3395e3808218e72910235658819bdc5 refs/pull/60/head
083102e1e2bad3bfc869f3072f134fc48a401550 refs/pull/61/head
0b963fe790c694a35c34b2b31caa84a681f74945 refs/pull/62/head
cfe64fa1f270ff99ae4c5bf36502656d5c77596f refs/pull/63/head
787c4fac1492d4d877127ccf086195b5051b5c01 refs/pull/64/head
478d3cc73fe173775883d35a2b0a073567da3b4b refs/pull/65/head
2a60245369a3e88485ed4f8c92ca5c378ce77c06 refs/pull/76/head
b70b6fec29949244914e7501725deb52370da0b0 refs/pull/77/head
303e1990d6317fc39c5c072483d18e4f0235db60 refs/pull/78/head
cfaab9a73140595755a5bcc138c45ad817dc4f44 refs/pull/79/head
8de85365808b3d984148d0adb5dc36125a71c36f refs/pull/8/head
976a8c276338a00a436f620f9cb8d3c0f74f6d81 refs/pull/80/head
1146f2644c44ff629c5dfc8f5588d6d4cc734a22 refs/pull/80/merge
07134a5bce472917a2fc2f2a19401861a688530b refs/pull/81/head
3d4aca47308287244f2dd7b9c2085dea63c27b60 refs/pull/82/head
140a1752fdfa9788db9e5b23ee32d8bdbed4c9f7 refs/pull/83/head
40ab3405b25719a490abea591d80b7ce27ab8803 refs/pull/84/head
52f77c4486ea96a3c5ed373932ee0220d5a7ebee refs/pull/85/head
029dd258a1d19cbcd8e22523b0811c7dcb6d450a refs/pull/86/head
8ef7b779cd17e95baeef138a612c48b063036aca refs/pull/87/head
ace0073826e3e2bdc1b08d78e6fe6f1efc700aab refs/pull/9/head
e78605942c7fb08c3e8812a166e85bcae2ddd15e refs/pull/91/head
7c68b05ed94391100c1933770cd18e95533bd53d refs/pull/92/head
d6774be62f7f857f0b30dae49a3a6f02b58e5679 refs/pull/93/head
6192ad1fc8795b647f8fb9eec20257ae2cb4716d refs/pull/95/head
dcdd7ebabbdcac6442e45db68f6e3d10b96f0c88 refs/pull/96/head
41bfaaae0af3809b808405df0fab4a5e02ddd206 refs/pull/97/head
462fb1d3fc318f4e1f81d6945b87f1dc32dd8079 refs/pull/98/head
c1c9541a3b91ec076076ad8e9a4e28a00b80cb6b refs/pull/99/head
bd924007a25488900d2e3f3437a0388a97636020 refs/tags/0.0.1
2d719d75a2065f213e58a5164384a3d2fcf9b59a refs/tags/0.0.2
d45e63421d3dff834949ac69d3c37691e994bd69 refs/tags/0.0.3
3426dba9ee5c9f8e4981b0fc9d39a818d36eec28 refs/tags/0.0.4
0959ba76a1d4a98fd11163aa83fd49c25b93bfae refs/tags/0.0.5
9d8719c8bebdc79740b6969c912ac706eb721d7a refs/tags/0.0.7
07e47b1e93e5a1e0ef0c50fcb2d6739fb6be4003 refs/tags/1.0.0
2d33a0ea89c961dcb2b3da2157963d9c0370347e refs/tags/1.0.1
48254824bb4248676bf7ce56014ff57b142b77eb refs/tags/1.0.2
f504716c27d2e5d4144fa4794b12129301d17729 refs/tags/1.0.3
937e904258d22af6e447a0b72c0bc67583ef64a2 refs/tags/1.0.4
a902f1823a7ff3c9ab2fba0f992396b948eda307 refs/tags/1.0.5
d029d9d39c87bed85b1c50adee7c41795261a192 refs/tags/1.0.6
94cf62b3ba8d4bed62680a282d4c25f9c63c2efb refs/tags/1.1.0
ee97538f5b81ae89698fd95938896dec5217b148 refs/tags/1.1.1
3d2dc41a01f9e49d84f0a3925fb858bed64f702d refs/tags/1.1.2
9bf03ff58ce34478e66aaee630e491823326fd06 refs/tags/1.1.3
671108c96644956dddcd89dd59c203dcdb36cec7 refs/tags/1.1.4
ad9f6723fd29591e6c0a19a9c4982cae51d65b1d refs/tags/1.1.5
c11818f3cae0780656baa430b49e7f163f08dffd refs/tags/1.1.6
c1805596154bb3a265fd91b8ac0c4433b4348fb0 refs/tags/1.2.0
8c0c0a8b49e080e54e5e328cc552821ff07cd341 refs/tags/1.2.1
7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e refs/tags/1.3.0

View File

@@ -0,0 +1 @@
534c0cbbfef9d2f6e7a6519930967d75f7c60336

View File

@@ -0,0 +1 @@
c35ca292f71bd0c2d7eb37e1dbac9318fae5bb68

View File

@@ -0,0 +1 @@
b36804e15608a070213059cf803cc353ef88263a

View File

@@ -0,0 +1 @@
80b8a6fb80ebb1ce7f5e918027b77a99fc57759c

View File

@@ -0,0 +1 @@
fdaf3fe24c72ac54998e4d2361aaa5d9fedd12b5

View File

@@ -0,0 +1 @@
59bb505b1a18e05342fd58d873a967b484f2f268

View File

@@ -0,0 +1 @@
de54709ca9dffef94ee4f1b04f6a6483d620d1a3

View File

@@ -0,0 +1 @@
d1efcb19db72befae31841116b43586350a60a72

30
_spm/workspace-state.json Normal file
View File

@@ -0,0 +1,30 @@
{
"object" : {
"artifacts" : [
],
"dependencies" : [
{
"basedOn" : null,
"packageRef" : {
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"name" : "swift-collections"
},
"state" : {
"checkoutState" : {
"revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e",
"version" : "1.3.0"
},
"name" : "sourceControlCheckout"
},
"subpath" : "swift-collections"
}
],
"prebuilts" : [
]
},
"version" : 7
}

View File

@@ -23,6 +23,7 @@
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FAC2EC73C0100EF7AB3 /* KBVipSubscribeCell.m */; };
04122FB02EC73C0100EF7AB3 /* KBVipReviewItemCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FAF2EC73C0100EF7AB3 /* KBVipReviewItemCell.m */; };
04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */; };
0419C9662F2C7693002E86D3 /* KBVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0419C9652F2C7693002E86D3 /* KBVM.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 */; };
@@ -52,6 +53,29 @@
0459D1B42EBA284C00F2D189 /* KBSkinCenterVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */; };
0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B62EBA287900F2D189 /* KBSkinManager.m */; };
0459D1B82EBA287900F2D189 /* KBSkinManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0459D1B62EBA287900F2D189 /* KBSkinManager.m */; };
0460866B2F18D75500757C95 /* ai_test.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 0460866A2F18D75500757C95 /* ai_test.m4a */; };
046086732F191B6900757C95 /* KBAiMainVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086722F191B6900757C95 /* KBAiMainVC.m */; };
046086752F191CC700757C95 /* AI技术分析.txt in Resources */ = {isa = PBXBuildFile; fileRef = 046086742F191CC700757C95 /* AI技术分析.txt */; };
0460869A2F19238500757C95 /* KBAiWaveformView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086992F19238500757C95 /* KBAiWaveformView.m */; };
0460869C2F19238500757C95 /* KBAiRecordButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086972F19238500757C95 /* KBAiRecordButton.m */; };
046086B12F19239B00757C95 /* SubtitleSync.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086AC2F19239B00757C95 /* SubtitleSync.m */; };
046086B22F19239B00757C95 /* TTSServiceClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086B02F19239B00757C95 /* TTSServiceClient.m */; };
046086B32F19239B00757C95 /* AudioSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086A22F19239B00757C95 /* AudioSessionManager.m */; };
046086B42F19239B00757C95 /* LLMStreamClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086A82F19239B00757C95 /* LLMStreamClient.m */; };
046086B52F19239B00757C95 /* Segmenter.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086AA2F19239B00757C95 /* Segmenter.m */; };
046086B62F19239B00757C95 /* TTSPlaybackPipeline.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086AE2F19239B00757C95 /* TTSPlaybackPipeline.m */; };
046086B72F19239B00757C95 /* ConversationOrchestrator.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086A62F19239B00757C95 /* ConversationOrchestrator.m */; };
046086B82F19239B00757C95 /* ASRStreamClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0460869E2F19239B00757C95 /* ASRStreamClient.m */; };
046086B92F19239B00757C95 /* AudioCaptureManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086A02F19239B00757C95 /* AudioCaptureManager.m */; };
046086BA2F19239B00757C95 /* AudioStreamPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086A42F19239B00757C95 /* AudioStreamPlayer.m */; };
046086BD2F1A039F00757C95 /* KBAICommentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086BC2F1A039F00757C95 /* KBAICommentView.m */; };
046086CB2F1A092500757C95 /* comments_mock.json in Resources */ = {isa = PBXBuildFile; fileRef = 046086C62F1A092500757C95 /* comments_mock.json */; };
046086CC2F1A092500757C95 /* KBAIReplyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086CA2F1A092500757C95 /* KBAIReplyModel.m */; };
046086CD2F1A092500757C95 /* KBAICommentModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086C82F1A092500757C95 /* KBAICommentModel.m */; };
046086D62F1A093400757C95 /* KBAICommentInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086D32F1A093400757C95 /* KBAICommentInputView.m */; };
046086D72F1A093400757C95 /* KBAICommentFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086CF2F1A093400757C95 /* KBAICommentFooterView.m */; };
046086D82F1A093400757C95 /* KBAIReplyCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086D52F1A093400757C95 /* KBAIReplyCell.m */; };
046086D92F1A093400757C95 /* KBAICommentHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046086D12F1A093400757C95 /* KBAICommentHeaderView.m */; };
046131142ECF454500A6FADF /* KBKeyPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 046131132ECF454500A6FADF /* KBKeyPreviewView.m */; };
0477BDF02EBB76E30055D639 /* HomeSheetVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDEF2EBB76E30055D639 /* HomeSheetVC.m */; };
0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF22EBB7B850055D639 /* KBDirectionIndicatorView.m */; };
@@ -112,6 +136,32 @@
04890A042EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A012EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m */; };
04890A052EC0BBBB00FABA60 /* KBCategoryTitleImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */; };
04890B122EC2F00000FABA60 /* KBMyHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04890B112EC2F00000FABA60 /* KBMyHeaderView.m */; };
048FFD0B2F273BFC005D62AE /* KBAIHomeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD0A2F273BFC005D62AE /* KBAIHomeVC.m */; };
048FFD102F27432D005D62AE /* KBPersonaModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD0D2F27432D005D62AE /* KBPersonaModel.m */; };
048FFD112F27432D005D62AE /* KBPersonaPageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD0F2F27432D005D62AE /* KBPersonaPageModel.m */; };
048FFD142F274342005D62AE /* KBPersonaChatCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD132F274342005D62AE /* KBPersonaChatCell.m */; };
048FFD182F2763A5005D62AE /* KBVoiceInputBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD172F2763A5005D62AE /* KBVoiceInputBar.m */; };
048FFD1D2F277486005D62AE /* KBChatHistoryPageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD1C2F277486005D62AE /* KBChatHistoryPageModel.m */; };
048FFD1E2F277486005D62AE /* KBChatHistoryModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD1A2F277486005D62AE /* KBChatHistoryModel.m */; };
048FFD242F28A836005D62AE /* KBChatLimitPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD232F28A836005D62AE /* KBChatLimitPopView.m */; };
048FFD272F28C6CF005D62AE /* KBImagePositionButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */; };
048FFD2A2F28E99A005D62AE /* KBCommentModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD292F28E99A005D62AE /* KBCommentModel.m */; };
048FFD2D2F29F356005D62AE /* KBAIMessageVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD2C2F29F356005D62AE /* KBAIMessageVC.m */; };
048FFD302F29F3C3005D62AE /* KBAIMessageZanVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD2F2F29F3C3005D62AE /* KBAIMessageZanVC.m */; };
048FFD332F29F3D2005D62AE /* KBAIMessageChatingVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD322F29F3D2005D62AE /* KBAIMessageChatingVC.m */; };
048FFD342F29F400005D62AE /* KBAIMessageListVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD362F29F400005D62AE /* KBAIMessageListVC.m */; };
048FFD362F29F88E005D62AE /* AIMessageVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD352F29F88E005D62AE /* AIMessageVM.m */; };
048FFD372F29F410005D62AE /* KBAIMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD392F29F410005D62AE /* KBAIMessageCell.m */; };
048FFD392F2A24C5005D62AE /* KBAIChatMessageCacheManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD382F2A24C5005D62AE /* KBAIChatMessageCacheManager.m */; };
048FFD3C2F29F500005D62AE /* KBLikedCompanionModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD3B2F29F500005D62AE /* KBLikedCompanionModel.m */; };
048FFD3F2F29F600005D62AE /* KBChattedCompanionModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD3E2F29F600005D62AE /* KBChattedCompanionModel.m */; };
048FFD422F29F700005D62AE /* KBChatSessionResetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */; };
048FFD472F2B45D4005D62AE /* AIPersonInfoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */; };
048FFD4A2F2B4AE4005D62AE /* KBAICompanionDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */; };
048FFD502F2B52E7005D62AE /* AIReportVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD4F2F2B52E7005D62AE /* AIReportVC.m */; };
048FFD512F2B68F7005D62AE /* KBPersonaModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD0D2F27432D005D62AE /* KBPersonaModel.m */; };
048FFD562F2B9C3D005D62AE /* KBChatAssistantCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD532F2B9C3D005D62AE /* KBChatAssistantCell.m */; };
048FFD572F2B9C3D005D62AE /* KBChatUserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 048FFD552F2B9C3D005D62AE /* KBChatUserCell.m */; };
0498BD622EDFFC12006CC1D5 /* KBMyVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD612EDFFC12006CC1D5 /* KBMyVM.m */; };
0498BD652EE0116D006CC1D5 /* KBEmailLoginVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD642EE0116D006CC1D5 /* KBEmailLoginVC.m */; };
0498BD682EE01180006CC1D5 /* KBEmailRegistVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD672EE01180006CC1D5 /* KBEmailRegistVC.m */; };
@@ -170,6 +220,22 @@
04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EADC2EAF8CEB0089C901 /* KBToolBar.m */; };
04D1F6B22EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
04D1F6B32EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */; };
04E0383E2F1A7C30002CA5A0 /* KBCustomTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E0383D2F1A7C30002CA5A0 /* KBCustomTabBar.m */; };
04E038D82F20BFFB002CA5A0 /* websocket-api.md in Resources */ = {isa = PBXBuildFile; fileRef = 04E038D72F20BFFB002CA5A0 /* websocket-api.md */; };
04E038DD2F20C420002CA5A0 /* VoiceChatStreamingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E038DA2F20C420002CA5A0 /* VoiceChatStreamingManager.m */; };
04E038DE2F20C420002CA5A0 /* VoiceChatWebSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E038DC2F20C420002CA5A0 /* VoiceChatWebSocketClient.m */; };
04E038E32F20E500002CA5A0 /* deepgramAPI.md in Resources */ = {isa = PBXBuildFile; fileRef = 04E038E22F20E500002CA5A0 /* deepgramAPI.md */; };
04E038E82F20E877002CA5A0 /* DeepgramWebSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E038E72F20E877002CA5A0 /* DeepgramWebSocketClient.m */; };
04E038E92F20E877002CA5A0 /* DeepgramStreamingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E038E52F20E877002CA5A0 /* DeepgramStreamingManager.m */; };
04E038EF2F21F0EC002CA5A0 /* AiVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E038EE2F21F0EC002CA5A0 /* AiVM.m */; };
04E0394B2F236E75002CA5A0 /* KBChatUserMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E0394A2F236E75002CA5A0 /* KBChatUserMessageCell.m */; };
04E0394C2F236E75002CA5A0 /* KBChatTimeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E039482F236E75002CA5A0 /* KBChatTimeCell.m */; };
04E0394D2F236E75002CA5A0 /* KBChatAssistantMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E039432F236E75002CA5A0 /* KBChatAssistantMessageCell.m */; };
04E0394E2F236E75002CA5A0 /* KBChatTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E039452F236E75002CA5A0 /* KBChatTableView.m */; };
04E0394F2F236E75002CA5A0 /* KBChatTableView_Usage.md in Resources */ = {isa = PBXBuildFile; fileRef = 04E039462F236E75002CA5A0 /* KBChatTableView_Usage.md */; };
04E039522F2387D2002CA5A0 /* KBAiChatMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E039512F2387D2002CA5A0 /* KBAiChatMessage.m */; };
04E0B1022F300001002CA5A0 /* KBVoiceToTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E0B1012F300001002CA5A0 /* KBVoiceToTextManager.m */; };
04E0B2022F300002002CA5A0 /* KBVoiceRecordManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E0B2012F300002002CA5A0 /* KBVoiceRecordManager.m */; };
04E161832F10E6470022C23B /* normal_hei_them.zip in Resources */ = {isa = PBXBuildFile; fileRef = 04E161812F10E6470022C23B /* normal_hei_them.zip */; };
04E161842F10E6470022C23B /* normal_them.zip in Resources */ = {isa = PBXBuildFile; fileRef = 04E161822F10E6470022C23B /* normal_them.zip */; };
04FC95672EB0546C007BD342 /* KBKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95652EB0546C007BD342 /* KBKey.m */; };
@@ -182,7 +248,6 @@
04FC95B22EB0B2CC007BD342 /* KBSettingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95B12EB0B2CC007BD342 /* KBSettingView.m */; };
04FC95C92EB1E4C9007BD342 /* BaseNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95C82EB1E4C9007BD342 /* BaseNavigationController.m */; };
04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95CB2EB1E780007BD342 /* BaseTabBarController.m */; };
04FC95CF2EB1E7A1007BD342 /* HomeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95CE2EB1E7A1007BD342 /* HomeVC.m */; };
04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D12EB1E7AE007BD342 /* MyVC.m */; };
04FC95D72EB1EA16007BD342 /* BaseTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D62EB1EA16007BD342 /* BaseTableView.m */; };
04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC95D42EB1EA16007BD342 /* BaseCell.m */; };
@@ -224,6 +289,9 @@
A1B2C9032FBD000100000001 /* KBBackspaceLongPressHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9022FBD000100000001 /* KBBackspaceLongPressHandler.m */; };
A1B2C9052FBD000200000001 /* KBBackspaceUndoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */; };
A1B2C9092FBD000200000005 /* KBInputBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9082FBD000200000004 /* KBInputBufferManager.m */; };
A1B2C9262FC9000100000001 /* KBChatMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9212FC9000100000001 /* KBChatMessage.m */; };
A1B2C9272FC9000100000001 /* KBChatMessageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9232FC9000100000001 /* KBChatMessageCell.m */; };
A1B2C9282FC9000100000001 /* KBChatPanelView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C9252FC9000100000001 /* KBChatPanelView.m */; };
A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2D7012EB8C00100000001 /* KBLangTestVC.m */; };
A1B2E1012EBC7AAA00000001 /* KBTopThreeView.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2E0022EBC7AAA00000001 /* KBTopThreeView.m */; };
A1B2E1022EBC7AAA00000001 /* HomeHotCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A1B2E0042EBC7AAA00000001 /* HomeHotCell.m */; };
@@ -290,6 +358,8 @@
04122FAF2EC73C0100EF7AB3 /* KBVipReviewItemCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipReviewItemCell.m; sourceTree = "<group>"; };
04122FB12EC73C0100EF7AB3 /* KBVipReviewListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipReviewListCell.h; sourceTree = "<group>"; };
04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipReviewListCell.m; sourceTree = "<group>"; };
0419C9642F2C7693002E86D3 /* KBVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVM.h; sourceTree = "<group>"; };
0419C9652F2C7693002E86D3 /* KBVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVM.m; sourceTree = "<group>"; };
042869FD2ECAEF2B00CE730C /* KBMoneyBtn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMoneyBtn.h; sourceTree = "<group>"; };
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>"; };
@@ -323,6 +393,49 @@
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>"; };
0459D1B62EBA287900F2D189 /* KBSkinManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinManager.m; sourceTree = "<group>"; };
0460866A2F18D75500757C95 /* ai_test.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = ai_test.m4a; sourceTree = "<group>"; };
046086712F191B6900757C95 /* KBAiMainVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAiMainVC.h; sourceTree = "<group>"; };
046086722F191B6900757C95 /* KBAiMainVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAiMainVC.m; sourceTree = "<group>"; };
046086742F191CC700757C95 /* AI技术分析.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "AI技术分析.txt"; sourceTree = "<group>"; };
046086962F19238500757C95 /* KBAiRecordButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAiRecordButton.h; sourceTree = "<group>"; };
046086972F19238500757C95 /* KBAiRecordButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAiRecordButton.m; sourceTree = "<group>"; };
046086982F19238500757C95 /* KBAiWaveformView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAiWaveformView.h; sourceTree = "<group>"; };
046086992F19238500757C95 /* KBAiWaveformView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAiWaveformView.m; sourceTree = "<group>"; };
0460869D2F19239B00757C95 /* ASRStreamClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASRStreamClient.h; sourceTree = "<group>"; };
0460869E2F19239B00757C95 /* ASRStreamClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASRStreamClient.m; sourceTree = "<group>"; };
0460869F2F19239B00757C95 /* AudioCaptureManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioCaptureManager.h; sourceTree = "<group>"; };
046086A02F19239B00757C95 /* AudioCaptureManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioCaptureManager.m; sourceTree = "<group>"; };
046086A12F19239B00757C95 /* AudioSessionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioSessionManager.h; sourceTree = "<group>"; };
046086A22F19239B00757C95 /* AudioSessionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioSessionManager.m; sourceTree = "<group>"; };
046086A32F19239B00757C95 /* AudioStreamPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioStreamPlayer.h; sourceTree = "<group>"; };
046086A42F19239B00757C95 /* AudioStreamPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioStreamPlayer.m; sourceTree = "<group>"; };
046086A52F19239B00757C95 /* ConversationOrchestrator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConversationOrchestrator.h; sourceTree = "<group>"; };
046086A62F19239B00757C95 /* ConversationOrchestrator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ConversationOrchestrator.m; sourceTree = "<group>"; };
046086A72F19239B00757C95 /* LLMStreamClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLMStreamClient.h; sourceTree = "<group>"; };
046086A82F19239B00757C95 /* LLMStreamClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LLMStreamClient.m; sourceTree = "<group>"; };
046086A92F19239B00757C95 /* Segmenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Segmenter.h; sourceTree = "<group>"; };
046086AA2F19239B00757C95 /* Segmenter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Segmenter.m; sourceTree = "<group>"; };
046086AB2F19239B00757C95 /* SubtitleSync.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubtitleSync.h; sourceTree = "<group>"; };
046086AC2F19239B00757C95 /* SubtitleSync.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubtitleSync.m; sourceTree = "<group>"; };
046086AD2F19239B00757C95 /* TTSPlaybackPipeline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TTSPlaybackPipeline.h; sourceTree = "<group>"; };
046086AE2F19239B00757C95 /* TTSPlaybackPipeline.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTSPlaybackPipeline.m; sourceTree = "<group>"; };
046086AF2F19239B00757C95 /* TTSServiceClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TTSServiceClient.h; sourceTree = "<group>"; };
046086B02F19239B00757C95 /* TTSServiceClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTSServiceClient.m; sourceTree = "<group>"; };
046086BB2F1A039F00757C95 /* KBAICommentView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICommentView.h; sourceTree = "<group>"; };
046086BC2F1A039F00757C95 /* KBAICommentView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICommentView.m; sourceTree = "<group>"; };
046086C62F1A092500757C95 /* comments_mock.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = comments_mock.json; sourceTree = "<group>"; };
046086C72F1A092500757C95 /* KBAICommentModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICommentModel.h; sourceTree = "<group>"; };
046086C82F1A092500757C95 /* KBAICommentModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICommentModel.m; sourceTree = "<group>"; };
046086C92F1A092500757C95 /* KBAIReplyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIReplyModel.h; sourceTree = "<group>"; };
046086CA2F1A092500757C95 /* KBAIReplyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIReplyModel.m; sourceTree = "<group>"; };
046086CE2F1A093400757C95 /* KBAICommentFooterView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICommentFooterView.h; sourceTree = "<group>"; };
046086CF2F1A093400757C95 /* KBAICommentFooterView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICommentFooterView.m; sourceTree = "<group>"; };
046086D02F1A093400757C95 /* KBAICommentHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICommentHeaderView.h; sourceTree = "<group>"; };
046086D12F1A093400757C95 /* KBAICommentHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICommentHeaderView.m; sourceTree = "<group>"; };
046086D22F1A093400757C95 /* KBAICommentInputView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICommentInputView.h; sourceTree = "<group>"; };
046086D32F1A093400757C95 /* KBAICommentInputView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICommentInputView.m; sourceTree = "<group>"; };
046086D42F1A093400757C95 /* KBAIReplyCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIReplyCell.h; sourceTree = "<group>"; };
046086D52F1A093400757C95 /* KBAIReplyCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIReplyCell.m; sourceTree = "<group>"; };
046131122ECF454500A6FADF /* KBKeyPreviewView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBKeyPreviewView.h; sourceTree = "<group>"; };
046131132ECF454500A6FADF /* KBKeyPreviewView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBKeyPreviewView.m; sourceTree = "<group>"; };
0477BDEE2EBB76E30055D639 /* HomeSheetVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeSheetVC.h; sourceTree = "<group>"; };
@@ -433,6 +546,56 @@
04890A032EC0BBBB00FABA60 /* KBCategoryTitleImageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCategoryTitleImageView.m; sourceTree = "<group>"; };
04890B102EC2F00000FABA60 /* KBMyHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyHeaderView.h; sourceTree = "<group>"; };
04890B112EC2F00000FABA60 /* KBMyHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyHeaderView.m; sourceTree = "<group>"; };
048FFD092F273BFC005D62AE /* KBAIHomeVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIHomeVC.h; sourceTree = "<group>"; };
048FFD0A2F273BFC005D62AE /* KBAIHomeVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIHomeVC.m; sourceTree = "<group>"; };
048FFD0C2F27432D005D62AE /* KBPersonaModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBPersonaModel.h; sourceTree = "<group>"; };
048FFD0D2F27432D005D62AE /* KBPersonaModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPersonaModel.m; sourceTree = "<group>"; };
048FFD0E2F27432D005D62AE /* KBPersonaPageModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBPersonaPageModel.h; sourceTree = "<group>"; };
048FFD0F2F27432D005D62AE /* KBPersonaPageModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPersonaPageModel.m; sourceTree = "<group>"; };
048FFD122F274342005D62AE /* KBPersonaChatCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBPersonaChatCell.h; sourceTree = "<group>"; };
048FFD132F274342005D62AE /* KBPersonaChatCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPersonaChatCell.m; sourceTree = "<group>"; };
048FFD162F2763A5005D62AE /* KBVoiceInputBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVoiceInputBar.h; sourceTree = "<group>"; };
048FFD172F2763A5005D62AE /* KBVoiceInputBar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVoiceInputBar.m; sourceTree = "<group>"; };
048FFD192F277486005D62AE /* KBChatHistoryModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatHistoryModel.h; sourceTree = "<group>"; };
048FFD1A2F277486005D62AE /* KBChatHistoryModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatHistoryModel.m; sourceTree = "<group>"; };
048FFD1B2F277486005D62AE /* KBChatHistoryPageModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatHistoryPageModel.h; sourceTree = "<group>"; };
048FFD1C2F277486005D62AE /* KBChatHistoryPageModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatHistoryPageModel.m; sourceTree = "<group>"; };
048FFD222F28A836005D62AE /* KBChatLimitPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatLimitPopView.h; sourceTree = "<group>"; };
048FFD232F28A836005D62AE /* KBChatLimitPopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatLimitPopView.m; sourceTree = "<group>"; };
048FFD252F28C6CF005D62AE /* KBImagePositionButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBImagePositionButton.h; sourceTree = "<group>"; };
048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBImagePositionButton.m; sourceTree = "<group>"; };
048FFD282F28E99A005D62AE /* KBCommentModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBCommentModel.h; sourceTree = "<group>"; };
048FFD292F28E99A005D62AE /* KBCommentModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCommentModel.m; sourceTree = "<group>"; };
048FFD2B2F29F356005D62AE /* KBAIMessageVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIMessageVC.h; sourceTree = "<group>"; };
048FFD2C2F29F356005D62AE /* KBAIMessageVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIMessageVC.m; sourceTree = "<group>"; };
048FFD2E2F29F3C3005D62AE /* KBAIMessageZanVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIMessageZanVC.h; sourceTree = "<group>"; };
048FFD2F2F29F3C3005D62AE /* KBAIMessageZanVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIMessageZanVC.m; sourceTree = "<group>"; };
048FFD312F29F3D2005D62AE /* KBAIMessageChatingVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIMessageChatingVC.h; sourceTree = "<group>"; };
048FFD322F29F3D2005D62AE /* KBAIMessageChatingVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIMessageChatingVC.m; sourceTree = "<group>"; };
048FFD342F29F88E005D62AE /* AIMessageVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIMessageVM.h; sourceTree = "<group>"; };
048FFD352F29F400005D62AE /* KBAIMessageListVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIMessageListVC.h; sourceTree = "<group>"; };
048FFD352F29F88E005D62AE /* AIMessageVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIMessageVM.m; sourceTree = "<group>"; };
048FFD362F29F400005D62AE /* KBAIMessageListVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIMessageListVC.m; sourceTree = "<group>"; };
048FFD372F2A24C5005D62AE /* KBAIChatMessageCacheManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIChatMessageCacheManager.h; sourceTree = "<group>"; };
048FFD382F29F410005D62AE /* KBAIMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAIMessageCell.h; sourceTree = "<group>"; };
048FFD382F2A24C5005D62AE /* KBAIChatMessageCacheManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIChatMessageCacheManager.m; sourceTree = "<group>"; };
048FFD392F29F410005D62AE /* KBAIMessageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAIMessageCell.m; sourceTree = "<group>"; };
048FFD3A2F29F500005D62AE /* KBLikedCompanionModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLikedCompanionModel.h; sourceTree = "<group>"; };
048FFD3B2F29F500005D62AE /* KBLikedCompanionModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLikedCompanionModel.m; sourceTree = "<group>"; };
048FFD3D2F29F600005D62AE /* KBChattedCompanionModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChattedCompanionModel.h; sourceTree = "<group>"; };
048FFD3E2F29F600005D62AE /* KBChattedCompanionModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChattedCompanionModel.m; sourceTree = "<group>"; };
048FFD402F29F700005D62AE /* KBChatSessionResetModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatSessionResetModel.h; sourceTree = "<group>"; };
048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatSessionResetModel.m; sourceTree = "<group>"; };
048FFD452F2B45D4005D62AE /* AIPersonInfoVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIPersonInfoVC.h; sourceTree = "<group>"; };
048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIPersonInfoVC.m; sourceTree = "<group>"; };
048FFD482F2B4AE4005D62AE /* KBAICompanionDetailModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAICompanionDetailModel.h; sourceTree = "<group>"; };
048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAICompanionDetailModel.m; sourceTree = "<group>"; };
048FFD4E2F2B52E7005D62AE /* AIReportVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIReportVC.h; sourceTree = "<group>"; };
048FFD4F2F2B52E7005D62AE /* AIReportVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIReportVC.m; sourceTree = "<group>"; };
048FFD522F2B9C3D005D62AE /* KBChatAssistantCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatAssistantCell.h; sourceTree = "<group>"; };
048FFD532F2B9C3D005D62AE /* KBChatAssistantCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatAssistantCell.m; sourceTree = "<group>"; };
048FFD542F2B9C3D005D62AE /* KBChatUserCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatUserCell.h; sourceTree = "<group>"; };
048FFD552F2B9C3D005D62AE /* KBChatUserCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatUserCell.m; sourceTree = "<group>"; };
0498BD5E2EDF2157006CC1D5 /* KBBizCode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBBizCode.h; sourceTree = "<group>"; };
0498BD602EDFFC12006CC1D5 /* KBMyVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyVM.h; sourceTree = "<group>"; };
0498BD612EDFFC12006CC1D5 /* KBMyVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyVM.m; sourceTree = "<group>"; };
@@ -534,6 +697,35 @@
04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPermissionViewController.m; sourceTree = "<group>"; };
04D1F6B02EDFF10A00B12345 /* KBSkinInstallBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinInstallBridge.h; sourceTree = "<group>"; };
04D1F6B12EDFF10A00B12345 /* KBSkinInstallBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinInstallBridge.m; sourceTree = "<group>"; };
04E0383C2F1A7C30002CA5A0 /* KBCustomTabBar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBCustomTabBar.h; sourceTree = "<group>"; };
04E0383D2F1A7C30002CA5A0 /* KBCustomTabBar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCustomTabBar.m; sourceTree = "<group>"; };
04E038D72F20BFFB002CA5A0 /* websocket-api.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "websocket-api.md"; sourceTree = "<group>"; };
04E038D92F20C420002CA5A0 /* VoiceChatStreamingManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoiceChatStreamingManager.h; sourceTree = "<group>"; };
04E038DA2F20C420002CA5A0 /* VoiceChatStreamingManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VoiceChatStreamingManager.m; sourceTree = "<group>"; };
04E038DB2F20C420002CA5A0 /* VoiceChatWebSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VoiceChatWebSocketClient.h; sourceTree = "<group>"; };
04E038DC2F20C420002CA5A0 /* VoiceChatWebSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VoiceChatWebSocketClient.m; sourceTree = "<group>"; };
04E038E22F20E500002CA5A0 /* deepgramAPI.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = deepgramAPI.md; sourceTree = "<group>"; };
04E038E42F20E877002CA5A0 /* DeepgramStreamingManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeepgramStreamingManager.h; sourceTree = "<group>"; };
04E038E52F20E877002CA5A0 /* DeepgramStreamingManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeepgramStreamingManager.m; sourceTree = "<group>"; };
04E038E62F20E877002CA5A0 /* DeepgramWebSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeepgramWebSocketClient.h; sourceTree = "<group>"; };
04E038E72F20E877002CA5A0 /* DeepgramWebSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeepgramWebSocketClient.m; sourceTree = "<group>"; };
04E038ED2F21F0EC002CA5A0 /* AiVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AiVM.h; sourceTree = "<group>"; };
04E038EE2F21F0EC002CA5A0 /* AiVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiVM.m; sourceTree = "<group>"; };
04E039422F236E75002CA5A0 /* KBChatAssistantMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatAssistantMessageCell.h; sourceTree = "<group>"; };
04E039432F236E75002CA5A0 /* KBChatAssistantMessageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatAssistantMessageCell.m; sourceTree = "<group>"; };
04E039442F236E75002CA5A0 /* KBChatTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatTableView.h; sourceTree = "<group>"; };
04E039452F236E75002CA5A0 /* KBChatTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatTableView.m; sourceTree = "<group>"; };
04E039462F236E75002CA5A0 /* KBChatTableView_Usage.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = KBChatTableView_Usage.md; sourceTree = "<group>"; };
04E039472F236E75002CA5A0 /* KBChatTimeCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatTimeCell.h; sourceTree = "<group>"; };
04E039482F236E75002CA5A0 /* KBChatTimeCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatTimeCell.m; sourceTree = "<group>"; };
04E039492F236E75002CA5A0 /* KBChatUserMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatUserMessageCell.h; sourceTree = "<group>"; };
04E0394A2F236E75002CA5A0 /* KBChatUserMessageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatUserMessageCell.m; sourceTree = "<group>"; };
04E039502F2387D2002CA5A0 /* KBAiChatMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAiChatMessage.h; sourceTree = "<group>"; };
04E039512F2387D2002CA5A0 /* KBAiChatMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBAiChatMessage.m; sourceTree = "<group>"; };
04E0B1002F300001002CA5A0 /* KBVoiceToTextManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVoiceToTextManager.h; sourceTree = "<group>"; };
04E0B1012F300001002CA5A0 /* KBVoiceToTextManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVoiceToTextManager.m; sourceTree = "<group>"; };
04E0B2002F300002002CA5A0 /* KBVoiceRecordManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVoiceRecordManager.h; sourceTree = "<group>"; };
04E0B2012F300002002CA5A0 /* KBVoiceRecordManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVoiceRecordManager.m; sourceTree = "<group>"; };
04E161812F10E6470022C23B /* normal_hei_them.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = normal_hei_them.zip; sourceTree = "<group>"; };
04E161822F10E6470022C23B /* normal_them.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = normal_them.zip; sourceTree = "<group>"; };
04FC953A2EAFAE56007BD342 /* KeyBoardPrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyBoardPrefixHeader.pch; sourceTree = "<group>"; };
@@ -557,8 +749,6 @@
04FC95C82EB1E4C9007BD342 /* BaseNavigationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseNavigationController.m; sourceTree = "<group>"; };
04FC95CA2EB1E780007BD342 /* BaseTabBarController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseTabBarController.h; sourceTree = "<group>"; };
04FC95CB2EB1E780007BD342 /* BaseTabBarController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseTabBarController.m; sourceTree = "<group>"; };
04FC95CD2EB1E7A1007BD342 /* HomeVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeVC.h; sourceTree = "<group>"; };
04FC95CE2EB1E7A1007BD342 /* HomeVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeVC.m; sourceTree = "<group>"; };
04FC95D02EB1E7AE007BD342 /* MyVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyVC.h; sourceTree = "<group>"; };
04FC95D12EB1E7AE007BD342 /* MyVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyVC.m; sourceTree = "<group>"; };
04FC95D32EB1EA16007BD342 /* BaseCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseCell.h; sourceTree = "<group>"; };
@@ -639,6 +829,12 @@
A1B2C9042FBD000200000001 /* KBBackspaceUndoManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBBackspaceUndoManager.m; sourceTree = "<group>"; };
A1B2C9072FBD000200000003 /* KBInputBufferManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBInputBufferManager.h; sourceTree = "<group>"; };
A1B2C9082FBD000200000004 /* KBInputBufferManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBInputBufferManager.m; sourceTree = "<group>"; };
A1B2C9202FC9000100000001 /* KBChatMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessage.h; sourceTree = "<group>"; };
A1B2C9212FC9000100000001 /* KBChatMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatMessage.m; sourceTree = "<group>"; };
A1B2C9222FC9000100000001 /* KBChatMessageCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatMessageCell.h; sourceTree = "<group>"; };
A1B2C9232FC9000100000001 /* KBChatMessageCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatMessageCell.m; sourceTree = "<group>"; };
A1B2C9242FC9000100000001 /* KBChatPanelView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChatPanelView.h; sourceTree = "<group>"; };
A1B2C9252FC9000100000001 /* KBChatPanelView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChatPanelView.m; sourceTree = "<group>"; };
A1B2D7002EB8C00100000001 /* KBLangTestVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLangTestVC.h; sourceTree = "<group>"; };
A1B2D7012EB8C00100000001 /* KBLangTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLangTestVC.m; sourceTree = "<group>"; };
A1B2E0012EBC7AAA00000001 /* KBTopThreeView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBTopThreeView.h; sourceTree = "<group>"; };
@@ -686,6 +882,7 @@
041007D02ECE010100D203BB /* Resource */ = {
isa = PBXGroup;
children = (
0460866A2F18D75500757C95 /* ai_test.m4a */,
04E161812F10E6470022C23B /* normal_hei_them.zip */,
04E161822F10E6470022C23B /* normal_them.zip */,
A1B2C3EC2F20000000000001 /* kb_words.txt */,
@@ -778,6 +975,28 @@
path = WMDragView;
sourceTree = "<group>";
};
0419C9632F2C7630002E86D3 /* VM */ = {
isa = PBXGroup;
children = (
0419C9642F2C7693002E86D3 /* KBVM.h */,
0419C9652F2C7693002E86D3 /* KBVM.m */,
);
path = VM;
sourceTree = "<group>";
};
0419C9672F2C78E4002E86D3 /* Chat */ = {
isa = PBXGroup;
children = (
A1B2C9242FC9000100000001 /* KBChatPanelView.h */,
A1B2C9252FC9000100000001 /* KBChatPanelView.m */,
048FFD522F2B9C3D005D62AE /* KBChatAssistantCell.h */,
048FFD532F2B9C3D005D62AE /* KBChatAssistantCell.m */,
048FFD542F2B9C3D005D62AE /* KBChatUserCell.h */,
048FFD552F2B9C3D005D62AE /* KBChatUserCell.m */,
);
path = Chat;
sourceTree = "<group>";
};
0450ABFB2EF11E4400B6AF06 /* Converts */ = {
isa = PBXGroup;
children = (
@@ -840,6 +1059,138 @@
path = StoreKit2Manager;
sourceTree = "<group>";
};
0460866C2F191A5100757C95 /* M */ = {
isa = PBXGroup;
children = (
046086C62F1A092500757C95 /* comments_mock.json */,
046086C72F1A092500757C95 /* KBAICommentModel.h */,
046086C82F1A092500757C95 /* KBAICommentModel.m */,
046086C92F1A092500757C95 /* KBAIReplyModel.h */,
046086CA2F1A092500757C95 /* KBAIReplyModel.m */,
04E039502F2387D2002CA5A0 /* KBAiChatMessage.h */,
04E039512F2387D2002CA5A0 /* KBAiChatMessage.m */,
048FFD0C2F27432D005D62AE /* KBPersonaModel.h */,
048FFD0D2F27432D005D62AE /* KBPersonaModel.m */,
048FFD0E2F27432D005D62AE /* KBPersonaPageModel.h */,
048FFD0F2F27432D005D62AE /* KBPersonaPageModel.m */,
048FFD192F277486005D62AE /* KBChatHistoryModel.h */,
048FFD1A2F277486005D62AE /* KBChatHistoryModel.m */,
048FFD1B2F277486005D62AE /* KBChatHistoryPageModel.h */,
048FFD1C2F277486005D62AE /* KBChatHistoryPageModel.m */,
048FFD282F28E99A005D62AE /* KBCommentModel.h */,
048FFD292F28E99A005D62AE /* KBCommentModel.m */,
048FFD3A2F29F500005D62AE /* KBLikedCompanionModel.h */,
048FFD3B2F29F500005D62AE /* KBLikedCompanionModel.m */,
048FFD3D2F29F600005D62AE /* KBChattedCompanionModel.h */,
048FFD3E2F29F600005D62AE /* KBChattedCompanionModel.m */,
048FFD402F29F700005D62AE /* KBChatSessionResetModel.h */,
048FFD412F29F700005D62AE /* KBChatSessionResetModel.m */,
048FFD372F2A24C5005D62AE /* KBAIChatMessageCacheManager.h */,
048FFD382F2A24C5005D62AE /* KBAIChatMessageCacheManager.m */,
048FFD482F2B4AE4005D62AE /* KBAICompanionDetailModel.h */,
048FFD492F2B4AE4005D62AE /* KBAICompanionDetailModel.m */,
);
path = M;
sourceTree = "<group>";
};
0460866D2F191A5100757C95 /* V */ = {
isa = PBXGroup;
children = (
048FFD3D2F2B2A14005D62AE /* PopView */,
048FFD3C2F2B2905005D62AE /* Chat */,
048FFD3B2F2B289C005D62AE /* Comment */,
048FFD3A2F2B2869005D62AE /* Message */,
046086962F19238500757C95 /* KBAiRecordButton.h */,
046086972F19238500757C95 /* KBAiRecordButton.m */,
046086982F19238500757C95 /* KBAiWaveformView.h */,
046086992F19238500757C95 /* KBAiWaveformView.m */,
04E039462F236E75002CA5A0 /* KBChatTableView_Usage.md */,
048FFD162F2763A5005D62AE /* KBVoiceInputBar.h */,
048FFD172F2763A5005D62AE /* KBVoiceInputBar.m */,
);
path = V;
sourceTree = "<group>";
};
0460866E2F191A5100757C95 /* VC */ = {
isa = PBXGroup;
children = (
046086712F191B6900757C95 /* KBAiMainVC.h */,
046086722F191B6900757C95 /* KBAiMainVC.m */,
048FFD092F273BFC005D62AE /* KBAIHomeVC.h */,
048FFD0A2F273BFC005D62AE /* KBAIHomeVC.m */,
048FFD2B2F29F356005D62AE /* KBAIMessageVC.h */,
048FFD2C2F29F356005D62AE /* KBAIMessageVC.m */,
048FFD2E2F29F3C3005D62AE /* KBAIMessageZanVC.h */,
048FFD2F2F29F3C3005D62AE /* KBAIMessageZanVC.m */,
048FFD312F29F3D2005D62AE /* KBAIMessageChatingVC.h */,
048FFD322F29F3D2005D62AE /* KBAIMessageChatingVC.m */,
048FFD352F29F400005D62AE /* KBAIMessageListVC.h */,
048FFD362F29F400005D62AE /* KBAIMessageListVC.m */,
048FFD452F2B45D4005D62AE /* AIPersonInfoVC.h */,
048FFD462F2B45D4005D62AE /* AIPersonInfoVC.m */,
048FFD4E2F2B52E7005D62AE /* AIReportVC.h */,
048FFD4F2F2B52E7005D62AE /* AIReportVC.m */,
);
path = VC;
sourceTree = "<group>";
};
0460866F2F191A5100757C95 /* VM */ = {
isa = PBXGroup;
children = (
0460869D2F19239B00757C95 /* ASRStreamClient.h */,
0460869E2F19239B00757C95 /* ASRStreamClient.m */,
0460869F2F19239B00757C95 /* AudioCaptureManager.h */,
046086A02F19239B00757C95 /* AudioCaptureManager.m */,
046086A12F19239B00757C95 /* AudioSessionManager.h */,
046086A22F19239B00757C95 /* AudioSessionManager.m */,
046086A32F19239B00757C95 /* AudioStreamPlayer.h */,
046086A42F19239B00757C95 /* AudioStreamPlayer.m */,
046086A52F19239B00757C95 /* ConversationOrchestrator.h */,
046086A62F19239B00757C95 /* ConversationOrchestrator.m */,
046086A72F19239B00757C95 /* LLMStreamClient.h */,
046086A82F19239B00757C95 /* LLMStreamClient.m */,
046086A92F19239B00757C95 /* Segmenter.h */,
046086AA2F19239B00757C95 /* Segmenter.m */,
046086AB2F19239B00757C95 /* SubtitleSync.h */,
046086AC2F19239B00757C95 /* SubtitleSync.m */,
046086AD2F19239B00757C95 /* TTSPlaybackPipeline.h */,
046086AE2F19239B00757C95 /* TTSPlaybackPipeline.m */,
046086AF2F19239B00757C95 /* TTSServiceClient.h */,
046086B02F19239B00757C95 /* TTSServiceClient.m */,
04E038D92F20C420002CA5A0 /* VoiceChatStreamingManager.h */,
04E038DA2F20C420002CA5A0 /* VoiceChatStreamingManager.m */,
04E038DB2F20C420002CA5A0 /* VoiceChatWebSocketClient.h */,
04E038DC2F20C420002CA5A0 /* VoiceChatWebSocketClient.m */,
04E038E42F20E877002CA5A0 /* DeepgramStreamingManager.h */,
04E038E52F20E877002CA5A0 /* DeepgramStreamingManager.m */,
04E0B1002F300001002CA5A0 /* KBVoiceToTextManager.h */,
04E0B1012F300001002CA5A0 /* KBVoiceToTextManager.m */,
04E0B2002F300002002CA5A0 /* KBVoiceRecordManager.h */,
04E0B2012F300002002CA5A0 /* KBVoiceRecordManager.m */,
04E038E62F20E877002CA5A0 /* DeepgramWebSocketClient.h */,
04E038E72F20E877002CA5A0 /* DeepgramWebSocketClient.m */,
04E038ED2F21F0EC002CA5A0 /* AiVM.h */,
04E038EE2F21F0EC002CA5A0 /* AiVM.m */,
048FFD342F29F88E005D62AE /* AIMessageVM.h */,
048FFD352F29F88E005D62AE /* AIMessageVM.m */,
);
path = VM;
sourceTree = "<group>";
};
046086702F191A5100757C95 /* AiTalk */ = {
isa = PBXGroup;
children = (
046086742F191CC700757C95 /* AI技术分析.txt */,
04E038D72F20BFFB002CA5A0 /* websocket-api.md */,
04E038E22F20E500002CA5A0 /* deepgramAPI.md */,
0460866C2F191A5100757C95 /* M */,
0460866D2F191A5100757C95 /* V */,
0460866E2F191A5100757C95 /* VC */,
0460866F2F191A5100757C95 /* VM */,
);
path = AiTalk;
sourceTree = "<group>";
};
0477BD942EBAFF4E0055D639 /* Utils */ = {
isa = PBXGroup;
children = (
@@ -963,6 +1314,8 @@
049FB20D2EC1CD2800FAB05D /* KBAlert.m */,
042869FD2ECAEF2B00CE730C /* KBMoneyBtn.h */,
042869FE2ECAEF2B00CE730C /* KBMoneyBtn.m */,
048FFD252F28C6CF005D62AE /* KBImagePositionButton.h */,
048FFD262F28C6CF005D62AE /* KBImagePositionButton.m */,
);
path = V;
sourceTree = "<group>";
@@ -1043,6 +1396,58 @@
path = UICollectionViewLeftAlignedLayout;
sourceTree = "<group>";
};
048FFD3A2F2B2869005D62AE /* Message */ = {
isa = PBXGroup;
children = (
048FFD382F29F410005D62AE /* KBAIMessageCell.h */,
048FFD392F29F410005D62AE /* KBAIMessageCell.m */,
);
path = Message;
sourceTree = "<group>";
};
048FFD3B2F2B289C005D62AE /* Comment */ = {
isa = PBXGroup;
children = (
046086BB2F1A039F00757C95 /* KBAICommentView.h */,
046086BC2F1A039F00757C95 /* KBAICommentView.m */,
046086CE2F1A093400757C95 /* KBAICommentFooterView.h */,
046086CF2F1A093400757C95 /* KBAICommentFooterView.m */,
046086D02F1A093400757C95 /* KBAICommentHeaderView.h */,
046086D12F1A093400757C95 /* KBAICommentHeaderView.m */,
046086D22F1A093400757C95 /* KBAICommentInputView.h */,
046086D32F1A093400757C95 /* KBAICommentInputView.m */,
046086D42F1A093400757C95 /* KBAIReplyCell.h */,
046086D52F1A093400757C95 /* KBAIReplyCell.m */,
);
path = Comment;
sourceTree = "<group>";
};
048FFD3C2F2B2905005D62AE /* Chat */ = {
isa = PBXGroup;
children = (
048FFD122F274342005D62AE /* KBPersonaChatCell.h */,
048FFD132F274342005D62AE /* KBPersonaChatCell.m */,
04E039442F236E75002CA5A0 /* KBChatTableView.h */,
04E039452F236E75002CA5A0 /* KBChatTableView.m */,
04E039492F236E75002CA5A0 /* KBChatUserMessageCell.h */,
04E0394A2F236E75002CA5A0 /* KBChatUserMessageCell.m */,
04E039422F236E75002CA5A0 /* KBChatAssistantMessageCell.h */,
04E039432F236E75002CA5A0 /* KBChatAssistantMessageCell.m */,
04E039472F236E75002CA5A0 /* KBChatTimeCell.h */,
04E039482F236E75002CA5A0 /* KBChatTimeCell.m */,
);
path = Chat;
sourceTree = "<group>";
};
048FFD3D2F2B2A14005D62AE /* PopView */ = {
isa = PBXGroup;
children = (
048FFD222F28A836005D62AE /* KBChatLimitPopView.h */,
048FFD232F28A836005D62AE /* KBChatLimitPopView.m */,
);
path = PopView;
sourceTree = "<group>";
};
0498BD5F2EDFFBFC006CC1D5 /* VM */ = {
isa = PBXGroup;
children = (
@@ -1158,6 +1563,7 @@
04C6EAD72EAF870B0089C901 /* CustomKeyboard */ = {
isa = PBXGroup;
children = (
0419C9632F2C7630002E86D3 /* VM */,
041007D02ECE010100D203BB /* Resource */,
0477BD942EBAFF4E0055D639 /* Utils */,
04A9FE122EB4D0D20020DB6D /* Manager */,
@@ -1176,6 +1582,7 @@
04C6EADA2EAF8C7B0089C901 /* View */ = {
isa = PBXGroup;
children = (
0419C9672F2C78E4002E86D3 /* Chat */,
04DC5CEC2EF2D1D300F1AC80 /* Buy */,
0498BDF62EEFF585006CC1D5 /* EmojiView */,
04C6EADB2EAF8CEB0089C901 /* KBToolBar.h */,
@@ -1203,6 +1610,8 @@
A1B2C3F22EB35A9900000001 /* KBFullAccessGuideView.m */,
04FC95B02EB0B2CC007BD342 /* KBSettingView.h */,
04FC95B12EB0B2CC007BD342 /* KBSettingView.m */,
A1B2C9222FC9000100000001 /* KBChatMessageCell.h */,
A1B2C9232FC9000100000001 /* KBChatMessageCell.m */,
049FB22D2EC34EB900FAB05D /* KBStreamTextView.h */,
049FB22E2EC34EB900FAB05D /* KBStreamTextView.m */,
049FB23A2EC4766700FAB05D /* Function */,
@@ -1248,6 +1657,8 @@
children = (
04FC95642EB0546C007BD342 /* KBKey.h */,
04FC95652EB0546C007BD342 /* KBKey.m */,
A1B2C9202FC9000100000001 /* KBChatMessage.h */,
A1B2C9212FC9000100000001 /* KBChatMessage.m */,
04FEDC202F00020000999999 /* KBKeyboardSubscriptionProduct.h */,
04FEDC212F00020000999999 /* KBKeyboardSubscriptionProduct.m */,
04FEDC232F10000100000001 /* KBKeyboardLayoutConfig.h */,
@@ -1293,8 +1704,6 @@
04FC95B52EB1E3B1007BD342 /* VC */ = {
isa = PBXGroup;
children = (
04FC95CD2EB1E7A1007BD342 /* HomeVC.h */,
04FC95CE2EB1E7A1007BD342 /* HomeVC.m */,
0477BE022EBC83130055D639 /* HomeMainVC.h */,
0477BE032EBC83130055D639 /* HomeMainVC.m */,
0477BDEE2EBB76E30055D639 /* HomeSheetVC.h */,
@@ -1437,6 +1846,7 @@
04FC95BF2EB1E3B1007BD342 /* Class */ = {
isa = PBXGroup;
children = (
046086702F191A5100757C95 /* AiTalk */,
04122F612EC5F3DF00EF7AB3 /* Pay */,
7276DDA22EC1B22500804C36 /* WebView */,
048908D32EBF618E00FABA60 /* Vender */,
@@ -1473,6 +1883,8 @@
04FC95D62EB1EA16007BD342 /* BaseTableView.m */,
048908FC2EC0CC2400FABA60 /* UIScrollView+KBEmptyView.h */,
048908FD2EC0CC2400FABA60 /* UIScrollView+KBEmptyView.m */,
04E0383C2F1A7C30002CA5A0 /* KBCustomTabBar.h */,
04E0383D2F1A7C30002CA5A0 /* KBCustomTabBar.m */,
);
path = V;
sourceTree = "<group>";
@@ -1818,6 +2230,7 @@
04E161832F10E6470022C23B /* normal_hei_them.zip in Resources */,
04E161842F10E6470022C23B /* normal_them.zip in Resources */,
04A9FE202EB893F10020DB6D /* Localizable.strings in Resources */,
0460866B2F18D75500757C95 /* ai_test.m4a in Resources */,
041007D42ECE012500D203BB /* 002.zip in Resources */,
041007D22ECE012000D203BB /* KBSkinIconMap.strings in Resources */,
A1B2C3ED2F20000000000001 /* kb_words.txt in Resources */,
@@ -1833,14 +2246,19 @@
buildActionMask = 2147483647;
files = (
04286A0F2ECDA71B00CE730C /* 001.zip in Resources */,
04E038D82F20BFFB002CA5A0 /* websocket-api.md in Resources */,
0479200B2ED87CEE004E8522 /* permiss_video.mp4 in Resources */,
04C6EABA2EAF86530089C901 /* Assets.xcassets in Resources */,
04A9FE212EB893F10020DB6D /* Localizable.strings in Resources */,
047920072ED86ABC004E8522 /* kb_guide_keyboard.gif in Resources */,
046086752F191CC700757C95 /* AI技术分析.txt in Resources */,
047920112ED98E7D004E8522 /* permiss_video_2.mp4 in Resources */,
04C6EABC2EAF86530089C901 /* LaunchScreen.storyboard in Resources */,
04E0394F2F236E75002CA5A0 /* KBChatTableView_Usage.md in Resources */,
04286A132ECDEBF900CE730C /* KBSkinIconMap.strings in Resources */,
04C6EABD2EAF86530089C901 /* Main.storyboard in Resources */,
046086CB2F1A092500757C95 /* comments_mock.json in Resources */,
04E038E32F20E500002CA5A0 /* deepgramAPI.md in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1923,8 +2341,15 @@
04791FFC2ED71D17004E8522 /* UIColor+Extension.m in Sources */,
0450AC4A2EF2C3ED00B6AF06 /* KBKeyboardSubscriptionOptionCell.m in Sources */,
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */,
048FFD562F2B9C3D005D62AE /* KBChatAssistantCell.m in Sources */,
048FFD572F2B9C3D005D62AE /* KBChatUserCell.m in Sources */,
04C6EADD2EAF8CEB0089C901 /* KBToolBar.m in Sources */,
A1B2C9262FC9000100000001 /* KBChatMessage.m in Sources */,
A1B2C9272FC9000100000001 /* KBChatMessageCell.m in Sources */,
A1B2C9282FC9000100000001 /* KBChatPanelView.m in Sources */,
A1B2C3EB2F20000000000001 /* KBSuggestionBarView.m in Sources */,
0419C9662F2C7693002E86D3 /* KBVM.m in Sources */,
048FFD512F2B68F7005D62AE /* KBPersonaModel.m in Sources */,
04FC95792EB09BC8007BD342 /* KBKeyBoardMainView.m in Sources */,
04FEDAB32EEDB05000123456 /* KBEmojiPanelView.m in Sources */,
04050ECB2F10FB8F008051EB /* UIImage+KBColor.m in Sources */,
@@ -1983,23 +2408,43 @@
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
04B5A1A22EEFA12300AAAAAA /* KBPayProductModel.m in Sources */,
046086D62F1A093400757C95 /* KBAICommentInputView.m in Sources */,
046086D72F1A093400757C95 /* KBAICommentFooterView.m in Sources */,
046086D82F1A093400757C95 /* KBAIReplyCell.m in Sources */,
046086D92F1A093400757C95 /* KBAICommentHeaderView.m in Sources */,
04E0394B2F236E75002CA5A0 /* KBChatUserMessageCell.m in Sources */,
04E0394C2F236E75002CA5A0 /* KBChatTimeCell.m in Sources */,
04E0394D2F236E75002CA5A0 /* KBChatAssistantMessageCell.m in Sources */,
04E0394E2F236E75002CA5A0 /* KBChatTableView.m in Sources */,
04286A062ECC81B200CE730C /* KBSkinService.m in Sources */,
0479204A2EDDCE25004E8522 /* KBUserSessionManager.m in Sources */,
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,
049FB31D2EC21BCD00FAB05D /* KBMyKeyboardCell.m in Sources */,
048909F62EC0AAAA00FABA60 /* KBCategoryTitleCell.m in Sources */,
046086732F191B6900757C95 /* KBAiMainVC.m in Sources */,
048909F72EC0AAAA00FABA60 /* KBCategoryTitleView.m in Sources */,
048FFD332F29F3D2005D62AE /* KBAIMessageChatingVC.m in Sources */,
048FFD342F29F400005D62AE /* KBAIMessageListVC.m in Sources */,
048FFD372F29F410005D62AE /* KBAIMessageCell.m in Sources */,
048FFD3C2F29F500005D62AE /* KBLikedCompanionModel.m in Sources */,
048FFD3F2F29F600005D62AE /* KBChattedCompanionModel.m in Sources */,
048FFD422F29F700005D62AE /* KBChatSessionResetModel.m in Sources */,
04791F952ED48028004E8522 /* KBFeedBackVC.m in Sources */,
04890A042EC0BBBB00FABA60 /* KBCategoryTitleImageCell.m in Sources */,
04890A052EC0BBBB00FABA60 /* KBCategoryTitleImageView.m in Sources */,
04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */,
04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */,
04286A032ECB0A1600CE730C /* KBSexSelVC.m in Sources */,
048FFD0B2F273BFC005D62AE /* KBAIHomeVC.m in Sources */,
048FFD242F28A836005D62AE /* KBChatLimitPopView.m in Sources */,
046086CC2F1A092500757C95 /* KBAIReplyModel.m in Sources */,
046086CD2F1A092500757C95 /* KBAICommentModel.m in Sources */,
04791F8F2ED469C0004E8522 /* KBHostAppLauncher.m in Sources */,
047C65582EBCC06D0035E841 /* HomeRankCardCell.m in Sources */,
04D1F6B32EDFF10A00B12345 /* KBSkinInstallBridge.m in Sources */,
04122F912EC73AF700EF7AB3 /* KBVipPay.m in Sources */,
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */,
048FFD472F2B45D4005D62AE /* AIPersonInfoVC.m in Sources */,
047C650D2EBC8A840035E841 /* KBPanModalView.m in Sources */,
0450AC0A2EF11E4400B6AF06 /* StoreKitManager.swift in Sources */,
0450AC0B2EF11E4400B6AF06 /* StoreKitStateConverter.swift in Sources */,
@@ -2010,14 +2455,19 @@
0450AC102EF11E4400B6AF06 /* StoreKitDelegate.swift in Sources */,
0450AC112EF11E4400B6AF06 /* StoreKitService.swift in Sources */,
0450AC122EF11E4400B6AF06 /* TransactionConverter.swift in Sources */,
048FFD4A2F2B4AE4005D62AE /* KBAICompanionDetailModel.m in Sources */,
0450AC132EF11E4400B6AF06 /* SubscriptionConverter.swift in Sources */,
0450AC142EF11E4400B6AF06 /* ProductConverter.swift in Sources */,
0450AC152EF11E4400B6AF06 /* TransactionHistory.swift in Sources */,
0450AC162EF11E4400B6AF06 /* StoreKitServiceDelegate.swift in Sources */,
048FFD1D2F277486005D62AE /* KBChatHistoryPageModel.m in Sources */,
048FFD1E2F277486005D62AE /* KBChatHistoryModel.m in Sources */,
048FFD302F29F3C3005D62AE /* KBAIMessageZanVC.m in Sources */,
0450AC172EF11E4400B6AF06 /* StoreKitState.swift in Sources */,
0450AC1B2EF11E4400B6AF06 /* KBStoreKitBridge.swift in Sources */,
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */,
049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */,
046086BD2F1A039F00757C95 /* KBAICommentView.m in Sources */,
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */,
04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */,
04791FFF2ED830FA004E8522 /* KBKeyboardMaskView.m in Sources */,
@@ -2029,6 +2479,7 @@
A1F0C1C32FABCDEF12345678 /* KBInviteCodeModel.m in Sources */,
A1F0C1D32FACAD0012345678 /* KBMaiPointReporter.m in Sources */,
471CAD3574798685B72ADD55 /* KBMyTheme.m in Sources */,
048FFD2D2F29F356005D62AE /* KBAIMessageVC.m in Sources */,
A1F0C1B12F1234567890ABCD /* KBConsumptionRecord.m in Sources */,
A1F0C1B22F1234567890ABCD /* KBConsumptionRecordCell.m in Sources */,
A1F0C1B32F1234567890ABCD /* KBConsumptionRecordVC.m in Sources */,
@@ -2036,8 +2487,13 @@
0498BD712EE02A41006CC1D5 /* KBForgetPwdNewPwdVC.m in Sources */,
048908EF2EBF861800FABA60 /* KBSkinSectionTitleCell.m in Sources */,
0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */,
04E038E82F20E877002CA5A0 /* DeepgramWebSocketClient.m in Sources */,
04E038E92F20E877002CA5A0 /* DeepgramStreamingManager.m in Sources */,
04E0B1022F300001002CA5A0 /* KBVoiceToTextManager.m in Sources */,
04E0B2022F300002002CA5A0 /* KBVoiceRecordManager.m in Sources */,
048908E32EBF821700FABA60 /* KBSkinDetailVC.m in Sources */,
0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */,
048FFD142F274342005D62AE /* KBPersonaChatCell.m in Sources */,
049FB21A2EC20A9E00FAB05D /* KBMyKeyBoardVC.m in Sources */,
049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */,
048908D22EBF611D00FABA60 /* KBHistoryMoreCell.m in Sources */,
@@ -2045,6 +2501,7 @@
0498BD852EE1B255006CC1D5 /* KBSignUtils.m in Sources */,
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */,
04122F7E2EC5FC5500EF7AB3 /* KBJfPayCell.m in Sources */,
048FFD502F2B52E7005D62AE /* AIReportVC.m in Sources */,
049FB2402EC4B6EF00FAB05D /* KBULBridgeNotification.m in Sources */,
04FC95C92EB1E4C9007BD342 /* BaseNavigationController.m in Sources */,
048908DD2EBF67EB00FABA60 /* KBSearchResultVC.m in Sources */,
@@ -2052,6 +2509,8 @@
05A1B2D22F5B1A2B3C4D5E60 /* KBSearchThemeModel.m in Sources */,
047C65102EBCA8DD0035E841 /* HomeRankContentVC.m in Sources */,
047C655C2EBCD0F80035E841 /* UIView+KBShadow.m in Sources */,
04E038DD2F20C420002CA5A0 /* VoiceChatStreamingManager.m in Sources */,
04E038DE2F20C420002CA5A0 /* VoiceChatWebSocketClient.m in Sources */,
049FB2262EC3136D00FAB05D /* KBPersonInfoItemCell.m in Sources */,
048908C32EBE32B800FABA60 /* KBSearchVC.m in Sources */,
049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */,
@@ -2059,6 +2518,7 @@
04FC95DD2EB202A3007BD342 /* KBGuideVC.m in Sources */,
04FC95E52EB220B5007BD342 /* UIColor+Extension.m in Sources */,
048908E02EBF73DC00FABA60 /* MySkinVC.m in Sources */,
048FFD362F29F88E005D62AE /* AIMessageVM.m in Sources */,
048908F22EC047FD00FABA60 /* KBShopHeadView.m in Sources */,
0498BD742EE02E3D006CC1D5 /* KBRegistVerEmailVC.m in Sources */,
049FB2292EC31BB000FAB05D /* KBChangeNicknamePopView.m in Sources */,
@@ -2076,20 +2536,35 @@
04FC97092EB31B14007BD342 /* KBHUD.m in Sources */,
04FC970E2EB334F8007BD342 /* UIImageView+KBWebImage.m in Sources */,
049FB2232EC311F900FAB05D /* KBPersonInfoVC.m in Sources */,
04E038EF2F21F0EC002CA5A0 /* AiVM.m in Sources */,
048FFD102F27432D005D62AE /* KBPersonaModel.m in Sources */,
048FFD112F27432D005D62AE /* KBPersonaPageModel.m in Sources */,
0498BD6B2EE025FC006CC1D5 /* KBForgetPwdVC.m in Sources */,
048FFD182F2763A5005D62AE /* KBVoiceInputBar.m in Sources */,
046086B12F19239B00757C95 /* SubtitleSync.m in Sources */,
046086B22F19239B00757C95 /* TTSServiceClient.m in Sources */,
046086B32F19239B00757C95 /* AudioSessionManager.m in Sources */,
046086B42F19239B00757C95 /* LLMStreamClient.m in Sources */,
046086B52F19239B00757C95 /* Segmenter.m in Sources */,
046086B62F19239B00757C95 /* TTSPlaybackPipeline.m in Sources */,
046086B72F19239B00757C95 /* ConversationOrchestrator.m in Sources */,
046086B82F19239B00757C95 /* ASRStreamClient.m in Sources */,
046086B92F19239B00757C95 /* AudioCaptureManager.m in Sources */,
046086BA2F19239B00757C95 /* AudioStreamPlayer.m in Sources */,
048908FE2EC0CC2400FABA60 /* UIScrollView+KBEmptyView.m in Sources */,
0498BD7E2EE04F9C006CC1D5 /* KBTag.m in Sources */,
04791F922ED48010004E8522 /* KBNoticeVC.m in Sources */,
04FC970F2EB334F8007BD342 /* KBWebImageManager.m in Sources */,
04FC95CF2EB1E7A1007BD342 /* HomeVC.m in Sources */,
0498BDDE2EE81508006CC1D5 /* KBShopVM.m in Sources */,
049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */,
048FFD392F2A24C5005D62AE /* KBAIChatMessageCacheManager.m in Sources */,
A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */,
0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */,
04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */,
048908DA2EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout.m in Sources */,
04C6EABF2EAF86530089C901 /* main.m in Sources */,
0498BD6E2EE0285D006CC1D5 /* KBForgetVerPwdVC.m in Sources */,
048FFD2A2F28E99A005D62AE /* KBCommentModel.m in Sources */,
0498BDE12EEA87C9006CC1D5 /* KBShopStyleModel.m in Sources */,
49B63DBAEE9076C591E13D68 /* KBShopThemeTagModel.m in Sources */,
EB72B60040437E3C0A4890FC /* KBShopThemeDetailModel.m in Sources */,
@@ -2104,6 +2579,9 @@
047C65502EBCBA9E0035E841 /* KBShopVC.m in Sources */,
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */,
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */,
04E039522F2387D2002CA5A0 /* KBAiChatMessage.m in Sources */,
0460869A2F19238500757C95 /* KBAiWaveformView.m in Sources */,
0460869C2F19238500757C95 /* KBAiRecordButton.m in Sources */,
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */,
0498BD622EDFFC12006CC1D5 /* KBMyVM.m in Sources */,
049FB2432EC4BBB700FAB05D /* KBLoginPopView.m in Sources */,
@@ -2117,11 +2595,13 @@
0477BEA22EBCF0000055D639 /* KBTopImageButton.m in Sources */,
A1B2E1012EBC7AAA00000001 /* KBTopThreeView.m in Sources */,
A1B2E1022EBC7AAA00000001 /* HomeHotCell.m in Sources */,
048FFD272F28C6CF005D62AE /* KBImagePositionButton.m in Sources */,
0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */,
04286A002ECAEF2B00CE730C /* KBMoneyBtn.m in Sources */,
048908F52EC0496400FABA60 /* KBShopItemVC.m in Sources */,
04FC95F42EB339C1007BD342 /* AppleSignInManager.m in Sources */,
04C6EAC12EAF86530089C901 /* ViewController.m in Sources */,
04E0383E2F1A7C30002CA5A0 /* KBCustomTabBar.m in Sources */,
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */,
A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */,
0498BD682EE01180006CC1D5 /* KBEmailRegistVC.m in Sources */,
@@ -2263,6 +2743,9 @@
INFOPLIST_FILE = keyBoard/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Key of Love";
INFOPLIST_KEY_CFBundleURLTypes = "{\n CFBundleURLName = \"com.loveKey.nyx.keyboard\";\n CFBundleURLSchemes = (\n kbkeyboardAppExtension\n );\n}";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "需要使用麦克风进行语音输入";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "保存图片需要写入您的相册";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "更换头像需要访问您的相册";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
@@ -2311,6 +2794,9 @@
INFOPLIST_FILE = keyBoard/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Key of Love";
INFOPLIST_KEY_CFBundleURLTypes = "{\n CFBundleURLName = \"com.loveKey.nyx.keyboard\";\n CFBundleURLSchemes = (\n kbkeyboardAppExtension\n );\n}";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "需要使用麦克风进行语音输入";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "保存图片需要写入您的相册";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "更换头像需要访问您的相册";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;

View File

@@ -190,7 +190,7 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
} else if ([host isEqualToString:@"settings"]) { // kbkeyboard://settings
[self kb_openAppSettings];
return YES;
}else if ([host isEqualToString:@"recharge"]) { // kbkeyboard://recharge
} else if ([host isEqualToString:@"recharge"]) { // kbkeyboard://recharge
NSDictionary<NSString *, NSString *> *params = [self kb_queryParametersFromURL:url];
NSString *productId = params[@"productId"];
BOOL autoPay = NO;

View File

@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_close_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_close_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_comment_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_comment_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_jianpan_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_jianpan_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_live_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_live_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_livesel_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_livesel_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_luyining_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_luyining_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_maikefeng_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_maikefeng_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_message_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_message_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_report_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_report_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ai_sendmessage_icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ai_sendmessage_icon@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Some files were not shown because too many files have changed in this diff Show More